|
@@ -1,156 +1,133 @@
|
|
-using System;
|
|
|
|
|
|
+#nullable enable
|
|
|
|
+
|
|
|
|
+using System;
|
|
using Esprima;
|
|
using Esprima;
|
|
-using Esprima.Ast;
|
|
|
|
using Jint.Native;
|
|
using Jint.Native;
|
|
using Jint.Native.Error;
|
|
using Jint.Native.Error;
|
|
|
|
+using Jint.Native.Object;
|
|
using Jint.Pooling;
|
|
using Jint.Pooling;
|
|
|
|
|
|
namespace Jint.Runtime
|
|
namespace Jint.Runtime
|
|
{
|
|
{
|
|
public class JavaScriptException : JintException
|
|
public class JavaScriptException : JintException
|
|
{
|
|
{
|
|
- private string _callStack;
|
|
|
|
|
|
+ private string? _callStack;
|
|
|
|
|
|
public JavaScriptException(ErrorConstructor errorConstructor) : base("")
|
|
public JavaScriptException(ErrorConstructor errorConstructor) : base("")
|
|
{
|
|
{
|
|
Error = errorConstructor.Construct(Arguments.Empty);
|
|
Error = errorConstructor.Construct(Arguments.Empty);
|
|
}
|
|
}
|
|
|
|
|
|
- public JavaScriptException(ErrorConstructor errorConstructor, string message, Exception innerException)
|
|
|
|
|
|
+ public JavaScriptException(ErrorConstructor errorConstructor, string? message, Exception? innerException)
|
|
: base(message, innerException)
|
|
: base(message, innerException)
|
|
{
|
|
{
|
|
Error = errorConstructor.Construct(new JsValue[] { message });
|
|
Error = errorConstructor.Construct(new JsValue[] { message });
|
|
}
|
|
}
|
|
|
|
|
|
- public JavaScriptException(ErrorConstructor errorConstructor, string message)
|
|
|
|
|
|
+ public JavaScriptException(ErrorConstructor errorConstructor, string? message)
|
|
: base(message)
|
|
: base(message)
|
|
{
|
|
{
|
|
Error = errorConstructor.Construct(new JsValue[] { message });
|
|
Error = errorConstructor.Construct(new JsValue[] { message });
|
|
}
|
|
}
|
|
|
|
|
|
public JavaScriptException(JsValue error)
|
|
public JavaScriptException(JsValue error)
|
|
- : base(GetErrorMessage(error))
|
|
|
|
{
|
|
{
|
|
Error = error;
|
|
Error = error;
|
|
}
|
|
}
|
|
|
|
|
|
- public JavaScriptException SetCallstack(Engine engine, Location? location = null)
|
|
|
|
|
|
+ internal JavaScriptException SetCallstack(Engine engine, Location location)
|
|
{
|
|
{
|
|
- Location = location ?? default;
|
|
|
|
-
|
|
|
|
- using (var sb = StringBuilderPool.Rent())
|
|
|
|
|
|
+ Location = location;
|
|
|
|
+ var value = engine.CallStack.BuildCallStackString(location);
|
|
|
|
+ _callStack = value;
|
|
|
|
+ if (Error.IsObject())
|
|
{
|
|
{
|
|
- foreach (var cse in engine.CallStack)
|
|
|
|
- {
|
|
|
|
- sb.Builder.Append(" at ")
|
|
|
|
- .Append(cse)
|
|
|
|
- .Append("(");
|
|
|
|
-
|
|
|
|
- for (var index = 0; index < cse.CallExpression.Arguments.Count; index++)
|
|
|
|
- {
|
|
|
|
- if (index != 0)
|
|
|
|
- {
|
|
|
|
- sb.Builder.Append(", ");
|
|
|
|
- }
|
|
|
|
- var arg = cse.CallExpression.Arguments[index];
|
|
|
|
- if (arg is Expression pke)
|
|
|
|
- {
|
|
|
|
- sb.Builder.Append(GetPropertyKey(pke));
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- sb.Builder.Append(arg);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- sb.Builder.Append(") @ ")
|
|
|
|
- .Append(cse.CallExpression.Location.Source)
|
|
|
|
- .Append(" ")
|
|
|
|
- .Append(cse.CallExpression.Location.Start.Column)
|
|
|
|
- .Append(":")
|
|
|
|
- .Append(cse.CallExpression.Location.Start.Line)
|
|
|
|
- .AppendLine();
|
|
|
|
- }
|
|
|
|
- CallStack = sb.ToString();
|
|
|
|
|
|
+ Error.AsObject()
|
|
|
|
+ .FastAddProperty(CommonProperties.Stack, new JsString(value), false, false, false);
|
|
}
|
|
}
|
|
|
|
|
|
return this;
|
|
return this;
|
|
}
|
|
}
|
|
|
|
|
|
- /// <summary>
|
|
|
|
- /// A version of <see cref="EsprimaExtensions.GetKey"/> that cannot get into loop as we are already building a stack.
|
|
|
|
- /// </summary>
|
|
|
|
- private static string GetPropertyKey(Expression expression)
|
|
|
|
- {
|
|
|
|
- if (expression is Literal literal)
|
|
|
|
- {
|
|
|
|
- return EsprimaExtensions.LiteralKeyToString(literal);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (expression is Identifier identifier)
|
|
|
|
- {
|
|
|
|
- return identifier.Name;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (expression is StaticMemberExpression staticMemberExpression)
|
|
|
|
- {
|
|
|
|
- return GetPropertyKey(staticMemberExpression.Object) + "." + GetPropertyKey(staticMemberExpression.Property);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return "?";
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private static string GetErrorMessage(JsValue error)
|
|
|
|
|
|
+ private string? GetErrorMessage()
|
|
{
|
|
{
|
|
- if (error.IsObject())
|
|
|
|
|
|
+ if (Error is ObjectInstance oi)
|
|
{
|
|
{
|
|
- var oi = error.AsObject();
|
|
|
|
- var message = oi.Get("message", oi).ToString();
|
|
|
|
- return message;
|
|
|
|
|
|
+ return oi.Get(CommonProperties.Message).ToString();
|
|
}
|
|
}
|
|
- if (error.IsString())
|
|
|
|
- return error.ToString();
|
|
|
|
|
|
|
|
- return error.ToString();
|
|
|
|
|
|
+ return null;
|
|
}
|
|
}
|
|
|
|
|
|
public JsValue Error { get; }
|
|
public JsValue Error { get; }
|
|
|
|
|
|
- public override string ToString()
|
|
|
|
- {
|
|
|
|
- return Error.ToString();
|
|
|
|
- }
|
|
|
|
|
|
+ public override string Message => GetErrorMessage() ?? TypeConverter.ToString(Error);
|
|
|
|
|
|
- public string CallStack
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Returns the call stack of the exception. Requires that engine was built using
|
|
|
|
+ /// <see cref="Options.CollectStackTrace"/>.
|
|
|
|
+ /// </summary>
|
|
|
|
+ public override string? StackTrace
|
|
{
|
|
{
|
|
get
|
|
get
|
|
{
|
|
{
|
|
- if (_callStack != null)
|
|
|
|
|
|
+ if (_callStack is not null)
|
|
|
|
+ {
|
|
return _callStack;
|
|
return _callStack;
|
|
- if (ReferenceEquals(Error, null))
|
|
|
|
- return null;
|
|
|
|
- if (Error.IsObject() == false)
|
|
|
|
- return null;
|
|
|
|
- var callstack = Error.AsObject().Get("callstack", Error);
|
|
|
|
- if (callstack.IsUndefined())
|
|
|
|
- return null;
|
|
|
|
- return callstack.AsString();
|
|
|
|
- }
|
|
|
|
- set
|
|
|
|
- {
|
|
|
|
- _callStack = value;
|
|
|
|
- if (value != null && Error.IsObject())
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (Error is not ObjectInstance oi)
|
|
{
|
|
{
|
|
- Error.AsObject()
|
|
|
|
- .FastAddProperty("callstack", new JsString(value), false, false, false);
|
|
|
|
|
|
+ return null;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ var callstack = oi.Get(CommonProperties.Stack, Error);
|
|
|
|
+
|
|
|
|
+ return callstack.IsUndefined()
|
|
|
|
+ ? null
|
|
|
|
+ : callstack.AsString();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- public Location Location { get; set; }
|
|
|
|
|
|
+ public Location Location { get; private set; }
|
|
|
|
|
|
public int LineNumber => Location.Start.Line;
|
|
public int LineNumber => Location.Start.Line;
|
|
|
|
|
|
public int Column => Location.Start.Column;
|
|
public int Column => Location.Start.Column;
|
|
|
|
+
|
|
|
|
+ public override string ToString()
|
|
|
|
+ {
|
|
|
|
+ // adapted custom version as logic differs between full framework and .NET Core
|
|
|
|
+ var className = GetType().ToString();
|
|
|
|
+ var message = Message;
|
|
|
|
+ var innerExceptionString = InnerException?.ToString() ?? "";
|
|
|
|
+ const string endOfInnerExceptionResource = "--- End of inner exception stack trace ---";
|
|
|
|
+ var stackTrace = StackTrace;
|
|
|
|
+
|
|
|
|
+ using var rent = StringBuilderPool.Rent();
|
|
|
|
+ var sb = rent.Builder;
|
|
|
|
+ sb.Append(className);
|
|
|
|
+ if (!string.IsNullOrEmpty(message))
|
|
|
|
+ {
|
|
|
|
+ sb.Append(": ");
|
|
|
|
+ sb.Append(message);
|
|
|
|
+ }
|
|
|
|
+ if (InnerException != null)
|
|
|
|
+ {
|
|
|
|
+ sb.Append(Environment.NewLine);
|
|
|
|
+ sb.Append(" ---> ");
|
|
|
|
+ sb.Append(innerExceptionString);
|
|
|
|
+ sb.Append(Environment.NewLine);
|
|
|
|
+ sb.Append(" ");
|
|
|
|
+ sb.Append(endOfInnerExceptionResource);
|
|
|
|
+ }
|
|
|
|
+ if (stackTrace != null)
|
|
|
|
+ {
|
|
|
|
+ sb.Append(Environment.NewLine);
|
|
|
|
+ sb.Append(stackTrace);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return rent.ToString();
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|