mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 23:50:19 +00:00
LibWeb: Add support for IDL value iterators
This also renames Interface::iterator_types to pair_iterator_types to reduce confusion between value and pair iterators.
This commit is contained in:
parent
2c0d329bf6
commit
bfd089fbd1
Notes:
sideshowbarker
2024-07-18 03:11:22 +09:00
Author: https://github.com/Lubrsi Commit: https://github.com/SerenityOS/serenity/commit/bfd089fbd1e Pull-request: https://github.com/SerenityOS/serenity/pull/10317
1 changed files with 41 additions and 16 deletions
|
@ -154,9 +154,11 @@ struct Interface {
|
|||
Vector<Function> static_functions;
|
||||
bool has_stringifier { false };
|
||||
Optional<String> stringifier_attribute;
|
||||
Optional<Tuple<Type, Type>> iterator_types;
|
||||
bool has_unscopable_member { false };
|
||||
|
||||
Optional<Type> value_iterator_type;
|
||||
Optional<Tuple<Type, Type>> pair_iterator_types;
|
||||
|
||||
Optional<Function> named_property_getter;
|
||||
Optional<Function> named_property_setter;
|
||||
|
||||
|
@ -412,17 +414,22 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView
|
|||
assert_string("iterable");
|
||||
assert_specific('<');
|
||||
auto first_type = parse_type();
|
||||
Optional<Type> second_type;
|
||||
if (lexer.next_is(',')) {
|
||||
if (interface->supports_indexed_properties())
|
||||
report_parsing_error("Interfaces with a pair iterator must not supported indexed properties.", filename, input, lexer.tell());
|
||||
|
||||
assert_specific(',');
|
||||
consume_whitespace();
|
||||
second_type = parse_type();
|
||||
auto second_type = parse_type();
|
||||
interface->pair_iterator_types = Tuple { move(first_type), move(second_type) };
|
||||
} else {
|
||||
TODO();
|
||||
if (!interface->supports_indexed_properties())
|
||||
report_parsing_error("Interfaces with a value iterator must supported indexed properties.", filename, input, lexer.tell());
|
||||
|
||||
interface->value_iterator_type = move(first_type);
|
||||
}
|
||||
assert_specific('>');
|
||||
assert_specific(';');
|
||||
interface->iterator_types = Tuple { first_type, *second_type };
|
||||
};
|
||||
|
||||
auto parse_getter = [&](HashMap<String, String>& extended_attributes) {
|
||||
|
@ -2637,7 +2644,7 @@ private:
|
|||
)~~~");
|
||||
}
|
||||
|
||||
if (interface.iterator_types.has_value()) {
|
||||
if (interface.pair_iterator_types.has_value()) {
|
||||
auto iterator_generator = generator.fork();
|
||||
iterator_generator.append(R"~~~(
|
||||
JS_DECLARE_NATIVE_FUNCTION(entries);
|
||||
|
@ -2684,7 +2691,7 @@ void generate_prototype_implementation(IDL::Interface const& interface)
|
|||
generator.set("prototype_class:snakecase", interface.prototype_class.to_snakecase());
|
||||
generator.set("fully_qualified_name", interface.fully_qualified_name);
|
||||
|
||||
if (interface.iterator_types.has_value()) {
|
||||
if (interface.pair_iterator_types.has_value()) {
|
||||
generator.set("iterator_name", String::formatted("{}Iterator", interface.name));
|
||||
generator.set("iterator_wrapper_class", String::formatted("{}IteratorWrapper", interface.name));
|
||||
generator.append(R"~~~(
|
||||
|
@ -2776,7 +2783,7 @@ void generate_prototype_implementation(IDL::Interface const& interface)
|
|||
|
||||
)~~~");
|
||||
|
||||
if (interface.iterator_types.has_value()) {
|
||||
if (interface.pair_iterator_types.has_value()) {
|
||||
generator.append(R"~~~(
|
||||
#if __has_include(<LibWeb/CSS/@iterator_name@.h>)
|
||||
# include <LibWeb/CSS/@iterator_name@.h>
|
||||
|
@ -2920,7 +2927,25 @@ void @prototype_class@::initialize(JS::GlobalObject& global_object)
|
|||
)~~~");
|
||||
}
|
||||
|
||||
if (interface.iterator_types.has_value()) {
|
||||
// https://heycam.github.io/webidl/#define-the-iteration-methods
|
||||
// This applies to this if block and the following if block.
|
||||
if (interface.indexed_property_getter.has_value()) {
|
||||
auto iterator_generator = generator.fork();
|
||||
iterator_generator.append(R"~~~(
|
||||
define_direct_property(*vm.well_known_symbol_iterator(), global_object.array_prototype()->get_without_side_effects(vm.names.values), JS::Attribute::Configurable | JS::Attribute::Writable);
|
||||
)~~~");
|
||||
|
||||
if (interface.value_iterator_type.has_value()) {
|
||||
iterator_generator.append(R"~~~(
|
||||
define_direct_property(vm.names.entries, global_object.array_prototype()->get_without_side_effects(vm.names.entries), default_attributes);
|
||||
define_direct_property(vm.names.keys, global_object.array_prototype()->get_without_side_effects(vm.names.keys), default_attributes);
|
||||
define_direct_property(vm.names.values, global_object.array_prototype()->get_without_side_effects(vm.names.values), default_attributes);
|
||||
define_direct_property(vm.names.forEach, global_object.array_prototype()->get_without_side_effects(vm.names.forEach), default_attributes);
|
||||
)~~~");
|
||||
}
|
||||
}
|
||||
|
||||
if (interface.pair_iterator_types.has_value()) {
|
||||
// FIXME: Do pair iterators need to be added to the unscopable list?
|
||||
|
||||
auto iterator_generator = generator.fork();
|
||||
|
@ -3116,7 +3141,7 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::to_string)
|
|||
)~~~");
|
||||
}
|
||||
|
||||
if (interface.iterator_types.has_value()) {
|
||||
if (interface.pair_iterator_types.has_value()) {
|
||||
auto iterator_generator = generator.fork();
|
||||
iterator_generator.append(R"~~~(
|
||||
JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::entries)
|
||||
|
@ -3143,8 +3168,8 @@ JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::for_each)
|
|||
auto this_value = vm.this_value(global_object);
|
||||
impl->for_each([&](auto key, auto value) {
|
||||
)~~~");
|
||||
generate_variable_statement(iterator_generator, "wrapped_key", interface.iterator_types->get<0>(), "key");
|
||||
generate_variable_statement(iterator_generator, "wrapped_value", interface.iterator_types->get<1>(), "value");
|
||||
generate_variable_statement(iterator_generator, "wrapped_key", interface.pair_iterator_types->get<0>(), "key");
|
||||
generate_variable_statement(iterator_generator, "wrapped_value", interface.pair_iterator_types->get<1>(), "value");
|
||||
iterator_generator.append(R"~~~(
|
||||
auto result = vm.call(callback.as_function(), vm.argument(1), wrapped_value, wrapped_key, this_value);
|
||||
return result.is_error() ? IterationDecision::Break : IterationDecision::Continue;
|
||||
|
@ -3184,7 +3209,7 @@ JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::values)
|
|||
|
||||
static void generate_iterator_header(IDL::Interface const& interface)
|
||||
{
|
||||
VERIFY(interface.iterator_types.has_value());
|
||||
VERIFY(interface.pair_iterator_types.has_value());
|
||||
StringBuilder builder;
|
||||
SourceGenerator generator { builder };
|
||||
|
||||
|
@ -3254,7 +3279,7 @@ private:
|
|||
|
||||
void generate_iterator_implementation(IDL::Interface const& interface)
|
||||
{
|
||||
VERIFY(interface.iterator_types.has_value());
|
||||
VERIFY(interface.pair_iterator_types.has_value());
|
||||
StringBuilder builder;
|
||||
SourceGenerator generator { builder };
|
||||
|
||||
|
@ -3324,7 +3349,7 @@ void @wrapper_class@::visit_edges(Cell::Visitor& visitor)
|
|||
|
||||
static void generate_iterator_prototype_header(IDL::Interface const& interface)
|
||||
{
|
||||
VERIFY(interface.iterator_types.has_value());
|
||||
VERIFY(interface.pair_iterator_types.has_value());
|
||||
StringBuilder builder;
|
||||
SourceGenerator generator { builder };
|
||||
|
||||
|
@ -3356,7 +3381,7 @@ private:
|
|||
|
||||
void generate_iterator_prototype_implementation(IDL::Interface const& interface)
|
||||
{
|
||||
VERIFY(interface.iterator_types.has_value());
|
||||
VERIFY(interface.pair_iterator_types.has_value());
|
||||
StringBuilder builder;
|
||||
SourceGenerator generator { builder };
|
||||
|
||||
|
|
Loading…
Reference in a new issue