Skip to content

Commit

Permalink
Implement Promise.withResolvers and update test suite (#1650)
Browse files Browse the repository at this point in the history
  • Loading branch information
lahma authored Oct 21, 2023
1 parent f4e0ce3 commit 1a6aa38
Show file tree
Hide file tree
Showing 8 changed files with 36 additions and 55 deletions.
1 change: 0 additions & 1 deletion Jint.Tests.PublicInterface/ShadowRealmTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using Jint.Native;
using Jint.Native.Object;

namespace Jint.Tests.PublicInterface;
Expand Down
3 changes: 2 additions & 1 deletion Jint.Tests.Test262/Test262Harness.settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"SuiteGitSha": "9437cab774ab2f22c5cb971b11b8512eca705721",
"SuiteGitSha": "6396ebde0316639292530460d1ef961fd9bbe0d4",
//"SuiteDirectory": "//mnt/c/work/test262",
"TargetPath": "./Generated",
"Namespace": "Jint.Tests.Test262",
Expand Down Expand Up @@ -46,6 +46,7 @@
// RegExp handling problems
"built-ins/RegExp/prototype/exec/S15.10.6.2_A1_T6.js",
"language/literals/regexp/u-case-mapping.js",
"built-ins/RegExp/lookahead-quantifier-match-groups.js",

// requires investigation how to process complex function name evaluation for property
"built-ins/Function/prototype/toString/method-computed-property-name.js",
Expand Down
31 changes: 21 additions & 10 deletions Jint/Native/Promise/PromiseConstructor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ internal sealed class PromiseConstructor : Constructor
{
private static readonly JsString _functionName = new JsString("Promise");

internal PromisePrototype PrototypeObject { get; private set; }

internal PromiseConstructor(
Engine engine,
Realm realm,
Expand All @@ -36,18 +34,21 @@ internal PromiseConstructor(
_prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
}

internal PromisePrototype PrototypeObject { get; }

protected override void Initialize()
{
const PropertyFlag propertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
const PropertyFlag lengthFlags = PropertyFlag.Configurable;
const PropertyFlag PropertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
const PropertyFlag LengthFlags = PropertyFlag.Configurable;
var properties = new PropertyDictionary(6, checkExistingKeys: false)
{
["resolve"] = new(new PropertyDescriptor(new ClrFunctionInstance(Engine, "resolve", Resolve, 1, lengthFlags), propertyFlags)),
["reject"] = new(new PropertyDescriptor(new ClrFunctionInstance(Engine, "reject", Reject, 1, lengthFlags), propertyFlags)),
["all"] = new(new PropertyDescriptor(new ClrFunctionInstance(Engine, "all", All, 1, lengthFlags), propertyFlags)),
["allSettled"] = new(new PropertyDescriptor(new ClrFunctionInstance(Engine, "allSettled", AllSettled, 1, lengthFlags), propertyFlags)),
["any"] = new(new PropertyDescriptor(new ClrFunctionInstance(Engine, "any", Any, 1, lengthFlags), propertyFlags)),
["race"] = new(new PropertyDescriptor(new ClrFunctionInstance(Engine, "race", Race, 1, lengthFlags), propertyFlags)),
["all"] = new(new PropertyDescriptor(new ClrFunctionInstance(Engine, "all", All, 1, LengthFlags), PropertyFlags)),
["allSettled"] = new(new PropertyDescriptor(new ClrFunctionInstance(Engine, "allSettled", AllSettled, 1, LengthFlags), PropertyFlags)),
["any"] = new(new PropertyDescriptor(new ClrFunctionInstance(Engine, "any", Any, 1, LengthFlags), PropertyFlags)),
["race"] = new(new PropertyDescriptor(new ClrFunctionInstance(Engine, "race", Race, 1, LengthFlags), PropertyFlags)),
["reject"] = new(new PropertyDescriptor(new ClrFunctionInstance(Engine, "reject", Reject, 1, LengthFlags), PropertyFlags)),
["resolve"] = new(new PropertyDescriptor(new ClrFunctionInstance(Engine, "resolve", Resolve, 1, LengthFlags), PropertyFlags)),
["withResolvers"] = new(new PropertyDescriptor(new ClrFunctionInstance(Engine, "withResolvers", WithResolvers , 0, LengthFlags), PropertyFlags)),
};
SetProperties(properties);

Expand Down Expand Up @@ -113,6 +114,16 @@ internal JsValue Resolve(JsValue thisObject, JsValue[] arguments)
return PromiseResolve(thisObject, x);
}

private JsValue WithResolvers(JsValue thisObject, JsValue[] arguments)
{
var promiseCapability = NewPromiseCapability(_engine, thisObject);
var obj = OrdinaryObjectCreate(_engine, _engine.Realm.Intrinsics.Object.PrototypeObject);
obj.CreateDataPropertyOrThrow("promise", promiseCapability.PromiseInstance);
obj.CreateDataPropertyOrThrow("resolve", promiseCapability.ResolveObj);
obj.CreateDataPropertyOrThrow("reject", promiseCapability.RejectObj);
return obj;
}

/// <summary>
/// https://tc39.es/ecma262/#sec-promise-resolve
/// </summary>
Expand Down
1 change: 0 additions & 1 deletion Jint/Native/Proxy/JsProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using Jint.Native.Object;
using Jint.Runtime;
using Jint.Runtime.Descriptors;
using Jint.Runtime.Interop;

namespace Jint.Native.Proxy
{
Expand Down
2 changes: 2 additions & 0 deletions Jint/Native/RegExp/JsRegExp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ public string Flags
public bool FullUnicode { get; private set; }
public bool UnicodeSets { get; private set; }

internal bool HasDefaultRegExpExec => Properties == null && Prototype is RegExpPrototype { HasDefaultExec: true };

public override PropertyDescriptor GetOwnProperty(JsValue property)
{
if (property == PropertyLastIndex)
Expand Down
25 changes: 2 additions & 23 deletions Jint/Native/RegExp/RegExpExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,26 +1,5 @@
using System.Diagnostics.CodeAnalysis;
using Jint.Native.Object;
namespace Jint.Native.RegExp;

namespace Jint.Native.RegExp
internal static class RegExpExtensions
{
internal static class RegExpExtensions
{
internal static bool TryGetDefaultRegExpExec(this ObjectInstance? o, [NotNullWhen(true)] out Func<JsValue, JsValue[], JsValue>? exec)
{
if (o is RegExpPrototype prototype)
{
return prototype.TryGetDefaultExec(prototype, out exec);
}

if (o is JsRegExp instance)
{
exec = default;
return instance.Properties == null
&& TryGetDefaultRegExpExec(instance.Prototype, out exec);
}

exec = default;
return false;
}
}
}
27 changes: 8 additions & 19 deletions Jint/Native/RegExp/RegExpPrototype.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using System.Text.RegularExpressions;
using System.Text.RegularExpressions;
using Jint.Collections;
using Jint.Native.Number;
using Jint.Native.Object;
Expand Down Expand Up @@ -158,7 +157,7 @@ private JsValue Replace(JsValue thisObject, JsValue[] arguments)
if (!fullUnicode
&& !mayHaveNamedCaptures
&& !TypeConverter.ToBoolean(rx.Get(PropertySticky))
&& rx is JsRegExp rei && rei.TryGetDefaultRegExpExec(out _))
&& rx is JsRegExp rei && rei.HasDefaultRegExpExec)
{
var count = global ? int.MaxValue : 1;

Expand Down Expand Up @@ -464,7 +463,7 @@ private JsValue Split(JsValue thisObject, JsValue[] arguments)
return a;
}

if (!unicodeMatching && rx is JsRegExp R && R.TryGetDefaultRegExpExec(out _))
if (!unicodeMatching && rx is JsRegExp R && R.HasDefaultRegExpExec)
{
// we can take faster path

Expand Down Expand Up @@ -690,7 +689,7 @@ private JsValue Match(JsValue thisObject, JsValue[] arguments)

if (!fullUnicode
&& rx is JsRegExp rei
&& rei.TryGetDefaultRegExpExec(out _))
&& rei.HasDefaultRegExpExec)
{
// fast path
var a = _realm.Intrinsics.Array.ArrayCreate(0);
Expand Down Expand Up @@ -812,8 +811,9 @@ private static ulong AdvanceStringIndex(string s, ulong index, bool unicode)

internal static JsValue RegExpExec(ObjectInstance r, string s)
{
var exec = r.Get(PropertyExec);
if (exec is ICallable callable)
var ri = r as JsRegExp;

if ((ri is null || !ri.HasDefaultRegExpExec) && r.Get(PropertyExec) is ICallable callable)
{
var result = callable.Call(r, new JsValue[] { s });
if (!result.IsNull() && !result.IsObject())
Expand All @@ -824,7 +824,6 @@ internal static JsValue RegExpExec(ObjectInstance r, string s)
return result;
}

var ri = r as JsRegExp;
if (ri is null)
{
ExceptionHelper.ThrowTypeError(r.Engine.Realm);
Expand All @@ -833,17 +832,7 @@ internal static JsValue RegExpExec(ObjectInstance r, string s)
return RegExpBuiltinExec(ri, s);
}

internal bool TryGetDefaultExec(ObjectInstance o, [NotNullWhen((true))] out Func<JsValue, JsValue[], JsValue>? exec)
{
if (o.Get(PropertyExec) is ClrFunctionInstance functionInstance && functionInstance._func == _defaultExec)
{
exec = _defaultExec;
return true;
}

exec = default;
return false;
}
internal bool HasDefaultExec => Get(PropertyExec) is ClrFunctionInstance functionInstance && functionInstance._func == _defaultExec;

/// <summary>
/// https://tc39.es/ecma262/#sec-regexpbuiltinexec
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ Following features are supported in version 3.x.
#### ECMAScript Stage 3 (no version yet)

- ✔ Array Grouping - `Object.groupBy` and `Map.groupBy`
- ✔ Promise.withResolvers
- ✔ ShadowRealm

#### Other
Expand Down

0 comments on commit 1a6aa38

Please sign in to comment.