mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-06-10 01:51:03 +09:00
LibWeb: Convert ArrayFromVector wrapper to instead be sequence<T>
This adds the ParamatizedType, as `Vector<String>` doesn't encode the full type information. It is a separate struct as you can't have `Vector<Type>` inside of `Type`. This also makes Type RefCounted because I had to make parse_type return a pointer to make dynamic casting work correctly. The reason I made it RefCounted instead of using a NonnullOwnPtr is because it causes compiler errors that I don't want to figure out right now.
This commit is contained in:
parent
8e4d53f216
commit
cb821e1539
Notes:
sideshowbarker
2024-07-18 02:17:53 +09:00
Author: https://github.com/Lubrsi
Commit: cb821e1539
Pull-request: https://github.com/SerenityOS/serenity/pull/10500
Reviewed-by: https://github.com/IdanHo ✅
1 changed files with 163 additions and 91 deletions
|
@ -81,15 +81,38 @@ static size_t get_function_length(FunctionType& function)
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Type {
|
struct Type : public RefCounted<Type> {
|
||||||
|
Type() = default;
|
||||||
|
|
||||||
|
Type(String name, bool nullable)
|
||||||
|
: name(move(name))
|
||||||
|
, nullable(nullable)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~Type() = default;
|
||||||
|
|
||||||
String name;
|
String name;
|
||||||
Vector<String> parameters;
|
|
||||||
bool nullable { false };
|
bool nullable { false };
|
||||||
bool is_string() const { return name.is_one_of("ByteString", "CSSOMString", "DOMString", "USVString"); }
|
bool is_string() const { return name.is_one_of("ByteString", "CSSOMString", "DOMString", "USVString"); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ParameterizedType : public Type {
|
||||||
|
ParameterizedType() = default;
|
||||||
|
|
||||||
|
ParameterizedType(String name, bool nullable, NonnullRefPtrVector<Type> parameters)
|
||||||
|
: Type(move(name), nullable)
|
||||||
|
, parameters(move(parameters))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~ParameterizedType() override = default;
|
||||||
|
|
||||||
|
NonnullRefPtrVector<Type> parameters;
|
||||||
|
};
|
||||||
|
|
||||||
struct Parameter {
|
struct Parameter {
|
||||||
Type type;
|
NonnullRefPtr<Type> type;
|
||||||
String name;
|
String name;
|
||||||
bool optional { false };
|
bool optional { false };
|
||||||
Optional<String> optional_default_value;
|
Optional<String> optional_default_value;
|
||||||
|
@ -97,7 +120,7 @@ struct Parameter {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Function {
|
struct Function {
|
||||||
Type return_type;
|
NonnullRefPtr<Type> return_type;
|
||||||
String name;
|
String name;
|
||||||
Vector<Parameter> parameters;
|
Vector<Parameter> parameters;
|
||||||
HashMap<String, String> extended_attributes;
|
HashMap<String, String> extended_attributes;
|
||||||
|
@ -113,14 +136,14 @@ struct Constructor {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Constant {
|
struct Constant {
|
||||||
Type type;
|
NonnullRefPtr<Type> type;
|
||||||
String name;
|
String name;
|
||||||
String value;
|
String value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Attribute {
|
struct Attribute {
|
||||||
bool readonly { false };
|
bool readonly { false };
|
||||||
Type type;
|
NonnullRefPtr<Type> type;
|
||||||
String name;
|
String name;
|
||||||
HashMap<String, String> extended_attributes;
|
HashMap<String, String> extended_attributes;
|
||||||
|
|
||||||
|
@ -131,7 +154,7 @@ struct Attribute {
|
||||||
|
|
||||||
struct DictionaryMember {
|
struct DictionaryMember {
|
||||||
bool required { false };
|
bool required { false };
|
||||||
Type type;
|
NonnullRefPtr<Type> type;
|
||||||
String name;
|
String name;
|
||||||
HashMap<String, String> extended_attributes;
|
HashMap<String, String> extended_attributes;
|
||||||
Optional<String> default_value;
|
Optional<String> default_value;
|
||||||
|
@ -157,8 +180,8 @@ struct Interface {
|
||||||
Optional<String> stringifier_attribute;
|
Optional<String> stringifier_attribute;
|
||||||
bool has_unscopable_member { false };
|
bool has_unscopable_member { false };
|
||||||
|
|
||||||
Optional<Type> value_iterator_type;
|
Optional<NonnullRefPtr<Type>> value_iterator_type;
|
||||||
Optional<Tuple<Type, Type>> pair_iterator_types;
|
Optional<Tuple<NonnullRefPtr<Type>, NonnullRefPtr<Type>>> pair_iterator_types;
|
||||||
|
|
||||||
Optional<Function> named_property_getter;
|
Optional<Function> named_property_getter;
|
||||||
Optional<Function> named_property_setter;
|
Optional<Function> named_property_setter;
|
||||||
|
@ -259,7 +282,7 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView
|
||||||
if (lexer.consume_specific('['))
|
if (lexer.consume_specific('['))
|
||||||
interface->extended_attributes = parse_extended_attributes();
|
interface->extended_attributes = parse_extended_attributes();
|
||||||
|
|
||||||
auto parse_type = [&] {
|
AK::Function<NonnullRefPtr<Type>()> parse_type = [&]() -> NonnullRefPtr<Type> {
|
||||||
auto consume_name = [&] {
|
auto consume_name = [&] {
|
||||||
return lexer.consume_until([](auto ch) { return !isalnum(ch) && ch != '_'; });
|
return lexer.consume_until([](auto ch) { return !isalnum(ch) && ch != '_'; });
|
||||||
};
|
};
|
||||||
|
@ -267,10 +290,12 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView
|
||||||
if (unsigned_)
|
if (unsigned_)
|
||||||
consume_whitespace();
|
consume_whitespace();
|
||||||
auto name = consume_name();
|
auto name = consume_name();
|
||||||
Vector<String> parameters;
|
NonnullRefPtrVector<Type> parameters;
|
||||||
|
bool is_parameterized_type = false;
|
||||||
if (lexer.consume_specific('<')) {
|
if (lexer.consume_specific('<')) {
|
||||||
|
is_parameterized_type = true;
|
||||||
// TODO: Parse multiple parameters if necessary
|
// TODO: Parse multiple parameters if necessary
|
||||||
parameters.append(consume_name());
|
parameters.append(parse_type());
|
||||||
lexer.consume_specific('>');
|
lexer.consume_specific('>');
|
||||||
}
|
}
|
||||||
auto nullable = lexer.consume_specific('?');
|
auto nullable = lexer.consume_specific('?');
|
||||||
|
@ -278,7 +303,11 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView
|
||||||
if (unsigned_)
|
if (unsigned_)
|
||||||
builder.append("unsigned ");
|
builder.append("unsigned ");
|
||||||
builder.append(name);
|
builder.append(name);
|
||||||
return Type { builder.to_string(), parameters, nullable };
|
|
||||||
|
if (is_parameterized_type)
|
||||||
|
return adopt_ref(*new ParameterizedType(builder.to_string(), nullable, move(parameters)));
|
||||||
|
|
||||||
|
return adopt_ref(*new Type(builder.to_string(), nullable));
|
||||||
};
|
};
|
||||||
|
|
||||||
auto parse_attribute = [&](HashMap<String, String>& extended_attributes) {
|
auto parse_attribute = [&](HashMap<String, String>& extended_attributes) {
|
||||||
|
@ -295,13 +324,19 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView
|
||||||
consume_whitespace();
|
consume_whitespace();
|
||||||
|
|
||||||
assert_specific(';');
|
assert_specific(';');
|
||||||
Attribute attribute;
|
|
||||||
attribute.readonly = readonly;
|
auto name_as_string = name.to_string();
|
||||||
attribute.type = type;
|
auto getter_callback_name = String::formatted("{}_getter", name_as_string.to_snakecase());
|
||||||
attribute.name = name;
|
auto setter_callback_name = String::formatted("{}_setter", name_as_string.to_snakecase());
|
||||||
attribute.getter_callback_name = String::formatted("{}_getter", attribute.name.to_snakecase());
|
|
||||||
attribute.setter_callback_name = String::formatted("{}_setter", attribute.name.to_snakecase());
|
Attribute attribute {
|
||||||
attribute.extended_attributes = move(extended_attributes);
|
readonly,
|
||||||
|
move(type),
|
||||||
|
move(name_as_string),
|
||||||
|
move(extended_attributes),
|
||||||
|
move(getter_callback_name),
|
||||||
|
move(setter_callback_name),
|
||||||
|
};
|
||||||
interface->attributes.append(move(attribute));
|
interface->attributes.append(move(attribute));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -309,17 +344,21 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView
|
||||||
lexer.consume_specific("const");
|
lexer.consume_specific("const");
|
||||||
consume_whitespace();
|
consume_whitespace();
|
||||||
|
|
||||||
Constant constant;
|
auto type = parse_type();
|
||||||
constant.type = parse_type();
|
|
||||||
consume_whitespace();
|
consume_whitespace();
|
||||||
constant.name = lexer.consume_until([](auto ch) { return isspace(ch) || ch == '='; });
|
auto name = lexer.consume_until([](auto ch) { return isspace(ch) || ch == '='; });
|
||||||
consume_whitespace();
|
consume_whitespace();
|
||||||
lexer.consume_specific('=');
|
lexer.consume_specific('=');
|
||||||
consume_whitespace();
|
consume_whitespace();
|
||||||
constant.value = lexer.consume_while([](auto ch) { return !isspace(ch) && ch != ';'; });
|
auto value = lexer.consume_while([](auto ch) { return !isspace(ch) && ch != ';'; });
|
||||||
consume_whitespace();
|
consume_whitespace();
|
||||||
assert_specific(';');
|
assert_specific(';');
|
||||||
|
|
||||||
|
Constant constant {
|
||||||
|
move(type),
|
||||||
|
move(name),
|
||||||
|
move(value),
|
||||||
|
};
|
||||||
interface->constants.append(move(constant));
|
interface->constants.append(move(constant));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -452,7 +491,7 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView
|
||||||
|
|
||||||
auto& identifier = function.parameters.first();
|
auto& identifier = function.parameters.first();
|
||||||
|
|
||||||
if (identifier.type.nullable)
|
if (identifier.type->nullable)
|
||||||
report_parsing_error("identifier's type must not be nullable.", filename, input, lexer.tell());
|
report_parsing_error("identifier's type must not be nullable.", filename, input, lexer.tell());
|
||||||
|
|
||||||
if (identifier.optional)
|
if (identifier.optional)
|
||||||
|
@ -460,18 +499,18 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView
|
||||||
|
|
||||||
// FIXME: Disallow variadic functions once they're supported.
|
// FIXME: Disallow variadic functions once they're supported.
|
||||||
|
|
||||||
if (identifier.type.name == "DOMString") {
|
if (identifier.type->name == "DOMString") {
|
||||||
if (interface->named_property_getter.has_value())
|
if (interface->named_property_getter.has_value())
|
||||||
report_parsing_error("An interface can only have one named property getter.", filename, input, lexer.tell());
|
report_parsing_error("An interface can only have one named property getter.", filename, input, lexer.tell());
|
||||||
|
|
||||||
interface->named_property_getter = move(function);
|
interface->named_property_getter = move(function);
|
||||||
} else if (identifier.type.name == "unsigned long") {
|
} else if (identifier.type->name == "unsigned long") {
|
||||||
if (interface->indexed_property_getter.has_value())
|
if (interface->indexed_property_getter.has_value())
|
||||||
report_parsing_error("An interface can only have one indexed property getter.", filename, input, lexer.tell());
|
report_parsing_error("An interface can only have one indexed property getter.", filename, input, lexer.tell());
|
||||||
|
|
||||||
interface->indexed_property_getter = move(function);
|
interface->indexed_property_getter = move(function);
|
||||||
} else {
|
} else {
|
||||||
report_parsing_error(String::formatted("Named/indexed property getter's identifier's type must be either 'DOMString' or 'unsigned long', got '{}'.", identifier.type.name), filename, input, lexer.tell());
|
report_parsing_error(String::formatted("Named/indexed property getter's identifier's type must be either 'DOMString' or 'unsigned long', got '{}'.", identifier.type->name), filename, input, lexer.tell());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -485,7 +524,7 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView
|
||||||
|
|
||||||
auto& identifier = function.parameters.first();
|
auto& identifier = function.parameters.first();
|
||||||
|
|
||||||
if (identifier.type.nullable)
|
if (identifier.type->nullable)
|
||||||
report_parsing_error("identifier's type must not be nullable.", filename, input, lexer.tell());
|
report_parsing_error("identifier's type must not be nullable.", filename, input, lexer.tell());
|
||||||
|
|
||||||
if (identifier.optional)
|
if (identifier.optional)
|
||||||
|
@ -493,7 +532,7 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView
|
||||||
|
|
||||||
// FIXME: Disallow variadic functions once they're supported.
|
// FIXME: Disallow variadic functions once they're supported.
|
||||||
|
|
||||||
if (identifier.type.name == "DOMString") {
|
if (identifier.type->name == "DOMString") {
|
||||||
if (interface->named_property_setter.has_value())
|
if (interface->named_property_setter.has_value())
|
||||||
report_parsing_error("An interface can only have one named property setter.", filename, input, lexer.tell());
|
report_parsing_error("An interface can only have one named property setter.", filename, input, lexer.tell());
|
||||||
|
|
||||||
|
@ -501,7 +540,7 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView
|
||||||
report_parsing_error("A named property setter must be accompanied by a named property getter.", filename, input, lexer.tell());
|
report_parsing_error("A named property setter must be accompanied by a named property getter.", filename, input, lexer.tell());
|
||||||
|
|
||||||
interface->named_property_setter = move(function);
|
interface->named_property_setter = move(function);
|
||||||
} else if (identifier.type.name == "unsigned long") {
|
} else if (identifier.type->name == "unsigned long") {
|
||||||
if (interface->indexed_property_setter.has_value())
|
if (interface->indexed_property_setter.has_value())
|
||||||
report_parsing_error("An interface can only have one indexed property setter.", filename, input, lexer.tell());
|
report_parsing_error("An interface can only have one indexed property setter.", filename, input, lexer.tell());
|
||||||
|
|
||||||
|
@ -510,7 +549,7 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView
|
||||||
|
|
||||||
interface->indexed_property_setter = move(function);
|
interface->indexed_property_setter = move(function);
|
||||||
} else {
|
} else {
|
||||||
report_parsing_error(String::formatted("Named/indexed property setter's identifier's type must be either 'DOMString' or 'unsigned long', got '{}'.", identifier.type.name), filename, input, lexer.tell());
|
report_parsing_error(String::formatted("Named/indexed property setter's identifier's type must be either 'DOMString' or 'unsigned long', got '{}'.", identifier.type->name), filename, input, lexer.tell());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -524,7 +563,7 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView
|
||||||
|
|
||||||
auto& identifier = function.parameters.first();
|
auto& identifier = function.parameters.first();
|
||||||
|
|
||||||
if (identifier.type.nullable)
|
if (identifier.type->nullable)
|
||||||
report_parsing_error("identifier's type must not be nullable.", filename, input, lexer.tell());
|
report_parsing_error("identifier's type must not be nullable.", filename, input, lexer.tell());
|
||||||
|
|
||||||
if (identifier.optional)
|
if (identifier.optional)
|
||||||
|
@ -532,7 +571,7 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView
|
||||||
|
|
||||||
// FIXME: Disallow variadic functions once they're supported.
|
// FIXME: Disallow variadic functions once they're supported.
|
||||||
|
|
||||||
if (identifier.type.name == "DOMString") {
|
if (identifier.type->name == "DOMString") {
|
||||||
if (interface->named_property_deleter.has_value())
|
if (interface->named_property_deleter.has_value())
|
||||||
report_parsing_error("An interface can only have one named property deleter.", filename, input, lexer.tell());
|
report_parsing_error("An interface can only have one named property deleter.", filename, input, lexer.tell());
|
||||||
|
|
||||||
|
@ -541,7 +580,7 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView
|
||||||
|
|
||||||
interface->named_property_deleter = move(function);
|
interface->named_property_deleter = move(function);
|
||||||
} else {
|
} else {
|
||||||
report_parsing_error(String::formatted("Named property deleter's identifier's type must be 'DOMString', got '{}'.", identifier.type.name), filename, input, lexer.tell());
|
report_parsing_error(String::formatted("Named property deleter's identifier's type must be 'DOMString', got '{}'.", identifier.type->name), filename, input, lexer.tell());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -649,29 +688,40 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
DictionaryMember member {};
|
bool required = false;
|
||||||
|
HashMap<String, String> extended_attributes;
|
||||||
|
|
||||||
if (lexer.consume_specific("required")) {
|
if (lexer.consume_specific("required")) {
|
||||||
member.required = true;
|
required = true;
|
||||||
consume_whitespace();
|
consume_whitespace();
|
||||||
if (lexer.consume_specific('['))
|
if (lexer.consume_specific('['))
|
||||||
member.extended_attributes = parse_extended_attributes();
|
extended_attributes = parse_extended_attributes();
|
||||||
}
|
}
|
||||||
|
|
||||||
member.type = parse_type();
|
auto type = parse_type();
|
||||||
consume_whitespace();
|
consume_whitespace();
|
||||||
|
|
||||||
member.name = lexer.consume_until([](auto ch) { return isspace(ch) || ch == ';'; });
|
auto name = lexer.consume_until([](auto ch) { return isspace(ch) || ch == ';'; });
|
||||||
consume_whitespace();
|
consume_whitespace();
|
||||||
|
|
||||||
|
Optional<StringView> default_value;
|
||||||
|
|
||||||
if (lexer.consume_specific('=')) {
|
if (lexer.consume_specific('=')) {
|
||||||
VERIFY(!member.required);
|
VERIFY(!required);
|
||||||
consume_whitespace();
|
consume_whitespace();
|
||||||
auto default_value = lexer.consume_until([](auto ch) { return isspace(ch) || ch == ';'; });
|
default_value = lexer.consume_until([](auto ch) { return isspace(ch) || ch == ';'; });
|
||||||
member.default_value = default_value;
|
|
||||||
consume_whitespace();
|
consume_whitespace();
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_specific(';');
|
assert_specific(';');
|
||||||
|
|
||||||
|
DictionaryMember member {
|
||||||
|
required,
|
||||||
|
move(type),
|
||||||
|
move(name),
|
||||||
|
move(extended_attributes),
|
||||||
|
default_value.has_value() ? default_value.value() : Optional<String> {},
|
||||||
|
};
|
||||||
dictionary.members.append(move(member));
|
dictionary.members.append(move(member));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -765,21 +815,21 @@ int main(int argc, char** argv)
|
||||||
for (auto& attribute : interface->attributes) {
|
for (auto& attribute : interface->attributes) {
|
||||||
dbgln(" {}{}{} {}",
|
dbgln(" {}{}{} {}",
|
||||||
attribute.readonly ? "readonly " : "",
|
attribute.readonly ? "readonly " : "",
|
||||||
attribute.type.name,
|
attribute.type->name,
|
||||||
attribute.type.nullable ? "?" : "",
|
attribute.type->nullable ? "?" : "",
|
||||||
attribute.name);
|
attribute.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
dbgln("Functions:");
|
dbgln("Functions:");
|
||||||
for (auto& function : interface->functions) {
|
for (auto& function : interface->functions) {
|
||||||
dbgln(" {}{} {}",
|
dbgln(" {}{} {}",
|
||||||
function.return_type.name,
|
function.return_type->name,
|
||||||
function.return_type.nullable ? "?" : "",
|
function.return_type->nullable ? "?" : "",
|
||||||
function.name);
|
function.name);
|
||||||
for (auto& parameter : function.parameters) {
|
for (auto& parameter : function.parameters) {
|
||||||
dbgln(" {}{} {}",
|
dbgln(" {}{} {}",
|
||||||
parameter.type.name,
|
parameter.type->name,
|
||||||
parameter.type.nullable ? "?" : "",
|
parameter.type->nullable ? "?" : "",
|
||||||
parameter.name);
|
parameter.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -787,13 +837,13 @@ int main(int argc, char** argv)
|
||||||
dbgln("Static Functions:");
|
dbgln("Static Functions:");
|
||||||
for (auto& function : interface->static_functions) {
|
for (auto& function : interface->static_functions) {
|
||||||
dbgln(" static {}{} {}",
|
dbgln(" static {}{} {}",
|
||||||
function.return_type.name,
|
function.return_type->name,
|
||||||
function.return_type.nullable ? "?" : "",
|
function.return_type->nullable ? "?" : "",
|
||||||
function.name);
|
function.name);
|
||||||
for (auto& parameter : function.parameters) {
|
for (auto& parameter : function.parameters) {
|
||||||
dbgln(" {}{} {}",
|
dbgln(" {}{} {}",
|
||||||
parameter.type.name,
|
parameter.type->name,
|
||||||
parameter.type.nullable ? "?" : "",
|
parameter.type->nullable ? "?" : "",
|
||||||
parameter.name);
|
parameter.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -887,11 +937,11 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
||||||
scoped_generator.set("js_name", js_name);
|
scoped_generator.set("js_name", js_name);
|
||||||
scoped_generator.set("js_suffix", js_suffix);
|
scoped_generator.set("js_suffix", js_suffix);
|
||||||
scoped_generator.set("legacy_null_to_empty_string", legacy_null_to_empty_string ? "true" : "false");
|
scoped_generator.set("legacy_null_to_empty_string", legacy_null_to_empty_string ? "true" : "false");
|
||||||
scoped_generator.set("parameter.type.name", parameter.type.name);
|
scoped_generator.set("parameter.type.name", parameter.type->name);
|
||||||
if (parameter.type.name == "Window")
|
if (parameter.type->name == "Window")
|
||||||
scoped_generator.set("wrapper_name", "WindowObject");
|
scoped_generator.set("wrapper_name", "WindowObject");
|
||||||
else
|
else
|
||||||
scoped_generator.set("wrapper_name", String::formatted("{}Wrapper", parameter.type.name));
|
scoped_generator.set("wrapper_name", String::formatted("{}Wrapper", parameter.type->name));
|
||||||
|
|
||||||
if (optional_default_value.has_value())
|
if (optional_default_value.has_value())
|
||||||
scoped_generator.set("parameter.optional_default_value", *optional_default_value);
|
scoped_generator.set("parameter.optional_default_value", *optional_default_value);
|
||||||
|
@ -902,9 +952,9 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
||||||
scoped_generator.set("return_statement", "return {};");
|
scoped_generator.set("return_statement", "return {};");
|
||||||
|
|
||||||
// FIXME: Add support for optional, nullable and default values to all types
|
// FIXME: Add support for optional, nullable and default values to all types
|
||||||
if (parameter.type.is_string()) {
|
if (parameter.type->is_string()) {
|
||||||
if (!optional) {
|
if (!optional) {
|
||||||
if (!parameter.type.nullable) {
|
if (!parameter.type->nullable) {
|
||||||
scoped_generator.append(R"~~~(
|
scoped_generator.append(R"~~~(
|
||||||
String @cpp_name@;
|
String @cpp_name@;
|
||||||
if (@js_name@@js_suffix@.is_null() && @legacy_null_to_empty_string@) {
|
if (@js_name@@js_suffix@.is_null() && @legacy_null_to_empty_string@) {
|
||||||
|
@ -940,7 +990,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
||||||
@cpp_name@ = to_string_result.release_value();
|
@cpp_name@ = to_string_result.release_value();
|
||||||
}
|
}
|
||||||
})~~~");
|
})~~~");
|
||||||
if (optional_default_value.has_value() && (!parameter.type.nullable || optional_default_value.value() != "null")) {
|
if (optional_default_value.has_value() && (!parameter.type->nullable || optional_default_value.value() != "null")) {
|
||||||
scoped_generator.append(R"~~~( else {
|
scoped_generator.append(R"~~~( else {
|
||||||
@cpp_name@ = @parameter.optional_default_value@;
|
@cpp_name@ = @parameter.optional_default_value@;
|
||||||
}
|
}
|
||||||
|
@ -950,8 +1000,8 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
||||||
)~~~");
|
)~~~");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (parameter.type.name == "EventListener") {
|
} else if (parameter.type->name == "EventListener") {
|
||||||
if (parameter.type.nullable) {
|
if (parameter.type->nullable) {
|
||||||
scoped_generator.append(R"~~~(
|
scoped_generator.append(R"~~~(
|
||||||
RefPtr<EventListener> @cpp_name@;
|
RefPtr<EventListener> @cpp_name@;
|
||||||
if (!@js_name@@js_suffix@.is_nullish()) {
|
if (!@js_name@@js_suffix@.is_nullish()) {
|
||||||
|
@ -971,8 +1021,8 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
||||||
auto @cpp_name@ = adopt_ref(*new EventListener(JS::make_handle(&@js_name@@js_suffix@.as_function())));
|
auto @cpp_name@ = adopt_ref(*new EventListener(JS::make_handle(&@js_name@@js_suffix@.as_function())));
|
||||||
)~~~");
|
)~~~");
|
||||||
}
|
}
|
||||||
} else if (is_wrappable_type(parameter.type)) {
|
} else if (is_wrappable_type(*parameter.type)) {
|
||||||
if (!parameter.type.nullable) {
|
if (!parameter.type->nullable) {
|
||||||
scoped_generator.append(R"~~~(
|
scoped_generator.append(R"~~~(
|
||||||
auto @cpp_name@_object_or_error = @js_name@@js_suffix@.to_object(global_object);
|
auto @cpp_name@_object_or_error = @js_name@@js_suffix@.to_object(global_object);
|
||||||
if (@cpp_name@_object_or_error.is_error())
|
if (@cpp_name@_object_or_error.is_error())
|
||||||
|
@ -1004,7 +1054,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
||||||
}
|
}
|
||||||
)~~~");
|
)~~~");
|
||||||
}
|
}
|
||||||
} else if (parameter.type.name == "double") {
|
} else if (parameter.type->name == "double") {
|
||||||
if (!optional) {
|
if (!optional) {
|
||||||
scoped_generator.append(R"~~~(
|
scoped_generator.append(R"~~~(
|
||||||
double @cpp_name@ = @js_name@@js_suffix@.to_double(global_object);
|
double @cpp_name@ = @js_name@@js_suffix@.to_double(global_object);
|
||||||
|
@ -1038,7 +1088,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
||||||
)~~~");
|
)~~~");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (parameter.type.name == "boolean") {
|
} else if (parameter.type->name == "boolean") {
|
||||||
if (!optional) {
|
if (!optional) {
|
||||||
scoped_generator.append(R"~~~(
|
scoped_generator.append(R"~~~(
|
||||||
bool @cpp_name@ = @js_name@@js_suffix@.to_boolean();
|
bool @cpp_name@ = @js_name@@js_suffix@.to_boolean();
|
||||||
|
@ -1066,25 +1116,25 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
||||||
)~~~");
|
)~~~");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (parameter.type.name == "unsigned long") {
|
} else if (parameter.type->name == "unsigned long") {
|
||||||
scoped_generator.append(R"~~~(
|
scoped_generator.append(R"~~~(
|
||||||
auto @cpp_name@ = @js_name@@js_suffix@.to_u32(global_object);
|
auto @cpp_name@ = @js_name@@js_suffix@.to_u32(global_object);
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
@return_statement@
|
@return_statement@
|
||||||
)~~~");
|
)~~~");
|
||||||
} else if (parameter.type.name == "unsigned short") {
|
} else if (parameter.type->name == "unsigned short") {
|
||||||
scoped_generator.append(R"~~~(
|
scoped_generator.append(R"~~~(
|
||||||
auto @cpp_name@ = (u16)@js_name@@js_suffix@.to_u32(global_object);
|
auto @cpp_name@ = (u16)@js_name@@js_suffix@.to_u32(global_object);
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
@return_statement@
|
@return_statement@
|
||||||
)~~~");
|
)~~~");
|
||||||
} else if (parameter.type.name == "long") {
|
} else if (parameter.type->name == "long") {
|
||||||
scoped_generator.append(R"~~~(
|
scoped_generator.append(R"~~~(
|
||||||
auto @cpp_name@ = @js_name@@js_suffix@.to_i32(global_object);
|
auto @cpp_name@ = @js_name@@js_suffix@.to_i32(global_object);
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
@return_statement@
|
@return_statement@
|
||||||
)~~~");
|
)~~~");
|
||||||
} else if (parameter.type.name == "EventHandler") {
|
} else if (parameter.type->name == "EventHandler") {
|
||||||
// x.onfoo = function() { ... }
|
// x.onfoo = function() { ... }
|
||||||
scoped_generator.append(R"~~~(
|
scoped_generator.append(R"~~~(
|
||||||
HTML::EventHandler @cpp_name@;
|
HTML::EventHandler @cpp_name@;
|
||||||
|
@ -1096,7 +1146,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
||||||
return JS::js_undefined();
|
return JS::js_undefined();
|
||||||
}
|
}
|
||||||
)~~~");
|
)~~~");
|
||||||
} else if (parameter.type.name == "Promise") {
|
} else if (parameter.type->name == "Promise") {
|
||||||
// NOTE: It's not clear to me where the implicit wrapping of non-Promise values in a resolved
|
// NOTE: It's not clear to me where the implicit wrapping of non-Promise values in a resolved
|
||||||
// Promise is defined in the spec; https://webidl.spec.whatwg.org/#idl-promise doesn't say
|
// Promise is defined in the spec; https://webidl.spec.whatwg.org/#idl-promise doesn't say
|
||||||
// anything of this sort. Both Gecko and Blink do it, however, so I'm sure it's correct.
|
// anything of this sort. Both Gecko and Blink do it, however, so I'm sure it's correct.
|
||||||
|
@ -1108,7 +1158,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
||||||
}
|
}
|
||||||
auto @cpp_name@ = JS::make_handle(&static_cast<JS::Promise&>(@js_name@@js_suffix@.as_object()));
|
auto @cpp_name@ = JS::make_handle(&static_cast<JS::Promise&>(@js_name@@js_suffix@.as_object()));
|
||||||
)~~~");
|
)~~~");
|
||||||
} else if (parameter.type.name == "any") {
|
} else if (parameter.type->name == "any") {
|
||||||
if (!optional) {
|
if (!optional) {
|
||||||
scoped_generator.append(R"~~~(
|
scoped_generator.append(R"~~~(
|
||||||
auto @cpp_name@ = @js_name@@js_suffix@;
|
auto @cpp_name@ = @js_name@@js_suffix@;
|
||||||
|
@ -1135,7 +1185,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (dictionaries.contains(parameter.type.name)) {
|
} else if (dictionaries.contains(parameter.type->name)) {
|
||||||
if (optional_default_value.has_value() && optional_default_value != "{}")
|
if (optional_default_value.has_value() && optional_default_value != "{}")
|
||||||
TODO();
|
TODO();
|
||||||
auto dictionary_generator = scoped_generator.fork();
|
auto dictionary_generator = scoped_generator.fork();
|
||||||
|
@ -1146,7 +1196,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
||||||
}
|
}
|
||||||
@parameter.type.name@ @cpp_name@ {};
|
@parameter.type.name@ @cpp_name@ {};
|
||||||
)~~~");
|
)~~~");
|
||||||
auto* current_dictionary = &dictionaries.find(parameter.type.name)->value;
|
auto* current_dictionary = &dictionaries.find(parameter.type->name)->value;
|
||||||
while (true) {
|
while (true) {
|
||||||
for (auto& member : current_dictionary->members) {
|
for (auto& member : current_dictionary->members) {
|
||||||
dictionary_generator.set("member_key", member.name);
|
dictionary_generator.set("member_key", member.name);
|
||||||
|
@ -1185,7 +1235,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
||||||
current_dictionary = &dictionaries.find(current_dictionary->parent_name)->value;
|
current_dictionary = &dictionaries.find(current_dictionary->parent_name)->value;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dbgln("Unimplemented JS-to-C++ conversion: {}", parameter.type.name);
|
dbgln("Unimplemented JS-to-C++ conversion: {}", parameter.type->name);
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1236,12 +1286,18 @@ static void generate_arguments(SourceGenerator& generator, Vector<IDL::Parameter
|
||||||
arguments_builder.join(", ", parameter_names);
|
arguments_builder.join(", ", parameter_names);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void generate_wrap_statement(SourceGenerator& generator, String const& value, IDL::Type const& type, StringView const& result_expression)
|
enum class WrappingReference {
|
||||||
|
No,
|
||||||
|
Yes,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void generate_wrap_statement(SourceGenerator& generator, String const& value, IDL::Type const& type, StringView const& result_expression, WrappingReference wrapping_reference = WrappingReference::No, size_t recursion_depth = 0)
|
||||||
{
|
{
|
||||||
auto scoped_generator = generator.fork();
|
auto scoped_generator = generator.fork();
|
||||||
scoped_generator.set("value", value);
|
scoped_generator.set("value", value);
|
||||||
scoped_generator.set("type", type.name);
|
scoped_generator.set("type", type.name);
|
||||||
scoped_generator.set("result_expression", result_expression);
|
scoped_generator.set("result_expression", result_expression);
|
||||||
|
scoped_generator.set("recursion_depth", String::number(recursion_depth));
|
||||||
|
|
||||||
if (type.name == "undefined") {
|
if (type.name == "undefined") {
|
||||||
scoped_generator.append(R"~~~(
|
scoped_generator.append(R"~~~(
|
||||||
|
@ -1270,15 +1326,25 @@ static void generate_wrap_statement(SourceGenerator& generator, String const& va
|
||||||
scoped_generator.append(R"~~~(
|
scoped_generator.append(R"~~~(
|
||||||
@result_expression@ JS::js_string(vm, @value@);
|
@result_expression@ JS::js_string(vm, @value@);
|
||||||
)~~~");
|
)~~~");
|
||||||
} else if (type.name == "ArrayFromVector") {
|
} else if (type.name == "sequence") {
|
||||||
// FIXME: Remove this fake type hack once it's no longer needed.
|
// https://webidl.spec.whatwg.org/#es-sequence
|
||||||
// Basically once we have sequence<T> we can throw this out.
|
auto& sequence_generic_type = verify_cast<IDL::ParameterizedType>(type);
|
||||||
scoped_generator.append(R"~~~(
|
|
||||||
auto* new_array = JS::Array::create(global_object, 0);
|
|
||||||
for (auto& element : @value@)
|
|
||||||
new_array->indexed_properties().append(wrap(global_object, element));
|
|
||||||
|
|
||||||
@result_expression@ new_array;
|
scoped_generator.append(R"~~~(
|
||||||
|
auto* new_array@recursion_depth@ = JS::Array::create(global_object, 0);
|
||||||
|
|
||||||
|
for (size_t i@recursion_depth@ = 0; i@recursion_depth@ < @value@.size(); ++i@recursion_depth@) {
|
||||||
|
auto& element@recursion_depth@ = @value@.at(i@recursion_depth@);
|
||||||
|
)~~~");
|
||||||
|
|
||||||
|
generate_wrap_statement(scoped_generator, String::formatted("element{}", recursion_depth), sequence_generic_type.parameters.first(), String::formatted("auto wrapped_element{} =", recursion_depth), WrappingReference::Yes, recursion_depth + 1);
|
||||||
|
|
||||||
|
scoped_generator.append(R"~~~(
|
||||||
|
auto property_index@recursion_depth@ = JS::PropertyName { i@recursion_depth@ };
|
||||||
|
MUST(new_array@recursion_depth@->create_data_property(property_index@recursion_depth@, wrapped_element@recursion_depth@));
|
||||||
|
}
|
||||||
|
|
||||||
|
@result_expression@ new_array@recursion_depth@;
|
||||||
)~~~");
|
)~~~");
|
||||||
} else if (type.name == "boolean" || type.name == "double") {
|
} else if (type.name == "boolean" || type.name == "double") {
|
||||||
scoped_generator.append(R"~~~(
|
scoped_generator.append(R"~~~(
|
||||||
|
@ -1300,9 +1366,15 @@ static void generate_wrap_statement(SourceGenerator& generator, String const& va
|
||||||
@result_expression@ @value@.callback.cell();
|
@result_expression@ @value@.callback.cell();
|
||||||
)~~~");
|
)~~~");
|
||||||
} else {
|
} else {
|
||||||
scoped_generator.append(R"~~~(
|
if (wrapping_reference == WrappingReference::No) {
|
||||||
|
scoped_generator.append(R"~~~(
|
||||||
@result_expression@ wrap(global_object, const_cast<@type@&>(*@value@));
|
@result_expression@ wrap(global_object, const_cast<@type@&>(*@value@));
|
||||||
)~~~");
|
)~~~");
|
||||||
|
} else {
|
||||||
|
scoped_generator.append(R"~~~(
|
||||||
|
@result_expression@ wrap(global_object, const_cast<@type@&>(@value@));
|
||||||
|
)~~~");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type.nullable) {
|
if (type.nullable) {
|
||||||
|
@ -1383,7 +1455,7 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@function.name:snakecase@)
|
||||||
[[maybe_unused]] auto retval = result.release_value();
|
[[maybe_unused]] auto retval = result.release_value();
|
||||||
)~~~");
|
)~~~");
|
||||||
|
|
||||||
generate_return_statement(generator, function.return_type);
|
generate_return_statement(generator, *function.return_type);
|
||||||
|
|
||||||
function_generator.append(R"~~~(
|
function_generator.append(R"~~~(
|
||||||
}
|
}
|
||||||
|
@ -1675,10 +1747,10 @@ static JS::Value wrap_for_legacy_platform_object_get_own_property(JS::GlobalObje
|
||||||
)~~~");
|
)~~~");
|
||||||
|
|
||||||
if (interface.named_property_getter.has_value()) {
|
if (interface.named_property_getter.has_value()) {
|
||||||
generate_return_statement(scoped_generator, interface.named_property_getter->return_type);
|
generate_return_statement(scoped_generator, *interface.named_property_getter->return_type);
|
||||||
} else {
|
} else {
|
||||||
VERIFY(interface.indexed_property_getter.has_value());
|
VERIFY(interface.indexed_property_getter.has_value());
|
||||||
generate_return_statement(scoped_generator, interface.indexed_property_getter->return_type);
|
generate_return_statement(scoped_generator, *interface.indexed_property_getter->return_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
scoped_generator.append(R"~~~(
|
scoped_generator.append(R"~~~(
|
||||||
|
@ -2319,7 +2391,7 @@ JS::ThrowCompletionOr<bool> @class_name@::internal_delete(JS::PropertyName const
|
||||||
)~~~");
|
)~~~");
|
||||||
|
|
||||||
// 2. If operation was declared with a return type of boolean and the steps returned false, then return false.
|
// 2. If operation was declared with a return type of boolean and the steps returned false, then return false.
|
||||||
if (interface.named_property_deleter->return_type.name == "boolean") {
|
if (interface.named_property_deleter->return_type->name == "boolean") {
|
||||||
function_scoped_generator.append(R"~~~(
|
function_scoped_generator.append(R"~~~(
|
||||||
bool succeeded = result.release_value();
|
bool succeeded = result.release_value();
|
||||||
if (!succeeded)
|
if (!succeeded)
|
||||||
|
@ -3112,7 +3184,7 @@ JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::@attribute.getter_callback@)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attribute.extended_attributes.contains("Reflect")) {
|
if (attribute.extended_attributes.contains("Reflect")) {
|
||||||
if (attribute.type.name != "boolean") {
|
if (attribute.type->name != "boolean") {
|
||||||
attribute_generator.append(R"~~~(
|
attribute_generator.append(R"~~~(
|
||||||
auto retval = impl->attribute(HTML::AttributeNames::@attribute.reflect_name@);
|
auto retval = impl->attribute(HTML::AttributeNames::@attribute.reflect_name@);
|
||||||
)~~~");
|
)~~~");
|
||||||
|
@ -3127,7 +3199,7 @@ JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::@attribute.getter_callback@)
|
||||||
)~~~");
|
)~~~");
|
||||||
}
|
}
|
||||||
|
|
||||||
generate_return_statement(generator, attribute.type);
|
generate_return_statement(generator, *attribute.type);
|
||||||
|
|
||||||
attribute_generator.append(R"~~~(
|
attribute_generator.append(R"~~~(
|
||||||
}
|
}
|
||||||
|
@ -3147,7 +3219,7 @@ JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::@attribute.setter_callback@)
|
||||||
generate_to_cpp(generator, attribute, "value", "", "cpp_value", interface.dictionaries, false, attribute.extended_attributes.contains("LegacyNullToEmptyString"));
|
generate_to_cpp(generator, attribute, "value", "", "cpp_value", interface.dictionaries, false, attribute.extended_attributes.contains("LegacyNullToEmptyString"));
|
||||||
|
|
||||||
if (attribute.extended_attributes.contains("Reflect")) {
|
if (attribute.extended_attributes.contains("Reflect")) {
|
||||||
if (attribute.type.name != "boolean") {
|
if (attribute.type->name != "boolean") {
|
||||||
attribute_generator.append(R"~~~(
|
attribute_generator.append(R"~~~(
|
||||||
impl->set_attribute(HTML::AttributeNames::@attribute.reflect_name@, cpp_value);
|
impl->set_attribute(HTML::AttributeNames::@attribute.reflect_name@, cpp_value);
|
||||||
)~~~");
|
)~~~");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue