Skip to content

Commit

Permalink
add IEnumerable support
Browse files Browse the repository at this point in the history
  • Loading branch information
lahma committed Sep 25, 2021
1 parent 858e741 commit 6b86b06
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 32 deletions.
8 changes: 8 additions & 0 deletions Jint.Tests/Runtime/Domain/Company.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,13 @@ int IComparable<ICompany>.CompareTo(ICompany other)
{
return string.Compare(_name, other.Name, StringComparison.CurrentCulture);
}

public IEnumerable<char> GetNameChars()
{
foreach (var c in _name)
{
yield return c;
}
}
}
}
10 changes: 10 additions & 0 deletions Jint.Tests/Runtime/InteropTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,16 @@ public void ShouldForOfOnExpandoObject()
Assert.Equal("a,1b,2", result);
}

[Fact]
public void ShouldForOfOnEnumerable()
{
_engine.SetValue("c", new Company("name"));

var result = _engine.Evaluate("var l = ''; for (var x of c.getNameChars()) l += x + ','; return l;").AsString();

Assert.Equal("n,a,m,e,", result);
}

[Fact]
public void ShouldThrowWhenForOfOnObject()
{
Expand Down
53 changes: 21 additions & 32 deletions Jint/Runtime/Interop/ObjectWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,22 +208,19 @@ public override PropertyDescriptor GetOwnProperty(JsValue property)
return x;
}

if (property.IsSymbol() && property == GlobalSymbolRegistry.Iterator)
// if we have array-like or dictionary or expando, we can provide iterator
if (property.IsSymbol() && property == GlobalSymbolRegistry.Iterator && _typeDescriptor.Iterable)
{
// if we have array-like or dictionary or expando, we can provide iterator
if (_typeDescriptor.IsArrayLike || _typeDescriptor.IsDictionary)
{
var iteratorFunction = new ClrFunctionInstance(
Engine,
"iterator",
Iterator,
1,
PropertyFlag.Configurable);

var iteratorProperty = new PropertyDescriptor(iteratorFunction, PropertyFlag.Configurable | PropertyFlag.Writable);
SetProperty(GlobalSymbolRegistry.Iterator, iteratorProperty);
return iteratorProperty;
}
var iteratorFunction = new ClrFunctionInstance(
Engine,
"iterator",
Iterator,
1,
PropertyFlag.Configurable);

var iteratorProperty = new PropertyDescriptor(iteratorFunction, PropertyFlag.Configurable | PropertyFlag.Writable);
SetProperty(GlobalSymbolRegistry.Iterator, iteratorProperty);
return iteratorProperty;
}

var member = property.ToString();
Expand Down Expand Up @@ -259,14 +256,10 @@ ReflectionAccessor Factory()
private static JsValue Iterator(JsValue thisObj, JsValue[] arguments)
{
var wrapper = (ObjectWrapper) thisObj;
var intrinsics = wrapper._engine.Realm.Intrinsics;

if (wrapper._typeDescriptor.IsDictionary)
{
return new DictionaryIterator(wrapper._engine, wrapper);
}

return new ListIterator(wrapper._engine, (IList) wrapper.Target);
return wrapper._typeDescriptor.IsDictionary
? new DictionaryIterator(wrapper._engine, wrapper)
: new EnumerableIterator(wrapper._engine, (IEnumerable) wrapper.Target);
}

private static JsValue GetLength(JsValue thisObj, JsValue[] arguments)
Expand Down Expand Up @@ -332,23 +325,20 @@ public override bool TryIteratorStep(out ObjectInstance nextItem)
}
}

private sealed class ListIterator : IteratorInstance
private sealed class EnumerableIterator : IteratorInstance
{
private readonly IList _list;
private int _position;
private readonly IEnumerator _enumerator;

public ListIterator(Engine engine, IList list) : base(engine)
public EnumerableIterator(Engine engine, IEnumerable target) : base(engine)
{
_list = list;
_position = 0;
_enumerator = target.GetEnumerator();
}

public override bool TryIteratorStep(out ObjectInstance nextItem)
{
if (_position < _list.Count)
if (_enumerator.MoveNext())
{
var value = _list[_position];
_position++;
var value = _enumerator.Current;
nextItem = new ValueIteratorPosition(_engine, FromObject(_engine, value));
return true;
}
Expand All @@ -357,6 +347,5 @@ public override bool TryIteratorStep(out ObjectInstance nextItem)
return false;
}
}

}
}
4 changes: 4 additions & 0 deletions Jint/Runtime/Interop/TypeDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ private TypeDescriptor(Type type)
{
IsArrayLike = DetermineIfObjectIsArrayLikeClrCollection(type);
IsDictionary = typeof(IDictionary).IsAssignableFrom(type) || typeof(IDictionary<string, object>).IsAssignableFrom(type);
IsEnumerable = typeof(IEnumerable).IsAssignableFrom(type);

if (IsArrayLike)
{
Expand All @@ -25,8 +26,11 @@ private TypeDescriptor(Type type)
public bool IsArrayLike { get; }
public bool IsIntegerIndexedArray { get; }
public bool IsDictionary { get; }
public bool IsEnumerable { get; }
public PropertyInfo LengthProperty { get; }

public bool Iterable => IsArrayLike || IsDictionary || IsEnumerable;

public static TypeDescriptor Get(Type type)
{
return _cache.GetOrAdd(type, t => new TypeDescriptor(t));
Expand Down

0 comments on commit 6b86b06

Please sign in to comment.