mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 05:47:35 +00:00
LibJS: Add spec comments to ObjectPrototype
This commit is contained in:
parent
50cb4f08a1
commit
b1ea436093
1 changed files with 199 additions and 120 deletions
|
@ -60,11 +60,74 @@ ThrowCompletionOr<bool> ObjectPrototype::internal_set_prototype_of(Object* proto
|
||||||
// 20.1.3.2 Object.prototype.hasOwnProperty ( V ), https://tc39.es/ecma262/#sec-object.prototype.hasownproperty
|
// 20.1.3.2 Object.prototype.hasOwnProperty ( V ), https://tc39.es/ecma262/#sec-object.prototype.hasownproperty
|
||||||
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::has_own_property)
|
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::has_own_property)
|
||||||
{
|
{
|
||||||
|
// 1. Let P be ? ToPropertyKey(V).
|
||||||
auto property_key = TRY(vm.argument(0).to_property_key(vm));
|
auto property_key = TRY(vm.argument(0).to_property_key(vm));
|
||||||
|
|
||||||
|
// 2. Let O be ? ToObject(this value).
|
||||||
auto this_object = TRY(vm.this_value().to_object(vm));
|
auto this_object = TRY(vm.this_value().to_object(vm));
|
||||||
|
|
||||||
|
// 3. Return ? HasOwnProperty(O, P).
|
||||||
return Value(TRY(this_object->has_own_property(property_key)));
|
return Value(TRY(this_object->has_own_property(property_key)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 20.1.3.3 Object.prototype.isPrototypeOf ( V ), https://tc39.es/ecma262/#sec-object.prototype.isprototypeof
|
||||||
|
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::is_prototype_of)
|
||||||
|
{
|
||||||
|
auto object_argument = vm.argument(0);
|
||||||
|
|
||||||
|
// 1. If V is not an Object, return false.
|
||||||
|
if (!object_argument.is_object())
|
||||||
|
return Value(false);
|
||||||
|
auto* object = &object_argument.as_object();
|
||||||
|
|
||||||
|
// 2. Let O be ? ToObject(this value).
|
||||||
|
auto this_object = TRY(vm.this_value().to_object(vm));
|
||||||
|
|
||||||
|
// 3. Repeat,
|
||||||
|
for (;;) {
|
||||||
|
// a. Set V to ? V.[[GetPrototypeOf]]().
|
||||||
|
object = TRY(object->internal_get_prototype_of());
|
||||||
|
|
||||||
|
// b. If V is null, return false.
|
||||||
|
if (!object)
|
||||||
|
return Value(false);
|
||||||
|
|
||||||
|
// c. If SameValue(O, V) is true, return true.
|
||||||
|
if (same_value(this_object, object))
|
||||||
|
return Value(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 20.1.3.4 Object.prototype.propertyIsEnumerable ( V ), https://tc39.es/ecma262/#sec-object.prototype.propertyisenumerable
|
||||||
|
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::property_is_enumerable)
|
||||||
|
{
|
||||||
|
// 1. Let P be ? ToPropertyKey(V).
|
||||||
|
auto property_key = TRY(vm.argument(0).to_property_key(vm));
|
||||||
|
|
||||||
|
// 2. Let O be ? ToObject(this value).
|
||||||
|
auto this_object = TRY(vm.this_value().to_object(vm));
|
||||||
|
|
||||||
|
// 3. Let desc be ? O.[[GetOwnProperty]](P).
|
||||||
|
auto property_descriptor = TRY(this_object->internal_get_own_property(property_key));
|
||||||
|
|
||||||
|
// 4. If desc is undefined, return false.
|
||||||
|
if (!property_descriptor.has_value())
|
||||||
|
return Value(false);
|
||||||
|
|
||||||
|
// 5. Return desc.[[Enumerable]].
|
||||||
|
return Value(*property_descriptor->enumerable);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 20.1.3.5 Object.prototype.toLocaleString ( [ reserved1 [ , reserved2 ] ] ), https://tc39.es/ecma262/#sec-object.prototype.tolocalestring
|
||||||
|
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::to_locale_string)
|
||||||
|
{
|
||||||
|
// 1. Let O be the this value.
|
||||||
|
auto this_value = vm.this_value();
|
||||||
|
|
||||||
|
// 2. Return ? Invoke(O, "toString").
|
||||||
|
return this_value.invoke(vm, vm.names.toString);
|
||||||
|
}
|
||||||
|
|
||||||
// 20.1.3.6 Object.prototype.toString ( ), https://tc39.es/ecma262/#sec-object.prototype.tostring
|
// 20.1.3.6 Object.prototype.toString ( ), https://tc39.es/ecma262/#sec-object.prototype.tostring
|
||||||
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::to_string)
|
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::to_string)
|
||||||
{
|
{
|
||||||
|
@ -133,153 +196,169 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::to_string)
|
||||||
return PrimitiveString::create(vm, DeprecatedString::formatted("[object {}]", tag));
|
return PrimitiveString::create(vm, DeprecatedString::formatted("[object {}]", tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 20.1.3.5 Object.prototype.toLocaleString ( [ reserved1 [ , reserved2 ] ] ), https://tc39.es/ecma262/#sec-object.prototype.tolocalestring
|
|
||||||
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::to_locale_string)
|
|
||||||
{
|
|
||||||
auto this_value = vm.this_value();
|
|
||||||
return this_value.invoke(vm, vm.names.toString);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 20.1.3.7 Object.prototype.valueOf ( ), https://tc39.es/ecma262/#sec-object.prototype.valueof
|
// 20.1.3.7 Object.prototype.valueOf ( ), https://tc39.es/ecma262/#sec-object.prototype.valueof
|
||||||
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::value_of)
|
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::value_of)
|
||||||
{
|
{
|
||||||
|
// 1. Return ? ToObject(this value).
|
||||||
return TRY(vm.this_value().to_object(vm));
|
return TRY(vm.this_value().to_object(vm));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 20.1.3.4 Object.prototype.propertyIsEnumerable ( V ), https://tc39.es/ecma262/#sec-object.prototype.propertyisenumerable
|
// 20.1.3.8.1 get Object.prototype.__proto__, https://tc39.es/ecma262/#sec-get-object.prototype.__proto__
|
||||||
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::property_is_enumerable)
|
|
||||||
{
|
|
||||||
// 1. Let P be ? ToPropertyKey(V).
|
|
||||||
auto property_key = TRY(vm.argument(0).to_property_key(vm));
|
|
||||||
// 2. Let O be ? ToObject(this value).
|
|
||||||
auto this_object = TRY(vm.this_value().to_object(vm));
|
|
||||||
// 3. Let desc be ? O.[[GetOwnProperty]](P).
|
|
||||||
auto property_descriptor = TRY(this_object->internal_get_own_property(property_key));
|
|
||||||
// 4. If desc is undefined, return false.
|
|
||||||
if (!property_descriptor.has_value())
|
|
||||||
return Value(false);
|
|
||||||
// 5. Return desc.[[Enumerable]].
|
|
||||||
return Value(*property_descriptor->enumerable);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 20.1.3.3 Object.prototype.isPrototypeOf ( V ), https://tc39.es/ecma262/#sec-object.prototype.isprototypeof
|
|
||||||
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::is_prototype_of)
|
|
||||||
{
|
|
||||||
auto object_argument = vm.argument(0);
|
|
||||||
if (!object_argument.is_object())
|
|
||||||
return Value(false);
|
|
||||||
auto* object = &object_argument.as_object();
|
|
||||||
auto this_object = TRY(vm.this_value().to_object(vm));
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
object = TRY(object->internal_get_prototype_of());
|
|
||||||
if (!object)
|
|
||||||
return Value(false);
|
|
||||||
if (same_value(this_object, object))
|
|
||||||
return Value(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// B.2.2.2 Object.prototype.__defineGetter__ ( P, getter ), https://tc39.es/ecma262/#sec-object.prototype.__defineGetter__
|
|
||||||
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::define_getter)
|
|
||||||
{
|
|
||||||
auto object = TRY(vm.this_value().to_object(vm));
|
|
||||||
|
|
||||||
auto getter = vm.argument(1);
|
|
||||||
if (!getter.is_function())
|
|
||||||
return vm.throw_completion<TypeError>(ErrorType::NotAFunction, TRY_OR_THROW_OOM(vm, getter.to_string_without_side_effects()));
|
|
||||||
|
|
||||||
auto descriptor = PropertyDescriptor { .get = &getter.as_function(), .enumerable = true, .configurable = true };
|
|
||||||
|
|
||||||
auto key = TRY(vm.argument(0).to_property_key(vm));
|
|
||||||
|
|
||||||
TRY(object->define_property_or_throw(key, descriptor));
|
|
||||||
|
|
||||||
return js_undefined();
|
|
||||||
}
|
|
||||||
|
|
||||||
// B.2.2.3 Object.prototype.__defineSetter__ ( P, getter ), https://tc39.es/ecma262/#sec-object.prototype.__defineSetter__
|
|
||||||
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::define_setter)
|
|
||||||
{
|
|
||||||
auto object = TRY(vm.this_value().to_object(vm));
|
|
||||||
|
|
||||||
auto setter = vm.argument(1);
|
|
||||||
if (!setter.is_function())
|
|
||||||
return vm.throw_completion<TypeError>(ErrorType::NotAFunction, TRY_OR_THROW_OOM(vm, setter.to_string_without_side_effects()));
|
|
||||||
|
|
||||||
auto descriptor = PropertyDescriptor { .set = &setter.as_function(), .enumerable = true, .configurable = true };
|
|
||||||
|
|
||||||
auto key = TRY(vm.argument(0).to_property_key(vm));
|
|
||||||
|
|
||||||
TRY(object->define_property_or_throw(key, descriptor));
|
|
||||||
|
|
||||||
return js_undefined();
|
|
||||||
}
|
|
||||||
|
|
||||||
// B.2.2.4 Object.prototype.__lookupGetter__ ( P ), https://tc39.es/ecma262/#sec-object.prototype.__lookupGetter__
|
|
||||||
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::lookup_getter)
|
|
||||||
{
|
|
||||||
auto object = GCPtr { TRY(vm.this_value().to_object(vm)) };
|
|
||||||
|
|
||||||
auto key = TRY(vm.argument(0).to_property_key(vm));
|
|
||||||
|
|
||||||
while (object) {
|
|
||||||
auto desc = TRY(object->internal_get_own_property(key));
|
|
||||||
if (desc.has_value()) {
|
|
||||||
if (desc->is_accessor_descriptor())
|
|
||||||
return *desc->get ?: js_undefined();
|
|
||||||
return js_undefined();
|
|
||||||
}
|
|
||||||
object = TRY(object->internal_get_prototype_of());
|
|
||||||
}
|
|
||||||
|
|
||||||
return js_undefined();
|
|
||||||
}
|
|
||||||
|
|
||||||
// B.2.2.5 Object.prototype.__lookupSetter__ ( P ), https://tc39.es/ecma262/#sec-object.prototype.__lookupSetter__
|
|
||||||
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::lookup_setter)
|
|
||||||
{
|
|
||||||
auto object = GCPtr { TRY(vm.this_value().to_object(vm)) };
|
|
||||||
|
|
||||||
auto key = TRY(vm.argument(0).to_property_key(vm));
|
|
||||||
|
|
||||||
while (object) {
|
|
||||||
auto desc = TRY(object->internal_get_own_property(key));
|
|
||||||
if (desc.has_value()) {
|
|
||||||
if (desc->is_accessor_descriptor())
|
|
||||||
return *desc->set ?: js_undefined();
|
|
||||||
return js_undefined();
|
|
||||||
}
|
|
||||||
object = TRY(object->internal_get_prototype_of());
|
|
||||||
}
|
|
||||||
|
|
||||||
return js_undefined();
|
|
||||||
}
|
|
||||||
|
|
||||||
// B.2.2.1.1 get Object.prototype.__proto__, https://tc39.es/ecma262/#sec-get-object.prototype.__proto__
|
|
||||||
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::proto_getter)
|
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::proto_getter)
|
||||||
{
|
{
|
||||||
|
// 1. Let O be ? ToObject(this value).
|
||||||
auto object = TRY(vm.this_value().to_object(vm));
|
auto object = TRY(vm.this_value().to_object(vm));
|
||||||
|
|
||||||
|
// 2. Return ? O.[[GetPrototypeOf]]().
|
||||||
return TRY(object->internal_get_prototype_of());
|
return TRY(object->internal_get_prototype_of());
|
||||||
}
|
}
|
||||||
|
|
||||||
// B.2.2.1.2 set Object.prototype.__proto__, https://tc39.es/ecma262/#sec-set-object.prototype.__proto__
|
// 20.1.3.8.2 set Object.prototype.__proto__, https://tc39.es/ecma262/#sec-set-object.prototype.__proto__
|
||||||
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::proto_setter)
|
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::proto_setter)
|
||||||
{
|
{
|
||||||
|
auto proto = vm.argument(0);
|
||||||
|
|
||||||
|
// 1. Let O be ? RequireObjectCoercible(this value).
|
||||||
auto object = TRY(require_object_coercible(vm, vm.this_value()));
|
auto object = TRY(require_object_coercible(vm, vm.this_value()));
|
||||||
|
|
||||||
auto proto = vm.argument(0);
|
// 2. If proto is not an Object and proto is not null, return undefined.
|
||||||
if (!proto.is_object() && !proto.is_null())
|
if (!proto.is_object() && !proto.is_null())
|
||||||
return js_undefined();
|
return js_undefined();
|
||||||
|
|
||||||
|
// 3. If O is not an Object, return undefined.
|
||||||
if (!object.is_object())
|
if (!object.is_object())
|
||||||
return js_undefined();
|
return js_undefined();
|
||||||
|
|
||||||
|
// 4. Let status be ? O.[[SetPrototypeOf]](proto).
|
||||||
auto status = TRY(object.as_object().internal_set_prototype_of(proto.is_object() ? &proto.as_object() : nullptr));
|
auto status = TRY(object.as_object().internal_set_prototype_of(proto.is_object() ? &proto.as_object() : nullptr));
|
||||||
|
|
||||||
|
// 5. If status is false, throw a TypeError exception.
|
||||||
if (!status) {
|
if (!status) {
|
||||||
// FIXME: Improve/contextualize error message
|
// FIXME: Improve/contextualize error message
|
||||||
return vm.throw_completion<TypeError>(ErrorType::ObjectSetPrototypeOfReturnedFalse);
|
return vm.throw_completion<TypeError>(ErrorType::ObjectSetPrototypeOfReturnedFalse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 6. Return undefined.
|
||||||
|
return js_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 20.1.3.9.1 Object.prototype.__defineGetter__ ( P, getter ), https://tc39.es/ecma262/#sec-object.prototype.__defineGetter__
|
||||||
|
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::define_getter)
|
||||||
|
{
|
||||||
|
auto property = vm.argument(0);
|
||||||
|
auto getter = vm.argument(1);
|
||||||
|
|
||||||
|
// 1. Let O be ? ToObject(this value).
|
||||||
|
auto object = TRY(vm.this_value().to_object(vm));
|
||||||
|
|
||||||
|
// 2. If IsCallable(getter) is false, throw a TypeError exception.
|
||||||
|
if (!getter.is_function())
|
||||||
|
return vm.throw_completion<TypeError>(ErrorType::NotAFunction, TRY_OR_THROW_OOM(vm, getter.to_string_without_side_effects()));
|
||||||
|
|
||||||
|
// 3. Let desc be PropertyDescriptor { [[Get]]: getter, [[Enumerable]]: true, [[Configurable]]: true }.
|
||||||
|
auto descriptor = PropertyDescriptor { .get = &getter.as_function(), .enumerable = true, .configurable = true };
|
||||||
|
|
||||||
|
// 4. Let key be ? ToPropertyKey(P).
|
||||||
|
auto key = TRY(property.to_property_key(vm));
|
||||||
|
|
||||||
|
// 5. Perform ? DefinePropertyOrThrow(O, key, desc).
|
||||||
|
TRY(object->define_property_or_throw(key, descriptor));
|
||||||
|
|
||||||
|
// 6. Return undefined.
|
||||||
|
return js_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 20.1.3.9.2 Object.prototype.__defineSetter__ ( P, setter ), https://tc39.es/ecma262/#sec-object.prototype.__defineSetter__
|
||||||
|
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::define_setter)
|
||||||
|
{
|
||||||
|
auto property = vm.argument(0);
|
||||||
|
auto setter = vm.argument(1);
|
||||||
|
|
||||||
|
// 1. Let O be ? ToObject(this value).
|
||||||
|
auto object = TRY(vm.this_value().to_object(vm));
|
||||||
|
|
||||||
|
// 2. If IsCallable(setter) is false, throw a TypeError exception.
|
||||||
|
if (!setter.is_function())
|
||||||
|
return vm.throw_completion<TypeError>(ErrorType::NotAFunction, TRY_OR_THROW_OOM(vm, setter.to_string_without_side_effects()));
|
||||||
|
|
||||||
|
// 3. Let desc be PropertyDescriptor { [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: true }.
|
||||||
|
auto descriptor = PropertyDescriptor { .set = &setter.as_function(), .enumerable = true, .configurable = true };
|
||||||
|
|
||||||
|
// 4. Let key be ? ToPropertyKey(P).
|
||||||
|
auto key = TRY(property.to_property_key(vm));
|
||||||
|
|
||||||
|
// 5. Perform ? DefinePropertyOrThrow(O, key, desc).
|
||||||
|
TRY(object->define_property_or_throw(key, descriptor));
|
||||||
|
|
||||||
|
// 6. Return undefined.
|
||||||
|
return js_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 20.1.3.9.3 Object.prototype.__lookupGetter__ ( P ), https://tc39.es/ecma262/#sec-object.prototype.__lookupGetter__
|
||||||
|
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::lookup_getter)
|
||||||
|
{
|
||||||
|
auto property = vm.argument(0);
|
||||||
|
|
||||||
|
// 1. Let O be ? ToObject(this value).
|
||||||
|
auto object = GCPtr { TRY(vm.this_value().to_object(vm)) };
|
||||||
|
|
||||||
|
// 2. Let key be ? ToPropertyKey(P).
|
||||||
|
auto key = TRY(property.to_property_key(vm));
|
||||||
|
|
||||||
|
// 3. Repeat,
|
||||||
|
while (object) {
|
||||||
|
// a. Let desc be ? O.[[GetOwnProperty]](key).
|
||||||
|
auto desc = TRY(object->internal_get_own_property(key));
|
||||||
|
|
||||||
|
// b. If desc is not undefined, then
|
||||||
|
if (desc.has_value()) {
|
||||||
|
// i. If IsAccessorDescriptor(desc) is true, return desc.[[Get]].
|
||||||
|
if (desc->is_accessor_descriptor())
|
||||||
|
return *desc->get ?: js_undefined();
|
||||||
|
|
||||||
|
// ii. Return undefined.
|
||||||
|
return js_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
// c. Set O to ? O.[[GetPrototypeOf]]().
|
||||||
|
object = TRY(object->internal_get_prototype_of());
|
||||||
|
}
|
||||||
|
|
||||||
|
// d. If O is null, return undefined.
|
||||||
|
return js_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 20.1.3.9.4 Object.prototype.__lookupSetter__ ( P ), https://tc39.es/ecma262/#sec-object.prototype.__lookupSetter__
|
||||||
|
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::lookup_setter)
|
||||||
|
{
|
||||||
|
auto property = vm.argument(0);
|
||||||
|
|
||||||
|
// 1. Let O be ? ToObject(this value).
|
||||||
|
auto object = GCPtr { TRY(vm.this_value().to_object(vm)) };
|
||||||
|
|
||||||
|
// 2. Let key be ? ToPropertyKey(P).
|
||||||
|
auto key = TRY(property.to_property_key(vm));
|
||||||
|
|
||||||
|
// 3. Repeat,
|
||||||
|
while (object) {
|
||||||
|
// a. Let desc be ? O.[[GetOwnProperty]](key).
|
||||||
|
auto desc = TRY(object->internal_get_own_property(key));
|
||||||
|
|
||||||
|
// b. If desc is not undefined, then
|
||||||
|
if (desc.has_value()) {
|
||||||
|
// i. If IsAccessorDescriptor(desc) is true, return desc.[[Set]].
|
||||||
|
if (desc->is_accessor_descriptor())
|
||||||
|
return *desc->set ?: js_undefined();
|
||||||
|
|
||||||
|
// ii. Return undefined.
|
||||||
|
return js_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
// c. Set O to ? O.[[GetPrototypeOf]]().
|
||||||
|
object = TRY(object->internal_get_prototype_of());
|
||||||
|
}
|
||||||
|
|
||||||
|
// d. If O is null, return undefined.
|
||||||
return js_undefined();
|
return js_undefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue