Skip to content
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
3 changes: 1 addition & 2 deletions Jint.Tests.Test262/Test262Harness.settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@
"source-phase-imports",
"tail-call-optimization",
"Temporal",
"u180e",
"upsert"
"u180e"
],
"ExcludedFlags": [
],
Expand Down
27 changes: 26 additions & 1 deletion Jint/JsValueExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ public static bool IsUndefined(this JsValue value)
return value._type == InternalTypes.Undefined;
}


[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsArray(this JsValue value)
Expand Down Expand Up @@ -738,4 +737,30 @@ internal static ICallable GetCallable(this JsValue source, Realm realm)

return TypeConverter.ToIndex(oi.Engine.Realm, maxByteLength);
}

/// <summary>
/// https://tc39.es/ecma262/#sec-canonicalize-keyed-collection-key
/// </summary>
internal static JsValue CanonicalizeKeyedCollectionKey(this JsValue key)
{
return key is JsNumber number && number.IsNegativeZero() ? JsNumber.PositiveZero : key;
}

/// <summary>
/// https://tc39.es/ecma262/#sec-canbeheldweakly
/// </summary>
internal static bool CanBeHeldWeakly(this JsValue v, Engine engine)
{
if (v.IsObject())
{
return true;
}

if (v is JsSymbol symbol && engine.GlobalSymbolRegistry.KeyForSymbol(symbol).IsUndefined())
{
return true;
}

return false;
}
}
24 changes: 24 additions & 0 deletions Jint/Native/JsMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,30 @@ protected override bool TryGetProperty(JsValue property, [NotNullWhen(true)] out
return value;
}

internal JsValue GetOrInsert(JsValue key, JsValue value)
{
if (_map.TryGetValue(key, out var temp))
{
return temp;
}

_map[key] = value;
return value;
}

internal JsValue GetOrInsertComputed(JsValue key, ICallable callbackfn)
{
if (_map.TryGetValue(key, out var temp))
{
return temp;
}

var value = callbackfn.Call(Undefined, key);

_map[key] = value;
return value;
}

public new void Set(JsValue key, JsValue value)
{
if (key is JsNumber number && number.IsNegativeZero())
Expand Down
23 changes: 23 additions & 0 deletions Jint/Native/JsWeakMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,27 @@ internal JsValue WeakMapGet(JsValue key)
return value;
}

internal JsValue GetOrInsert(JsValue key, JsValue value)
{
if (_table.TryGetValue(key, out var temp))
{
return temp;
}

_table.Add(key, value);
return value;
}

internal JsValue GetOrInsertComputed(JsValue key, ICallable callbackfn)
{
if (_table.TryGetValue(key, out var temp))
{
return temp;
}

var value = callbackfn.Call(Undefined, key);

_table.Add(key, value);
return value;
}
}
42 changes: 30 additions & 12 deletions Jint/Native/Map/MapPrototype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,29 @@ internal MapPrototype(

protected override void Initialize()
{
const PropertyFlag propertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
var properties = new PropertyDictionary(12, checkExistingKeys: false)
const PropertyFlag PropertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
var properties = new PropertyDictionary(14, checkExistingKeys: false)
{
["length"] = new PropertyDescriptor(0, PropertyFlag.Configurable),
["constructor"] = new PropertyDescriptor(_mapConstructor, PropertyFlag.NonEnumerable),
["clear"] = new PropertyDescriptor(new ClrFunction(Engine, "clear", Clear, 0, PropertyFlag.Configurable), propertyFlags),
["delete"] = new PropertyDescriptor(new ClrFunction(Engine, "delete", Delete, 1, PropertyFlag.Configurable), propertyFlags),
["entries"] = new PropertyDescriptor(new ClrFunction(Engine, "entries", Entries, 0, PropertyFlag.Configurable), propertyFlags),
["forEach"] = new PropertyDescriptor(new ClrFunction(Engine, "forEach", ForEach, 1, PropertyFlag.Configurable), propertyFlags),
["get"] = new PropertyDescriptor(new ClrFunction(Engine, "get", Get, 1, PropertyFlag.Configurable), propertyFlags),
["has"] = new PropertyDescriptor(new ClrFunction(Engine, "has", Has, 1, PropertyFlag.Configurable), propertyFlags),
["keys"] = new PropertyDescriptor(new ClrFunction(Engine, "keys", Keys, 0, PropertyFlag.Configurable), propertyFlags),
["set"] = new PropertyDescriptor(new ClrFunction(Engine, "set", Set, 2, PropertyFlag.Configurable), propertyFlags),
["values"] = new PropertyDescriptor(new ClrFunction(Engine, "values", Values, 0, PropertyFlag.Configurable), propertyFlags),
["clear"] = new PropertyDescriptor(new ClrFunction(Engine, "clear", Clear, 0, PropertyFlag.Configurable), PropertyFlags),
["delete"] = new PropertyDescriptor(new ClrFunction(Engine, "delete", Delete, 1, PropertyFlag.Configurable), PropertyFlags),
["entries"] = new PropertyDescriptor(new ClrFunction(Engine, "entries", Entries, 0, PropertyFlag.Configurable), PropertyFlags),
["forEach"] = new PropertyDescriptor(new ClrFunction(Engine, "forEach", ForEach, 1, PropertyFlag.Configurable), PropertyFlags),
["get"] = new PropertyDescriptor(new ClrFunction(Engine, "get", Get, 1, PropertyFlag.Configurable), PropertyFlags),
["getOrInsert"] = new PropertyDescriptor(new ClrFunction(Engine, "getOrInsert", GetOrInsert, 2, PropertyFlag.Configurable), PropertyFlags),
["getOrInsertComputed"] = new PropertyDescriptor(new ClrFunction(Engine, "getOrInsertComputed", GetOrInsertComputed, 2, PropertyFlag.Configurable), PropertyFlags),
["has"] = new PropertyDescriptor(new ClrFunction(Engine, "has", Has, 1, PropertyFlag.Configurable), PropertyFlags),
["keys"] = new PropertyDescriptor(new ClrFunction(Engine, "keys", Keys, 0, PropertyFlag.Configurable), PropertyFlags),
["set"] = new PropertyDescriptor(new ClrFunction(Engine, "set", Set, 2, PropertyFlag.Configurable), PropertyFlags),
["values"] = new PropertyDescriptor(new ClrFunction(Engine, "values", Values, 0, PropertyFlag.Configurable), PropertyFlags),
["size"] = new GetSetPropertyDescriptor(get: new ClrFunction(Engine, "get size", Size, 0, PropertyFlag.Configurable), set: null, PropertyFlag.Configurable)
};
SetProperties(properties);

var symbols = new SymbolDictionary(2)
{
[GlobalSymbolRegistry.Iterator] = new PropertyDescriptor(new ClrFunction(Engine, "iterator", Entries, 1, PropertyFlag.Configurable), propertyFlags),
[GlobalSymbolRegistry.Iterator] = new PropertyDescriptor(new ClrFunction(Engine, "iterator", Entries, 1, PropertyFlag.Configurable), PropertyFlags),
[GlobalSymbolRegistry.ToStringTag] = new PropertyDescriptor("Map", false, false, true),
};
SetSymbols(symbols);
Expand All @@ -65,6 +67,22 @@ private JsValue Get(JsValue thisObject, JsCallArguments arguments)
return map.Get(arguments.At(0));
}

private JsValue GetOrInsert(JsValue thisObject, JsCallArguments arguments)
{
var map = AssertMapInstance(thisObject);
var key = arguments.At(0).CanonicalizeKeyedCollectionKey();
var value = arguments.At(1);
return map.GetOrInsert(key, value);
}

private JsValue GetOrInsertComputed(JsValue thisObject, JsCallArguments arguments)
{
var map = AssertMapInstance(thisObject);
var key = arguments.At(0).CanonicalizeKeyedCollectionKey();
var callbackfn = arguments.At(1).GetCallable(_realm);
return map.GetOrInsertComputed(key, callbackfn);
}

private JsValue Clear(JsValue thisObject, JsCallArguments arguments)
{
var map = AssertMapInstance(thisObject);
Expand Down
18 changes: 18 additions & 0 deletions Jint/Native/Symbol/GlobalSymbolRegistry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,22 @@ internal bool ContainsCustom(JsValue value)
{
return value is JsSymbol symbol && _customSymbolLookup?.ContainsKey(symbol._value) == true;
}

internal JsValue KeyForSymbol(JsSymbol symbol)
{
if (_customSymbolLookup == null)
{
return JsValue.Undefined;
}

foreach (var pair in _customSymbolLookup)
{
if (pair.Value == symbol)
{
return pair.Key;
}
}

return JsValue.Undefined;
}
}
40 changes: 34 additions & 6 deletions Jint/Native/WeakMap/WeakMapPrototype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,17 @@ internal WeakMapPrototype(

protected override void Initialize()
{
const PropertyFlag propertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
var properties = new PropertyDictionary(6, checkExistingKeys: false)
const PropertyFlag PropertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
var properties = new PropertyDictionary(8, checkExistingKeys: false)
{
["length"] = new PropertyDescriptor(0, PropertyFlag.Configurable),
["constructor"] = new PropertyDescriptor(_constructor, PropertyFlag.NonEnumerable),
["delete"] = new PropertyDescriptor(new ClrFunction(Engine, "delete", Delete, 1, PropertyFlag.Configurable), propertyFlags),
["get"] = new PropertyDescriptor(new ClrFunction(Engine, "get", Get, 1, PropertyFlag.Configurable), propertyFlags),
["has"] = new PropertyDescriptor(new ClrFunction(Engine, "has", Has, 1, PropertyFlag.Configurable), propertyFlags),
["set"] = new PropertyDescriptor(new ClrFunction(Engine, "set", Set, 2, PropertyFlag.Configurable), propertyFlags),
["delete"] = new PropertyDescriptor(new ClrFunction(Engine, "delete", Delete, 1, PropertyFlag.Configurable), PropertyFlags),
["get"] = new PropertyDescriptor(new ClrFunction(Engine, "get", Get, 1, PropertyFlag.Configurable), PropertyFlags),
["getOrInsert"] = new PropertyDescriptor(new ClrFunction(Engine, "getOrInsert", GetOrInsert, 2, PropertyFlag.Configurable), PropertyFlags),
["getOrInsertComputed"] = new PropertyDescriptor(new ClrFunction(Engine, "getOrInsertComputed", GetOrInsertComputed, 2, PropertyFlag.Configurable), PropertyFlags),
["has"] = new PropertyDescriptor(new ClrFunction(Engine, "has", Has, 1, PropertyFlag.Configurable), PropertyFlags),
["set"] = new PropertyDescriptor(new ClrFunction(Engine, "set", Set, 2, PropertyFlag.Configurable), PropertyFlags),
};
SetProperties(properties);

Expand All @@ -52,6 +54,32 @@ private JsValue Get(JsValue thisObject, JsCallArguments arguments)
return map.WeakMapGet(arguments.At(0));
}

private JsValue GetOrInsert(JsValue thisObject, JsCallArguments arguments)
{
var map = AssertWeakMapInstance(thisObject);
var key = AssertCanBeHeldWeakly(arguments.At(0));
var value = arguments.At(1);
return map.GetOrInsert(key, value);
}

private JsValue GetOrInsertComputed(JsValue thisObject, JsCallArguments arguments)
{
var map = AssertWeakMapInstance(thisObject);
var key = AssertCanBeHeldWeakly(arguments.At(0));
var callbackfn = arguments.At(1).GetCallable(_realm);
return map.GetOrInsertComputed(key, callbackfn);
}

private JsValue AssertCanBeHeldWeakly(JsValue key)
{
if (!key.CanBeHeldWeakly(_engine))
{
ExceptionHelper.ThrowTypeError(_realm);
}

return key;
}

private JsValue Delete(JsValue thisObject, JsCallArguments arguments)
{
var map = AssertWeakMapInstance(thisObject);
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,13 @@ and many more.
- ❌ Duplicate named capture groups
- ✔ Set methods (`intersection`, `union`, `difference`, `symmetricDifference`, `isSubsetOf`, `isSupersetOf`, `isDisjointFrom`)

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

- ✔ `Error.isError`
- ✔ `Math.sumPrecise`
- ✔ `ShadowRealm`
- ✔ `Uint8Array` to/from base64
- ✔ `Upsert`

#### Other

Expand Down