Forráskód Böngészése

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.
Andreas Kling 4 éve
szülő
commit
25056830f0

+ 63 - 2
Userland/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org>
  * 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<Attribute> attributes;
+    Vector<Constant> constants;
     Vector<Function> functions;
 
     // Added for convenience after parsing
@@ -237,6 +244,27 @@ static OwnPtr<Interface> 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<String, String>& extended_attributes) {
         auto return_type = parse_type();
         consume_whitespace();
@@ -302,6 +330,11 @@ static OwnPtr<Interface> 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"~~~(