From b1ea436093f4b7df41e2137d8533153f8af0dfab Mon Sep 17 00:00:00 2001 From: Linus Groh Date: Fri, 14 Apr 2023 17:05:50 +0200 Subject: LibJS: Add spec comments to ObjectPrototype --- .../Libraries/LibJS/Runtime/ObjectPrototype.cpp | 219 ++++++++++++++------- 1 file changed, 149 insertions(+), 70 deletions(-) (limited to 'Userland/Libraries/LibJS/Runtime') diff --git a/Userland/Libraries/LibJS/Runtime/ObjectPrototype.cpp b/Userland/Libraries/LibJS/Runtime/ObjectPrototype.cpp index 7c13b1a583..addd958b37 100644 --- a/Userland/Libraries/LibJS/Runtime/ObjectPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/ObjectPrototype.cpp @@ -60,11 +60,74 @@ ThrowCompletionOr ObjectPrototype::internal_set_prototype_of(Object* proto // 20.1.3.2 Object.prototype.hasOwnProperty ( V ), https://tc39.es/ecma262/#sec-object.prototype.hasownproperty 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)); + + // 2. Let O be ? ToObject(this value). 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))); } +// 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 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)); } -// 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 JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::value_of) { + // 1. Return ? ToObject(this value). return TRY(vm.this_value().to_object(vm)); } -// 20.1.3.4 Object.prototype.propertyIsEnumerable ( V ), https://tc39.es/ecma262/#sec-object.prototype.propertyisenumerable -JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::property_is_enumerable) +// 20.1.3.8.1 get Object.prototype.__proto__, https://tc39.es/ecma262/#sec-get-object.prototype.__proto__ +JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::proto_getter) { - // 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); + // 1. Let O be ? ToObject(this value). + auto object = TRY(vm.this_value().to_object(vm)); + + // 2. Return ? O.[[GetPrototypeOf]](). + return TRY(object->internal_get_prototype_of()); } -// 20.1.3.3 Object.prototype.isPrototypeOf ( V ), https://tc39.es/ecma262/#sec-object.prototype.isprototypeof -JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::is_prototype_of) +// 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) { - 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)); + auto proto = vm.argument(0); - for (;;) { - object = TRY(object->internal_get_prototype_of()); - if (!object) - return Value(false); - if (same_value(this_object, object)) - return Value(true); + // 1. Let O be ? RequireObjectCoercible(this value). + auto object = TRY(require_object_coercible(vm, vm.this_value())); + + // 2. If proto is not an Object and proto is not null, return undefined. + if (!proto.is_object() && !proto.is_null()) + return js_undefined(); + + // 3. If O is not an Object, return undefined. + if (!object.is_object()) + 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)); + + // 5. If status is false, throw a TypeError exception. + if (!status) { + // FIXME: Improve/contextualize error message + return vm.throw_completion(ErrorType::ObjectSetPrototypeOfReturnedFalse); } + + // 6. Return undefined. + return js_undefined(); } -// B.2.2.2 Object.prototype.__defineGetter__ ( P, getter ), https://tc39.es/ecma262/#sec-object.prototype.__defineGetter__ +// 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)); - auto getter = vm.argument(1); + // 2. If IsCallable(getter) is false, throw a TypeError exception. if (!getter.is_function()) return vm.throw_completion(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 }; - auto key = TRY(vm.argument(0).to_property_key(vm)); + // 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(); } -// B.2.2.3 Object.prototype.__defineSetter__ ( P, getter ), https://tc39.es/ecma262/#sec-object.prototype.__defineSetter__ +// 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)); - auto setter = vm.argument(1); + // 2. If IsCallable(setter) is false, throw a TypeError exception. if (!setter.is_function()) return vm.throw_completion(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 }; - auto key = TRY(vm.argument(0).to_property_key(vm)); + // 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(); } -// B.2.2.4 Object.prototype.__lookupGetter__ ( P ), https://tc39.es/ecma262/#sec-object.prototype.__lookupGetter__ +// 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)) }; - auto key = TRY(vm.argument(0).to_property_key(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(); } -// B.2.2.5 Object.prototype.__lookupSetter__ ( P ), https://tc39.es/ecma262/#sec-object.prototype.__lookupSetter__ +// 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)) }; - auto key = TRY(vm.argument(0).to_property_key(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()); } - 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) -{ - auto object = TRY(vm.this_value().to_object(vm)); - 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__ -JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::proto_setter) -{ - auto object = TRY(require_object_coercible(vm, vm.this_value())); - - auto proto = vm.argument(0); - if (!proto.is_object() && !proto.is_null()) - return js_undefined(); - - if (!object.is_object()) - return js_undefined(); - - auto status = TRY(object.as_object().internal_set_prototype_of(proto.is_object() ? &proto.as_object() : nullptr)); - if (!status) { - // FIXME: Improve/contextualize error message - return vm.throw_completion(ErrorType::ObjectSetPrototypeOfReturnedFalse); - } + // d. If O is null, return undefined. return js_undefined(); } -- cgit v1.2.3