Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update test262 test suite and fix issues #1589

Merged
merged 1 commit into from
Jul 27, 2023
Merged
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
4 changes: 3 additions & 1 deletion Jint.Tests.Test262/Test262Harness.settings.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
{
"SuiteGitSha": "9704d7f22f6342d6c4753ab9a8d62d6725de8c4e",
"SuiteGitSha": "9437cab774ab2f22c5cb971b11b8512eca705721",
//"SuiteDirectory": "//mnt/c/work/test262",
"TargetPath": "./Generated",
"Namespace": "Jint.Tests.Test262",
"Parallel": true,
"ExcludedFeatures": [
"Array.fromAsync",
"arraybuffer-transfer",
"async-iteration",
"Atomics",
"decorators",
"generators",
"import-assertions",
"iterator-helpers",
"regexp-duplicate-named-groups",
"regexp-lookbehind",
"regexp-unicode-property-escapes",
Expand Down
11 changes: 11 additions & 0 deletions Jint/JsValueExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -582,5 +582,16 @@ internal static BigInteger ToBigInteger(this JsValue value, Engine engine)
return default;
}
}

internal static ICallable GetCallable(this JsValue source, Realm realm)
{
if (source is ICallable callable)
{
return callable;
}

ExceptionHelper.ThrowTypeError(realm, "Argument must be callable");
return null;
}
}
}
79 changes: 1 addition & 78 deletions Jint/Native/Array/ArrayPrototype.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System.Linq;
using Jint.Collections;
using Jint.Native.Iterator;
using Jint.Native.Map;
using Jint.Native.Number;
using Jint.Native.Object;
using Jint.Native.Symbol;
Expand Down Expand Up @@ -37,7 +36,7 @@ internal ArrayPrototype(
protected override void Initialize()
{
const PropertyFlag PropertyFlags = PropertyFlag.Writable | PropertyFlag.Configurable;
var properties = new PropertyDictionary(40, checkExistingKeys: false)
var properties = new PropertyDictionary(38, checkExistingKeys: false)
{
["constructor"] = new PropertyDescriptor(_constructor, PropertyFlag.NonEnumerable),

Expand All @@ -55,8 +54,6 @@ protected override void Initialize()
["flat"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "flat", Flat, 0, PropertyFlag.Configurable), PropertyFlags),
["flatMap"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "flatMap", FlatMap, 1, PropertyFlag.Configurable), PropertyFlags),
["forEach"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "forEach", ForEach, 1, PropertyFlag.Configurable), PropertyFlags),
["group"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "group", Group, 1, PropertyFlag.Configurable), PropertyFlags),
["groupToMap"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "groupToMap", GroupToMap, 1, PropertyFlag.Configurable), PropertyFlags),
["includes"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "includes", Includes, 1, PropertyFlag.Configurable), PropertyFlags),
["indexOf"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "indexOf", IndexOf, 1, PropertyFlag.Configurable), PropertyFlags),
["join"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "join", Join, 1, PropertyFlag.Configurable), PropertyFlags),
Expand Down Expand Up @@ -105,10 +102,6 @@ protected override void Initialize()
unscopables.FastSetDataProperty("findLastIndex", JsBoolean.True);
unscopables.FastSetDataProperty("flat", JsBoolean.True);
unscopables.FastSetDataProperty("flatMap", JsBoolean.True);
unscopables.FastSetDataProperty("group", JsBoolean.True);
unscopables.FastSetDataProperty("groupBy", JsBoolean.True);
unscopables.FastSetDataProperty("groupByToMap", JsBoolean.True);
unscopables.FastSetDataProperty("groupToMap", JsBoolean.True);
unscopables.FastSetDataProperty("includes", JsBoolean.True);
unscopables.FastSetDataProperty("keys", JsBoolean.True);
unscopables.FastSetDataProperty("toReversed", JsBoolean.True);
Expand Down Expand Up @@ -1655,76 +1648,6 @@ public JsValue Pop(JsValue thisObject, JsValue[] arguments)
return element;
}

/// <summary>
/// https://tc39.es/proposal-array-grouping/#sec-array.prototype.group
/// </summary>
private JsValue Group(JsValue thisObject, JsValue[] arguments)
{
var grouping = BuildArrayGrouping(thisObject, arguments, mapMode: false);

var obj = OrdinaryObjectCreate(_engine, null);
foreach (var pair in grouping)
{
obj.FastSetProperty(pair.Key, new PropertyDescriptor(pair.Value, PropertyFlag.ConfigurableEnumerableWritable));
}

return obj;
}

/// <summary>
/// https://tc39.es/proposal-array-grouping/#sec-array.prototype.grouptomap
/// </summary>
private JsValue GroupToMap(JsValue thisObject, JsValue[] arguments)
{
var grouping = BuildArrayGrouping(thisObject, arguments, mapMode: true);
var map = (MapInstance) Construct(_realm.Intrinsics.Map);
foreach (var pair in grouping)
{
map.MapSet(pair.Key, pair.Value);
}

return map;
}

private Dictionary<JsValue, JsArray> BuildArrayGrouping(JsValue thisObject, JsValue[] arguments, bool mapMode)
{
var o = ArrayOperations.For(_realm, thisObject);
var len = o.GetLongLength();
var callbackfn = arguments.At(0);
var callable = GetCallable(callbackfn);
var thisArg = arguments.At(1);

var result = new Dictionary<JsValue, JsArray>();
var args = _engine._jsValueArrayPool.RentArray(3);
args[2] = o.Target;
for (uint k = 0; k < len; k++)
{
var kValue = o.Get(k);
args[0] = kValue;
args[1] = k;

var value = callable.Call(thisArg, args);
JsValue key;
if (mapMode)
{
key = (value as JsNumber)?.IsNegativeZero() == true ? JsNumber.PositiveZero : value;
}
else
{
key = TypeConverter.ToPropertyKey(value);
}
if (!result.TryGetValue(key, out var list))
{
result[key] = list = new JsArray(_engine);
}

list.SetIndexValue(list.GetLength(), kValue, updateLength: true);
}

_engine._jsValueArrayPool.ReturnArray(args);
return result;
}

private object[] CreateBackingArray(ulong length)
{
ValidateArrayLength(length);
Expand Down
75 changes: 75 additions & 0 deletions Jint/Native/GroupByHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using Jint.Native.Array;
using Jint.Native.Iterator;
using Jint.Runtime;

namespace Jint.Native;

internal static class GroupByHelper
{
internal static Dictionary<JsValue, JsArray> GroupBy(
Engine engine,
Realm realm,
JsValue items,
JsValue callbackfn,
bool mapMode)
{
var callable = callbackfn.GetCallable(realm);
var groups = new Dictionary<JsValue, JsArray>();
var iteratorRecord = items.GetIterator(realm);
new GroupByProtocol(engine, groups, iteratorRecord, callable, mapMode).Execute();
return groups;
}

private sealed class GroupByProtocol : IteratorProtocol
{
private readonly Engine _engine;
private readonly Dictionary<JsValue, JsArray> _result;
private readonly ICallable _callable;
private readonly bool _mapMode;
private ulong _k;
private readonly JsValue[] _callArgs = new JsValue[2];

public GroupByProtocol(
Engine engine,
Dictionary<JsValue, JsArray> result,
IteratorInstance iterator,
ICallable callable,
bool mapMode) : base(engine, iterator, 0)
{
_engine = engine;
_result = result;
_callable = callable;
_mapMode = mapMode;
}

protected override void ProcessItem(JsValue[] args, JsValue currentValue)
{
if (_k >= ArrayOperations.MaxArrayLength)
{
ExceptionHelper.ThrowTypeError(_engine.Realm);
}

_callArgs[0] = currentValue;
_callArgs[1] = _k;

var value = _callable.Call(JsValue.Undefined, _callArgs);
JsValue key;
if (_mapMode)
{
key = (value as JsNumber)?.IsNegativeZero() == true ? JsNumber.PositiveZero : value;
}
else
{
key = TypeConverter.ToPropertyKey(value);
}

if (!_result.TryGetValue(key, out var list))
{
_result[key] = list = new JsArray(_engine);
}

list.Push(currentValue);
_k++;
}
}
}
25 changes: 25 additions & 0 deletions Jint/Native/Map/MapConstructor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ internal MapConstructor(

protected override void Initialize()
{
const PropertyFlag PropertyFlags = PropertyFlag.Writable | PropertyFlag.Configurable;
var properties = new PropertyDictionary(1, checkExistingKeys: false)
{
["groupBy"] = new(new ClrFunctionInstance(Engine, "groupBy", GroupBy, 2, PropertyFlag.Configurable), PropertyFlags),
};
SetProperties(properties);

var symbols = new SymbolDictionary(1)
{
[GlobalSymbolRegistry.Species] = new GetSetPropertyDescriptor(get: new ClrFunctionInstance(_engine, "get [Symbol.species]", Species, 0, PropertyFlag.Configurable), set: Undefined, PropertyFlag.Configurable)
Expand Down Expand Up @@ -67,4 +74,22 @@ public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)

return map;
}


/// <summary>
/// https://tc39.es/proposal-array-grouping/#sec-map.groupby
/// </summary>
private JsValue GroupBy(JsValue thisObject, JsValue[] arguments)
{
var items = arguments.At(0);
var callbackfn = arguments.At(1);
var grouping = GroupByHelper.GroupBy(_engine, _realm, items, callbackfn, mapMode: true);
var map = (MapInstance) Construct(_realm.Intrinsics.Map);
foreach (var pair in grouping)
{
map.MapSet(pair.Key, pair.Value);
}

return map;
}
}
69 changes: 44 additions & 25 deletions Jint/Native/Object/ObjectConstructor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,32 +26,33 @@ protected override void Initialize()
{
_prototype = _realm.Intrinsics.Function.PrototypeObject;

const PropertyFlag propertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
const PropertyFlag lengthFlags = PropertyFlag.Configurable;
var properties = new PropertyDictionary(15, checkExistingKeys: false)
const PropertyFlag PropertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
const PropertyFlag LengthFlags = PropertyFlag.Configurable;
var properties = new PropertyDictionary(16, checkExistingKeys: false)
{
["assign"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "assign", Assign, 2, lengthFlags), propertyFlags),
["entries"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "entries", Entries, 1, lengthFlags), propertyFlags),
["fromEntries"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "fromEntries", FromEntries, 1, lengthFlags), propertyFlags),
["getPrototypeOf"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getPrototypeOf", GetPrototypeOf, 1), propertyFlags),
["getOwnPropertyDescriptor"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getOwnPropertyDescriptor", GetOwnPropertyDescriptor, 2, lengthFlags), propertyFlags),
["getOwnPropertyDescriptors"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getOwnPropertyDescriptors", GetOwnPropertyDescriptors, 1, lengthFlags), propertyFlags),
["getOwnPropertyNames"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getOwnPropertyNames", GetOwnPropertyNames, 1), propertyFlags),
["getOwnPropertySymbols"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getOwnPropertySymbols", GetOwnPropertySymbols, 1, lengthFlags), propertyFlags),
["create"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "create", Create, 2), propertyFlags),
["defineProperty"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "defineProperty", DefineProperty, 3), propertyFlags),
["defineProperties"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "defineProperties", DefineProperties, 2), propertyFlags),
["is"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "is", Is, 2, lengthFlags), propertyFlags),
["seal"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "seal", Seal, 1, lengthFlags), propertyFlags),
["freeze"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "freeze", Freeze, 1), propertyFlags),
["preventExtensions"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "preventExtensions", PreventExtensions, 1), propertyFlags),
["isSealed"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "isSealed", IsSealed, 1), propertyFlags),
["isFrozen"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "isFrozen", IsFrozen, 1), propertyFlags),
["isExtensible"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "isExtensible", IsExtensible, 1), propertyFlags),
["keys"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "keys", Keys, 1, lengthFlags), propertyFlags),
["values"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "values", Values, 1, lengthFlags), propertyFlags),
["setPrototypeOf"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setPrototypeOf", SetPrototypeOf, 2, lengthFlags), propertyFlags),
["hasOwn"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "hasOwn", HasOwn, 2, lengthFlags), propertyFlags),
["assign"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "assign", Assign, 2, LengthFlags), PropertyFlags),
["entries"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "entries", Entries, 1, LengthFlags), PropertyFlags),
["fromEntries"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "fromEntries", FromEntries, 1, LengthFlags), PropertyFlags),
["getPrototypeOf"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getPrototypeOf", GetPrototypeOf, 1), PropertyFlags),
["getOwnPropertyDescriptor"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getOwnPropertyDescriptor", GetOwnPropertyDescriptor, 2, LengthFlags), PropertyFlags),
["getOwnPropertyDescriptors"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getOwnPropertyDescriptors", GetOwnPropertyDescriptors, 1, LengthFlags), PropertyFlags),
["getOwnPropertyNames"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getOwnPropertyNames", GetOwnPropertyNames, 1), PropertyFlags),
["getOwnPropertySymbols"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getOwnPropertySymbols", GetOwnPropertySymbols, 1, LengthFlags), PropertyFlags),
["groupBy"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "groupBy", GroupBy, 2, PropertyFlag.Configurable), PropertyFlags),
["create"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "create", Create, 2), PropertyFlags),
["defineProperty"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "defineProperty", DefineProperty, 3), PropertyFlags),
["defineProperties"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "defineProperties", DefineProperties, 2), PropertyFlags),
["is"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "is", Is, 2, LengthFlags), PropertyFlags),
["seal"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "seal", Seal, 1, LengthFlags), PropertyFlags),
["freeze"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "freeze", Freeze, 1), PropertyFlags),
["preventExtensions"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "preventExtensions", PreventExtensions, 1), PropertyFlags),
["isSealed"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "isSealed", IsSealed, 1), PropertyFlags),
["isFrozen"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "isFrozen", IsFrozen, 1), PropertyFlags),
["isExtensible"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "isExtensible", IsExtensible, 1), PropertyFlags),
["keys"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "keys", Keys, 1, LengthFlags), PropertyFlags),
["values"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "values", Values, 1, LengthFlags), PropertyFlags),
["setPrototypeOf"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setPrototypeOf", SetPrototypeOf, 2, LengthFlags), PropertyFlags),
["hasOwn"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "hasOwn", HasOwn, 2, LengthFlags), PropertyFlags),
};
SetProperties(properties);
}
Expand Down Expand Up @@ -525,6 +526,24 @@ private JsValue Values(JsValue thisObject, JsValue[] arguments)
return o.EnumerableOwnPropertyNames(EnumerableOwnPropertyNamesKind.Value);
}

/// <summary>
/// https://tc39.es/proposal-array-grouping/#sec-object.groupby
/// </summary>
private JsValue GroupBy(JsValue thisObject, JsValue[] arguments)
{
var items = arguments.At(0);
var callbackfn = arguments.At(1);
var grouping = GroupByHelper.GroupBy(_engine, _realm, items, callbackfn, mapMode: false);

var obj = OrdinaryObjectCreate(_engine, null);
foreach (var pair in grouping)
{
obj.FastSetProperty(pair.Key, new PropertyDescriptor(pair.Value, PropertyFlag.ConfigurableEnumerableWritable));
}

return obj;
}

private sealed class CreateDataPropertyOnObject : ICallable
{
internal static readonly CreateDataPropertyOnObject Instance = new();
Expand Down
11 changes: 1 addition & 10 deletions Jint/Native/Object/ObjectInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1173,16 +1173,7 @@ bool TryGetValue(ulong idx, out JsValue jsValue)
return false;
}

internal ICallable GetCallable(JsValue source)
{
if (source is ICallable callable)
{
return callable;
}

ExceptionHelper.ThrowTypeError(_engine.Realm, "Argument must be callable");
return null;
}
internal ICallable GetCallable(JsValue source) => source.GetCallable(_engine.Realm);

internal bool IsConcatSpreadable
{
Expand Down
2 changes: 2 additions & 0 deletions NuGet.config
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
<packageSources>
<clear />
<add key="NuGet" value="https://api.nuget.org/v3/index.json" />
<!--
<add key="Esprima" value="https://www.myget.org/F/esprimadotnet/api/v3/index.json" />
-->
</packageSources>
<disabledPackageSources />
</configuration>
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ Following features are supported in version 3.x.

#### ECMAScript Stage 3 (no version yet)

- ✔ Array.group and Array.groupToMap
- ✔ Array Grouping - `Object.groupBy` and `Map.groupBy`
- ✔ ShadowRealm

#### Other
Expand Down