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); \
|
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>) \
|
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); \
|
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>) \
|
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); \
|
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>) \
|
else if constexpr (IsSame<Namespace::ConstructorName, RegExpConstructor>) \
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <LibJS/Runtime/FunctionObject.h>
|
#include <LibJS/Runtime/FunctionObject.h>
|
||||||
#include <LibJS/Runtime/GlobalObject.h>
|
#include <LibJS/Runtime/GlobalObject.h>
|
||||||
#include <LibJS/Runtime/Iterator.h>
|
#include <LibJS/Runtime/Iterator.h>
|
||||||
|
#include <LibJS/Runtime/IteratorConstructor.h>
|
||||||
#include <LibJS/Runtime/IteratorHelper.h>
|
#include <LibJS/Runtime/IteratorHelper.h>
|
||||||
#include <LibJS/Runtime/IteratorPrototype.h>
|
#include <LibJS/Runtime/IteratorPrototype.h>
|
||||||
#include <LibJS/Runtime/ValueInlines.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.every, every, 1, attr);
|
||||||
define_native_function(realm, vm.names.find, find, 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
|
// 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);
|
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();
|
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
|
// 3.1.3.2 Iterator.prototype.map ( mapper ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.map
|
||||||
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::map)
|
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::map)
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,6 +22,9 @@ public:
|
||||||
private:
|
private:
|
||||||
IteratorPrototype(Realm&);
|
IteratorPrototype(Realm&);
|
||||||
|
|
||||||
|
JS_DECLARE_NATIVE_FUNCTION(constructor_getter);
|
||||||
|
JS_DECLARE_NATIVE_FUNCTION(constructor_setter);
|
||||||
|
|
||||||
JS_DECLARE_NATIVE_FUNCTION(symbol_iterator);
|
JS_DECLARE_NATIVE_FUNCTION(symbol_iterator);
|
||||||
JS_DECLARE_NATIVE_FUNCTION(map);
|
JS_DECLARE_NATIVE_FUNCTION(map);
|
||||||
JS_DECLARE_NATIVE_FUNCTION(filter);
|
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