1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 20:17:44 +00:00

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.
This commit is contained in:
Andreas Kling 2021-01-23 13:20:24 +01:00
parent 5b91362d4e
commit 25056830f0

View file

@ -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"~~~(