LibWeb: Implement WebIDL constructor flow for derived classes
Following the rules in the algorithm from https://webidl.spec.whatwg.org/#js-platform-objects, "To Internally create a new object implementing the interface interface", this change incorporates the steps to load a prototype from new.target, and write it to the created instance returned from constructor_impl(). This mirrors the code for generate_html_constructor(), which incorporates additional steps needed by Custom Elements. Bug #334
This commit is contained in:
parent
7dc28a20d0
commit
80cd3712c2
Notes:
sideshowbarker
2024-07-17 10:54:57 +09:00
Author: https://github.com/caitp 🔰 Commit: https://github.com/LadybirdBrowser/ladybird/commit/80cd3712c2 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/379 Reviewed-by: https://github.com/awesomekling Reviewed-by: https://github.com/tcl3
3 changed files with 68 additions and 0 deletions
|
@ -2513,6 +2513,26 @@ JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Object>> @constructor_class@::constru
|
|||
if (is_html_constructor) {
|
||||
generate_html_constructor(generator, constructor, interface);
|
||||
} else {
|
||||
generator.append(R"~~~(
|
||||
// To internally create a new object implementing the interface @name@:
|
||||
|
||||
// 3.2. Let prototype be ? Get(newTarget, "prototype").
|
||||
auto prototype = TRY(new_target.get(vm.names.prototype));
|
||||
|
||||
// 3.3. If Type(prototype) is not Object, then:
|
||||
if (!prototype.is_object()) {
|
||||
// 1. Let targetRealm be ? GetFunctionRealm(newTarget).
|
||||
auto* target_realm = TRY(JS::get_function_realm(vm, new_target));
|
||||
|
||||
// 2. Set prototype to the interface prototype object for interface in targetRealm.
|
||||
VERIFY(target_realm);
|
||||
prototype = &Bindings::ensure_web_prototype<@prototype_class@>(*target_realm, "@name@"_fly_string);
|
||||
}
|
||||
|
||||
// 4. Let instance be MakeBasicObject( « [[Prototype]], [[Extensible]], [[Realm]], [[PrimaryInterface]] »).
|
||||
// 5. Set instance.[[Realm]] to realm.
|
||||
// 6. Set instance.[[PrimaryInterface]] to interface.
|
||||
)~~~");
|
||||
if (!constructor.parameters.is_empty()) {
|
||||
generate_argument_count_check(generator, constructor.name, constructor.shortest_length());
|
||||
|
||||
|
@ -2530,6 +2550,34 @@ JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Object>> @constructor_class@::constru
|
|||
}
|
||||
|
||||
constructor_generator.append(R"~~~(
|
||||
// 7. Set instance.[[Prototype]] to prototype.
|
||||
VERIFY(prototype.is_object());
|
||||
impl->set_prototype(&prototype.as_object());
|
||||
|
||||
// FIXME: Steps 8...11. of the "internally create a new object implementing the interface @name@" algorithm
|
||||
// (https://webidl.spec.whatwg.org/#js-platform-objects) are currently not handled, or are handled within @fully_qualified_name@::construct_impl().
|
||||
// 8. Let interfaces be the inclusive inherited interfaces of interface.
|
||||
// 9. For every interface ancestor interface in interfaces:
|
||||
// 9.1. Let unforgeables be the value of the [[Unforgeables]] slot of the interface object of ancestor interface in realm.
|
||||
// 9.2. Let keys be ! unforgeables.[[OwnPropertyKeys]]().
|
||||
// 9.3. For each element key of keys:
|
||||
// 9.3.1. Let descriptor be ! unforgeables.[[GetOwnProperty]](key).
|
||||
// 9.3.2. Perform ! DefinePropertyOrThrow(instance, key, descriptor).
|
||||
// 10. If interface is declared with the [Global] extended attribute, then:
|
||||
// 10.1. Define the regular operations of interface on instance, given realm.
|
||||
// 10.2. Define the regular attributes of interface on instance, given realm.
|
||||
// 10.3. Define the iteration methods of interface on instance given realm.
|
||||
// 10.4. Define the asynchronous iteration methods of interface on instance given realm.
|
||||
// 10.5. Define the global property references on instance, given realm.
|
||||
// 10.6. Set instance.[[SetPrototypeOf]] as defined in § 3.8.1 [[SetPrototypeOf]].
|
||||
// 11. Otherwise, if interfaces contains an interface which supports indexed properties, named properties, or both:
|
||||
// 11.1. Set instance.[[GetOwnProperty]] as defined in § 3.9.1 [[GetOwnProperty]].
|
||||
// 11.2. Set instance.[[Set]] as defined in § 3.9.2 [[Set]].
|
||||
// 11.3. Set instance.[[DefineOwnProperty]] as defined in § 3.9.3 [[DefineOwnProperty]].
|
||||
// 11.4. Set instance.[[Delete]] as defined in § 3.9.4 [[Delete]].
|
||||
// 11.5. Set instance.[[PreventExtensions]] as defined in § 3.9.5 [[PreventExtensions]].
|
||||
// 11.6. Set instance.[[OwnPropertyKeys]] as defined in § 3.9.6 [[OwnPropertyKeys]].
|
||||
|
||||
return *impl;
|
||||
}
|
||||
)~~~");
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
derived class method present and invoked!
|
19
Tests/LibWeb/Text/input/DOM/derived-interface-prototype.html
Normal file
19
Tests/LibWeb/Text/input/DOM/derived-interface-prototype.html
Normal file
|
@ -0,0 +1,19 @@
|
|||
<script src="../include.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
class MyEventTarget extends EventTarget {
|
||||
derivedClassMethod() {
|
||||
println("derived class method present and invoked!");
|
||||
}
|
||||
}
|
||||
let instance = new MyEventTarget();
|
||||
if (instance.__proto__ !== MyEventTarget.prototype) {
|
||||
println("Derived class MyEventTarget has incorrect prototype.");
|
||||
}
|
||||
try {
|
||||
instance.derivedClassMethod();
|
||||
} catch (e) {
|
||||
println(e);
|
||||
}
|
||||
});
|
||||
</script>
|
Loading…
Add table
Reference in a new issue