mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-29 04:39:10 +00:00
LibJS: Implement Iterator.prototype.constructor according to spec
The spec allows setting a constructor on non built-in Iterator objects.
This is a normative change in the Iterator Helpers proposal. See:
30b3501
This commit is contained in:
parent
734e37442d
commit
fb228a3d85
Notes:
sideshowbarker
2024-07-18 23:45:44 +09:00
Author: https://github.com/trflynn89
Commit: fb228a3d85
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/663
4 changed files with 63 additions and 0 deletions
|
@ -306,6 +306,8 @@ JS_ENUMERATE_TYPED_ARRAYS
|
|||
initialize_constructor(vm, vm.names.Boolean, *m_##snake_namespace##snake_name##_constructor, m_##snake_namespace##snake_name##_prototype); \
|
||||
else if constexpr (IsSame<Namespace::ConstructorName, FunctionConstructor>) \
|
||||
initialize_constructor(vm, vm.names.Function, *m_##snake_namespace##snake_name##_constructor, m_##snake_namespace##snake_name##_prototype); \
|
||||
else if constexpr (IsSame<Namespace::ConstructorName, IteratorConstructor>) \
|
||||
initialize_constructor(vm, vm.names.Iterator, *m_##snake_namespace##snake_name##_constructor, nullptr); \
|
||||
else if constexpr (IsSame<Namespace::ConstructorName, NumberConstructor>) \
|
||||
initialize_constructor(vm, vm.names.Number, *m_##snake_namespace##snake_name##_constructor, m_##snake_namespace##snake_name##_prototype); \
|
||||
else if constexpr (IsSame<Namespace::ConstructorName, RegExpConstructor>) \
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <LibJS/Runtime/FunctionObject.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/Iterator.h>
|
||||
#include <LibJS/Runtime/IteratorConstructor.h>
|
||||
#include <LibJS/Runtime/IteratorHelper.h>
|
||||
#include <LibJS/Runtime/IteratorPrototype.h>
|
||||
#include <LibJS/Runtime/ValueInlines.h>
|
||||
|
@ -43,6 +44,9 @@ void IteratorPrototype::initialize(Realm& realm)
|
|||
define_native_function(realm, vm.names.every, every, 1, attr);
|
||||
define_native_function(realm, vm.names.find, find, 1, attr);
|
||||
|
||||
// 3.1.3.1 Iterator.prototype.constructor, https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.constructor
|
||||
define_native_accessor(realm, vm.names.constructor, constructor_getter, constructor_setter, Attribute::Configurable);
|
||||
|
||||
// 3.1.3.13 Iterator.prototype [ @@toStringTag ], https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype-@@tostringtag
|
||||
define_native_accessor(realm, vm.well_known_symbol_to_string_tag(), to_string_tag_getter, to_string_tag_setter, Attribute::Configurable);
|
||||
}
|
||||
|
@ -54,6 +58,27 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::symbol_iterator)
|
|||
return vm.this_value();
|
||||
}
|
||||
|
||||
// 3.1.3.1.1 get Iterator.prototype.constructor, https://tc39.es/proposal-iterator-helpers/#sec-get-iteratorprototype-constructor
|
||||
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::constructor_getter)
|
||||
{
|
||||
auto& realm = *vm.current_realm();
|
||||
|
||||
// 1. Return %Iterator%.
|
||||
return realm.intrinsics().iterator_constructor();
|
||||
}
|
||||
|
||||
// 3.1.3.1.2 set Iterator.prototype.constructor, https://tc39.es/proposal-iterator-helpers/#sec-set-iteratorprototype-constructor
|
||||
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::constructor_setter)
|
||||
{
|
||||
auto& realm = *vm.current_realm();
|
||||
|
||||
// 1. Perform ? SetterThatIgnoresPrototypeProperties(this value, %Iterator.prototype%, "constructor", v).
|
||||
TRY(setter_that_ignores_prototype_properties(vm, vm.this_value(), realm.intrinsics().iterator_prototype(), vm.names.constructor, vm.argument(0)));
|
||||
|
||||
// 2. Return undefined.
|
||||
return js_undefined();
|
||||
}
|
||||
|
||||
// 3.1.3.2 Iterator.prototype.map ( mapper ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.map
|
||||
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::map)
|
||||
{
|
||||
|
|
|
@ -22,6 +22,9 @@ public:
|
|||
private:
|
||||
IteratorPrototype(Realm&);
|
||||
|
||||
JS_DECLARE_NATIVE_FUNCTION(constructor_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(constructor_setter);
|
||||
|
||||
JS_DECLARE_NATIVE_FUNCTION(symbol_iterator);
|
||||
JS_DECLARE_NATIVE_FUNCTION(map);
|
||||
JS_DECLARE_NATIVE_FUNCTION(filter);
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
const sentinel = "whf :^)";
|
||||
|
||||
describe("errors", () => {
|
||||
test("setter called on non-object", () => {
|
||||
let { get, set } = Object.getOwnPropertyDescriptor(Iterator.prototype, "constructor");
|
||||
|
||||
expect(() => {
|
||||
set.call(undefined, sentinel);
|
||||
}).toThrowWithMessage(TypeError, "undefined is not an object");
|
||||
});
|
||||
|
||||
test("cannot set the built-in Iterator's constructor", () => {
|
||||
expect(() => {
|
||||
Iterator.prototype.constructor = sentinel;
|
||||
}).toThrowWithMessage(
|
||||
TypeError,
|
||||
"Cannot write to non-writable property '[object IteratorPrototype]'"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("correct behavior", () => {
|
||||
test("basic functionality", () => {
|
||||
expect(Iterator.prototype.constructor).toBe(Iterator);
|
||||
});
|
||||
|
||||
test("constructor setter", () => {
|
||||
let Proto = Object.create(Iterator.prototype);
|
||||
Proto.constructor = sentinel;
|
||||
|
||||
expect(Proto.constructor).toBe(sentinel);
|
||||
});
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue