From 25056830f02f68c1819ef68988ca8e9e2ed4258e Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sat, 23 Jan 2021 13:20:24 +0100 Subject: [PATCH] LibWeb: Add very basic support for IDL constants You can now put constants on an IDL interface and they will pop up on both the constructor and prototype objects. --- .../CodeGenerators/WrapperGenerator.cpp | 65 ++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/Userland/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp b/Userland/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp index 7df091e171..3d2f7f5519 100644 --- a/Userland/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp +++ b/Userland/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Andreas Kling + * Copyright (c) 2020-2021, Andreas Kling * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -136,6 +136,12 @@ struct Function { } }; +struct Constant { + Type type; + String name; + String value; +}; + struct Attribute { bool readonly { false }; bool unsigned_ { false }; @@ -153,6 +159,7 @@ struct Interface { String parent_name; Vector attributes; + Vector constants; Vector functions; // Added for convenience after parsing @@ -237,6 +244,27 @@ static OwnPtr parse_interface(StringView filename, const StringView& interface->attributes.append(move(attribute)); }; + auto parse_constant = [&] { + lexer.consume_specific("const"); + consume_whitespace(); + + Constant constant; + bool unsigned_ = lexer.consume_specific("unsigned"); + if (unsigned_) + consume_whitespace(); + constant.type = parse_type(); + consume_whitespace(); + constant.name = lexer.consume_until([](auto ch) { return isspace(ch) || ch == '='; }); + consume_whitespace(); + lexer.consume_specific('='); + consume_whitespace(); + constant.value = lexer.consume_while([](auto ch) { return !isspace(ch) && ch != ';'; }); + consume_whitespace(); + assert_specific(';'); + + interface->constants.append(move(constant)); + }; + auto parse_function = [&](HashMap& extended_attributes) { auto return_type = parse_type(); consume_whitespace(); @@ -302,6 +330,11 @@ static OwnPtr parse_interface(StringView filename, const StringView& extended_attributes = parse_extended_attributes(); } + if (lexer.next_is("const")) { + parse_constant(); + continue; + } + if (lexer.next_is("readonly") || lexer.next_is("attribute")) { parse_attribute(extended_attributes); continue; @@ -748,6 +781,20 @@ void @constructor_class@::initialize(JS::GlobalObject& global_object) NativeFunction::initialize(global_object); define_property(vm.names.prototype, &window.ensure_web_prototype<@prototype_class@>("@name@"), 0); define_property(vm.names.length, JS::Value(1), JS::Attribute::Configurable); + +)~~~"); + + for (auto& constant : interface.constants) { + auto constant_generator = generator.fork(); + constant_generator.set("constant.name", constant.name); + constant_generator.set("constant.value", constant.value); + + constant_generator.append(R"~~~( +define_property("@constant.name@", JS::Value((i32)@constant.value@), JS::Attribute::Enumerable); +)~~~"); + } + + generator.append(R"~~~( } } // namespace Web::Bindings @@ -922,6 +969,16 @@ void @prototype_class@::initialize(JS::GlobalObject& global_object) )~~~"); } + for (auto& constant : interface.constants) { + auto constant_generator = generator.fork(); + constant_generator.set("constant.name", constant.name); + constant_generator.set("constant.value", constant.value); + + constant_generator.append(R"~~~( + define_property("@constant.name@", JS::Value((i32)@constant.value@), JS::Attribute::Enumerable); +)~~~"); + } + for (auto& function : interface.functions) { auto function_generator = generator.fork(); function_generator.set("function.name", function.name); @@ -1093,9 +1150,13 @@ static @fully_qualified_name@* impl_from(JS::VM& vm, JS::GlobalObject& global_ob return new_array; )~~~"); - } else if (return_type.name == "long" || return_type.name == "double" || return_type.name == "boolean" || return_type.name == "short") { + } else if (return_type.name == "boolean" || return_type.name == "double" || return_type.name == "long") { scoped_generator.append(R"~~~( return JS::Value(retval); +)~~~"); + } else if (return_type.name == "short") { + scoped_generator.append(R"~~~( + return JS::Value((i32)retval); )~~~"); } else if (return_type.name == "Uint8ClampedArray") { scoped_generator.append(R"~~~(