Browse Source

Update test suite and implement Set.union (#1692)

Marko Lahma 1 năm trước cách đây
mục cha
commit
c3fe5c5dbc

+ 1 - 1
Jint.Benchmark/README.md

@@ -9,7 +9,7 @@ dotnet run -c Release --allCategories EngineComparison
 * tests are run in global engine strict mode, as YantraJS always uses strict mode which improves performance
 * `Jint` and `Jint_ParsedScript` shows the difference between always parsing the script source file and reusing parsed `Script` instance.
 
-Last updated 2023-11-05
+Last updated 2023-11-24
 
 * Jint main
 * Jurassic 3.2.7

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

@@ -1,5 +1,5 @@
 {
-  "SuiteGitSha": "6396ebde0316639292530460d1ef961fd9bbe0d4",
+  "SuiteGitSha": "2060494f280ba89d71a0f51d4ff171bafe476a05",
   //"SuiteDirectory": "//mnt/c/work/test262",
   "TargetPath": "./Generated",
   "Namespace": "Jint.Tests.Test262",
@@ -12,6 +12,7 @@
     "decorators",
     "generators",
     "import-assertions",
+    "import-attributes",
     "iterator-helpers",
     "regexp-duplicate-named-groups",
     "regexp-lookbehind",
@@ -47,6 +48,7 @@
     "built-ins/RegExp/prototype/exec/S15.10.6.2_A1_T6.js",
     "language/literals/regexp/u-case-mapping.js",
     "built-ins/RegExp/lookahead-quantifier-match-groups.js",
+    "built-ins/RegExp/unicode_full_case_folding.js",
 
     // requires investigation how to process complex function name evaluation for property
     "built-ins/Function/prototype/toString/method-computed-property-name.js",
@@ -85,6 +87,8 @@
     "language/expressions/object/method-definition/name-prop-name-yield-id.js",
     "language/statements/class/elements/*-generator-method-*.js",
     "language/expressions/class/elements/*-generator-method-*.js",
+    "built-ins/Set/prototype/union/allows-set-like-class.js",
+    "built-ins/Set/prototype/union/allows-set-like-object.js",
 
     // generators not implemented
     "built-ins/Object/prototype/toString/proxy-function.js",

+ 12 - 1
Jint/Native/JsValue.cs

@@ -54,7 +54,18 @@ namespace Jint.Native
         }
 
         [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        internal IteratorInstance GetIteratorFromMethod(Realm realm, ICallable method)
+        {
+            var iterator = method.Call(this);
+            if (iterator is not ObjectInstance objectInstance)
+            {
+                ExceptionHelper.ThrowTypeError(realm);
+                return null!;
+            }
+            return new IteratorInstance.ObjectIterator(objectInstance);
+        }
+
+        [Pure]
         internal bool TryGetIterator(Realm realm, [NotNullWhen(true)] out IteratorInstance? iterator, GeneratorKind hint = GeneratorKind.Sync, ICallable? method = null)
         {
             var obj = TypeConverter.ToObject(realm, this);

+ 6 - 2
Jint/Native/Set/JsSet.cs

@@ -9,9 +9,13 @@ internal sealed class JsSet : ObjectInstance
 {
     internal readonly OrderedSet<JsValue> _set;
 
-    public JsSet(Engine engine) : base(engine)
+    public JsSet(Engine engine) : this(engine, new OrderedSet<JsValue>(SameValueZeroComparer.Instance))
     {
-        _set = new OrderedSet<JsValue>(SameValueZeroComparer.Instance);
+    }
+
+    public JsSet(Engine engine, OrderedSet<JsValue> set) : base(engine)
+    {
+        _set = set;
     }
 
     public override PropertyDescriptor GetOwnProperty(JsValue property)

+ 1 - 1
Jint/Native/Set/SetConstructor.cs

@@ -25,7 +25,7 @@ internal sealed class SetConstructor : Constructor
         _prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
     }
 
-    private SetPrototype PrototypeObject { get; }
+    internal SetPrototype PrototypeObject { get; }
 
     protected override void Initialize()
     {

+ 72 - 9
Jint/Native/Set/SetPrototype.cs

@@ -32,15 +32,16 @@ internal sealed class SetPrototype : Prototype
         {
             ["length"] = new PropertyDescriptor(0, PropertyFlag.Configurable),
             ["constructor"] = new PropertyDescriptor(_constructor, PropertyFlag.NonEnumerable),
-            ["add"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "add", Add, 1, PropertyFlag.Configurable), true, false, true),
-            ["clear"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "clear", Clear, 0, PropertyFlag.Configurable), true, false, true),
-            ["delete"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "delete", Delete, 1, PropertyFlag.Configurable), true, false, true),
-            ["entries"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "entries", Entries, 0, PropertyFlag.Configurable), true, false, true),
-            ["forEach"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "forEach", ForEach, 1, PropertyFlag.Configurable), true, false, true),
-            ["has"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "has", Has, 1, PropertyFlag.Configurable), true, false, true),
-            ["keys"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "keys", Values, 0, PropertyFlag.Configurable), true, false, true),
-            ["values"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "values", Values, 0, PropertyFlag.Configurable), true, false, true),
-            ["size"] = new GetSetPropertyDescriptor(get: new ClrFunctionInstance(Engine, "get size", Size, 0, PropertyFlag.Configurable), set: null, PropertyFlag.Configurable)
+            ["add"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "add", Add, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
+            ["clear"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "clear", Clear, 0, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
+            ["delete"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "delete", Delete, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
+            ["entries"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "entries", Entries, 0, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
+            ["forEach"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "forEach", ForEach, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
+            ["has"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "has", Has, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
+            ["keys"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "keys", Values, 0, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
+            ["values"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "values", Values, 0, PropertyFlag.Configurable), PropertyFlag.NonEnumerable),
+            ["size"] = new GetSetPropertyDescriptor(get: new ClrFunctionInstance(Engine, "get size", Size, 0, PropertyFlag.Configurable), set: null, PropertyFlag.Configurable),
+            ["union"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "union", Union, 1, PropertyFlag.Configurable), PropertyFlag.NonEnumerable)
         };
         SetProperties(properties);
 
@@ -112,6 +113,68 @@ internal sealed class SetPrototype : Prototype
         return Undefined;
     }
 
+    private JsValue Union(JsValue thisObject, JsValue[] arguments)
+    {
+        var set = AssertSetInstance(thisObject);
+        var other = arguments.At(0);
+        var otherRec = GetSetRecord(other);
+        var keysIter = otherRec.Set.GetIteratorFromMethod(_realm, otherRec.Keys);
+        var resultSetData = set._set.Clone();
+        while (keysIter.TryIteratorStep(out var next))
+        {
+            var nextValue = next.Get(CommonProperties.Value);
+            if (nextValue == JsNumber.NegativeZero)
+            {
+                nextValue = JsNumber.PositiveZero;
+            }
+            resultSetData.Add(nextValue);
+        }
+
+        var result = new JsSet(_engine, resultSetData)
+        {
+            _prototype = _engine.Realm.Intrinsics.Set.PrototypeObject
+        };
+        return result;
+
+    }
+
+    private readonly record struct SetRecord(JsValue Set, double Size, ICallable Has, ICallable Keys);
+
+    private SetRecord GetSetRecord(JsValue obj)
+    {
+        if (obj is not ObjectInstance)
+        {
+            ExceptionHelper.ThrowTypeError(_realm);
+        }
+
+        var rawSize = obj.Get("size");
+        var numSize = TypeConverter.ToNumber(rawSize);
+        if (double.IsNaN(numSize))
+        {
+            ExceptionHelper.ThrowTypeError(_realm);
+        }
+
+        var intSize = TypeConverter.ToIntegerOrInfinity(numSize);
+        if (intSize < 0)
+        {
+            ExceptionHelper.ThrowRangeError(_realm);
+        }
+
+        var has = obj.Get(CommonProperties.Has);
+        if (!has.IsCallable)
+        {
+            ExceptionHelper.ThrowTypeError(_realm);
+        }
+
+        var keys = obj.Get(CommonProperties.Keys);
+        if (!keys.IsCallable)
+        {
+            ExceptionHelper.ThrowTypeError(_realm);
+        }
+
+        return new SetRecord(Set: obj, Size: intSize, Has: (ICallable) has, Keys: (ICallable) keys);
+    }
+
     private ObjectInstance Values(JsValue thisObject, JsValue[] arguments)
     {
         var set = AssertSetInstance(thisObject);

+ 26 - 25
Jint/Runtime/CommonProperties.cs

@@ -1,29 +1,30 @@
 using Jint.Native;
 
-namespace Jint.Runtime
+namespace Jint.Runtime;
+
+internal static class CommonProperties
 {
-    internal static class CommonProperties
-    {
-        internal static readonly JsString Arguments = JsString.CachedCreate("arguments");
-        internal static readonly JsString Caller = JsString.CachedCreate("caller");
-        internal static readonly JsString Callee = JsString.CachedCreate("callee");
-        internal static readonly JsString Constructor = JsString.CachedCreate("constructor");
-        internal static readonly JsString Eval = JsString.CachedCreate("eval");
-        internal static readonly JsString Infinity = JsString.CachedCreate("Infinity");
-        internal static readonly JsString Length = JsString.CachedCreate("length");
-        internal static readonly JsString Name = JsString.CachedCreate("name");
-        internal static readonly JsString Prototype = JsString.CachedCreate("prototype");
-        internal static readonly JsString Size = JsString.CachedCreate("size");
-        internal static readonly JsString Next = JsString.CachedCreate("next");
-        internal static readonly JsString Done = JsString.CachedCreate("done");
-        internal static readonly JsString Value = JsString.CachedCreate("value");
-        internal static readonly JsString Return = JsString.CachedCreate("return");
-        internal static readonly JsString Set = JsString.CachedCreate("set");
-        internal static readonly JsString Get = JsString.CachedCreate("get");
-        internal static readonly JsString Writable = JsString.CachedCreate("writable");
-        internal static readonly JsString Enumerable = JsString.CachedCreate("enumerable");
-        internal static readonly JsString Configurable = JsString.CachedCreate("configurable");
-        internal static readonly JsString Stack = JsString.CachedCreate("stack");
-        internal static readonly JsString Message = JsString.CachedCreate("message");
-    }
+    internal static readonly JsString Arguments = JsString.CachedCreate("arguments");
+    internal static readonly JsString Callee = JsString.CachedCreate("callee");
+    internal static readonly JsString Caller = JsString.CachedCreate("caller");
+    internal static readonly JsString Configurable = JsString.CachedCreate("configurable");
+    internal static readonly JsString Constructor = JsString.CachedCreate("constructor");
+    internal static readonly JsString Done = JsString.CachedCreate("done");
+    internal static readonly JsString Enumerable = JsString.CachedCreate("enumerable");
+    internal static readonly JsString Eval = JsString.CachedCreate("eval");
+    internal static readonly JsString Get = JsString.CachedCreate("get");
+    internal static readonly JsString Has = JsString.CachedCreate("has");
+    internal static readonly JsString Infinity = JsString.CachedCreate("Infinity");
+    internal static readonly JsString Keys = JsString.CachedCreate("keys");
+    internal static readonly JsString Length = JsString.CachedCreate("length");
+    internal static readonly JsString Message = JsString.CachedCreate("message");
+    internal static readonly JsString Name = JsString.CachedCreate("name");
+    internal static readonly JsString Next = JsString.CachedCreate("next");
+    internal static readonly JsString Prototype = JsString.CachedCreate("prototype");
+    internal static readonly JsString Return = JsString.CachedCreate("return");
+    internal static readonly JsString Set = JsString.CachedCreate("set");
+    internal static readonly JsString Size = JsString.CachedCreate("size");
+    internal static readonly JsString Stack = JsString.CachedCreate("stack");
+    internal static readonly JsString Value = JsString.CachedCreate("value");
+    internal static readonly JsString Writable = JsString.CachedCreate("writable");
 }

+ 41 - 33
Jint/Runtime/OrderedSet.cs

@@ -1,50 +1,58 @@
-namespace Jint.Runtime
+namespace Jint.Runtime;
+
+internal sealed class OrderedSet<T>
 {
-    internal sealed class OrderedSet<T>
-    {
-        internal readonly List<T> _list;
-        private readonly HashSet<T> _set;
+    internal List<T> _list;
+    private HashSet<T> _set;
 
-        public OrderedSet(IEqualityComparer<T> comparer)
-        {
-            _list = new List<T>();
-            _set = new HashSet<T>(comparer);
-        }
+    public OrderedSet(IEqualityComparer<T> comparer)
+    {
+        _list = new List<T>();
+        _set = new HashSet<T>(comparer);
+    }
 
-        public T this[int index]
+    public T this[int index]
+    {
+        get => _list[index];
+        set
         {
-            get => _list[index];
-            set
+            if (_set.Add(value))
             {
-                if (_set.Add(value))
-                {
-                    _list[index] = value;
-                }
+                _list[index] = value;
             }
         }
+    }
 
-        public void Add(T item)
+    public OrderedSet<T> Clone()
+    {
+        return new OrderedSet<T>(EqualityComparer<T>.Default)
         {
-            if (_set.Add(item))
-            {
-                _list.Add(item);
-            }
-        }
+            _set = new HashSet<T>(this._set, this._set.Comparer),
+            _list = new List<T>(this._list)
+        };
+    }
 
-        public void Clear()
+    public void Add(T item)
+    {
+        if (_set.Add(item))
         {
-            _list.Clear();
-            _set.Clear();
+            _list.Add(item);
         }
+    }
+
+    public void Clear()
+    {
+        _list.Clear();
+        _set.Clear();
+    }
 
-        public bool Contains(T item) => _set.Contains(item);
+    public bool Contains(T item) => _set.Contains(item);
 
-        public int Count => _list.Count;
+    public int Count => _list.Count;
 
-        public bool Remove(T item)
-        {
-            _set.Remove(item);
-            return _list.Remove(item);
-        }
+    public bool Remove(T item)
+    {
+        _set.Remove(item);
+        return _list.Remove(item);
     }
 }