Browse Source

Implement __defineGetter__ and __defineSetter__ (#1203)

Marko Lahma 3 years ago
parent
commit
6b2fcd467f

+ 0 - 2
Jint.Tests.Test262/Test262Harness.settings.json

@@ -5,8 +5,6 @@
   "Namespace": "Jint.Tests.Test262",
   "Namespace": "Jint.Tests.Test262",
   "Parallel": true,
   "Parallel": true,
   "ExcludedFeatures": [
   "ExcludedFeatures": [
-    "__getter__",
-    "__setter__",
     "async-functions",
     "async-functions",
     "async-iteration",
     "async-iteration",
     "Atomics",
     "Atomics",

+ 106 - 4
Jint/Native/Object/ObjectPrototype.cs

@@ -25,15 +25,19 @@ namespace Jint.Native.Object
         {
         {
             const PropertyFlag propertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
             const PropertyFlag propertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
             const PropertyFlag lengthFlags = PropertyFlag.Configurable;
             const PropertyFlag lengthFlags = PropertyFlag.Configurable;
-            var properties = new PropertyDictionary(8, checkExistingKeys: false)
+            var properties = new PropertyDictionary(12, checkExistingKeys: false)
             {
             {
                 ["constructor"] = new PropertyDescriptor(_constructor, propertyFlags),
                 ["constructor"] = new PropertyDescriptor(_constructor, propertyFlags),
+                ["__defineGetter__"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "__defineGetter__", DefineGetter, 2, lengthFlags), propertyFlags),
+                ["__defineSetter__"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "__defineSetter__", DefineSetter, 2, lengthFlags), propertyFlags),
+                ["__lookupGetter__"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "__lookupGetter__", LookupGetter, 1, lengthFlags), propertyFlags),
+                ["__lookupSetter__"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "__lookupSetter__", LookupSetter, 1, lengthFlags), propertyFlags),
                 ["__proto__"] = new GetSetPropertyDescriptor(
                 ["__proto__"] = new GetSetPropertyDescriptor(
                     new ClrFunctionInstance(Engine, "get __proto__", (thisObject, _) => TypeConverter.ToObject(_realm, thisObject).GetPrototypeOf() ?? Null, 0, lengthFlags),
                     new ClrFunctionInstance(Engine, "get __proto__", (thisObject, _) => TypeConverter.ToObject(_realm, thisObject).GetPrototypeOf() ?? Null, 0, lengthFlags),
                     new ClrFunctionInstance(Engine, "set __proto__", (thisObject, arguments) =>
                     new ClrFunctionInstance(Engine, "set __proto__", (thisObject, arguments) =>
                     {
                     {
                         TypeConverter.CheckObjectCoercible(_engine, thisObject);
                         TypeConverter.CheckObjectCoercible(_engine, thisObject);
-                        
+
                         var proto = arguments.At(0);
                         var proto = arguments.At(0);
                         if (!proto.IsObject() && !proto.IsNull() || thisObject is not ObjectInstance objectInstance)
                         if (!proto.IsObject() && !proto.IsNull() || thisObject is not ObjectInstance objectInstance)
                         {
                         {
@@ -44,7 +48,7 @@ namespace Jint.Native.Object
                         {
                         {
                             ExceptionHelper.ThrowTypeError(_realm, "Invalid prototype");
                             ExceptionHelper.ThrowTypeError(_realm, "Invalid prototype");
                         }
                         }
-                        
+
                         return Undefined;
                         return Undefined;
                     }, 0, lengthFlags),
                     }, 0, lengthFlags),
                     enumerable: false, configurable: true),
                     enumerable: false, configurable: true),
@@ -57,7 +61,7 @@ namespace Jint.Native.Object
             };
             };
             SetProperties(properties);
             SetProperties(properties);
         }
         }
-        
+
         public override bool DefineOwnProperty(JsValue property, PropertyDescriptor desc)
         public override bool DefineOwnProperty(JsValue property, PropertyDescriptor desc)
         {
         {
             TrackChanges(property);
             TrackChanges(property);
@@ -83,6 +87,104 @@ namespace Jint.Native.Object
             }
             }
         }
         }
 
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-object.prototype.__defineGetter__
+        /// </summary>
+        private JsValue DefineGetter(JsValue thisObject, JsValue[] arguments)
+        {
+            var o = TypeConverter.ToObject(_realm, thisObject);
+            var p = arguments.At(0);
+            var getter = arguments.At(1);
+
+            if (!getter.IsCallable)
+            {
+                ExceptionHelper.ThrowTypeError(_realm, "Target is not callable");
+            }
+
+            var desc = new GetSetPropertyDescriptor(getter, null, enumerable: true, configurable: true);
+            var key = TypeConverter.ToPropertyKey(p);
+            o.DefinePropertyOrThrow(key, desc);
+
+            return Undefined;
+        }
+
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-object.prototype.__defineSetter__
+        /// </summary>
+        private JsValue DefineSetter(JsValue thisObject, JsValue[] arguments)
+        {
+            var o = TypeConverter.ToObject(_realm, thisObject);
+            var p = arguments.At(0);
+            var setter = arguments.At(1);
+
+            if (!setter.IsCallable)
+            {
+                ExceptionHelper.ThrowTypeError(_realm, "Target is not callable");
+            }
+
+            var desc = new GetSetPropertyDescriptor(null, setter, enumerable: true, configurable: true);
+            var key = TypeConverter.ToPropertyKey(p);
+            o.DefinePropertyOrThrow(key, desc);
+
+            return Undefined;
+        }
+
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-object.prototype.__lookupGetter__
+        /// </summary>
+        private JsValue LookupGetter(JsValue thisObject, JsValue[] arguments)
+        {
+            var o = TypeConverter.ToObject(_realm, thisObject);
+            var key = TypeConverter.ToPropertyKey(arguments.At(0));
+            while (true)
+            {
+                var desc = o.GetOwnProperty(key);
+                if (!ReferenceEquals(desc, PropertyDescriptor.Undefined))
+                {
+                    if (desc.IsAccessorDescriptor())
+                    {
+                        return desc.Get ?? Undefined;
+                    }
+
+                    return Undefined;
+                }
+
+                o = o.GetPrototypeOf();
+                if (o is null)
+                {
+                    return Undefined;
+                }
+            }
+        }
+
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-object.prototype.__lookupSetter__
+        /// </summary>
+        private JsValue LookupSetter(JsValue thisObject, JsValue[] arguments)
+        {
+            var o = TypeConverter.ToObject(_realm, thisObject);
+            var key = TypeConverter.ToPropertyKey(arguments.At(0));
+            while (true)
+            {
+                var desc = o.GetOwnProperty(key);
+                if (!ReferenceEquals(desc, PropertyDescriptor.Undefined))
+                {
+                    if (desc.IsAccessorDescriptor())
+                    {
+                        return desc.Set ?? Undefined;
+                    }
+
+                    return Undefined;
+                }
+
+                o = o.GetPrototypeOf();
+                if (o is null)
+                {
+                    return Undefined;
+                }
+            }
+        }
+
         private JsValue PropertyIsEnumerable(JsValue thisObject, JsValue[] arguments)
         private JsValue PropertyIsEnumerable(JsValue thisObject, JsValue[] arguments)
         {
         {
             var p = TypeConverter.ToPropertyKey(arguments[0]);
             var p = TypeConverter.ToPropertyKey(arguments[0]);