Skip to content

Commit

Permalink
Catch exceptions from lazily evaluated code when stringifying evaluat…
Browse files Browse the repository at this point in the history
…ion result for REPL
  • Loading branch information
PaddiM8 committed Nov 17, 2024
1 parent 026fb10 commit fcf3130
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 9 deletions.
30 changes: 27 additions & 3 deletions src/ShellSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
using System.Reflection.Metadata.Ecma335;
using System.Text;
using Elk.Analysis;
using Elk.Exceptions;
using Elk.Lexing;
using Elk.Parsing;
using Elk.Scoping;
using Elk.Std.DataTypes;
Expand Down Expand Up @@ -126,9 +128,11 @@ public void RunCommand(
}
else
{
resultBuilder.AppendLine(
evaluationResult.Value.ToString() ?? ""
);
var evaluationResultValue = GetEvaluationResultValue(evaluationResult);
if (evaluationResultValue.isError)
textWriter = Console.Error;

resultBuilder.AppendLine(evaluationResultValue.value);
}

if (!printReturnedValue && !evaluationResult.Diagnostics.Any())
Expand All @@ -151,6 +155,26 @@ public void RunCommand(
Console.ResetColor();
}

private (string value, bool isError) GetEvaluationResultValue(EvaluationResult evaluationResult)
{
try
{
var value = evaluationResult.Value?.ToString() ?? "";

return (value, isError: false);
}
catch (RuntimeException ex)
{
var diagnostic = new DiagnosticMessage(ex.Message, ex.StartPosition ?? TextPos.Default, ex.EndPosition ?? TextPos.Default)
{
StackTrace = ex.ElkStackTrace,
};
var value = diagnostic.ToString(includePosition: false).Trim();

return (value, isError: true);
}
}

public void RunFile(string filePath, IEnumerable<string>? arguments)
{
arguments ??= new List<string>();
Expand Down
2 changes: 1 addition & 1 deletion src/Std/DataTypes/RuntimeList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public override string ToString()
var totalIndentationLength = 3 * Values.Count;

return json.Length - totalIndentationLength < lineLimit
? $"[{string.Join(", ", Values.Select(x => x.ToDisplayString()))}]"
? $"[{string.Join(", ", Values.Select(x => x?.ToDisplayString()))}]"
: json;
}
}
8 changes: 4 additions & 4 deletions src/Std/Serialization/RuntimeObjectJsonConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,11 @@ private JValue BuildValue(RuntimeObject value)
{
return value switch
{
RuntimeBoolean boolean => new(boolean.IsTrue),
RuntimeFloat floatValue => new(floatValue.Value),
RuntimeInteger integerValue => new(integerValue.Value),
RuntimeBoolean boolean => new JValue(boolean.IsTrue),
RuntimeFloat floatValue => new JValue(floatValue.Value),
RuntimeInteger integerValue => new JValue(integerValue.Value),
RuntimeNil => JValue.CreateNull(),
_ => new(value.ToString() ?? ""),
_ => new JValue(value?.ToString() ?? ""),
};
}

Expand Down
10 changes: 9 additions & 1 deletion src/Vm/InstructionExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,12 +190,20 @@ private void ExecuteCurrentPage()
throw;

var exceptionFrame = _context.ExceptionStack.Pop();
while (_currentPage != exceptionFrame.Page)
while (_callStack.Any() && _currentPage != exceptionFrame.Page)
{
ex.ElkStackTrace.Add(CreateTrace(_currentPage.Name));
PopFrame();
}

// If the current context doesn't have the exception frame,
// add it back and throw, to let the parent context handle it
if (_currentPage != exceptionFrame.Page)
{
_context.ExceptionStack.Push(exceptionFrame);
throw;
}

while (_stack.Count > exceptionFrame.StackSize)
_stack.PopObject();

Expand Down

0 comments on commit fcf3130

Please sign in to comment.