diff --git a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h index a2bbf9e2b1..852d089f4b 100644 --- a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h +++ b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h @@ -13,6 +13,8 @@ namespace JS { #define ENUMERATE_STANDARD_PROPERTY_NAMES(P) \ P(__proto__) \ + P(__defineGetter__) \ + P(__defineSetter__) \ P(BYTES_PER_ELEMENT) \ P(BigInt) \ P(Boolean) \ diff --git a/Userland/Libraries/LibJS/Runtime/ObjectPrototype.cpp b/Userland/Libraries/LibJS/Runtime/ObjectPrototype.cpp index 97e2049c36..87c16d533c 100644 --- a/Userland/Libraries/LibJS/Runtime/ObjectPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/ObjectPrototype.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -37,6 +38,8 @@ void ObjectPrototype::initialize(GlobalObject& global_object) define_native_function(vm.names.isPrototypeOf, is_prototype_of, 1, attr); // Annex B + define_native_function(vm.names.__defineGetter__, define_getter, 2, attr); + define_native_function(vm.names.__defineSetter__, define_setter, 2, attr); define_native_accessor(vm.names.__proto__, proto_getter, proto_setter, Attribute::Configurable); } @@ -147,6 +150,70 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::is_prototype_of) } } +// 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 = vm.this_value(global_object).to_object(global_object); + if (vm.exception()) + return {}; + + auto getter = vm.argument(1); + if (!getter.is_function()) { + vm.throw_exception(global_object, ErrorType::NotAFunction, getter.to_string_without_side_effects()); + return {}; + } + + auto key = vm.argument(0).to_property_key(global_object); + if (vm.exception()) + return {}; + + auto descriptor = Object::create(global_object, global_object.object_prototype()); + descriptor->define_property(vm.names.get, getter); + descriptor->define_property(vm.names.enumerable, Value(true)); + descriptor->define_property(vm.names.configurable, Value(true)); + + auto success = object->define_property(key, *descriptor); + if (vm.exception()) + return {}; + if (!success) { + vm.throw_exception(global_object, ErrorType::ObjectDefinePropertyReturnedFalse); + return {}; + } + 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 = vm.this_value(global_object).to_object(global_object); + if (vm.exception()) + return {}; + + auto setter = vm.argument(1); + if (!setter.is_function()) { + vm.throw_exception(global_object, ErrorType::NotAFunction, setter.to_string_without_side_effects()); + return {}; + } + + auto key = vm.argument(0).to_property_key(global_object); + if (vm.exception()) + return {}; + + auto descriptor = Object::create(global_object, global_object.object_prototype()); + descriptor->define_property(vm.names.set, setter); + descriptor->define_property(vm.names.enumerable, Value(true)); + descriptor->define_property(vm.names.configurable, Value(true)); + + auto success = object->define_property(key, *descriptor); + if (vm.exception()) + return {}; + if (!success) { + vm.throw_exception(global_object, ErrorType::ObjectDefinePropertyReturnedFalse); + return {}; + } + 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) { diff --git a/Userland/Libraries/LibJS/Runtime/ObjectPrototype.h b/Userland/Libraries/LibJS/Runtime/ObjectPrototype.h index b01208a93b..83f41f8f0f 100644 --- a/Userland/Libraries/LibJS/Runtime/ObjectPrototype.h +++ b/Userland/Libraries/LibJS/Runtime/ObjectPrototype.h @@ -27,6 +27,8 @@ private: JS_DECLARE_NATIVE_FUNCTION(value_of); JS_DECLARE_NATIVE_FUNCTION(property_is_enumerable); JS_DECLARE_NATIVE_FUNCTION(is_prototype_of); + JS_DECLARE_NATIVE_FUNCTION(define_getter); + JS_DECLARE_NATIVE_FUNCTION(define_setter); JS_DECLARE_NATIVE_FUNCTION(proto_getter); JS_DECLARE_NATIVE_FUNCTION(proto_setter); };