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 AggregateError #1175

Merged
merged 1 commit into from
May 22, 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 @@ -7,7 +7,6 @@
"ExcludedFeatures": [
"__getter__",
"__setter__",
"AggregateError",
"async-functions",
"async-iteration",
"Atomics",
Expand Down
67 changes: 67 additions & 0 deletions Jint/Native/AggregateError/AggregateErrorConstructor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#nullable enable

using Jint.Native.Error;
using Jint.Native.Function;
using Jint.Native.Object;
using Jint.Native.TypedArray;
using Jint.Runtime;
using Jint.Runtime.Descriptors;

namespace Jint.Native.AggregateError;

/// <summary>
/// https://tc39.es/ecma262/#sec-aggregate-error-constructor
/// </summary>
internal sealed class AggregateErrorConstructor : FunctionInstance, IConstructor
{
private static readonly JsString _name = new("AggregateError");

internal AggregateErrorConstructor(
Engine engine,
Realm realm,
ErrorConstructor errorConstructor)
: base(engine, realm, _name)
{
_prototype = errorConstructor;
PrototypeObject = new AggregateErrorPrototype(engine, realm, this, errorConstructor.PrototypeObject);
_length = new PropertyDescriptor(JsNumber.PositiveTwo, PropertyFlag.Configurable);
_prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
}

private AggregateErrorPrototype PrototypeObject { get; }

protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
{
return Construct(arguments, this);
}

ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget) => Construct(arguments, newTarget);

/// <summary>
/// https://tc39.es/ecma262/#sec-nativeerror
/// </summary>
private ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
{
var errors = arguments.At(0);
var message = arguments.At(1);
var options = arguments.At(2);

var o = OrdinaryCreateFromConstructor(
newTarget,
static intrinsics => intrinsics.AggregateError.PrototypeObject,
static (Engine engine, Realm _, object? _) => new ErrorInstance(engine));

if (!message.IsUndefined())
{
var msg = TypeConverter.ToString(message);
o.CreateNonEnumerableDataPropertyOrThrow("message", msg);
}

o.InstallErrorCause(options);

var errorsList = TypedArrayConstructor.IterableToList(_realm, errors);
o.DefinePropertyOrThrow("errors", new PropertyDescriptor(_realm.Intrinsics.Array.CreateArrayFromList(errorsList), configurable: true, enumerable: false, writable: true));

return o;
}
}
38 changes: 38 additions & 0 deletions Jint/Native/AggregateError/AggregateErrorPrototype.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#nullable enable

using Jint.Collections;
using Jint.Native.Object;
using Jint.Runtime;
using Jint.Runtime.Descriptors;

namespace Jint.Native.AggregateError;

/// <summary>
/// https://tc39.es/ecma262/#sec-properties-of-the-aggregate-error-prototype-objects
/// </summary>
internal sealed class AggregateErrorPrototype : Prototype
{
private readonly AggregateErrorConstructor _constructor;

internal AggregateErrorPrototype(
Engine engine,
Realm realm,
AggregateErrorConstructor constructor,
ObjectInstance prototype)
: base(engine, realm)
{
_constructor = constructor;
_prototype = prototype;
}

protected override void Initialize()
{
var properties = new PropertyDictionary(3, checkExistingKeys: false)
{
["constructor"] = new PropertyDescriptor(_constructor, PropertyFlag.NonEnumerable),
["message"] = new PropertyDescriptor(JsString.Empty, PropertyFlag.Configurable | PropertyFlag.Writable),
["name"] = new PropertyDescriptor("AggregateError", PropertyFlag.Configurable | PropertyFlag.Writable),
};
SetProperties(properties);
}
}
9 changes: 2 additions & 7 deletions Jint/Native/Error/ErrorConstructor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public sealed class ErrorConstructor : FunctionInstance, IConstructor
{
_intrinsicDefaultProto = intrinsicDefaultProto;
_prototype = functionPrototype;
PrototypeObject = new ErrorPrototype(engine, realm, this, objectPrototype, name, ObjectClass.Object);
PrototypeObject = new ErrorPrototype(engine, realm, this, objectPrototype, name);
_length = new PropertyDescriptor(JsNumber.PositiveOne, PropertyFlag.Configurable);
_prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
}
Expand Down Expand Up @@ -64,12 +64,7 @@ private ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)

var options = arguments.At(1);

if (options is ObjectInstance oi && oi.HasProperty("cause"))
{
var cause = oi.Get("cause");
var causeDesc = new PropertyDescriptor(cause, PropertyFlag.NonEnumerable);
o.DefinePropertyOrThrow("cause", causeDesc);
}
o.InstallErrorCause(options);

return o;
}
Expand Down
33 changes: 22 additions & 11 deletions Jint/Native/Error/ErrorInstance.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
using Jint.Native.Object;
#nullable enable

using Jint.Native.Object;
using Jint.Runtime;

namespace Jint.Native.Error
namespace Jint.Native.Error;

public class ErrorInstance : ObjectInstance
{
public class ErrorInstance : ObjectInstance
internal ErrorInstance(Engine engine, ObjectClass objectClass = ObjectClass.Error)
: base(engine, objectClass)
{
internal ErrorInstance(
Engine engine,
ObjectClass objectClass = ObjectClass.Error)
: base(engine, objectClass)
{
}
}

public override string ToString()
/// <summary>
/// https://tc39.es/ecma262/#sec-installerrorcause
/// </summary>
internal void InstallErrorCause(JsValue options)
{
if (options is ObjectInstance oi && oi.HasProperty("cause"))
{
return Engine.Realm.Intrinsics.Error.PrototypeObject.ToString(this, Arguments.Empty).ToObject().ToString();
var cause = oi.Get("cause");
CreateNonEnumerableDataPropertyOrThrow("cause", cause);
}
}

public override string ToString()
{
return Engine.Realm.Intrinsics.Error.PrototypeObject.ToString(this, Arguments.Empty).ToObject().ToString();
}
}
5 changes: 2 additions & 3 deletions Jint/Native/Error/ErrorPrototype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@ public sealed class ErrorPrototype : ErrorInstance
Realm realm,
ErrorConstructor constructor,
ObjectInstance prototype,
JsString name,
ObjectClass objectClass)
: base(engine, objectClass)
JsString name)
: base(engine, ObjectClass.Object)
{
_realm = realm;
_name = name;
Expand Down
2 changes: 1 addition & 1 deletion Jint/Native/Global/GlobalObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ protected override void Initialize()

var properties = new PropertyDictionary(55, checkExistingKeys: false)
{
["AggregateError"] = new LazyPropertyDescriptor(this, static state => Undefined, propertyFlags),
["AggregateError"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state)._realm.Intrinsics.AggregateError, propertyFlags),
["Array"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state)._realm.Intrinsics.Array, propertyFlags),
["ArrayBuffer"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state)._realm.Intrinsics.ArrayBuffer, propertyFlags),
["Atomics"] = new LazyPropertyDescriptor(this, static state => Undefined, propertyFlags),
Expand Down
9 changes: 9 additions & 0 deletions Jint/Native/Object/ObjectInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1234,6 +1234,15 @@ internal bool CreateDataPropertyOrThrow(JsValue p, JsValue v)
return true;
}

/// <summary>
/// https://tc39.es/ecma262/#sec-createnonenumerabledatapropertyorthrow
/// </summary>
internal void CreateNonEnumerableDataPropertyOrThrow(JsValue p, JsValue v)
{
var newDesc = new PropertyDescriptor(v, true, false, true);
DefinePropertyOrThrow(p, newDesc);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ICallable GetMethod(JsValue property)
{
Expand Down
2 changes: 1 addition & 1 deletion Jint/Native/TypedArray/TypedArrayConstructor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ internal ObjectInstance Construct(JsValue[] args, JsValue newTarget)
/// <summary>
/// https://tc39.es/ecma262/#sec-iterabletolist
/// </summary>
internal static List<JsValue> IterableToList(Realm realm, JsValue items, ICallable usingIterator)
internal static List<JsValue> IterableToList(Realm realm, JsValue items, ICallable method = null)
{
var iteratorRecord = items.GetIterator(realm);
var values = new List<JsValue>();
Expand Down
5 changes: 5 additions & 0 deletions Jint/Runtime/Intrinsics.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Jint.Native;
using Jint.Native.AggregateError;
using Jint.Native.Array;
using Jint.Native.ArrayBuffer;
using Jint.Native.BigInt;
Expand Down Expand Up @@ -42,6 +43,7 @@ public sealed class Intrinsics

// lazy properties
private ThrowTypeError _throwTypeError;
private AggregateErrorConstructor _aggregateError;
private ErrorConstructor _error;
private ErrorConstructor _evalError;
private ErrorConstructor _rangeError;
Expand Down Expand Up @@ -113,6 +115,9 @@ internal Intrinsics(Engine engine, Realm realm)
public ArrayConstructor Array =>
_array ??= new ArrayConstructor(_engine, _realm, Function.PrototypeObject, Object.PrototypeObject);

internal AggregateErrorConstructor AggregateError =>
_aggregateError ??= new AggregateErrorConstructor(_engine, _realm, Error);

internal ArrayIteratorPrototype ArrayIteratorPrototype =>
_arrayIteratorPrototype ??= new ArrayIteratorPrototype(_engine, _realm, this.IteratorPrototype);

Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ The entire execution engine was rebuild with performance in mind, in many cases

- ✔ Logical Assignment Operators (`&&=` `||=` `??=`)
- ✔ Numeric Separators (`1_000`)
- ❌ `Promise.any` and `AggregateError`
- ✔ `AggregateError`
- ❌ `Promise.any`
- ✔ `String.prototype.replaceAll`
- ❌ `WeakRef` and `FinalizationRegistry`

Expand Down