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

Implement Array.group and Array.groupToMap #1306

Merged
merged 1 commit into from
Sep 26, 2022
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.
Jump to
Jump to file
Failed to load files.
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 @@ -5,7 +5,6 @@
"Namespace": "Jint.Tests.Test262",
"Parallel": true,
"ExcludedFeatures": [
"array-grouping",
"async-functions",
"async-iteration",
"Atomics",
Expand Down
80 changes: 79 additions & 1 deletion Jint/Native/Array/ArrayPrototype.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
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 @@ -35,7 +36,7 @@ public sealed class ArrayPrototype : ArrayInstance
protected override void Initialize()
{
const PropertyFlag propertyFlags = PropertyFlag.Writable | PropertyFlag.Configurable;
var properties = new PropertyDictionary(34, checkExistingKeys: false)
var properties = new PropertyDictionary(36, checkExistingKeys: false)
{
["constructor"] = new PropertyDescriptor(_constructor, PropertyFlag.NonEnumerable),
["toString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toString", ToString, 0, PropertyFlag.Configurable), propertyFlags),
Expand Down Expand Up @@ -72,6 +73,8 @@ 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),
["at"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "at", At, 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),
};
SetProperties(properties);

Expand Down Expand Up @@ -101,6 +104,8 @@ protected override void Initialize()
unscopables.SetDataProperty("includes", JsBoolean.True);
unscopables.SetDataProperty("keys", JsBoolean.True);
unscopables.SetDataProperty("values", JsBoolean.True);
unscopables.SetDataProperty("group", JsBoolean.True);
unscopables.SetDataProperty("groupToMap", JsBoolean.True);

return unscopables;
}, PropertyFlag.Configurable)
Expand Down Expand Up @@ -1462,6 +1467,79 @@ 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(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, ArrayInstance> 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, ArrayInstance>();
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 ArrayInstance(_engine)
{
_length = new PropertyDescriptor(JsNumber.PositiveZero, PropertyFlag.OnlyWritable)
};
}

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

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

internal sealed class ArrayComparer : IComparer<JsValue>
{
/// <summary>
Expand Down
12 changes: 0 additions & 12 deletions Jint/Native/Function/FunctionInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -273,18 +273,6 @@ internal void MakeMethod(ObjectInstance homeObject)
_homeObject = homeObject;
}

/// <summary>
/// https://tc39.es/ecma262/#sec-ordinaryobjectcreate
/// </summary>
internal ObjectInstance OrdinaryObjectCreate(ObjectInstance proto)
{
var prototype = new ObjectInstance(_engine)
{
_prototype = proto
};
return prototype;
}

/// <summary>
/// https://tc39.es/ecma262/#sec-ordinarycallbindthis
/// </summary>
Expand Down
4 changes: 2 additions & 2 deletions Jint/Native/Map/MapConstructor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Jint.Native.Map
{
public sealed class MapConstructor : FunctionInstance, IConstructor
{
private static readonly JsString _functionName = new JsString("Map");
private static readonly JsString _functionName = new("Map");

internal MapConstructor(
Engine engine,
Expand All @@ -26,7 +26,7 @@ public sealed class MapConstructor : FunctionInstance, IConstructor
_prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
}

public MapPrototype PrototypeObject { get; private set; }
public MapPrototype PrototypeObject { get; }

protected override void Initialize()
{
Expand Down
12 changes: 12 additions & 0 deletions Jint/Native/Object/ObjectInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1240,6 +1240,18 @@ internal void CreateNonEnumerableDataPropertyOrThrow(JsValue p, JsValue v)
DefinePropertyOrThrow(p, newDesc);
}

/// <summary>
/// https://tc39.es/ecma262/#sec-ordinaryobjectcreate
/// </summary>
internal ObjectInstance OrdinaryObjectCreate(ObjectInstance? proto)
{
var prototype = new ObjectInstance(_engine)
{
_prototype = proto
};
return prototype;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ICallable? GetMethod(JsValue property)
{
Expand Down
4 changes: 2 additions & 2 deletions Jint/Native/Set/SetConstructor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Jint.Native.Set
{
public sealed class SetConstructor : FunctionInstance, IConstructor
{
private static readonly JsString _functionName = new JsString("Set");
private static readonly JsString _functionName = new("Set");

internal SetConstructor(
Engine engine,
Expand All @@ -25,7 +25,7 @@ public sealed class SetConstructor : FunctionInstance, IConstructor
_prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
}

public SetPrototype PrototypeObject { get; private set; }
public SetPrototype PrototypeObject { get; }

protected override void Initialize()
{
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ The entire execution engine was rebuild with performance in mind, in many cases
#### ECMAScript Stage 3 (no version yet)

- ✔ Array find from last
- ✔ Array.group and Array.groupToMap
- ✔ ShadowRealm

#### Other
Expand Down