Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Jint.Tests.Test262/Test262Harness.settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
"decorators",
"explicit-resource-management",
"import-defer",
"iterator-helpers",
"iterator-sequencing",
"json-parse-with-source",
"regexp-lookbehind",
Expand Down
2 changes: 2 additions & 0 deletions Jint/Native/Global/GlobalObject.Properties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public partial class GlobalObject
private static readonly Key propertyInt16Array = "Int16Array";
private static readonly Key propertyInt32Array = "Int32Array";
private static readonly Key propertyInt8Array = "Int8Array";
private static readonly Key propertyIterator = "Iterator";
//private static readonly Key propertyIntl = "Intl";
private static readonly Key propertyJSON = "JSON";
private static readonly Key propertyMap = "Map";
Expand Down Expand Up @@ -110,6 +111,7 @@ protected override void Initialize()
properties.AddDangerous(propertyInt32Array, new LazyPropertyDescriptor<GlobalObject>(this, static global => global._realm.Intrinsics.Int32Array, PropertyFlags));
properties.AddDangerous(propertyInt8Array, new LazyPropertyDescriptor<GlobalObject>(this, static global => global._realm.Intrinsics.Int8Array, PropertyFlags));
// TODO properties.AddDapropertygerous(propertyIntl, new LazyPropertyDescriptor<GlobalObject>(this, static global => global._realm.Intrinsics.Intl, propertyFlags));
properties.AddDangerous(propertyIterator, new LazyPropertyDescriptor<GlobalObject>(this, static global => global._realm.Intrinsics.Iterator, PropertyFlags));
properties.AddDangerous(propertyJSON, new LazyPropertyDescriptor<GlobalObject>(this, static global => global._realm.Intrinsics.Json, PropertyFlags));
properties.AddDangerous(propertyMap, new LazyPropertyDescriptor<GlobalObject>(this, static global => global._realm.Intrinsics.Map, PropertyFlags));
properties.AddDangerous(propertyMath, new LazyPropertyDescriptor<GlobalObject>(this, static global => global._realm.Intrinsics.Math, PropertyFlags));
Expand Down
141 changes: 141 additions & 0 deletions Jint/Native/Iterator/IteratorConstructor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
using Jint.Native.Function;
using Jint.Native.Object;
using Jint.Native.Symbol;
using Jint.Runtime;
using Jint.Runtime.Descriptors;
using Jint.Runtime.Interop;

namespace Jint.Native.Iterator;

internal sealed class IteratorConstructor : Constructor
{
private static readonly JsString _functionName = new("Iterator");

internal IteratorConstructor(
Engine engine,
Realm realm,
FunctionPrototype functionPrototype,
ObjectPrototype objectPrototype)
: base(engine, realm, _functionName)
{
_prototype = functionPrototype;
PrototypeObject = new IteratorPrototype(engine, realm, this);
_length = new PropertyDescriptor(0, PropertyFlag.Configurable);
_prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
}

private IteratorPrototype PrototypeObject { get; }

protected override void Initialize()
{
const PropertyFlag PropertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
const PropertyFlag LengthFlags = PropertyFlag.Configurable;
var properties = new PropertyDictionary(1, checkExistingKeys: false) { ["from"] = new(new PropertyDescriptor(new ClrFunction(Engine, "from", From, 1, LengthFlags), PropertyFlags)), };
SetProperties(properties);
}

public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
{
if (newTarget.IsUndefined() || ReferenceEquals(this, newTarget))
{
ExceptionHelper.ThrowTypeError(_realm);
}

return OrdinaryCreateFromConstructor(
newTarget,
static intrinsics => intrinsics.Iterator.PrototypeObject,
static (Engine engine, Realm realm, object? _) => new JsObject(engine));
}

/// <summary>
/// https://tc39.es/ecma262/#sec-iterator.from
/// </summary>
private JsValue From(JsValue thisObject, JsValue[] arguments)
{
var iteratorRecord = GetIteratorFlattenable(thisObject, StringHandlingType.IterateStringPrimitives);
var hasInstance = _engine.Intrinsics.Iterator.OrdinaryHasInstance(iteratorRecord);
if (hasInstance)
{
return iteratorRecord;
}

var wrapper = new WrapForValidIteratorPrototype(_engine, iteratorRecord);
return wrapper;
}

private IteratorInstance.ObjectIterator GetIteratorFlattenable(JsValue obj, StringHandlingType stringHandling)
{
if (obj is not ObjectInstance)
{
if (stringHandling == StringHandlingType.RejectStrings || obj.IsString())
{
ExceptionHelper.ThrowTypeError(_realm);
}
}

JsValue iterator;
var method = JsValue.GetMethod(_realm, obj, GlobalSymbolRegistry.Iterator);
if (method is null)
{
iterator = obj;
}
else
{
iterator = method.Call(obj);
}

if (iterator is not ObjectInstance objectInstance)
{
ExceptionHelper.ThrowTypeError(_realm);
return null;
}

return new IteratorInstance.ObjectIterator(objectInstance);
}

private sealed class WrapForValidIteratorPrototype : ObjectInstance
{
public WrapForValidIteratorPrototype(
Engine engine,
IteratorInstance.ObjectIterator iterated) : base(engine)
{
Iterated = iterated;
SetPrototypeOf(engine.Intrinsics.IteratorPrototype);
}

public IteratorInstance.ObjectIterator Iterated { get; }

public ObjectInstance Next()
{
var iteratorRecord = Iterated;
iteratorRecord.TryIteratorStep(out var obj);
return obj;
}

public JsValue Return()
{
var iterator = Iterated.GetIterator(_engine.Realm);
var returnMethod = iterator.GetMethod(CommonProperties.Return);
if (returnMethod is null)
{
return CreateIteratorResultObject(Undefined, done: JsBoolean.True);
}

return returnMethod.Call(iterator);
}

/// <summary>
/// https://tc39.es/ecma262/#sec-createiterresultobject
/// </summary>
private IteratorResult CreateIteratorResultObject(JsValue value, JsBoolean done)
{
return IteratorResult.CreateValueIteratorPosition(_engine, value, done);
}
}

private enum StringHandlingType
{
IterateStringPrimitives,
RejectStrings
}
}
Loading
Loading