瀏覽代碼

Update test262 test suite and fix issues (#1589)

* Array.group and Array.groupToMap are now Object.groupBy and Map.groupBy
* add new feature flags to ignore until implementation
Marko Lahma 2 年之前
父節點
當前提交
4057029fe5

+ 3 - 1
Jint.Tests.Test262/Test262Harness.settings.json

@@ -1,16 +1,18 @@
 {
-  "SuiteGitSha": "9704d7f22f6342d6c4753ab9a8d62d6725de8c4e",
+  "SuiteGitSha": "9437cab774ab2f22c5cb971b11b8512eca705721",
   //"SuiteDirectory": "//mnt/c/work/test262",
   "TargetPath": "./Generated",
   "Namespace": "Jint.Tests.Test262",
   "Parallel": true,
   "ExcludedFeatures": [
     "Array.fromAsync",
+    "arraybuffer-transfer",
     "async-iteration",
     "Atomics",
     "decorators",
     "generators",
     "import-assertions",
+    "iterator-helpers",
     "regexp-duplicate-named-groups",
     "regexp-lookbehind",
     "regexp-unicode-property-escapes",

+ 11 - 0
Jint/JsValueExtensions.cs

@@ -582,5 +582,16 @@ namespace Jint
                 return default;
             }
         }
+
+        internal static ICallable GetCallable(this JsValue source, Realm realm)
+        {
+            if (source is ICallable callable)
+            {
+                return callable;
+            }
+
+            ExceptionHelper.ThrowTypeError(realm, "Argument must be callable");
+            return null;
+        }
     }
 }

+ 1 - 78
Jint/Native/Array/ArrayPrototype.cs

@@ -1,7 +1,6 @@
 using System.Linq;
 using Jint.Collections;
 using Jint.Native.Iterator;
-using Jint.Native.Map;
 using Jint.Native.Number;
 using Jint.Native.Object;
 using Jint.Native.Symbol;
@@ -37,7 +36,7 @@ namespace Jint.Native.Array
         protected override void Initialize()
         {
             const PropertyFlag PropertyFlags = PropertyFlag.Writable | PropertyFlag.Configurable;
-            var properties = new PropertyDictionary(40, checkExistingKeys: false)
+            var properties = new PropertyDictionary(38, checkExistingKeys: false)
             {
                 ["constructor"] = new PropertyDescriptor(_constructor, PropertyFlag.NonEnumerable),
 
@@ -55,8 +54,6 @@ namespace Jint.Native.Array
                 ["flat"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "flat", Flat, 0, PropertyFlag.Configurable), PropertyFlags),
                 ["flatMap"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "flatMap", FlatMap, 1, PropertyFlag.Configurable), PropertyFlags),
                 ["forEach"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "forEach", ForEach, 1, PropertyFlag.Configurable), PropertyFlags),
-                ["group"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "group", Group, 1, PropertyFlag.Configurable), PropertyFlags),
-                ["groupToMap"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "groupToMap", GroupToMap, 1, PropertyFlag.Configurable), PropertyFlags),
                 ["includes"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "includes", Includes, 1, PropertyFlag.Configurable), PropertyFlags),
                 ["indexOf"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "indexOf", IndexOf, 1, PropertyFlag.Configurable), PropertyFlags),
                 ["join"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "join", Join, 1, PropertyFlag.Configurable), PropertyFlags),
@@ -105,10 +102,6 @@ namespace Jint.Native.Array
                     unscopables.FastSetDataProperty("findLastIndex", JsBoolean.True);
                     unscopables.FastSetDataProperty("flat", JsBoolean.True);
                     unscopables.FastSetDataProperty("flatMap", JsBoolean.True);
-                    unscopables.FastSetDataProperty("group", JsBoolean.True);
-                    unscopables.FastSetDataProperty("groupBy", JsBoolean.True);
-                    unscopables.FastSetDataProperty("groupByToMap", JsBoolean.True);
-                    unscopables.FastSetDataProperty("groupToMap", JsBoolean.True);
                     unscopables.FastSetDataProperty("includes", JsBoolean.True);
                     unscopables.FastSetDataProperty("keys", JsBoolean.True);
                     unscopables.FastSetDataProperty("toReversed", JsBoolean.True);
@@ -1655,76 +1648,6 @@ namespace Jint.Native.Array
             return element;
         }
 
-        /// <summary>
-        /// https://tc39.es/proposal-array-grouping/#sec-array.prototype.group
-        /// </summary>
-        private JsValue Group(JsValue thisObject, JsValue[] arguments)
-        {
-            var grouping = BuildArrayGrouping(thisObject, arguments, mapMode: false);
-
-            var obj = OrdinaryObjectCreate(_engine, null);
-            foreach (var pair in grouping)
-            {
-                obj.FastSetProperty(pair.Key, new PropertyDescriptor(pair.Value, PropertyFlag.ConfigurableEnumerableWritable));
-            }
-
-            return obj;
-        }
-
-        /// <summary>
-        /// https://tc39.es/proposal-array-grouping/#sec-array.prototype.grouptomap
-        /// </summary>
-        private JsValue GroupToMap(JsValue thisObject, JsValue[] arguments)
-        {
-            var grouping = BuildArrayGrouping(thisObject, arguments, mapMode: true);
-            var map = (MapInstance) Construct(_realm.Intrinsics.Map);
-            foreach (var pair in grouping)
-            {
-                map.MapSet(pair.Key, pair.Value);
-            }
-
-            return map;
-        }
-
-        private Dictionary<JsValue, JsArray> BuildArrayGrouping(JsValue thisObject, JsValue[] arguments, bool mapMode)
-        {
-            var o = ArrayOperations.For(_realm, thisObject);
-            var len = o.GetLongLength();
-            var callbackfn = arguments.At(0);
-            var callable = GetCallable(callbackfn);
-            var thisArg = arguments.At(1);
-
-            var result = new Dictionary<JsValue, JsArray>();
-            var args = _engine._jsValueArrayPool.RentArray(3);
-            args[2] = o.Target;
-            for (uint k = 0; k < len; k++)
-            {
-                var kValue = o.Get(k);
-                args[0] = kValue;
-                args[1] = k;
-
-                var value = callable.Call(thisArg, args);
-                JsValue key;
-                if (mapMode)
-                {
-                    key = (value as JsNumber)?.IsNegativeZero() == true ? JsNumber.PositiveZero : value;
-                }
-                else
-                {
-                    key = TypeConverter.ToPropertyKey(value);
-                }
-                if (!result.TryGetValue(key, out var list))
-                {
-                    result[key] = list = new JsArray(_engine);
-                }
-
-                list.SetIndexValue(list.GetLength(), kValue, updateLength: true);
-            }
-
-            _engine._jsValueArrayPool.ReturnArray(args);
-            return result;
-        }
-
         private object[] CreateBackingArray(ulong length)
         {
             ValidateArrayLength(length);

+ 75 - 0
Jint/Native/GroupByHelper.cs

@@ -0,0 +1,75 @@
+using Jint.Native.Array;
+using Jint.Native.Iterator;
+using Jint.Runtime;
+
+namespace Jint.Native;
+
+internal static class GroupByHelper
+{
+    internal static Dictionary<JsValue, JsArray> GroupBy(
+        Engine engine,
+        Realm realm,
+        JsValue items,
+        JsValue callbackfn,
+        bool mapMode)
+    {
+        var callable = callbackfn.GetCallable(realm);
+        var groups = new Dictionary<JsValue, JsArray>();
+        var iteratorRecord = items.GetIterator(realm);
+        new GroupByProtocol(engine, groups, iteratorRecord, callable, mapMode).Execute();
+        return groups;
+    }
+
+    private sealed class GroupByProtocol : IteratorProtocol
+    {
+        private readonly Engine _engine;
+        private readonly Dictionary<JsValue, JsArray> _result;
+        private readonly ICallable _callable;
+        private readonly bool _mapMode;
+        private ulong _k;
+        private readonly JsValue[] _callArgs = new JsValue[2];
+
+        public GroupByProtocol(
+            Engine engine,
+            Dictionary<JsValue, JsArray> result,
+            IteratorInstance iterator,
+            ICallable callable,
+            bool mapMode) : base(engine, iterator, 0)
+        {
+            _engine = engine;
+            _result = result;
+            _callable = callable;
+            _mapMode = mapMode;
+        }
+
+        protected override void ProcessItem(JsValue[] args, JsValue currentValue)
+        {
+            if (_k >= ArrayOperations.MaxArrayLength)
+            {
+                ExceptionHelper.ThrowTypeError(_engine.Realm);
+            }
+
+            _callArgs[0] = currentValue;
+            _callArgs[1] = _k;
+
+            var value = _callable.Call(JsValue.Undefined, _callArgs);
+            JsValue key;
+            if (_mapMode)
+            {
+                key = (value as JsNumber)?.IsNegativeZero() == true ? JsNumber.PositiveZero : value;
+            }
+            else
+            {
+                key = TypeConverter.ToPropertyKey(value);
+            }
+
+            if (!_result.TryGetValue(key, out var list))
+            {
+                _result[key] = list = new JsArray(_engine);
+            }
+
+            list.Push(currentValue);
+            _k++;
+        }
+    }
+}

+ 25 - 0
Jint/Native/Map/MapConstructor.cs

@@ -30,6 +30,13 @@ internal sealed class MapConstructor : Constructor
 
     protected override void Initialize()
     {
+        const PropertyFlag PropertyFlags = PropertyFlag.Writable | PropertyFlag.Configurable;
+        var properties = new PropertyDictionary(1, checkExistingKeys: false)
+        {
+            ["groupBy"] = new(new ClrFunctionInstance(Engine, "groupBy", GroupBy, 2, PropertyFlag.Configurable), PropertyFlags),
+        };
+        SetProperties(properties);
+
         var symbols = new SymbolDictionary(1)
         {
             [GlobalSymbolRegistry.Species] = new GetSetPropertyDescriptor(get: new ClrFunctionInstance(_engine, "get [Symbol.species]", Species, 0, PropertyFlag.Configurable), set: Undefined, PropertyFlag.Configurable)
@@ -67,4 +74,22 @@ internal sealed class MapConstructor : Constructor
 
         return map;
     }
+
+
+    /// <summary>
+    /// https://tc39.es/proposal-array-grouping/#sec-map.groupby
+    /// </summary>
+    private JsValue GroupBy(JsValue thisObject, JsValue[] arguments)
+    {
+        var items = arguments.At(0);
+        var callbackfn = arguments.At(1);
+        var grouping = GroupByHelper.GroupBy(_engine, _realm, items, callbackfn, mapMode: true);
+        var map = (MapInstance) Construct(_realm.Intrinsics.Map);
+        foreach (var pair in grouping)
+        {
+            map.MapSet(pair.Key, pair.Value);
+        }
+
+        return map;
+    }
 }

+ 44 - 25
Jint/Native/Object/ObjectConstructor.cs

@@ -26,32 +26,33 @@ namespace Jint.Native.Object
         {
             _prototype = _realm.Intrinsics.Function.PrototypeObject;
 
-            const PropertyFlag propertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
-            const PropertyFlag lengthFlags = PropertyFlag.Configurable;
-            var properties = new PropertyDictionary(15, checkExistingKeys: false)
+            const PropertyFlag PropertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
+            const PropertyFlag LengthFlags = PropertyFlag.Configurable;
+            var properties = new PropertyDictionary(16, checkExistingKeys: false)
             {
-                ["assign"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "assign", Assign, 2, lengthFlags), propertyFlags),
-                ["entries"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "entries", Entries, 1, lengthFlags), propertyFlags),
-                ["fromEntries"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "fromEntries", FromEntries, 1, lengthFlags), propertyFlags),
-                ["getPrototypeOf"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getPrototypeOf", GetPrototypeOf, 1), propertyFlags),
-                ["getOwnPropertyDescriptor"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getOwnPropertyDescriptor", GetOwnPropertyDescriptor, 2, lengthFlags), propertyFlags),
-                ["getOwnPropertyDescriptors"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getOwnPropertyDescriptors", GetOwnPropertyDescriptors, 1, lengthFlags), propertyFlags),
-                ["getOwnPropertyNames"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getOwnPropertyNames", GetOwnPropertyNames, 1), propertyFlags),
-                ["getOwnPropertySymbols"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getOwnPropertySymbols", GetOwnPropertySymbols, 1, lengthFlags), propertyFlags),
-                ["create"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "create", Create, 2), propertyFlags),
-                ["defineProperty"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "defineProperty", DefineProperty, 3), propertyFlags),
-                ["defineProperties"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "defineProperties", DefineProperties, 2), propertyFlags),
-                ["is"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "is", Is, 2, lengthFlags), propertyFlags),
-                ["seal"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "seal", Seal, 1, lengthFlags), propertyFlags),
-                ["freeze"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "freeze", Freeze, 1), propertyFlags),
-                ["preventExtensions"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "preventExtensions", PreventExtensions, 1), propertyFlags),
-                ["isSealed"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "isSealed", IsSealed, 1), propertyFlags),
-                ["isFrozen"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "isFrozen", IsFrozen, 1), propertyFlags),
-                ["isExtensible"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "isExtensible", IsExtensible, 1), propertyFlags),
-                ["keys"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "keys", Keys, 1, lengthFlags), propertyFlags),
-                ["values"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "values", Values, 1, lengthFlags), propertyFlags),
-                ["setPrototypeOf"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setPrototypeOf", SetPrototypeOf, 2, lengthFlags), propertyFlags),
-                ["hasOwn"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "hasOwn", HasOwn, 2, lengthFlags), propertyFlags),
+                ["assign"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "assign", Assign, 2, LengthFlags), PropertyFlags),
+                ["entries"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "entries", Entries, 1, LengthFlags), PropertyFlags),
+                ["fromEntries"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "fromEntries", FromEntries, 1, LengthFlags), PropertyFlags),
+                ["getPrototypeOf"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getPrototypeOf", GetPrototypeOf, 1), PropertyFlags),
+                ["getOwnPropertyDescriptor"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getOwnPropertyDescriptor", GetOwnPropertyDescriptor, 2, LengthFlags), PropertyFlags),
+                ["getOwnPropertyDescriptors"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getOwnPropertyDescriptors", GetOwnPropertyDescriptors, 1, LengthFlags), PropertyFlags),
+                ["getOwnPropertyNames"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getOwnPropertyNames", GetOwnPropertyNames, 1), PropertyFlags),
+                ["getOwnPropertySymbols"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getOwnPropertySymbols", GetOwnPropertySymbols, 1, LengthFlags), PropertyFlags),
+                ["groupBy"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "groupBy", GroupBy, 2, PropertyFlag.Configurable), PropertyFlags),
+                ["create"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "create", Create, 2), PropertyFlags),
+                ["defineProperty"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "defineProperty", DefineProperty, 3), PropertyFlags),
+                ["defineProperties"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "defineProperties", DefineProperties, 2), PropertyFlags),
+                ["is"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "is", Is, 2, LengthFlags), PropertyFlags),
+                ["seal"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "seal", Seal, 1, LengthFlags), PropertyFlags),
+                ["freeze"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "freeze", Freeze, 1), PropertyFlags),
+                ["preventExtensions"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "preventExtensions", PreventExtensions, 1), PropertyFlags),
+                ["isSealed"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "isSealed", IsSealed, 1), PropertyFlags),
+                ["isFrozen"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "isFrozen", IsFrozen, 1), PropertyFlags),
+                ["isExtensible"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "isExtensible", IsExtensible, 1), PropertyFlags),
+                ["keys"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "keys", Keys, 1, LengthFlags), PropertyFlags),
+                ["values"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "values", Values, 1, LengthFlags), PropertyFlags),
+                ["setPrototypeOf"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setPrototypeOf", SetPrototypeOf, 2, LengthFlags), PropertyFlags),
+                ["hasOwn"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "hasOwn", HasOwn, 2, LengthFlags), PropertyFlags),
             };
             SetProperties(properties);
         }
@@ -525,6 +526,24 @@ namespace Jint.Native.Object
             return o.EnumerableOwnPropertyNames(EnumerableOwnPropertyNamesKind.Value);
         }
 
+        /// <summary>
+        /// https://tc39.es/proposal-array-grouping/#sec-object.groupby
+        /// </summary>
+        private JsValue GroupBy(JsValue thisObject, JsValue[] arguments)
+        {
+            var items = arguments.At(0);
+            var callbackfn = arguments.At(1);
+            var grouping = GroupByHelper.GroupBy(_engine, _realm, items, callbackfn, mapMode: false);
+
+            var obj = OrdinaryObjectCreate(_engine, null);
+            foreach (var pair in grouping)
+            {
+                obj.FastSetProperty(pair.Key, new PropertyDescriptor(pair.Value, PropertyFlag.ConfigurableEnumerableWritable));
+            }
+
+            return obj;
+        }
+
         private sealed class CreateDataPropertyOnObject : ICallable
         {
             internal static readonly CreateDataPropertyOnObject Instance = new();

+ 1 - 10
Jint/Native/Object/ObjectInstance.cs

@@ -1173,16 +1173,7 @@ namespace Jint.Native.Object
             return false;
         }
 
-        internal ICallable GetCallable(JsValue source)
-        {
-            if (source is ICallable callable)
-            {
-                return callable;
-            }
-
-            ExceptionHelper.ThrowTypeError(_engine.Realm, "Argument must be callable");
-            return null;
-        }
+        internal ICallable GetCallable(JsValue source) => source.GetCallable(_engine.Realm);
 
         internal bool IsConcatSpreadable
         {

+ 2 - 0
NuGet.config

@@ -3,7 +3,9 @@
   <packageSources>
     <clear />
     <add key="NuGet" value="https://api.nuget.org/v3/index.json" />
+    <!--
     <add key="Esprima" value="https://www.myget.org/F/esprimadotnet/api/v3/index.json" />
+    -->
   </packageSources>
   <disabledPackageSources />
 </configuration>

+ 1 - 1
README.md

@@ -108,7 +108,7 @@ Following features are supported in version 3.x.
 
 #### ECMAScript Stage 3 (no version yet)
 
-- ✔ Array.group and Array.groupToMap
+- ✔ Array Grouping - `Object.groupBy` and `Map.groupBy`
 - ✔ ShadowRealm
 
 #### Other