mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 05:37:34 +00:00
IDLGenerators: Allow specifying multiple constructors
This commit is contained in:
parent
9b022239c3
commit
99bb5a1d08
1 changed files with 106 additions and 18 deletions
|
@ -5,6 +5,7 @@
|
||||||
* Copyright (c) 2022, Ali Mohammad Pur <mpfard@serenityos.org>
|
* Copyright (c) 2022, Ali Mohammad Pur <mpfard@serenityos.org>
|
||||||
* Copyright (c) 2023, Kenneth Myhra <kennethmyhra@serenityos.org>
|
* Copyright (c) 2023, Kenneth Myhra <kennethmyhra@serenityos.org>
|
||||||
* Copyright (c) 2023, Shannon Booth <shannon@serenityos.org>
|
* Copyright (c) 2023, Shannon Booth <shannon@serenityos.org>
|
||||||
|
* Copyright (c) 2023, Matthew Olsson <mattco@serenityos.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -3635,24 +3636,37 @@ JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Object>> @constructor_class@::constru
|
||||||
{
|
{
|
||||||
)~~~");
|
)~~~");
|
||||||
|
|
||||||
|
// FIXME: Unify this code with the overload arbiter and possibly WebIDL::resolve_overload
|
||||||
if (interface.constructors.is_empty()) {
|
if (interface.constructors.is_empty()) {
|
||||||
// No constructor
|
// No constructor
|
||||||
generator.set("constructor.length", "0");
|
generator.set("constructor.length", "0");
|
||||||
generator.append(R"~~~(
|
generator.append(R"~~~(
|
||||||
return vm().throw_completion<JS::TypeError>(JS::ErrorType::NotAConstructor, "@namespaced_name@");
|
return vm().throw_completion<JS::TypeError>(JS::ErrorType::NotAConstructor, "@namespaced_name@");
|
||||||
)~~~");
|
)~~~");
|
||||||
} else if (interface.constructors.size() == 1) {
|
} else {
|
||||||
// Single constructor
|
auto shortest_length = NumericLimits<size_t>::max();
|
||||||
|
Optional<IDL::Constructor> html_constructor;
|
||||||
|
|
||||||
auto& constructor = interface.constructors[0];
|
for (auto const& constructor : interface.constructors) {
|
||||||
generator.set("constructor.length", DeprecatedString::number(constructor.shortest_length()));
|
shortest_length = min(shortest_length, constructor.shortest_length());
|
||||||
|
|
||||||
|
if (constructor.extended_attributes.contains("HTMLConstructor"sv)) {
|
||||||
|
html_constructor = constructor;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
generator.set("constructor.length", DeprecatedString::number(shortest_length));
|
||||||
|
|
||||||
generator.append(R"~~~(
|
generator.append(R"~~~(
|
||||||
auto& vm = this->vm();
|
auto& vm = this->vm();
|
||||||
auto& realm = *vm.current_realm();
|
auto& realm = *vm.current_realm();
|
||||||
)~~~");
|
)~~~");
|
||||||
|
|
||||||
if (!constructor.extended_attributes.contains("HTMLConstructor"sv)) {
|
if (!html_constructor.has_value()) {
|
||||||
|
if (interface.constructors.size() == 1) {
|
||||||
|
auto const& constructor = interface.constructors[0];
|
||||||
|
|
||||||
if (!constructor.parameters.is_empty()) {
|
if (!constructor.parameters.is_empty()) {
|
||||||
generate_argument_count_check(generator, constructor.name, constructor.shortest_length());
|
generate_argument_count_check(generator, constructor.name, constructor.shortest_length());
|
||||||
|
|
||||||
|
@ -3668,13 +3682,90 @@ JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Object>> @constructor_class@::constru
|
||||||
auto impl = TRY(throw_dom_exception_if_needed(vm, [&] { return @fully_qualified_name@::construct_impl(realm); }));
|
auto impl = TRY(throw_dom_exception_if_needed(vm, [&] { return @fully_qualified_name@::construct_impl(realm); }));
|
||||||
)~~~");
|
)~~~");
|
||||||
}
|
}
|
||||||
|
|
||||||
generator.append(R"~~~(
|
generator.append(R"~~~(
|
||||||
return *impl;
|
return *impl;
|
||||||
)~~~");
|
)~~~");
|
||||||
|
} else {
|
||||||
|
HashTable<size_t> observed_parameter_counts;
|
||||||
|
|
||||||
|
generator.append(R"~~~(
|
||||||
|
switch (vm.argument_count()) {
|
||||||
|
)~~~");
|
||||||
|
|
||||||
|
for (auto const& constructor : interface.constructors) {
|
||||||
|
for (ssize_t i = static_cast<ssize_t>(constructor.parameters.size()); i >= 0; --i) {
|
||||||
|
if (observed_parameter_counts.contains(i)) {
|
||||||
|
dbgln("Interface {} has multiple constructors that can accept {} parameters", interface.name, i);
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
observed_parameter_counts.set(i);
|
||||||
|
|
||||||
|
generator.set("parameter_count", MUST(String::number(i)));
|
||||||
|
generator.append(R"~~~(
|
||||||
|
case @parameter_count@:
|
||||||
|
)~~~");
|
||||||
|
|
||||||
|
if (!constructor.parameters[i - 1].optional)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
generator.append(R"~~~(
|
||||||
|
{
|
||||||
|
)~~~");
|
||||||
|
|
||||||
|
if (!constructor.parameters.is_empty()) {
|
||||||
|
StringBuilder arguments_builder;
|
||||||
|
generate_arguments(generator, constructor.parameters, arguments_builder, interface);
|
||||||
|
generator.set(".constructor_arguments", arguments_builder.string_view());
|
||||||
|
|
||||||
|
generator.append(R"~~~(
|
||||||
|
auto impl = TRY(throw_dom_exception_if_needed(vm, [&] { return @fully_qualified_name@::construct_impl(realm, @.constructor_arguments@); }));
|
||||||
|
return *impl;
|
||||||
|
)~~~");
|
||||||
|
} else {
|
||||||
|
generator.append(R"~~~(
|
||||||
|
auto impl = TRY(throw_dom_exception_if_needed(vm, [&] { return @fully_qualified_name@::construct_impl(realm); }));
|
||||||
|
return *impl;
|
||||||
|
)~~~");
|
||||||
|
}
|
||||||
|
|
||||||
|
generator.append(R"~~~(
|
||||||
|
}
|
||||||
|
)~~~");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shortest_length == 1) {
|
||||||
|
generator.set(".bad_arg_count", "JS::ErrorType::BadArgCountOne");
|
||||||
|
generator.set(".arg_count_suffix", "");
|
||||||
|
} else {
|
||||||
|
generator.set(".bad_arg_count", "JS::ErrorType::BadArgCountMany");
|
||||||
|
generator.set(".arg_count_suffix", DeprecatedString::formatted(", \"{}\"", shortest_length));
|
||||||
|
}
|
||||||
|
|
||||||
|
generator.append(R"~~~(
|
||||||
|
default:
|
||||||
|
return vm.throw_completion<JS::TypeError>(@.bad_arg_count@, "constructor"@.arg_count_suffix@);
|
||||||
|
}
|
||||||
|
)~~~");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// https://html.spec.whatwg.org/multipage/dom.html#html-element-constructors
|
// https://html.spec.whatwg.org/multipage/dom.html#html-element-constructors
|
||||||
// NOTE: The active function object in this context is always going to be the current constructor that has just been called.
|
// NOTE: The active function object in this context is always going to be the current constructor that has just been called.
|
||||||
|
|
||||||
|
// The [HTMLConstructor] extended attribute must take no arguments, and must only appear on constructor operations. It must
|
||||||
|
// appear only once on a constructor operation, and the interface must contain only the single, annotated constructor
|
||||||
|
// operation, and no others
|
||||||
|
if (interface.constructors.size() != 1) {
|
||||||
|
dbgln("Interface {}'s constructor annotated with [HTMLConstructor] must be the only constructor", interface.name);
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!interface.constructors[0].parameters.is_empty()) {
|
||||||
|
dbgln("Interface {}'s constructor marked with [HTMLConstructor] must not have any parameters", interface.name);
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
generator.append(R"~~~(
|
generator.append(R"~~~(
|
||||||
auto& window = verify_cast<HTML::Window>(HTML::current_global_object());
|
auto& window = verify_cast<HTML::Window>(HTML::current_global_object());
|
||||||
|
|
||||||
|
@ -3794,9 +3885,6 @@ JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Object>> @constructor_class@::constru
|
||||||
return *actual_element;
|
return *actual_element;
|
||||||
)~~~");
|
)~~~");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Multiple constructor overloads - can't do that yet.
|
|
||||||
TODO();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
generator.append(R"~~~(
|
generator.append(R"~~~(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue