From 3d0ca46de5983ce460dbeafd83d654148c2d3d18 Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Sun, 25 Feb 2024 09:09:36 -0800 Subject: [PATCH] Repl now shows backtraces on exceptions --- src/main.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index 02550dd..564a031 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,8 +4,9 @@ use std::path::PathBuf; use ariadne::{Cache, Label, Span}; use muse::compiler::Compiler; +use muse::exception::Exception; use muse::syntax::{parse, Ranged, SourceId, SourceRange, Sources}; -use muse::vm::Vm; +use muse::vm::{ExecutionError, StackFrame, Vm}; use muse::Error; use rustyline::completion::Completer; use rustyline::config::Configurer; @@ -49,9 +50,20 @@ fn main() { println!("{value:?}"); } } - Err(err) => { - eprintln!("Execution error: {err:?}"); - } + Err(err) => match err { + ExecutionError::Exception(exception) => { + let Some(exception) = exception.as_downcast_ref::() + else { + unreachable!() + }; + + let mut printer = editor + .create_external_printer() + .expect("can't create printer"); + printer.print(print_exception(exception, &sources)).unwrap(); + } + other => eprintln!("Execution error: {other:?}"), + }, }, Err(err) => { let errors = print_errors(err, &sources); @@ -69,6 +81,38 @@ fn main() { } } +fn print_exception(exception: &Exception, sources: &Sources) -> String { + let mut text = Vec::new(); + + let last_range = exception + .backtrace() + .iter() + .rev() + .find_map(StackFrame::source_range) + .expect("missing instruction range"); + let mut report = ariadne::Report::::build( + ariadne::ReportKind::Error, + last_range.source_id, + last_range.start, + ) + .with_message(format!("Exception: {:?}", exception.value())); + + for range in exception + .backtrace() + .iter() + .rev() + .filter_map(StackFrame::source_range) + { + report = report.with_label(Label::new(MuseSpan(range)).with_message("while executing")); + } + report + .finish() + .write_for_stdout(SourceCache(sources, HashMap::default()), &mut text) + .expect("error building report"); + + String::from_utf8(text).expect("invalid utf-8 in error report") +} + fn print_errors(errs: Vec>, sources: &Sources) -> String { let mut text = Vec::new(); for (index, err) in errs.into_iter().enumerate() {