using Jint.Native.Object; using Jint.Runtime; using Jint.Runtime.Descriptors; namespace Jint.Native.Error; public sealed class ErrorConstructor : Constructor { private readonly Func _intrinsicDefaultProto; internal ErrorConstructor( Engine engine, Realm realm, ObjectInstance functionPrototype, ObjectInstance objectPrototype, JsString name, Func intrinsicDefaultProto) : base(engine, realm, name) { _intrinsicDefaultProto = intrinsicDefaultProto; _prototype = functionPrototype; PrototypeObject = new ErrorPrototype(engine, realm, this, objectPrototype, name); _length = new PropertyDescriptor(JsNumber.PositiveOne, PropertyFlag.Configurable); _prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden); } internal ErrorPrototype PrototypeObject { get; } protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments) { return Construct(arguments, this); } public ObjectInstance Construct(string? message = null) { return Construct(message != null ? new JsValue[]{ message } : System.Array.Empty(), this); } /// /// https://tc39.es/ecma262/#sec-nativeerror /// public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget) { var o = OrdinaryCreateFromConstructor( newTarget, _intrinsicDefaultProto, static (Engine engine, Realm _, object? _) => new JsError(engine)); var jsValue = arguments.At(0); if (!jsValue.IsUndefined()) { var msg = TypeConverter.ToJsString(jsValue); o.CreateNonEnumerableDataPropertyOrThrow(CommonProperties.Message, msg); } var stackString = BuildStackString(); if (stackString is not null) { var stackDesc = new PropertyDescriptor(stackString, PropertyFlag.NonEnumerable); o.DefinePropertyOrThrow(CommonProperties.Stack, stackDesc); } var options = arguments.At(1); if (!options.IsUndefined()) { o.InstallErrorCause(options); } return o; JsValue? BuildStackString() { var lastSyntaxNode = _engine.GetLastSyntaxElement(); if (lastSyntaxNode == null) { return null; } var callStack = _engine.CallStack; var currentFunction = callStack.TryPeek(out var element) ? element.Function : null; // If the current function is the ErrorConstructor itself (i.e. "throw new Error(...)" was called // from script), exclude it from the stack trace, because the trace should begin at the throw point. return callStack.BuildCallStackString(lastSyntaxNode.Location, currentFunction == this ? 1 : 0); } } }