From d6b542a3f9441af5378dc2703ecc887369691ca6 Mon Sep 17 00:00:00 2001 From: Roger Johansson Date: Sun, 30 Nov 2025 13:16:13 +0100 Subject: [PATCH] Refactor array iterator creation helper --- .../StdLib/StandardLibrary.Array.cs | 80 +++---------------- .../StdLib/StandardLibrary.IteratorHelpers.cs | 77 ++++++++++++------ 2 files changed, 65 insertions(+), 92 deletions(-) diff --git a/src/Asynkron.JsEngine/StdLib/StandardLibrary.Array.cs b/src/Asynkron.JsEngine/StdLib/StandardLibrary.Array.cs index a33f1a4..953e967 100644 --- a/src/Asynkron.JsEngine/StdLib/StandardLibrary.Array.cs +++ b/src/Asynkron.JsEngine/StdLib/StandardLibrary.Array.cs @@ -11,6 +11,18 @@ public static partial class StandardLibrary { private const long MaxArrayLength = 9007199254740991L; // 2^53 - 1 + private static double ToLengthValue(object? candidate) + { + var num = JsOps.ToNumber(candidate); + if (double.IsNaN(num) || double.IsInfinity(num) || num <= 0) + { + return 0; + } + + var truncated = Math.Floor(num); + return Math.Min(truncated, (double)MaxArrayLength); // 2^53 - 1 + } + public static void AddArrayMethods(IJsPropertyAccessor array, RealmState? realm = null, JsObject? prototypeOverride = null) { @@ -109,72 +121,6 @@ public static void AddArrayMethods(IJsPropertyAccessor array, RealmState? realm }); return; - static double ToLengthValue(object? candidate) - { - var num = JsOps.ToNumber(candidate); - if (double.IsNaN(num) || double.IsInfinity(num) || num <= 0) - { - return 0; - } - - var truncated = Math.Floor(num); - return Math.Min(truncated, (double)MaxArrayLength); // 2^53 - 1 - } - - static object CreateArrayIterator(object? thisValue, IJsPropertyAccessor accessor, - Func projector) - { - var iterator = new JsObject(); - var iteratorSymbol = TypedAstSymbol.For("Symbol.iterator"); - var iteratorKey = $"@@symbol:{iteratorSymbol.GetHashCode()}"; - - uint index = 0; - var exhausted = false; - - iterator.SetHostedProperty("next", Next); - - iterator.SetHostedProperty(iteratorKey, ReturnIterator); - return iterator; - - object? Next(object? _, IReadOnlyList __) - { - if (exhausted) - { - var doneResult = new JsObject(); - doneResult.SetProperty("value", Symbol.Undefined); - doneResult.SetProperty("done", true); - return doneResult; - } - - uint length = 0; - if (accessor.TryGetProperty("length", out var lengthValue)) - { - length = (uint)ToLengthValue(lengthValue); - } - - var result = new JsObject(); - if (index < length) - { - result.SetProperty("value", projector(index)); - result.SetProperty("done", false); - index++; - } - else - { - result.SetProperty("value", Symbol.Undefined); - result.SetProperty("done", true); - exhausted = true; - } - - return result; - } - - object? ReturnIterator(object? _, IReadOnlyList __) - { - return iterator; - } - } - HostFunction DefineArrayIteratorFunction(string name, Func> projectorFactory) { @@ -197,7 +143,7 @@ HostFunction DefineArrayIteratorFunction(string name, } var projector = projectorFactory(accessor, thisValue); - return CreateArrayIterator(thisValue, accessor, projector); + return CreateArrayIterator(accessor, projector); }) { IsConstructor = false }; fn.DefineProperty("name", diff --git a/src/Asynkron.JsEngine/StdLib/StandardLibrary.IteratorHelpers.cs b/src/Asynkron.JsEngine/StdLib/StandardLibrary.IteratorHelpers.cs index cf62670..29533b1 100644 --- a/src/Asynkron.JsEngine/StdLib/StandardLibrary.IteratorHelpers.cs +++ b/src/Asynkron.JsEngine/StdLib/StandardLibrary.IteratorHelpers.cs @@ -46,7 +46,7 @@ public static HostFunction CreateGetAsyncIteratorHelper(JsEngine engine) if (iterable is JsArray jsArray) { - var iteratorObj = CreateArrayIterator(jsArray); + var iteratorObj = CreateArrayIterator(jsArray, idx => jsArray.GetElement((int)idx)); engine.WriteAsyncIteratorTrace( $"getAsyncIterator: branch=array length={jsArray.Length}"); return iteratorObj; @@ -104,37 +104,64 @@ static JsObject CreateStringIterator(string str) } } - static JsObject CreateArrayIterator(JsArray array) + static bool HasCallableNext(object? candidate) { - var iteratorObj = new JsObject(); - var index = 0; - iteratorObj.SetHostedProperty("next", Next); - return iteratorObj; + return candidate is JsObject obj && + obj.TryGetProperty("next", out var nextProp) && + nextProp is IJsCallable; + } + } + } - object? Next(IReadOnlyList _) - { - var result = new JsObject(); - if (index < array.Length) - { - result.SetProperty("value", array.GetElement(index)); - result.SetProperty("done", false); - index++; - } - else - { - result.SetProperty("done", true); - } + private static JsObject CreateArrayIterator(IJsPropertyAccessor accessor, Func projector) + { + var iterator = new JsObject(); + var iteratorSymbol = TypedAstSymbol.For("Symbol.iterator"); + var iteratorKey = $"@@symbol:{iteratorSymbol.GetHashCode()}"; - return result; - } + uint index = 0; + var exhausted = false; + + iterator.SetHostedProperty("next", Next); + iterator.SetHostedProperty(iteratorKey, ReturnIterator); + return iterator; + + object? Next(object? _, IReadOnlyList __) + { + if (exhausted) + { + var doneResult = new JsObject(); + doneResult.SetProperty("value", Symbol.Undefined); + doneResult.SetProperty("done", true); + return doneResult; } - static bool HasCallableNext(object? candidate) + uint length = 0; + if (accessor.TryGetProperty("length", out var lengthValue)) { - return candidate is JsObject obj && - obj.TryGetProperty("next", out var nextProp) && - nextProp is IJsCallable; + length = (uint)ToLengthValue(lengthValue); + } + + var result = new JsObject(); + if (index < length) + { + result.SetProperty("value", projector(index)); + result.SetProperty("done", false); + index++; + } + else + { + result.SetProperty("value", Symbol.Undefined); + result.SetProperty("done", true); + exhausted = true; } + + return result; + } + + object? ReturnIterator(object? _, IReadOnlyList __) + { + return iterator; } }