Просмотр исходного кода

Fix some prototype chain issues uncovered by compat-table (#1334)

Marko Lahma 2 лет назад
Родитель
Сommit
b826cd659a

+ 134 - 123
Jint.Tests/Runtime/ArrayTests.cs

@@ -1,82 +1,76 @@
 using Jint.Native.Array;
 
-namespace Jint.Tests.Runtime
-{
-    public class ArrayTests
-    {
-        private readonly Engine _engine;
-
-        public ArrayTests()
-        {
-            _engine = new Engine()
-                    .SetValue("log", new Action<object>(Console.WriteLine))
-                    .SetValue("assert", new Action<bool>(Assert.True))
-                    .SetValue("equal", new Action<object, object>(Assert.Equal));
-        }
+namespace Jint.Tests.Runtime;
 
-        private void RunTest(string source)
-        {
-            _engine.Execute(source);
-        }
+public class ArrayTests
+{
+    private readonly Engine _engine;
 
+    public ArrayTests()
+    {
+        _engine = new Engine()
+            .SetValue("log", new Action<object>(Console.WriteLine))
+            .SetValue("assert", new Action<bool>(Assert.True))
+            .SetValue("equal", new Action<object, object>(Assert.Equal));
+    }
 
-        [Fact]
-        public void ArrayPrototypeToStringWithArray()
-        {
-            var result = _engine.Evaluate("Array.prototype.toString.call([1,2,3]);").AsString();
+    [Fact]
+    public void ArrayPrototypeToStringWithArray()
+    {
+        var result = _engine.Evaluate("Array.prototype.toString.call([1,2,3]);").AsString();
 
-            Assert.Equal("1,2,3", result);
-        }
+        Assert.Equal("1,2,3", result);
+    }
 
-        [Fact]
-        public void ArrayPrototypeToStringWithNumber()
-        {
-            var result = _engine.Evaluate("Array.prototype.toString.call(1);").AsString();
+    [Fact]
+    public void ArrayPrototypeToStringWithNumber()
+    {
+        var result = _engine.Evaluate("Array.prototype.toString.call(1);").AsString();
 
-            Assert.Equal("[object Number]", result);
-        }
+        Assert.Equal("[object Number]", result);
+    }
 
-        [Fact]
-        public void ArrayPrototypeToStringWithObject()
-        {
-            var result = _engine.Evaluate("Array.prototype.toString.call({});").AsString();
+    [Fact]
+    public void ArrayPrototypeToStringWithObject()
+    {
+        var result = _engine.Evaluate("Array.prototype.toString.call({});").AsString();
 
-            Assert.Equal("[object Object]", result);
-        }
+        Assert.Equal("[object Object]", result);
+    }
 
-        [Fact]
-        public void EmptyStringKey()
-        {
-            var result = _engine.Evaluate("var x=[];x[\"\"]=8;x[\"\"];").AsNumber();
+    [Fact]
+    public void EmptyStringKey()
+    {
+        var result = _engine.Evaluate("var x=[];x[\"\"]=8;x[\"\"];").AsNumber();
 
-            Assert.Equal(8, result);
-        }
+        Assert.Equal(8, result);
+    }
 
-        [Fact]
-        public void LargeArraySize()
-        {
-            const string code = @"
+    [Fact]
+    public void LargeArraySize()
+    {
+        const string code = @"
             let arr = [];
             for (let i = 0; i < 10000; i++) arr.push(i);
             for (let i=0;i<10000;i++) arr.splice(0, 1);
             ";
-            var engine = new Engine();
-            engine.Execute(code);
-        }
+        var engine = new Engine();
+        engine.Execute(code);
+    }
 
-        [Fact]
-        public void ArrayLengthFromInitialState()
-        {
-            var engine = new Engine();
-            var array = new ArrayInstance(engine, 0);
-            var length = (int) array.Length;
-            Assert.Equal(0, length);
-        }
+    [Fact]
+    public void ArrayLengthFromInitialState()
+    {
+        var engine = new Engine();
+        var array = new ArrayInstance(engine, 0);
+        var length = (int) array.Length;
+        Assert.Equal(0, length);
+    }
 
-        [Fact]
-        public void ArraySortIsStable()
-        {
-            const string code = @"
+    [Fact]
+    public void ArraySortIsStable()
+    {
+        const string code = @"
                 var items = [
                     { name: 'Edward', value: 0 },
                     { name: 'Sharpe', value: 0 },
@@ -110,8 +104,8 @@ namespace Jint.Tests.Runtime
                 assert(a[5].name == 'The');
             ";
 
-            _engine.Execute(code);
-        }
+        _engine.Execute(code);
+    }
 
 #if !NETCOREAPP
         // this test case only triggers on older full framework where the is no checks for infinite comparisons
@@ -129,87 +123,104 @@ namespace Jint.Tests.Runtime
         }
 #endif
 
-        [Fact]
-        public void ExtendingArrayAndInstanceOf()
-        {
-            const string script = @"
+    [Fact]
+    public void ExtendingArrayAndInstanceOf()
+    {
+        const string script = @"
                 class MyArr extends Array {
                     constructor(...args) {
                         super(...args);
                     } 
                 }";
 
-            _engine.Execute(script);
-            _engine.Evaluate("const a = new MyArr(1,2);");
-            Assert.True(_engine.Evaluate("a instanceof MyArr").AsBoolean());
-        }
-
-        [Fact]
-        public void IteratorShouldBeConvertibleToArray()
-        {
-            Assert.Equal("hello;again", _engine.Evaluate("Array.from(['hello', 'again'].values()).join(';')"));
-            Assert.Equal("hello;another", _engine.Evaluate("Array.from(new Map([['hello', 'world'], ['another', 'value']]).keys()).join(';')"));
-        }
+        _engine.Execute(script);
+        _engine.Evaluate("const a = new MyArr(1,2);");
+        Assert.True(_engine.Evaluate("a instanceof MyArr").AsBoolean());
+    }
 
-        [Fact]
-        public void ArrayFromShouldNotFlattenInputArray()
-        {
-            Assert.Equal("a;b", _engine.Evaluate("[...['a', 'b']].join(';')"));
-            Assert.Equal("0,a;1,b", _engine.Evaluate("[...['a', 'b'].entries()].join(';')"));
-            Assert.Equal("0,c;1,d", _engine.Evaluate("Array.from(['c', 'd'].entries()).join(';')"));
-            Assert.Equal("0,e;1,f", _engine.Evaluate("Array.from([[0, 'e'],[1, 'f']]).join(';')"));
-        }
+    [Fact]
+    public void IteratorShouldBeConvertibleToArray()
+    {
+        Assert.Equal("hello;again", _engine.Evaluate("Array.from(['hello', 'again'].values()).join(';')"));
+        Assert.Equal("hello;another", _engine.Evaluate("Array.from(new Map([['hello', 'world'], ['another', 'value']]).keys()).join(';')"));
+    }
 
-        [Fact]
-        public void ArrayEntriesShouldReturnKeyValuePairs()
-        {
-            Assert.Equal("0,hello,1,world", _engine.Evaluate("Array.from(['hello', 'world'].entries()).join()"));
-            Assert.Equal("0,hello;1,world", _engine.Evaluate("Array.from(['hello', 'world'].entries()).join(';')"));
-            Assert.Equal("0,;1,1;2,5", _engine.Evaluate("Array.from([,1,5,].entries()).join(';')"));
-        }
+    [Fact]
+    public void ArrayFromShouldNotFlattenInputArray()
+    {
+        Assert.Equal("a;b", _engine.Evaluate("[...['a', 'b']].join(';')"));
+        Assert.Equal("0,a;1,b", _engine.Evaluate("[...['a', 'b'].entries()].join(';')"));
+        Assert.Equal("0,c;1,d", _engine.Evaluate("Array.from(['c', 'd'].entries()).join(';')"));
+        Assert.Equal("0,e;1,f", _engine.Evaluate("Array.from([[0, 'e'],[1, 'f']]).join(';')"));
+    }
 
-        [Fact]
-        public void IteratorsShouldHaveIteratorSymbol()
-        {
-            _engine.Execute("assert(!!['hello'].values()[Symbol.iterator])");
-            _engine.Execute("assert(!!new Map([['hello', 'world']]).keys()[Symbol.iterator])");
-        }
+    [Fact]
+    public void ArrayEntriesShouldReturnKeyValuePairs()
+    {
+        Assert.Equal("0,hello,1,world", _engine.Evaluate("Array.from(['hello', 'world'].entries()).join()"));
+        Assert.Equal("0,hello;1,world", _engine.Evaluate("Array.from(['hello', 'world'].entries()).join(';')"));
+        Assert.Equal("0,;1,1;2,5", _engine.Evaluate("Array.from([,1,5,].entries()).join(';')"));
+    }
 
+    [Fact]
+    public void IteratorsShouldHaveIteratorSymbol()
+    {
+        _engine.Execute("assert(!!['hello'].values()[Symbol.iterator])");
+        _engine.Execute("assert(!!new Map([['hello', 'world']]).keys()[Symbol.iterator])");
+    }
 
 
-        [Fact]
-        public void ArraySortDoesNotCrashInDebugMode()
+    [Fact]
+    public void ArraySortDoesNotCrashInDebugMode()
+    {
+        var engine = new Engine(o =>
         {
-            var engine = new Engine(o =>
-            {
-                o.DebugMode(true);
-            });
-            engine.SetValue("equal", new Action<object, object>(Assert.Equal));
+            o.DebugMode(true);
+        });
+        engine.SetValue("equal", new Action<object, object>(Assert.Equal));
 
-            const string code = @"
+        const string code = @"
                 var items = [5,2,4,1];
                 items.sort((a,b) => a - b);
                 equal('1,2,4,5', items.join());
             ";
 
-            engine.Execute(code);
-        }
+        engine.Execute(code);
+    }
 
-        [Fact]
-        public void ArrayConstructorFromHoles()
-        {
-            _engine.Evaluate("var a = Array(...[,,]);");
-            Assert.True(_engine.Evaluate("\"0\" in a").AsBoolean());
-            Assert.True(_engine.Evaluate("\"1\" in a").AsBoolean());
-            Assert.Equal("undefinedundefined", _engine.Evaluate("'' + a[0] + a[1]"));
-        }
+    [Fact]
+    public void ArrayConstructorFromHoles()
+    {
+        _engine.Evaluate("var a = Array(...[,,]);");
+        Assert.True(_engine.Evaluate("\"0\" in a").AsBoolean());
+        Assert.True(_engine.Evaluate("\"1\" in a").AsBoolean());
+        Assert.Equal("undefinedundefined", _engine.Evaluate("'' + a[0] + a[1]"));
+    }
 
-        [Fact]
-        public void ArrayIsSubclassable()
-        {
-            _engine.Evaluate("class C extends Array {}");
-            _engine.Evaluate("var c = new C();");
-            Assert.True(_engine.Evaluate("c.map(Boolean) instanceof C").AsBoolean());
-        }
+    [Fact]
+    public void ArrayIsSubclassable()
+    {
+        _engine.Evaluate("class C extends Array {}");
+        _engine.Evaluate("var c = new C();");
+        Assert.True(_engine.Evaluate("c.map(Boolean) instanceof C").AsBoolean());
+    }
+
+    [Fact]
+    public void HasProperIteratorPrototypeChain()
+    {
+        const string Script = @"
+        // Iterator instance
+        var iterator = [][Symbol.iterator]();
+        // %ArrayIteratorPrototype%
+        var proto1 = Object.getPrototypeOf(iterator);
+        // %IteratorPrototype%
+        var proto2 = Object.getPrototypeOf(proto1);";
+
+        var engine = new Engine();
+        engine.Execute(Script);
+        Assert.True(engine.Evaluate("proto2.hasOwnProperty(Symbol.iterator)").AsBoolean());
+        Assert.True(engine.Evaluate("!proto1.hasOwnProperty(Symbol.iterator)").AsBoolean());
+        Assert.True(engine.Evaluate("!iterator.hasOwnProperty(Symbol.iterator)").AsBoolean());
+        Assert.True(engine.Evaluate("iterator[Symbol.iterator]() === iterator").AsBoolean());
     }
 }

+ 41 - 8
Jint.Tests/Runtime/MapTests.cs

@@ -1,14 +1,47 @@
 using Jint.Runtime;
 
-namespace Jint.Tests.Runtime
+namespace Jint.Tests.Runtime;
+
+public class MapTests
 {
-    public class MapTests
+    [Fact]
+    public void ShouldThrowWhenCalledWithoutNew()
     {
-        [Fact]
-        public void ShouldThrowWhenCalledWithoutNew()
-        {
-            var e = Assert.Throws<JavaScriptException>(() => new Engine().Execute("const m = new Map(); Map.call(m,[]);"));
-            Assert.Equal("Constructor Map requires 'new'", e.Message);
-        }
+        var e = Assert.Throws<JavaScriptException>(() => new Engine().Execute("const m = new Map(); Map.call(m,[]);"));
+        Assert.Equal("Constructor Map requires 'new'", e.Message);
+    }
+
+    [Fact]
+    public void NegativeZeroKeyConvertsToPositiveZero()
+    {
+        const string Script = @"
+            var map = new Map();
+            map.set(-0, ""foo"");
+            var k;
+            map.forEach(function (value, key) {
+              k = 1 / key;
+            });
+            return k === Infinity && map.get(+0) === ""foo"";";
+
+        Assert.True(new Engine().Evaluate(Script).AsBoolean());
+    }
+
+    [Fact]
+    public void HasProperIteratorPrototypeChain()
+    {
+        const string Script = @"
+        // Iterator instance
+        var iterator = new Map()[Symbol.iterator]();
+        // %MapIteratorPrototype%
+        var proto1 = Object.getPrototypeOf(iterator);
+        // %IteratorPrototype%
+        var proto2 = Object.getPrototypeOf(proto1);";
+
+        var engine = new Engine();
+        engine.Execute(Script);
+        Assert.True(engine.Evaluate("proto2.hasOwnProperty(Symbol.iterator)").AsBoolean());
+        Assert.True(engine.Evaluate("!proto1.hasOwnProperty(Symbol.iterator)").AsBoolean());
+        Assert.True(engine.Evaluate("!iterator.hasOwnProperty(Symbol.iterator)").AsBoolean());
+        Assert.True(engine.Evaluate("iterator[Symbol.iterator]() === iterator").AsBoolean());
     }
 }

+ 41 - 8
Jint.Tests/Runtime/SetTests.cs

@@ -1,14 +1,47 @@
 using Jint.Runtime;
 
-namespace Jint.Tests.Runtime
+namespace Jint.Tests.Runtime;
+
+public class SetTests
 {
-    public class SetTests
+    [Fact]
+    public void ShouldThrowWhenCalledWithoutNew()
     {
-        [Fact]
-        public void ShouldThrowWhenCalledWithoutNew()
-        {
-            var e = Assert.Throws<JavaScriptException>(() => new Engine().Execute("const m = new Set(); Set.call(m,[]);"));
-            Assert.Equal("Constructor Set requires 'new'", e.Message);
-        }
+        var e = Assert.Throws<JavaScriptException>(() => new Engine().Execute("const m = new Set(); Set.call(m,[]);"));
+        Assert.Equal("Constructor Set requires 'new'", e.Message);
+    }
+
+    [Fact]
+    public void NegativeZeroKeyConvertsToPositiveZero()
+    {
+        const string Script = @"
+            var set = new Set();
+            set.add(-0);
+            var k;
+            set.forEach(function (value) {
+              k = 1 / value;
+            });
+            return k === Infinity && set.has(+0);";
+
+        Assert.True(new Engine().Evaluate(Script).AsBoolean());
+    }
+
+    [Fact]
+    public void HasProperIteratorPrototypeChain()
+    {
+        const string Script = @"
+            // Iterator instance
+            var iterator = new Set()[Symbol.iterator]();
+            // %SetIteratorPrototype%
+            var proto1 = Object.getPrototypeOf(iterator);
+            // %IteratorPrototype%
+            var proto2 = Object.getPrototypeOf(proto1);";
+
+        var engine = new Engine();
+        engine.Execute(Script);
+        Assert.True(engine.Evaluate("proto2.hasOwnProperty(Symbol.iterator)").AsBoolean());
+        Assert.True(engine.Evaluate("!proto1.hasOwnProperty(Symbol.iterator)").AsBoolean());
+        Assert.True(engine.Evaluate("!iterator.hasOwnProperty(Symbol.iterator)").AsBoolean());
+        Assert.True(engine.Evaluate("iterator[Symbol.iterator]() === iterator").AsBoolean());
     }
 }

+ 43 - 25
Jint.Tests/Runtime/StringTests.cs

@@ -1,40 +1,58 @@
-namespace Jint.Tests.Runtime
+namespace Jint.Tests.Runtime;
+
+public class StringTests
 {
-    public class StringTests
+    public StringTests()
     {
-        public StringTests()
-        {
-            _engine = new Engine()
-                .SetValue("log", new Action<object>(Console.WriteLine))
-                .SetValue("assert", new Action<bool>(Assert.True))
-                .SetValue("equal", new Action<object, object>(Assert.Equal));
-        }
+        _engine = new Engine()
+            .SetValue("log", new Action<object>(Console.WriteLine))
+            .SetValue("assert", new Action<bool>(Assert.True))
+            .SetValue("equal", new Action<object, object>(Assert.Equal));
+    }
 
-        private readonly Engine _engine;
+    private readonly Engine _engine;
 
-        [Fact]
-        public void StringConcatenationAndReferences()
-        {
-            const string script = @"
+    [Fact]
+    public void StringConcatenationAndReferences()
+    {
+        const string script = @"
 var foo = 'foo';
 foo += 'foo';
 var bar = foo;
 bar += 'bar';
 ";
-            var value = _engine.Execute(script);
-            var foo = _engine.Evaluate("foo").AsString();
-            var bar = _engine.Evaluate("bar").AsString();
-            Assert.Equal("foofoo", foo);
-            Assert.Equal("foofoobar", bar);
-        }
+        var value = _engine.Execute(script);
+        var foo = _engine.Evaluate("foo").AsString();
+        var bar = _engine.Evaluate("bar").AsString();
+        Assert.Equal("foofoo", foo);
+        Assert.Equal("foofoobar", bar);
+    }
 
-        [Fact]
-        public void TrimLeftRightShouldBeSameAsTrimStartEnd()
-        {
-            _engine.Execute(@"
+    [Fact]
+    public void TrimLeftRightShouldBeSameAsTrimStartEnd()
+    {
+        _engine.Execute(@"
                 assert(''.trimLeft === ''.trimStart);
                 assert(''.trimRight === ''.trimEnd);
 ");
-        }
+    }
+
+    [Fact]
+    public void HasProperIteratorPrototypeChain()
+    {
+        const string Script = @"
+        // Iterator instance
+        var iterator = ''[Symbol.iterator]();
+        // %StringIteratorPrototype%
+        var proto1 = Object.getPrototypeOf(iterator);
+        // %IteratorPrototype%
+        var proto2 = Object.getPrototypeOf(proto1);";
+
+        var engine = new Engine();
+        engine.Execute(Script);
+        Assert.True(engine.Evaluate("proto2.hasOwnProperty(Symbol.iterator)").AsBoolean());
+        Assert.True(engine.Evaluate("!proto1.hasOwnProperty(Symbol.iterator)").AsBoolean());
+        Assert.True(engine.Evaluate("!iterator.hasOwnProperty(Symbol.iterator)").AsBoolean());
+        Assert.True(engine.Evaluate("iterator[Symbol.iterator]() === iterator").AsBoolean());
     }
 }

+ 84 - 66
Jint/Native/Array/ArrayIteratorPrototype.cs

@@ -1,101 +1,119 @@
+using Jint.Collections;
 using Jint.Native.Iterator;
 using Jint.Native.Object;
+using Jint.Native.Symbol;
 using Jint.Native.TypedArray;
 using Jint.Runtime;
+using Jint.Runtime.Descriptors;
+using Jint.Runtime.Interop;
 
-namespace Jint.Native.Array
+namespace Jint.Native.Array;
+
+/// <summary>
+/// https://tc39.es/ecma262/#sec-%arrayiteratorprototype%-object
+/// </summary>
+internal sealed class ArrayIteratorPrototype : IteratorPrototype
 {
-    /// <summary>
-    /// https://tc39.es/ecma262/#sec-%arrayiteratorprototype%-object
-    /// </summary>
-    internal sealed class ArrayIteratorPrototype : IteratorPrototype
+    internal ArrayIteratorPrototype(
+        Engine engine,
+        Realm realm,
+        IteratorPrototype objectPrototype) : base(engine, realm, objectPrototype)
+    {
+    }
+
+    protected override void Initialize()
     {
-        internal ArrayIteratorPrototype(
-            Engine engine,
-            Realm realm,
-            IteratorPrototype objectPrototype) : base(engine, realm, "Array Iterator", objectPrototype)
+        var properties = new PropertyDictionary(1, checkExistingKeys: false)
         {
-        }
+            [KnownKeys.Next] = new(new ClrFunctionInstance(Engine, "next", Next, 0, PropertyFlag.Configurable), true, false, true)
+        };
+        SetProperties(properties);
+
+        var symbols = new SymbolDictionary(1)
+        {
+            [GlobalSymbolRegistry.ToStringTag] = new("Array Iterator", PropertyFlag.Configurable)
+        };
+        SetSymbols(symbols);
+    }
+
+    internal IteratorInstance Construct(ObjectInstance array, ArrayIteratorType kind)
+    {
+        var instance = new ArrayLikeIterator(Engine, array, kind)
+        {
+            _prototype = this
+        };
+
+        return instance;
+    }
+
+    private sealed class ArrayLikeIterator : IteratorInstance
+    {
+        private readonly ArrayIteratorType _kind;
+        private readonly TypedArrayInstance? _typedArray;
+        private readonly ArrayOperations? _operations;
+        private uint _position;
+        private bool _closed;
 
-        internal IteratorInstance Construct(ObjectInstance array, ArrayIteratorType kind)
+        public ArrayLikeIterator(Engine engine, ObjectInstance objectInstance, ArrayIteratorType kind) : base(engine)
         {
-            var instance = new ArrayLikeIterator(Engine, array, kind)
+            _kind = kind;
+            _typedArray = objectInstance as TypedArrayInstance;
+            if (_typedArray is null)
             {
-                _prototype = this
-            };
+                _operations = ArrayOperations.For(objectInstance);
+            }
 
-            return instance;
+            _position = 0;
         }
 
-        private sealed class ArrayLikeIterator : IteratorInstance
+        public override bool TryIteratorStep(out ObjectInstance nextItem)
         {
-            private readonly ArrayIteratorType _kind;
-            private readonly TypedArrayInstance? _typedArray;
-            private readonly ArrayOperations? _operations;
-            private uint _position;
-            private bool _closed;
-
-            public ArrayLikeIterator(Engine engine, ObjectInstance objectInstance, ArrayIteratorType kind) : base(engine)
+            uint len;
+            if (_typedArray is not null)
             {
-                _kind = kind;
-                _typedArray = objectInstance as TypedArrayInstance;
-                if (_typedArray is null)
-                {
-                    _operations = ArrayOperations.For(objectInstance);
-                }
-
-                _position = 0;
+                _typedArray._viewedArrayBuffer.AssertNotDetached();
+                len = _typedArray.Length;
+            }
+            else
+            {
+                len = _operations!.GetLength();
             }
 
-            public override bool TryIteratorStep(out ObjectInstance nextItem)
+            if (!_closed && _position < len)
             {
-                uint len;
                 if (_typedArray is not null)
                 {
-                    _typedArray._viewedArrayBuffer.AssertNotDetached();
-                    len = _typedArray.Length;
+                    nextItem = _kind switch
+                    {
+                        ArrayIteratorType.Key => new ValueIteratorPosition(_engine, _position),
+                        ArrayIteratorType.Value => new ValueIteratorPosition(_engine, _typedArray[(int) _position]),
+                        _ => new KeyValueIteratorPosition(_engine, _position, _typedArray[(int) _position])
+                    };
                 }
                 else
                 {
-                    len = _operations!.GetLength();
-                }
-
-                if (!_closed && _position < len)
-                {
-                    if (_typedArray is not null)
+                    _operations!.TryGetValue(_position, out var value);
+                    if (_kind == ArrayIteratorType.Key)
                     {
-                        nextItem = _kind switch
-                        {
-                            ArrayIteratorType.Key => new ValueIteratorPosition(_engine, _position),
-                            ArrayIteratorType.Value => new ValueIteratorPosition(_engine, _typedArray[(int) _position]),
-                            _ => new KeyValueIteratorPosition(_engine, _position, _typedArray[(int) _position])
-                        };
+                        nextItem = new ValueIteratorPosition(_engine, _position);
+                    }
+                    else if (_kind == ArrayIteratorType.Value)
+                    {
+                        nextItem = new ValueIteratorPosition(_engine, value);
                     }
                     else
                     {
-                        _operations!.TryGetValue(_position, out var value);
-                        if (_kind == ArrayIteratorType.Key)
-                        {
-                            nextItem = new ValueIteratorPosition(_engine, _position);
-                        }
-                        else if (_kind == ArrayIteratorType.Value)
-                        {
-                            nextItem = new ValueIteratorPosition(_engine, value);
-                        }
-                        else
-                        {
-                            nextItem = new KeyValueIteratorPosition(_engine, _position, value);
-                        }
+                        nextItem = new KeyValueIteratorPosition(_engine, _position, value);
                     }
-
-                    _position++;
-                    return true;
                 }
 
-                _closed = true;
-                nextItem = KeyValueIteratorPosition.Done(_engine);
-                return false;
+                _position++;
+                return true;
             }
+
+            _closed = true;
+            nextItem = KeyValueIteratorPosition.Done(_engine);
+            return false;
         }
     }
 }

+ 6 - 7
Jint/Native/Iterator/ArrayIteratorType.cs

@@ -1,9 +1,8 @@
-namespace Jint.Native.Iterator
+namespace Jint.Native.Iterator;
+
+internal enum ArrayIteratorType
 {
-    internal enum ArrayIteratorType
-    {
-        Key,
-        Value,
-        KeyAndValue
-    }
+    Key,
+    Value,
+    KeyAndValue
 }

+ 2 - 35
Jint/Native/Iterator/IteratorInstance.cs

@@ -10,7 +10,7 @@ namespace Jint.Native.Iterator
     {
         private readonly IEnumerator<JsValue> _enumerable;
 
-        public IteratorInstance(Engine engine)
+        protected IteratorInstance(Engine engine)
             : this(engine, Enumerable.Empty<JsValue>())
         {
         }
@@ -20,7 +20,7 @@ namespace Jint.Native.Iterator
             IEnumerable<JsValue> enumerable) : base(engine)
         {
             _enumerable = enumerable.GetEnumerator();
-            _prototype = engine.Realm.Intrinsics.IteratorPrototype;
+            _prototype = engine.Realm.Intrinsics.ArrayIteratorPrototype;
        }
 
         public override object ToObject()
@@ -29,11 +29,6 @@ namespace Jint.Native.Iterator
             return null;
         }
 
-        public override bool Equals(JsValue? other)
-        {
-            return false;
-        }
-
         public virtual bool TryIteratorStep(out ObjectInstance nextItem)
         {
             if (_enumerable.MoveNext())
@@ -91,34 +86,6 @@ namespace Jint.Native.Iterator
             }
         }
 
-        public sealed class ListIterator : IteratorInstance
-        {
-            private readonly List<JsValue> _values;
-            private int _position;
-            private bool _closed;
-
-            public ListIterator(Engine engine, List<JsValue> values) : base(engine)
-            {
-                _values = values;
-                _position = 0;
-            }
-
-            public override bool TryIteratorStep(out ObjectInstance nextItem)
-            {
-                if (!_closed && _position < _values.Count)
-                {
-                    var value = _values[_position];
-                    _position++;
-                    nextItem = new ValueIteratorPosition(_engine, value);
-                    return true;
-                }
-
-                _closed = true;
-                nextItem = KeyValueIteratorPosition.Done(_engine);
-                return false;
-            }
-        }
-
         internal sealed class ObjectIterator : IteratorInstance
         {
             private readonly ObjectInstance _target;

+ 30 - 67
Jint/Native/Iterator/IteratorPrototype.cs

@@ -4,81 +4,44 @@ using Jint.Runtime;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
 
-namespace Jint.Native.Iterator
+namespace Jint.Native.Iterator;
+
+/// <summary>
+/// https://tc39.es/ecma262/#sec-%iteratorprototype%-object
+/// </summary>
+internal class IteratorPrototype : Prototype
 {
-    /// <summary>
-    /// https://tc39.es/ecma262/#sec-%iteratorprototype%-object
-    /// </summary>
-    internal class IteratorPrototype : Prototype
+    internal IteratorPrototype(
+        Engine engine,
+        Realm realm,
+        Prototype objectPrototype) : base(engine, realm)
     {
-        private readonly string? _name;
-
-        internal IteratorPrototype(
-            Engine engine,
-            Realm realm,
-            string? name,
-            Prototype objectPrototype) : base(engine, realm)
-        {
-            _prototype = objectPrototype;
-            _name = name;
-        }
-
-        protected override void Initialize()
-        {
-            var properties = new PropertyDictionary(2, checkExistingKeys: false)
-            {
-                ["name"] = new PropertyDescriptor("Map", PropertyFlag.Configurable),
-                ["next"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "next", Next, 0, PropertyFlag.Configurable), true, false, true)
-            };
-            SetProperties(properties);
-
-            var symbols = new SymbolDictionary(_name != null ? 2 : 1)
-            {
-                [GlobalSymbolRegistry.Iterator] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "[Symbol.iterator]", ToIterator, 0, PropertyFlag.Configurable), true, false, true),
-            };
-
-            if (_name != null)
-            {
-                symbols[GlobalSymbolRegistry.ToStringTag] = new PropertyDescriptor(_name, PropertyFlag.Configurable);
-            }
-            SetSymbols(symbols);
-        }
-
-        internal IteratorInstance Construct(IEnumerable<JsValue> enumerable)
-        {
-            var instance = new IteratorInstance(Engine, enumerable)
-            {
-                _prototype = this
-            };
-
-            return instance;
-        }
+        _prototype = objectPrototype;
+    }
 
-        internal IteratorInstance Construct(List<JsValue> enumerable)
+    protected override void Initialize()
+    {
+        var symbols = new SymbolDictionary(1)
         {
-            var instance = new IteratorInstance.ListIterator(Engine, enumerable)
-            {
-                _prototype = this
-            };
+            [GlobalSymbolRegistry.Iterator] = new(new ClrFunctionInstance(Engine, "[Symbol.iterator]", ToIterator, 0, PropertyFlag.Configurable), true, false, true),
+        };
+        SetSymbols(symbols);
+    }
 
-            return instance;
-        }
+    private static JsValue ToIterator(JsValue thisObj, JsValue[] arguments)
+    {
+        return thisObj;
+    }
 
-        private static JsValue ToIterator(JsValue thisObj, JsValue[] arguments)
+    internal JsValue Next(JsValue thisObj, JsValue[] arguments)
+    {
+        var iterator = thisObj as IteratorInstance;
+        if (iterator is null)
         {
-            return thisObj;
+            ExceptionHelper.ThrowTypeError(_engine.Realm);
         }
 
-        private JsValue Next(JsValue thisObj, JsValue[] arguments)
-        {
-            var iterator = thisObj as IteratorInstance;
-            if (iterator is null)
-            {
-                ExceptionHelper.ThrowTypeError(_engine.Realm);
-            }
-
-            iterator.TryIteratorStep(out var result);
-            return result;
-        }
+        iterator.TryIteratorStep(out var result);
+        return result;
     }
 }

+ 0 - 5
Jint/Native/Iterator/IteratorResult.cs

@@ -36,10 +36,5 @@ namespace Jint.Native.Iterator
         {
             return this;
         }
-
-        public override bool Equals(JsValue? other)
-        {
-            return ReferenceEquals(this, other);
-        }
     }
 }

+ 51 - 52
Jint/Native/Map/MapConstructor.cs

@@ -7,71 +7,70 @@ using Jint.Runtime;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
 
-namespace Jint.Native.Map
+namespace Jint.Native.Map;
+
+public sealed class MapConstructor : FunctionInstance, IConstructor
 {
-    public sealed class MapConstructor : FunctionInstance, IConstructor
+    private static readonly JsString _functionName = new("Map");
+
+    internal MapConstructor(
+        Engine engine,
+        Realm realm,
+        FunctionPrototype functionPrototype,
+        ObjectPrototype objectPrototype)
+        : base(engine, realm, _functionName)
     {
-        private static readonly JsString _functionName = new("Map");
+        _prototype = functionPrototype;
+        PrototypeObject = new MapPrototype(engine, realm, this, objectPrototype);
+        _length = new PropertyDescriptor(0, PropertyFlag.Configurable);
+        _prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
+    }
 
-        internal MapConstructor(
-            Engine engine,
-            Realm realm,
-            FunctionPrototype functionPrototype,
-            ObjectPrototype objectPrototype)
-            : base(engine, realm, _functionName)
+    private MapPrototype PrototypeObject { get; }
+
+    protected override void Initialize()
+    {
+        var symbols = new SymbolDictionary(1)
         {
-            _prototype = functionPrototype;
-            PrototypeObject = new MapPrototype(engine, realm, this, objectPrototype);
-            _length = new PropertyDescriptor(0, PropertyFlag.Configurable);
-            _prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
-        }
+            [GlobalSymbolRegistry.Species] = new GetSetPropertyDescriptor(get: new ClrFunctionInstance(_engine, "get [Symbol.species]", Species, 0, PropertyFlag.Configurable), set: Undefined, PropertyFlag.Configurable)
+        };
+        SetSymbols(symbols);
+    }
 
-        public MapPrototype PrototypeObject { get; }
+    private static JsValue Species(JsValue thisObject, JsValue[] arguments)
+    {
+        return thisObject;
+    }
 
-        protected override void Initialize()
-        {
-            var symbols = new SymbolDictionary(1)
-            {
-                [GlobalSymbolRegistry.Species] = new GetSetPropertyDescriptor(get: new ClrFunctionInstance(_engine, "get [Symbol.species]", Species, 0, PropertyFlag.Configurable), set: Undefined, PropertyFlag.Configurable)
-            };
-            SetSymbols(symbols);
-        }
+    protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
+    {
+        ExceptionHelper.ThrowTypeError(_realm, "Constructor Map requires 'new'");
+        return null;
+    }
 
-        private static JsValue Species(JsValue thisObject, JsValue[] arguments)
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-map-iterable
+    /// </summary>
+    ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget)
+    {
+        if (newTarget.IsUndefined())
         {
-            return thisObject;
+            ExceptionHelper.ThrowTypeError(_realm);
         }
 
-        protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
-        {
-            ExceptionHelper.ThrowTypeError(_realm, "Constructor Map requires 'new'");
-            return null;
-        }
+        var map = OrdinaryCreateFromConstructor(
+            newTarget,
+            static intrinsics => intrinsics.Map.PrototypeObject,
+            static (Engine engine, Realm realm, object? _) => new MapInstance(engine, realm));
 
-        /// <summary>
-        /// https://tc39.es/ecma262/#sec-map-iterable
-        /// </summary>
-        ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget)
+        if (arguments.Length > 0 && !arguments[0].IsNullOrUndefined())
         {
-            if (newTarget.IsUndefined())
-            {
-                ExceptionHelper.ThrowTypeError(_realm);
-            }
-
-            var map = OrdinaryCreateFromConstructor(
-                newTarget,
-                static intrinsics => intrinsics.Map.PrototypeObject,
-                static (Engine engine, Realm realm, object? _) => new MapInstance(engine, realm));
-
-            if (arguments.Length > 0 && !arguments[0].IsNullOrUndefined())
-            {
-                var adder = map.Get("set");
-                var iterator = arguments.At(0).GetIterator(_realm);
+            var adder = map.Get("set");
+            var iterator = arguments.At(0).GetIterator(_realm);
 
-                IteratorProtocol.AddEntriesFromIterable(map, iterator, adder);
-            }
-
-            return map;
+            IteratorProtocol.AddEntriesFromIterable(map, iterator, adder);
         }
+
+        return map;
     }
 }

+ 76 - 73
Jint/Native/Map/MapInstance.cs

@@ -4,104 +4,107 @@ using Jint.Native.Object;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
 
-namespace Jint.Native.Map
+namespace Jint.Native.Map;
+
+public sealed class MapInstance : ObjectInstance
 {
-    public sealed class MapInstance : ObjectInstance
+    private readonly Realm _realm;
+    internal readonly OrderedDictionary<JsValue, JsValue> _map;
+
+    public MapInstance(Engine engine, Realm realm) : base(engine)
     {
-        private readonly Realm _realm;
-        internal readonly OrderedDictionary<JsValue, JsValue> _map;
+        _realm = realm;
+        _map = new OrderedDictionary<JsValue, JsValue>(SameValueZeroComparer.Instance);
+    }
 
-        public MapInstance(Engine engine, Realm realm) : base(engine)
+    public override PropertyDescriptor GetOwnProperty(JsValue property)
+    {
+        if (property == CommonProperties.Size)
         {
-            _realm = realm;
-            _map = new OrderedDictionary<JsValue, JsValue>(SameValueZeroComparer.Instance);
+            return new PropertyDescriptor(_map.Count, PropertyFlag.AllForbidden);
         }
 
-        public override PropertyDescriptor GetOwnProperty(JsValue property)
-        {
-            if (property == CommonProperties.Size)
-            {
-                return new PropertyDescriptor(_map.Count, PropertyFlag.AllForbidden);
-            }
+        return base.GetOwnProperty(property);
+    }
 
-            return base.GetOwnProperty(property);
+    protected override bool TryGetProperty(JsValue property, [NotNullWhen(true)] out PropertyDescriptor? descriptor)
+    {
+        if (property == CommonProperties.Size)
+        {
+            descriptor = new PropertyDescriptor(_map.Count, PropertyFlag.AllForbidden);
+            return true;
         }
 
-        protected override bool TryGetProperty(JsValue property, [NotNullWhen(true)] out PropertyDescriptor? descriptor)
-        {
-            if (property == CommonProperties.Size)
-            {
-                descriptor = new PropertyDescriptor(_map.Count, PropertyFlag.AllForbidden);
-                return true;
-            }
+        return base.TryGetProperty(property, out descriptor);
+    }
 
-            return base.TryGetProperty(property, out descriptor);
-        }
+    internal void Clear()
+    {
+        _map.Clear();
+    }
 
-        internal void Clear()
-        {
-            _map.Clear();
-        }
+    internal bool Has(JsValue key)
+    {
+        return _map.ContainsKey(key);
+    }
 
-        internal bool Has(JsValue key)
-        {
-            return _map.ContainsKey(key);
-        }
+    internal bool MapDelete(JsValue key)
+    {
+        return _map.Remove(key);
+    }
 
-        internal bool MapDelete(JsValue key)
+    internal void MapSet(JsValue key, JsValue value)
+    {
+        if (key is JsNumber number && number.IsNegativeZero())
         {
-            return _map.Remove(key);
+            key = JsNumber.PositiveZero;
         }
+        _map[key] = value;
+    }
 
-        internal void MapSet(JsValue key, JsValue value)
-        {
-            _map[key] = value;
-        }
+    internal void ForEach(ICallable callable, JsValue thisArg)
+    {
+        var args = _engine._jsValueArrayPool.RentArray(3);
+        args[2] = this;
 
-        internal void ForEach(ICallable callable, JsValue thisArg)
+        for (var i = 0; i < _map.Count; i++)
         {
-            var args = _engine._jsValueArrayPool.RentArray(3);
-            args[2] = this;
-
-            for (var i = 0; i < _map.Count; i++)
-            {
-                args[0] = _map[i];
-                args[1] = _map.GetKey(i);
-                callable.Call(thisArg, args);
-            }
-
-            _engine._jsValueArrayPool.ReturnArray(args);
+            args[0] = _map[i];
+            args[1] = _map.GetKey(i);
+            callable.Call(thisArg, args);
         }
 
-        internal JsValue MapGet(JsValue key)
-        {
-            if (!_map.TryGetValue(key, out var value))
-            {
-                return Undefined;
-            }
-
-            return value;
-        }
+        _engine._jsValueArrayPool.ReturnArray(args);
+    }
 
-        internal ObjectInstance Iterator()
+    internal JsValue MapGet(JsValue key)
+    {
+        if (!_map.TryGetValue(key, out var value))
         {
-            return _realm.Intrinsics.MapIteratorPrototype.ConstructEntryIterator(this);
+            return Undefined;
         }
 
-        internal ObjectInstance Keys()
-        {
-            return _realm.Intrinsics.MapIteratorPrototype.ConstructKeyIterator(this);
-        }
+        return value;
+    }
 
-        internal ObjectInstance Values()
-        {
-            return _realm.Intrinsics.MapIteratorPrototype.ConstructValueIterator(this);
-        }
+    internal ObjectInstance Iterator()
+    {
+        return _realm.Intrinsics.MapIteratorPrototype.ConstructEntryIterator(this);
+    }
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        internal uint GetSize()
-        {
-            return (uint) _map.Count;
-        }
+    internal ObjectInstance Keys()
+    {
+        return _realm.Intrinsics.MapIteratorPrototype.ConstructKeyIterator(this);
+    }
+
+    internal ObjectInstance Values()
+    {
+        return _realm.Intrinsics.MapIteratorPrototype.ConstructValueIterator(this);
+    }
+
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    internal uint GetSize()
+    {
+        return (uint) _map.Count;
     }
 }

+ 71 - 53
Jint/Native/Map/MapIteratorPrototype.cs

@@ -1,78 +1,96 @@
+using Jint.Collections;
 using Jint.Native.Iterator;
 using Jint.Native.Object;
+using Jint.Native.Symbol;
 using Jint.Runtime;
+using Jint.Runtime.Descriptors;
+using Jint.Runtime.Interop;
 
-namespace Jint.Native.Map
+namespace Jint.Native.Map;
+
+/// <summary>
+/// https://tc39.es/ecma262/#sec-%mapiteratorprototype%-object
+/// </summary>
+internal sealed class MapIteratorPrototype : IteratorPrototype
 {
-    /// <summary>
-    /// https://tc39.es/ecma262/#sec-%mapiteratorprototype%-object
-    /// </summary>
-    internal sealed class MapIteratorPrototype : IteratorPrototype
+    internal MapIteratorPrototype(
+        Engine engine,
+        Realm realm,
+        IteratorPrototype iteratorPrototype) : base(engine, realm, iteratorPrototype)
     {
-        internal MapIteratorPrototype(
-            Engine engine,
-            Realm realm,
-            Prototype objectPrototype) : base(engine, realm, "Map Iterator", objectPrototype)
-        {
-        }
+    }
 
-        internal IteratorInstance ConstructEntryIterator(MapInstance map)
+    protected override void Initialize()
+    {
+        var properties = new PropertyDictionary(1, checkExistingKeys: false)
         {
-            var instance = new MapIterator(Engine, map)
-            {
-                _prototype = this
-            };
+            [KnownKeys.Next] = new(new ClrFunctionInstance(Engine, "next", Next, 0, PropertyFlag.Configurable), true, false, true)
+        };
+        SetProperties(properties);
 
-            return instance;
-        }
+        var symbols = new SymbolDictionary(1)
+        {
+            [GlobalSymbolRegistry.ToStringTag] = new("Map Iterator", PropertyFlag.Configurable)
+        };
+        SetSymbols(symbols);
+    }
 
-        internal IteratorInstance ConstructKeyIterator(MapInstance map)
+    internal IteratorInstance ConstructEntryIterator(MapInstance map)
+    {
+        var instance = new MapIterator(Engine, map)
         {
-            var instance = new IteratorInstance(Engine, map._map.Keys)
-            {
-                _prototype = this
-            };
+            _prototype = this
+        };
 
-            return instance;
-        }
+        return instance;
+    }
 
-        internal IteratorInstance ConstructValueIterator(MapInstance map)
+    internal IteratorInstance ConstructKeyIterator(MapInstance map)
+    {
+        var instance = new IteratorInstance(Engine, map._map.Keys)
         {
-            var instance = new IteratorInstance(Engine, map._map.Values)
-            {
-                _prototype = this
-            };
+            _prototype = this
+        };
 
-            return instance;
-        }
+        return instance;
+    }
 
-        private sealed class MapIterator : IteratorInstance
+    internal IteratorInstance ConstructValueIterator(MapInstance map)
+    {
+        var instance = new IteratorInstance(Engine, map._map.Values)
         {
-            private readonly MapInstance _map;
+            _prototype = this
+        };
 
-            private int _position;
+        return instance;
+    }
 
-            public MapIterator(Engine engine, MapInstance map) : base(engine)
-            {
-                _map = map;
-                _position = 0;
-            }
+    private sealed class MapIterator : IteratorInstance
+    {
+        private readonly MapInstance _map;
 
-            public override bool TryIteratorStep(out ObjectInstance nextItem)
+        private int _position;
+
+        public MapIterator(Engine engine, MapInstance map) : base(engine)
+        {
+            _map = map;
+            _position = 0;
+        }
+
+        public override bool TryIteratorStep(out ObjectInstance nextItem)
+        {
+            if (_position < _map.GetSize())
             {
-                if (_position < _map.GetSize())
-                {
-                    var key = _map._map.GetKey(_position);
-                    var value = _map._map[key];
-
-                    _position++;
-                    nextItem = new KeyValueIteratorPosition(_engine, key, value);
-                    return true;
-                }
-
-                nextItem = KeyValueIteratorPosition.Done(_engine);
-                return false;
+                var key = _map._map.GetKey(_position);
+                var value = _map._map[key];
+
+                _position++;
+                nextItem = new KeyValueIteratorPosition(_engine, key, value);
+                return true;
             }
+
+            nextItem = KeyValueIteratorPosition.Done(_engine);
+            return false;
         }
     }
 }

+ 108 - 109
Jint/Native/Map/MapPrototype.cs

@@ -5,135 +5,134 @@ using Jint.Runtime;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
 
-namespace Jint.Native.Map
+namespace Jint.Native.Map;
+
+/// <summary>
+/// https://tc39.es/ecma262/#sec-map-objects
+/// </summary>
+public sealed class MapPrototype : Prototype
 {
-    /// <summary>
-    /// https://www.ecma-international.org/ecma-262/6.0/#sec-map-objects
-    /// </summary>
-    public sealed class MapPrototype : Prototype
+    private readonly MapConstructor _mapConstructor;
+
+    internal MapPrototype(
+        Engine engine,
+        Realm realm,
+        MapConstructor mapConstructor,
+        ObjectPrototype objectPrototype) : base(engine, realm)
     {
-        private readonly MapConstructor _mapConstructor;
+        _prototype = objectPrototype;
+        _mapConstructor = mapConstructor;
+    }
 
-        internal MapPrototype(
-            Engine engine,
-            Realm realm,
-            MapConstructor mapConstructor,
-            ObjectPrototype objectPrototype) : base(engine, realm)
+    protected override void Initialize()
+    {
+        const PropertyFlag propertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
+        var properties = new PropertyDictionary(12, checkExistingKeys: false)
         {
-            _prototype = objectPrototype;
-            _mapConstructor = mapConstructor;
-        }
-
-        protected override void Initialize()
+            ["length"] = new PropertyDescriptor(0, PropertyFlag.Configurable),
+            ["constructor"] = new PropertyDescriptor(_mapConstructor, PropertyFlag.NonEnumerable),
+            ["clear"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "clear", Clear, 0, PropertyFlag.Configurable), propertyFlags),
+            ["delete"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "delete", Delete, 1, PropertyFlag.Configurable), propertyFlags),
+            ["entries"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "entries", Entries, 0, PropertyFlag.Configurable), propertyFlags),
+            ["forEach"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "forEach", ForEach, 1, PropertyFlag.Configurable), propertyFlags),
+            ["get"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "get", Get, 1, PropertyFlag.Configurable), propertyFlags),
+            ["has"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "has", Has, 1, PropertyFlag.Configurable), propertyFlags),
+            ["keys"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "keys", Keys, 0, PropertyFlag.Configurable), propertyFlags),
+            ["set"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "set", Set, 2, PropertyFlag.Configurable), propertyFlags),
+            ["values"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "values", Values, 0, PropertyFlag.Configurable), propertyFlags),
+            ["size"] = new GetSetPropertyDescriptor(get: new ClrFunctionInstance(Engine, "get size", Size, 0, PropertyFlag.Configurable), set: null, PropertyFlag.Configurable)
+        };
+        SetProperties(properties);
+
+        var symbols = new SymbolDictionary(2)
         {
-            const PropertyFlag propertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
-            var properties = new PropertyDictionary(12, checkExistingKeys: false)
-            {
-                ["length"] = new PropertyDescriptor(0, PropertyFlag.Configurable),
-                ["constructor"] = new PropertyDescriptor(_mapConstructor, PropertyFlag.NonEnumerable),
-                ["clear"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "clear", Clear, 0, PropertyFlag.Configurable), propertyFlags),
-                ["delete"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "delete", Delete, 1, PropertyFlag.Configurable), propertyFlags),
-                ["entries"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "entries", Entries, 0, PropertyFlag.Configurable), propertyFlags),
-                ["forEach"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "forEach", ForEach, 1, PropertyFlag.Configurable), propertyFlags),
-                ["get"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "get", Get, 1, PropertyFlag.Configurable), propertyFlags),
-                ["has"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "has", Has, 1, PropertyFlag.Configurable), propertyFlags),
-                ["keys"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "keys", Keys, 0, PropertyFlag.Configurable), propertyFlags),
-                ["set"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "set", Set, 2, PropertyFlag.Configurable), propertyFlags),
-                ["values"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "values", Values, 0, PropertyFlag.Configurable), propertyFlags),
-                ["size"] = new GetSetPropertyDescriptor(get: new ClrFunctionInstance(Engine, "get size", Size, 0, PropertyFlag.Configurable), set: null, PropertyFlag.Configurable)
-            };
-            SetProperties(properties);
-
-            var symbols = new SymbolDictionary(2)
-            {
-                [GlobalSymbolRegistry.Iterator] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "iterator", Entries, 1, PropertyFlag.Configurable), propertyFlags),
-                [GlobalSymbolRegistry.ToStringTag] = new PropertyDescriptor("Map", false, false, true),
-            };
-            SetSymbols(symbols);
-        }
+            [GlobalSymbolRegistry.Iterator] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "iterator", Entries, 1, PropertyFlag.Configurable), propertyFlags),
+            [GlobalSymbolRegistry.ToStringTag] = new PropertyDescriptor("Map", false, false, true),
+        };
+        SetSymbols(symbols);
+    }
 
-        private JsValue Size(JsValue thisObj, JsValue[] arguments)
-        {
-            AssertMapInstance(thisObj);
-            return JsNumber.Create(0);
-        }
+    private JsValue Size(JsValue thisObj, JsValue[] arguments)
+    {
+        AssertMapInstance(thisObj);
+        return JsNumber.Create(0);
+    }
 
-        private JsValue Get(JsValue thisObj, JsValue[] arguments)
-        {
-            var map = AssertMapInstance(thisObj);
-            return map.MapGet(arguments.At(0));
-        }
+    private JsValue Get(JsValue thisObj, JsValue[] arguments)
+    {
+        var map = AssertMapInstance(thisObj);
+        return map.MapGet(arguments.At(0));
+    }
 
-        private JsValue Clear(JsValue thisObj, JsValue[] arguments)
-        {
-            var map = AssertMapInstance(thisObj);
-            map.Clear();
-            return Undefined;
-        }
+    private JsValue Clear(JsValue thisObj, JsValue[] arguments)
+    {
+        var map = AssertMapInstance(thisObj);
+        map.Clear();
+        return Undefined;
+    }
 
-        private JsValue Delete(JsValue thisObj, JsValue[] arguments)
-        {
-            var map = AssertMapInstance(thisObj);
-            return map.MapDelete(arguments[0])
-                ? JsBoolean.True
-                : JsBoolean.False;
-        }
+    private JsValue Delete(JsValue thisObj, JsValue[] arguments)
+    {
+        var map = AssertMapInstance(thisObj);
+        return map.MapDelete(arguments.At(0))
+            ? JsBoolean.True
+            : JsBoolean.False;
+    }
 
-        private JsValue Set(JsValue thisObj, JsValue[] arguments)
-        {
-            var map = AssertMapInstance(thisObj);
-            map.MapSet(arguments[0], arguments[1]);
-            return thisObj;
-        }
+    private JsValue Set(JsValue thisObj, JsValue[] arguments)
+    {
+        var map = AssertMapInstance(thisObj);
+        map.MapSet(arguments.At(0), arguments.At(1));
+        return thisObj;
+    }
 
-        private JsValue Has(JsValue thisObj, JsValue[] arguments)
-        {
-            var map = AssertMapInstance(thisObj);
-            return map.Has(arguments[0])
-                ? JsBoolean.True
-                : JsBoolean.False;
-        }
+    private JsValue Has(JsValue thisObj, JsValue[] arguments)
+    {
+        var map = AssertMapInstance(thisObj);
+        return map.Has(arguments.At(0))
+            ? JsBoolean.True
+            : JsBoolean.False;
+    }
 
-        private JsValue ForEach(JsValue thisObj, JsValue[] arguments)
-        {
-            var map = AssertMapInstance(thisObj);
-            var callbackfn = arguments.At(0);
-            var thisArg = arguments.At(1);
+    private JsValue ForEach(JsValue thisObj, JsValue[] arguments)
+    {
+        var map = AssertMapInstance(thisObj);
+        var callbackfn = arguments.At(0);
+        var thisArg = arguments.At(1);
 
-            var callable = GetCallable(callbackfn);
+        var callable = GetCallable(callbackfn);
 
-            map.ForEach(callable, thisArg);
+        map.ForEach(callable, thisArg);
 
-            return Undefined;
-        }
+        return Undefined;
+    }
 
-        private ObjectInstance Entries(JsValue thisObj, JsValue[] arguments)
-        {
-            var map = AssertMapInstance(thisObj);
-            return map.Iterator();
-        }
+    private ObjectInstance Entries(JsValue thisObj, JsValue[] arguments)
+    {
+        var map = AssertMapInstance(thisObj);
+        return map.Iterator();
+    }
 
-        private ObjectInstance Keys(JsValue thisObj, JsValue[] arguments)
-        {
-            var map = AssertMapInstance(thisObj);
-            return map.Keys();
-        }
+    private ObjectInstance Keys(JsValue thisObj, JsValue[] arguments)
+    {
+        var map = AssertMapInstance(thisObj);
+        return map.Keys();
+    }
 
-        private ObjectInstance Values(JsValue thisObj, JsValue[] arguments)
-        {
-            var map = AssertMapInstance(thisObj);
-            return map.Values();
-        }
+    private ObjectInstance Values(JsValue thisObj, JsValue[] arguments)
+    {
+        var map = AssertMapInstance(thisObj);
+        return map.Values();
+    }
 
-        private MapInstance AssertMapInstance(JsValue thisObj)
+    private MapInstance AssertMapInstance(JsValue thisObj)
+    {
+        var map = thisObj as MapInstance;
+        if (map is null)
         {
-            var map = thisObj as MapInstance;
-            if (map is null)
-            {
-                ExceptionHelper.ThrowTypeError(_realm, "object must be a Map");
-            }
-
-            return map;
+            ExceptionHelper.ThrowTypeError(_realm, "object must be a Map");
         }
+
+        return map;
     }
 }

+ 35 - 17
Jint/Native/RegExp/RegExpStringIteratorPrototype.cs

@@ -1,29 +1,47 @@
+using Jint.Collections;
 using Jint.Native.Iterator;
 using Jint.Native.Object;
+using Jint.Native.Symbol;
 using Jint.Runtime;
+using Jint.Runtime.Descriptors;
+using Jint.Runtime.Interop;
 
-namespace Jint.Native.RegExp
+namespace Jint.Native.RegExp;
+
+/// <summary>
+/// https://tc39.es/ecma262/#sec-%regexpstringiteratorprototype%-object
+/// </summary>
+internal sealed class RegExpStringIteratorPrototype : IteratorPrototype
 {
-    /// <summary>
-    /// https://tc39.es/ecma262/#sec-%regexpstringiteratorprototype%-object
-    /// </summary>
-    internal sealed class RegExpStringIteratorPrototype : IteratorPrototype
+    internal RegExpStringIteratorPrototype(
+        Engine engine,
+        Realm realm,
+        IteratorPrototype iteratorPrototype) : base(engine, realm, iteratorPrototype)
+    {
+    }
+
+    protected override void Initialize()
     {
-        internal RegExpStringIteratorPrototype(
-            Engine engine,
-            Realm realm,
-            Prototype objectPrototype) : base(engine, realm, "RegExp String Iterator", objectPrototype)
+        var properties = new PropertyDictionary(1, checkExistingKeys: false)
         {
-        }
+            [KnownKeys.Next] = new(new ClrFunctionInstance(Engine, "next", Next, 0, PropertyFlag.Configurable), true, false, true)
+        };
+        SetProperties(properties);
 
-        internal IteratorInstance Construct(ObjectInstance iteratingRegExp, string iteratedString, bool global, bool unicode)
+        var symbols = new SymbolDictionary(1)
+        {
+            [GlobalSymbolRegistry.ToStringTag] = new("RegExp String Iterator", PropertyFlag.Configurable)
+        };
+        SetSymbols(symbols);
+    }
+
+    internal IteratorInstance Construct(ObjectInstance iteratingRegExp, string iteratedString, bool global, bool unicode)
+    {
+        var instance = new IteratorInstance.RegExpStringIterator(Engine, iteratingRegExp, iteratedString, global, unicode)
         {
-            var instance = new IteratorInstance.RegExpStringIterator(Engine, iteratingRegExp, iteratedString, global, unicode)
-            {
-                _prototype = this
-            };
+            _prototype = this
+        };
 
-            return instance;
-        }
+        return instance;
     }
 }

+ 0 - 26
Jint/Native/RegExp/RegExpStringIteratorPrototypeObject.cs

@@ -1,26 +0,0 @@
-using Jint.Native.Iterator;
-using Jint.Native.Object;
-using Jint.Runtime;
-
-namespace Jint.Native.RegExp
-{
-    internal sealed class RegExpStringIteratorPrototypeObject : IteratorPrototype
-    {
-        internal RegExpStringIteratorPrototypeObject(
-            Engine engine,
-            Realm realm,
-            Prototype objectPrototype) : base(engine, realm, "RegExp String Iterator", objectPrototype)
-        {
-        }
-
-        internal IteratorInstance Construct(ObjectInstance iteratingRegExp, string iteratedString, bool global, bool unicode)
-        {
-            var instance = new IteratorInstance.RegExpStringIterator(Engine, iteratingRegExp, iteratedString, global, unicode)
-            {
-                _prototype = this
-            };
-
-            return instance;
-        }
-    }
-}

+ 68 - 69
Jint/Native/Set/SetConstructor.cs

@@ -6,97 +6,96 @@ using Jint.Runtime;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
 
-namespace Jint.Native.Set
+namespace Jint.Native.Set;
+
+public sealed class SetConstructor : FunctionInstance, IConstructor
 {
-    public sealed class SetConstructor : FunctionInstance, IConstructor
+    private static readonly JsString _functionName = new("Set");
+
+    internal SetConstructor(
+        Engine engine,
+        Realm realm,
+        FunctionPrototype functionPrototype,
+        ObjectPrototype objectPrototype)
+        : base(engine, realm, _functionName, FunctionThisMode.Global)
     {
-        private static readonly JsString _functionName = new("Set");
+        _prototype = functionPrototype;
+        PrototypeObject = new SetPrototype(engine, realm, this, objectPrototype);
+        _length = new PropertyDescriptor(0, PropertyFlag.Configurable);
+        _prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
+    }
+
+    private SetPrototype PrototypeObject { get; }
 
-        internal SetConstructor(
-            Engine engine,
-            Realm realm,
-            FunctionPrototype functionPrototype,
-            ObjectPrototype objectPrototype)
-            : base(engine, realm, _functionName, FunctionThisMode.Global)
+    protected override void Initialize()
+    {
+        var symbols = new SymbolDictionary(1)
         {
-            _prototype = functionPrototype;
-            PrototypeObject = new SetPrototype(engine, realm, this, objectPrototype);
-            _length = new PropertyDescriptor(0, PropertyFlag.Configurable);
-            _prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
-        }
+            [GlobalSymbolRegistry.Species] = new GetSetPropertyDescriptor(get: new ClrFunctionInstance(_engine, "get [Symbol.species]", Species, 0, PropertyFlag.Configurable), set: Undefined, PropertyFlag.Configurable)
+        };
 
-        public SetPrototype PrototypeObject { get; }
+        SetSymbols(symbols);
+    }
 
-        protected override void Initialize()
-        {
-            var symbols = new SymbolDictionary(1)
-            {
-                [GlobalSymbolRegistry.Species] = new GetSetPropertyDescriptor(get: new ClrFunctionInstance(_engine, "get [Symbol.species]", Species, 0, PropertyFlag.Configurable), set: Undefined, PropertyFlag.Configurable)
-            };
+    private static JsValue Species(JsValue thisObject, JsValue[] arguments)
+    {
+        return thisObject;
+    }
 
-            SetSymbols(symbols);
-        }
+    protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
+    {
+        ExceptionHelper.ThrowTypeError(_engine.Realm, "Constructor Set requires 'new'");
+        return null;
+    }
 
-        private static JsValue Species(JsValue thisObject, JsValue[] arguments)
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-set-iterable
+    /// </summary>
+    ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget)
+    {
+        if (newTarget.IsUndefined())
         {
-            return thisObject;
+            ExceptionHelper.ThrowTypeError(_engine.Realm);
         }
 
-        protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
-        {
-            ExceptionHelper.ThrowTypeError(_engine.Realm, "Constructor Set requires 'new'");
-            return null;
-        }
+        var set = OrdinaryCreateFromConstructor(
+            newTarget,
+            static intrinsics => intrinsics.Set.PrototypeObject,
+            static (Engine engine, Realm _, object? _) => new SetInstance(engine));
 
-        /// <summary>
-        /// https://tc39.es/ecma262/#sec-set-iterable
-        /// </summary>
-        ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget)
+        if (arguments.Length > 0 && !arguments[0].IsNullOrUndefined())
         {
-            if (newTarget.IsUndefined())
+            var adderValue = set.Get("add");
+            var adder = adderValue as ICallable;
+            if (adder is null)
             {
-                ExceptionHelper.ThrowTypeError(_engine.Realm);
+                ExceptionHelper.ThrowTypeError(_engine.Realm, "add must be callable");
             }
 
-            var set = OrdinaryCreateFromConstructor(
-                newTarget,
-                static intrinsics => intrinsics.Set.PrototypeObject,
-                static (Engine engine, Realm _, object? _) => new SetInstance(engine));
+            var iterable = arguments.At(0).GetIterator(_realm);
 
-            if (arguments.Length > 0 && !arguments[0].IsNullOrUndefined())
+            try
             {
-                var adderValue = set.Get("add");
-                var adder = adderValue as ICallable;
-                if (adder is null)
-                {
-                    ExceptionHelper.ThrowTypeError(_engine.Realm, "add must be callable");
-                }
-
-                var iterable = arguments.At(0).GetIterator(_realm);
-
-                try
+                var args = new JsValue[1];
+                do
                 {
-                    var args = new JsValue[1];
-                    do
+                    if (!iterable.TryIteratorStep(out var next))
                     {
-                        if (!iterable.TryIteratorStep(out var next))
-                        {
-                            return set;
-                        }
+                        return set;
+                    }
 
-                        var nextValue = next.Get(CommonProperties.Value);
-                        args[0] = nextValue;
-                        adder.Call(set, args);
-                    } while (true);
-                }
-                catch
-                {
-                    iterable.Close(CompletionType.Throw);
-                    throw;
-                }
+                    var nextValue = next.Get(CommonProperties.Value);
+                    args[0] = nextValue;
+                    adder.Call(set, args);
+                } while (true);
+            }
+            catch
+            {
+                iterable.Close(CompletionType.Throw);
+                throw;
             }
-
-            return set;
         }
+
+        return set;
     }
 }

+ 57 - 58
Jint/Native/Set/SetInstance.cs

@@ -3,82 +3,81 @@ using Jint.Native.Object;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
 
-namespace Jint.Native.Set
+namespace Jint.Native.Set;
+
+public sealed class SetInstance : ObjectInstance
 {
-    public sealed class SetInstance : ObjectInstance
+    internal readonly OrderedSet<JsValue> _set;
+
+    public SetInstance(Engine engine) : base(engine)
     {
-        internal readonly OrderedSet<JsValue> _set;
+        _set = new OrderedSet<JsValue>(SameValueZeroComparer.Instance);
+    }
 
-        public SetInstance(Engine engine) : base(engine)
+    public override PropertyDescriptor GetOwnProperty(JsValue property)
+    {
+        if (property == CommonProperties.Size)
         {
-            _set = new OrderedSet<JsValue>(SameValueZeroComparer.Instance);
+            return new PropertyDescriptor(_set.Count, PropertyFlag.AllForbidden);
         }
 
-        public override PropertyDescriptor GetOwnProperty(JsValue property)
-        {
-            if (property == CommonProperties.Size)
-            {
-                return new PropertyDescriptor(_set.Count, PropertyFlag.AllForbidden);
-            }
+        return base.GetOwnProperty(property);
+    }
 
-            return base.GetOwnProperty(property);
+    protected override bool TryGetProperty(JsValue property, [NotNullWhen(true)] out PropertyDescriptor? descriptor)
+    {
+        if (property == CommonProperties.Size)
+        {
+            descriptor = new PropertyDescriptor(_set.Count, PropertyFlag.AllForbidden);
+            return true;
         }
 
-        protected override bool TryGetProperty(JsValue property, [NotNullWhen(true)] out PropertyDescriptor? descriptor)
-        {
-            if (property == CommonProperties.Size)
-            {
-                descriptor = new PropertyDescriptor(_set.Count, PropertyFlag.AllForbidden);
-                return true;
-            }
+        return base.TryGetProperty(property, out descriptor);
+    }
 
-            return base.TryGetProperty(property, out descriptor);
-        }
+    internal void Add(JsValue value)
+    {
+        _set.Add(value);
+    }
 
-        internal void Add(JsValue value)
-        {
-            _set.Add(value);
-        }
+    internal void Clear()
+    {
+        _set.Clear();
+    }
 
-        internal void Clear()
-        {
-            _set.Clear();
-        }
+    internal bool Has(JsValue key)
+    {
+        return _set.Contains(key);
+    }
 
-        internal bool Has(JsValue key)
-        {
-            return _set.Contains(key);
-        }
+    internal bool SetDelete(JsValue key)
+    {
+        return _set.Remove(key);
+    }
 
-        internal bool SetDelete(JsValue key)
-        {
-            return _set.Remove(key);
-        }
+    internal void ForEach(ICallable callable, JsValue thisArg)
+    {
+        var args = _engine._jsValueArrayPool.RentArray(3);
+        args[2] = this;
 
-        internal void ForEach(ICallable callable, JsValue thisArg)
+        for (var i = 0; i < _set._list.Count; i++)
         {
-            var args = _engine._jsValueArrayPool.RentArray(3);
-            args[2] = this;
-
-            for (var i = 0; i < _set._list.Count; i++)
-            {
-                var value = _set._list[i];
-                args[0] = value;
-                args[1] = value;
-                callable.Call(thisArg, args);
-            }
-
-            _engine._jsValueArrayPool.ReturnArray(args);
+            var value = _set._list[i];
+            args[0] = value;
+            args[1] = value;
+            callable.Call(thisArg, args);
         }
 
-        internal ObjectInstance Entries()
-        {
-            return _engine.Realm.Intrinsics.SetIteratorPrototype.ConstructEntryIterator(this);
-        }
+        _engine._jsValueArrayPool.ReturnArray(args);
+    }
 
-        internal ObjectInstance Values()
-        {
-            return _engine.Realm.Intrinsics.SetIteratorPrototype.ConstructValueIterator(this);
-        }
+    internal ObjectInstance Entries()
+    {
+        return _engine.Realm.Intrinsics.SetIteratorPrototype.ConstructEntryIterator(this);
+    }
+
+    internal ObjectInstance Values()
+    {
+        return _engine.Realm.Intrinsics.SetIteratorPrototype.ConstructValueIterator(this);
     }
 }

+ 80 - 41
Jint/Native/Set/SetIteratorPrototype.cs

@@ -1,66 +1,105 @@
+using Jint.Collections;
 using Jint.Native.Iterator;
 using Jint.Native.Object;
+using Jint.Native.Symbol;
 using Jint.Runtime;
+using Jint.Runtime.Descriptors;
+using Jint.Runtime.Interop;
 
-namespace Jint.Native.Set
+namespace Jint.Native.Set;
+
+/// <summary>
+/// https://tc39.es/ecma262/#sec-%setiteratorprototype%-object
+/// </summary>
+internal sealed class SetIteratorPrototype : IteratorPrototype
 {
-    /// <summary>
-    /// https://tc39.es/ecma262/#sec-%setiteratorprototype%-object
-    /// </summary>
-    internal sealed class SetIteratorPrototype : IteratorPrototype
+    internal SetIteratorPrototype(
+        Engine engine,
+        Realm realm,
+        IteratorPrototype iteratorPrototype) : base(engine, realm, iteratorPrototype)
+    {
+    }
+
+    protected override void Initialize()
     {
-        internal SetIteratorPrototype(
-            Engine engine,
-            Realm realm,
-            Prototype objectPrototype) : base(engine, realm, "Set Iterator", objectPrototype)
+        var properties = new PropertyDictionary(1, checkExistingKeys: false)
         {
-        }
+            [KnownKeys.Next] = new(new ClrFunctionInstance(Engine, "next", Next, 0, PropertyFlag.Configurable), true, false, true)
+        };
+        SetProperties(properties);
 
-        internal IteratorInstance ConstructEntryIterator(SetInstance set)
+        var symbols = new SymbolDictionary(1)
         {
-            var instance = new SetEntryIterator(Engine, set)
-            {
-                _prototype = this
-            };
+            [GlobalSymbolRegistry.ToStringTag] = new("Set Iterator", PropertyFlag.Configurable)
+        };
+        SetSymbols(symbols);
+    }
+
+    internal IteratorInstance ConstructEntryIterator(SetInstance set)
+    {
+        var instance = new SetEntryIterator(Engine, set);
+        return instance;
+    }
+
+    internal IteratorInstance ConstructValueIterator(SetInstance set)
+    {
+        var instance = new SetValueIterator(Engine, set._set._list);
+        return instance;
+    }
 
-            return instance;
+    private sealed class SetEntryIterator : IteratorInstance
+    {
+        private readonly SetInstance _set;
+        private int _position;
+
+        public SetEntryIterator(Engine engine, SetInstance set) : base(engine)
+        {
+            _prototype = engine.Realm.Intrinsics.SetIteratorPrototype;
+            _set = set;
+            _position = 0;
         }
 
-        internal IteratorInstance ConstructValueIterator(SetInstance set)
+        public override bool TryIteratorStep(out ObjectInstance nextItem)
         {
-            var instance = new IteratorInstance.ListIterator(Engine, set._set._list)
+            if (_position < _set._set._list.Count)
             {
-                _prototype = this
-            };
+                var value = _set._set[_position];
+                _position++;
+                nextItem = new KeyValueIteratorPosition(_engine, value, value);
+                return true;
+            }
 
-            return instance;
+            nextItem = KeyValueIteratorPosition.Done(_engine);
+            return false;
         }
+    }
+
+    private sealed class SetValueIterator : IteratorInstance
+    {
+        private readonly List<JsValue> _values;
+        private int _position;
+        private bool _closed;
 
-        private sealed class SetEntryIterator : IteratorInstance
+        public SetValueIterator(Engine engine, List<JsValue> values) : base(engine)
         {
-            private readonly SetInstance _set;
-            private int _position;
+            _prototype = engine.Realm.Intrinsics.SetIteratorPrototype;
+            _values = values;
+            _position = 0;
+        }
 
-            public SetEntryIterator(Engine engine, SetInstance set) : base(engine)
+        public override bool TryIteratorStep(out ObjectInstance nextItem)
+        {
+            if (!_closed && _position < _values.Count)
             {
-                _set = set;
-                _position = 0;
+                var value = _values[_position];
+                _position++;
+                nextItem = new ValueIteratorPosition(_engine, value);
+                return true;
             }
 
-            public override bool TryIteratorStep(out ObjectInstance nextItem)
-            {
-                if (_position < _set._set._list.Count)
-                {
-                    var value = _set._set[_position];
-                    _position++;
-                    nextItem = new KeyValueIteratorPosition(_engine, value, value);
-                    return true;
-                }
-
-                nextItem = KeyValueIteratorPosition.Done(_engine);
-                return false;
-            }
+            _closed = true;
+            nextItem = KeyValueIteratorPosition.Done(_engine);
+            return false;
         }
-
     }
 }

+ 99 - 95
Jint/Native/Set/SetPrototype.cs

@@ -5,121 +5,125 @@ using Jint.Runtime;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
 
-namespace Jint.Native.Set
+namespace Jint.Native.Set;
+
+/// <summary>
+/// https://www.ecma-international.org/ecma-262/6.0/#sec-set-objects
+/// </summary>
+internal sealed class SetPrototype : Prototype
 {
-    /// <summary>
-    /// https://www.ecma-international.org/ecma-262/6.0/#sec-set-objects
-    /// </summary>
-    public sealed class SetPrototype : Prototype
+    private readonly SetConstructor _constructor;
+
+    internal SetPrototype(
+        Engine engine,
+        Realm realm,
+        SetConstructor setConstructor,
+        ObjectPrototype objectPrototype) : base(engine, realm)
     {
-        private readonly SetConstructor _constructor;
+        _prototype = objectPrototype;
+        _constructor = setConstructor;
+    }
 
-        internal SetPrototype(
-            Engine engine,
-            Realm realm,
-            SetConstructor setConstructor,
-            ObjectPrototype objectPrototype) : base(engine, realm)
+    protected override void Initialize()
+    {
+        var properties = new PropertyDictionary(12, checkExistingKeys: false)
         {
-            _prototype = objectPrototype;
-            _constructor = setConstructor;
-        }
-
-        protected override void Initialize()
+            ["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)
+        };
+        SetProperties(properties);
+
+        var symbols = new SymbolDictionary(2)
         {
-            var properties = new PropertyDictionary(12, checkExistingKeys: false)
-            {
-                ["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)
-            };
-            SetProperties(properties);
-
-            var symbols = new SymbolDictionary(2)
-            {
-                [GlobalSymbolRegistry.Iterator] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "iterator", Values, 1, PropertyFlag.Configurable), true, false, true),
-                [GlobalSymbolRegistry.ToStringTag] = new PropertyDescriptor("Set", false, false, true)
-            };
-            SetSymbols(symbols);
-        }
+            [GlobalSymbolRegistry.Iterator] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "iterator", Values, 1, PropertyFlag.Configurable), true, false, true),
+            [GlobalSymbolRegistry.ToStringTag] = new PropertyDescriptor("Set", false, false, true)
+        };
+        SetSymbols(symbols);
+    }
 
-        private JsValue Size(JsValue thisObj, JsValue[] arguments)
-        {
-            AssertSetInstance(thisObj);
-            return JsNumber.Create(0);
-        }
+    private JsValue Size(JsValue thisObj, JsValue[] arguments)
+    {
+        AssertSetInstance(thisObj);
+        return JsNumber.Create(0);
+    }
 
-        private JsValue Add(JsValue thisObj, JsValue[] arguments)
+    private JsValue Add(JsValue thisObj, JsValue[] arguments)
+    {
+        var set = AssertSetInstance(thisObj);
+        var value = arguments.At(0);
+        if (value is JsNumber number && number.IsNegativeZero())
         {
-            var set = AssertSetInstance(thisObj);
-            set.Add(arguments[0]);
-            return thisObj;
+            value = JsNumber.PositiveZero;
         }
+        set.Add(value);
+        return thisObj;
+    }
 
-        private JsValue Clear(JsValue thisObj, JsValue[] arguments)
-        {
-            var set = AssertSetInstance(thisObj);
-            set.Clear();
-            return Undefined;
-        }
+    private JsValue Clear(JsValue thisObj, JsValue[] arguments)
+    {
+        var set = AssertSetInstance(thisObj);
+        set.Clear();
+        return Undefined;
+    }
 
-        private JsValue Delete(JsValue thisObj, JsValue[] arguments)
-        {
-            var set = AssertSetInstance(thisObj);
-            return set.SetDelete(arguments[0])
-                ? JsBoolean.True
-                : JsBoolean.False;
-        }
+    private JsValue Delete(JsValue thisObj, JsValue[] arguments)
+    {
+        var set = AssertSetInstance(thisObj);
+        return set.SetDelete(arguments.At(0))
+            ? JsBoolean.True
+            : JsBoolean.False;
+    }
 
-        private JsValue Has(JsValue thisObj, JsValue[] arguments)
-        {
-            var set = AssertSetInstance(thisObj);
-            return set.Has(arguments[0])
-                ? JsBoolean.True
-                : JsBoolean.False;
-        }
+    private JsValue Has(JsValue thisObj, JsValue[] arguments)
+    {
+        var set = AssertSetInstance(thisObj);
+        return set.Has(arguments.At(0))
+            ? JsBoolean.True
+            : JsBoolean.False;
+    }
 
-        private JsValue Entries(JsValue thisObj, JsValue[] arguments)
-        {
-            var set = AssertSetInstance(thisObj);
-            return set.Entries();
-        }
+    private JsValue Entries(JsValue thisObj, JsValue[] arguments)
+    {
+        var set = AssertSetInstance(thisObj);
+        return set.Entries();
+    }
 
-        private JsValue ForEach(JsValue thisObj, JsValue[] arguments)
-        {
-            var callbackfn = arguments.At(0);
-            var thisArg = arguments.At(1);
+    private JsValue ForEach(JsValue thisObj, JsValue[] arguments)
+    {
+        var callbackfn = arguments.At(0);
+        var thisArg = arguments.At(1);
 
-            var set = AssertSetInstance(thisObj);
-            var callable = GetCallable(callbackfn);
+        var set = AssertSetInstance(thisObj);
+        var callable = GetCallable(callbackfn);
 
-            set.ForEach(callable, thisArg);
+        set.ForEach(callable, thisArg);
 
-            return Undefined;
-        }
+        return Undefined;
+    }
 
-        private ObjectInstance Values(JsValue thisObj, JsValue[] arguments)
-        {
-            var set = AssertSetInstance(thisObj);
-            return set.Values();
-        }
+    private ObjectInstance Values(JsValue thisObj, JsValue[] arguments)
+    {
+        var set = AssertSetInstance(thisObj);
+        return set.Values();
+    }
 
-        private SetInstance AssertSetInstance(JsValue thisObj)
+    private SetInstance AssertSetInstance(JsValue thisObj)
+    {
+        var set = thisObj as SetInstance;
+        if (set is null)
         {
-            var set = thisObj as SetInstance;
-            if (set is null)
-            {
-                ExceptionHelper.ThrowTypeError(_realm, "object must be a Set");
-            }
-
-            return set;
+            ExceptionHelper.ThrowTypeError(_realm, "object must be a Set");
         }
+
+        return set;
     }
 }

+ 35 - 17
Jint/Native/String/StringIteratorPrototype.cs

@@ -1,29 +1,47 @@
+using Jint.Collections;
 using Jint.Native.Iterator;
 using Jint.Native.Object;
+using Jint.Native.Symbol;
 using Jint.Runtime;
+using Jint.Runtime.Descriptors;
+using Jint.Runtime.Interop;
 
-namespace Jint.Native.String
+namespace Jint.Native.String;
+
+/// <summary>
+/// https://tc39.es/ecma262/#sec-%stringiteratorprototype%-object
+/// </summary>
+internal sealed class StringIteratorPrototype : IteratorPrototype
 {
-    /// <summary>
-    /// https://tc39.es/ecma262/#sec-%stringiteratorprototype%-object
-    /// </summary>
-    internal sealed class StringIteratorPrototype : IteratorPrototype
+    internal StringIteratorPrototype(
+        Engine engine,
+        Realm realm,
+        IteratorPrototype iteratorPrototype) : base(engine, realm, iteratorPrototype)
+    {
+    }
+
+    protected override void Initialize()
     {
-        internal StringIteratorPrototype(
-            Engine engine,
-            Realm realm,
-            Prototype objectPrototype) : base(engine, realm, "String Iterator", objectPrototype)
+        var properties = new PropertyDictionary(1, checkExistingKeys: false)
         {
-        }
+            [KnownKeys.Next] = new(new ClrFunctionInstance(Engine, "next", Next, 0, PropertyFlag.Configurable), true, false, true)
+        };
+        SetProperties(properties);
 
-        public ObjectInstance Construct(string str)
+        var symbols = new SymbolDictionary(1)
+        {
+            [GlobalSymbolRegistry.ToStringTag] = new("String Iterator", PropertyFlag.Configurable)
+        };
+        SetSymbols(symbols);
+    }
+
+    public ObjectInstance Construct(string str)
+    {
+        var instance = new IteratorInstance.StringIterator(Engine, str)
         {
-            var instance = new IteratorInstance.StringIterator(Engine, str)
-            {
-                _prototype = this
-            };
+            _prototype = this
+        };
 
-            return instance;
-        }
+        return instance;
     }
 }

+ 0 - 1
Jint/Runtime/Host.cs

@@ -1,5 +1,4 @@
 using Jint.Native;
-using Jint.Native.Function;
 using Jint.Native.Global;
 using Jint.Native.Object;
 using Jint.Native.Promise;

+ 3 - 3
Jint/Runtime/Intrinsics.cs

@@ -179,13 +179,13 @@ namespace Jint.Runtime
             _map ??= new MapConstructor(_engine, _realm, Function.PrototypeObject, Object.PrototypeObject);
 
         internal MapIteratorPrototype MapIteratorPrototype =>
-            _mapIteratorPrototype ??= new MapIteratorPrototype(_engine, _realm, Object.PrototypeObject);
+            _mapIteratorPrototype ??= new MapIteratorPrototype(_engine, _realm, IteratorPrototype);
 
         public SetConstructor Set =>
             _set ??= new SetConstructor(_engine, _realm, Function.PrototypeObject, Object.PrototypeObject);
 
         internal SetIteratorPrototype SetIteratorPrototype =>
-            _setIteratorPrototype ??= new SetIteratorPrototype(_engine, _realm, Object.PrototypeObject);
+            _setIteratorPrototype ??= new SetIteratorPrototype(_engine, _realm, IteratorPrototype);
 
         public WeakMapConstructor WeakMap =>
             _weakMap ??= new WeakMapConstructor(_engine, _realm, Function.PrototypeObject, Object.PrototypeObject);
@@ -200,7 +200,7 @@ namespace Jint.Runtime
             _promise ??= new PromiseConstructor(_engine, _realm, Function.PrototypeObject, Object.PrototypeObject);
 
         internal IteratorPrototype IteratorPrototype =>
-            _iteratorPrototype ??= new IteratorPrototype(_engine, _realm, null, Object.PrototypeObject);
+            _iteratorPrototype ??= new IteratorPrototype(_engine, _realm, Object.PrototypeObject);
 
         public StringConstructor String =>
             _string ??= new StringConstructor(_engine, _realm, Function.PrototypeObject, Object.PrototypeObject);

+ 1 - 0
Jint/Runtime/KnownKeys.cs

@@ -10,4 +10,5 @@ internal static class KnownKeys
     internal static readonly Key Value = "value";
     internal static readonly Key Undefined = "undefined";
     internal static readonly Key Constructor = "constructor";
+    internal static readonly Key Next = "next";
 }