diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs index 0e028117bbf7e9..a348a42534c312 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs @@ -125,42 +125,42 @@ public struct Result public JObject Value { get; private set; } public JObject Error { get; private set; } - public bool IsOk => Value != null; - public bool IsErr => Error != null; + public bool IsOk => Error == null; - private Result(JObject result, JObject error) + private Result(JObject resultOrError, bool isError) { - if (result != null && error != null) - throw new ArgumentException($"Both {nameof(result)} and {nameof(error)} arguments cannot be non-null."); - - bool resultHasError = string.Equals((result?["result"] as JObject)?["subtype"]?.Value(), "error"); - if (result != null && resultHasError) + bool resultHasError = isError || string.Equals((resultOrError?["result"] as JObject)?["subtype"]?.Value(), "error"); + if (resultHasError) { - this.Value = null; - this.Error = result; + Value = null; + Error = resultOrError; } else { - this.Value = result; - this.Error = error; + Value = resultOrError; + Error = null; } } - public static Result FromJson(JObject obj) { - //Log ("protocol", $"from result: {obj}"); - return new Result(obj["result"] as JObject, obj["error"] as JObject); + var error = obj["error"] as JObject; + if (error != null) + return new Result(error, true); + var result = obj["result"] as JObject; + return new Result(result, false); } - public static Result Ok(JObject ok) => new Result(ok, null); + public static Result Ok(JObject ok) => new Result(ok, false); public static Result OkFromObject(object ok) => Ok(JObject.FromObject(ok)); - public static Result Err(JObject err) => new Result(null, err); + public static Result Err(JObject err) => new Result(err, true); + + public static Result Err(string msg) => new Result(JObject.FromObject(new { message = msg }), true); - public static Result Err(string msg) => new Result(null, JObject.FromObject(new { message = msg })); + public static Result UserVisibleErr(JObject result) => new Result { Value = result }; - public static Result Exception(Exception e) => new Result(null, JObject.FromObject(new { message = e.Message })); + public static Result Exception(Exception e) => new Result(JObject.FromObject(new { message = e.Message }), true); public JObject ToJObject(MessageId target) { @@ -186,7 +186,7 @@ public JObject ToJObject(MessageId target) public override string ToString() { - return $"[Result: IsOk: {IsOk}, IsErr: {IsErr}, Value: {Value?.ToString()}, Error: {Error?.ToString()} ]"; + return $"[Result: IsOk: {IsOk}, IsErr: {!IsOk}, Value: {Value?.ToString()}, Error: {Error?.ToString()} ]"; } } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsProxy.cs index 63e8025fc19eeb..28033d58dad95a 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsProxy.cs @@ -234,7 +234,7 @@ internal void SendResponse(MessageId id, Result result, CancellationToken token) private void SendResponseInternal(MessageId id, Result result, CancellationToken token) { JObject o = result.ToJObject(id); - if (result.IsErr) + if (!result.IsOk) logger.LogError($"sending error response for id: {id} -> {result}"); Send(this.ide, o, token); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/EvaluateExpression.cs b/src/mono/wasm/debugger/BrowserDebugProxy/EvaluateExpression.cs index 6e52ae37c528e8..213a50ae1ce7eb 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/EvaluateExpression.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/EvaluateExpression.cs @@ -390,17 +390,21 @@ internal static async Task CompileAndRunTheExpression(string expression if (expressionTree == null) throw new Exception($"BUG: Unable to evaluate {expression}, could not get expression from the syntax tree"); - try { + try + { var newScript = script.ContinueWith( string.Join("\n", findVarNMethodCall.variableDefinitions) + "\nreturn " + syntaxTree.ToString()); var state = await newScript.RunAsync(cancellationToken: token); - return JObject.FromObject(ConvertCSharpToJSType(state.ReturnValue, state.ReturnValue.GetType())); } - catch (Exception) + catch (CompilationErrorException cee) + { + throw new ReturnAsErrorException($"Cannot evaluate '{expression}': {cee.Message}", "CompilationError"); + } + catch (Exception ex) { - throw new ReturnAsErrorException($"Cannot evaluate '{expression}'.", "CompilationError"); + throw new Exception($"Internal Error: Unable to run {expression}, error: {ex.Message}.", ex); } } @@ -429,22 +433,38 @@ private static object ConvertCSharpToJSType(object v, Type type) internal class ReturnAsErrorException : Exception { - public Result Error { get; } + private Result _error; + public Result Error + { + get + { + _error.Value["exceptionDetails"]["stackTrace"] = StackTrace; + return _error; + } + set { } + } public ReturnAsErrorException(JObject error) => Error = Result.Err(error); public ReturnAsErrorException(string message, string className) { - Error = Result.Err(JObject.FromObject(new + var result = new { - result = new + type = "object", + subtype = "error", + description = message, + className + }; + _error = Result.UserVisibleErr(JObject.FromObject( + new { - type = "object", - subtype = "error", - description = message, - className - } - })); + result = result, + exceptionDetails = new + { + exception = result, + stackTrace = StackTrace + } + })); } } } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs index b7df8863a1f1cb..eebb3557fea677 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs @@ -219,7 +219,7 @@ async Task ResolveAsLocalOrThisMember(string name) if (scopeCache.Locals.Count == 0 && !localsFetched) { Result scope_res = await proxy.GetScopeProperties(sessionId, scopeId, token); - if (scope_res.IsErr) + if (!scope_res.IsOk) throw new Exception($"BUG: Unable to get properties for scope: {scopeId}. {scope_res}"); localsFetched = true; } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index 0bda696e16265f..8a9d714428ceac 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -674,7 +674,7 @@ private async Task CallOnFunction(MessageId id, JObject args, Cancellation return false; } Result res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(RuntimeId, args), token); - if (res.IsErr) + if (!res.IsOk) { SendResponse(id, res, token); return true; @@ -1004,7 +1004,7 @@ async Task SkipMethod(bool isSkippable, bool shouldBeSkipped, StepKind ste private async Task OnReceiveDebuggerAgentEvent(SessionId sessionId, JObject args, CancellationToken token) { Result res = await SendMonoCommand(sessionId, MonoCommands.GetDebuggerAgentBufferReceived(RuntimeId), token); - if (res.IsErr) + if (!res.IsOk) return false; ExecutionContext context = GetContext(sessionId); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index b3e1feb4e3a9b3..793d3c980b9f15 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -435,10 +435,10 @@ public MonoBinaryReader(byte [] data) : base(new MemoryStream(data)) {} public static MonoBinaryReader From(Result result) { byte[] newBytes = Array.Empty(); - if (!result.IsErr) { + if (result.IsOk) { newBytes = Convert.FromBase64String(result.Value?["result"]?["value"]?["value"]?.Value()); } - return new MonoBinaryReader(new MemoryStream(newBytes), result.IsErr); + return new MonoBinaryReader(new MemoryStream(newBytes), !result.IsOk); } public override string ReadString() diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/CallFunctionOnTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/CallFunctionOnTests.cs index 3e7d482b9ac290..03819fe99c00e2 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/CallFunctionOnTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/CallFunctionOnTests.cs @@ -534,7 +534,6 @@ public async Task CFOWithSilentReturnsErrors(string eval_fn, string bp_loc, int // doesn't get reported, and the execution is NOT paused even with setPauseOnException=true result = await cli.SendCommand("Runtime.callFunctionOn", cfo_args, token); Assert.False(result.IsOk, "result.IsOk"); - Assert.True(result.IsErr, "result.IsErr"); var hasErrorMessage = result.Error["exceptionDetails"]?["exception"]?["description"]?.Value()?.Contains(error_msg); Assert.True((hasErrorMessage ?? false), "Exception message not found"); @@ -785,7 +784,7 @@ public async Task RunOnInvalidCfoId(string eval_fn, string bp_loc, int line, int }); var res = await cli.SendCommand("Runtime.callFunctionOn", cfo_args, token); - Assert.True(res.IsErr); + Assert.False(res.IsOk); }); [Theory] @@ -811,7 +810,7 @@ public async Task RunOnInvalidThirdSegmentOfObjectId(string eval_fn, string bp_l }); var res = await cli.SendCommand("Runtime.callFunctionOn", cfo_args, token); - Assert.True(res.IsErr); + Assert.False(res.IsOk); } [Theory] diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs b/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs index 26ea6e47e1ee31..a4104328b982be 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs @@ -1008,7 +1008,7 @@ internal async Task RemoveBreakpoint(string id, bool expect_ok = true) }); var res = await cli.SendCommand("Debugger.removeBreakpoint", remove_bp, token); - Assert.True(expect_ok ? res.IsOk : res.IsErr); + Assert.True(expect_ok ? res.IsOk : !res.IsOk); return res; } @@ -1020,7 +1020,7 @@ internal async Task SetBreakpoint(string url_key, int line, int column, JObject.FromObject(new { lineNumber = line, columnNumber = column, urlRegex = url_key, condition }); var bp1_res = await cli.SendCommand("Debugger.setBreakpointByUrl", bp1_req, token); - Assert.True(expect_ok ? bp1_res.IsOk : bp1_res.IsErr); + Assert.True(expect_ok ? bp1_res.IsOk : !bp1_res.IsOk); return bp1_res; } diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/Inspector.cs b/src/mono/wasm/debugger/DebuggerTestSuite/Inspector.cs index b44dddd02dbded..517c46dd56334c 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/Inspector.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/Inspector.cs @@ -259,7 +259,7 @@ public async Task OpenSessionAsync(Func()); } @@ -245,7 +245,7 @@ await EvaluateAndCheck( }); var frame_props = await cli.SendCommand("Runtime.getProperties", get_prop_req, token); - Assert.True(frame_props.IsErr); + Assert.False(frame_props.IsOk); } ); }