Files
@ 88611f9fd179
Branch filter:
Location: CSY/reowolf/src/protocol/eval/error.rs
88611f9fd179
3.2 KiB
application/rls-services+xml
Merge branch 'feat-examples' into 'master'
feat: examples
See merge request nl-cwi-csy/reowolf!12
feat: examples
See merge request nl-cwi-csy/reowolf!12
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | use std::fmt;
use crate::protocol::{
ast::*,
Module,
input_source::{ErrorStatement, StatementKind}
};
use super::executor::*;
/// Represents a stack frame recorded in an error
#[derive(Debug)]
pub struct EvalFrame {
pub line: Option<u32>,
pub module_name: String,
pub procedure: String, // function or component
pub is_func: bool,
}
impl fmt::Display for EvalFrame {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let func_or_comp = if self.is_func {
"function "
} else {
"component"
};
let line_str = match self.line {
Some(line_number) => line_number.to_string(),
None => String::from("??"),
};
if self.module_name.is_empty() {
write!(f, "{} {}:{}", func_or_comp, &self.procedure, line_str)
} else {
write!(f, "{} {}:{}:{}", func_or_comp, &self.module_name, &self.procedure, line_str)
}
}
}
/// Represents an error that ocurred during evaluation. Contains error
/// statements just like in parsing errors. Additionally may display the current
/// execution state.
#[derive(Debug)]
pub struct EvalError {
pub(crate) statements: Vec<ErrorStatement>,
pub(crate) frames: Vec<EvalFrame>,
}
impl EvalError {
pub(crate) fn new_error_at_expr(prompt: &Prompt, modules: &[Module], heap: &Heap, expr_id: ExpressionId, msg: String) -> EvalError {
// Create frames
debug_assert!(!prompt.frames.is_empty());
let mut frames = Vec::with_capacity(prompt.frames.len());
let mut last_module_source = &modules[0].source;
for frame in prompt.frames.iter() {
let definition = &heap[frame.definition];
let statement = &heap[frame.position];
let statement_span = statement.maybe_span();
// Lookup module name, if it has one
let module = modules.iter().find(|m| m.root_id == definition.defined_in).unwrap();
let module_name = if let Some(name) = &module.name {
name.as_str().to_string()
} else {
String::new()
};
last_module_source = &module.source;
frames.push(EvalFrame{
line: statement_span.map(|v| v.begin.line),
module_name,
procedure: definition.identifier.value.as_str().to_string(),
is_func: definition.kind == ProcedureKind::Function,
});
}
let expr = &heap[expr_id];
let statements = vec![
ErrorStatement::from_source_at_span(StatementKind::Error, last_module_source, expr.full_span(), msg)
];
EvalError{ statements, frames }
}
}
impl fmt::Display for EvalError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Display error statement(s)
self.statements[0].fmt(f)?;
for statement in self.statements.iter().skip(1) {
writeln!(f)?;
statement.fmt(f)?;
}
// Display stack trace
writeln!(f)?;
writeln!(f, " +- Stack trace:")?;
for frame in self.frames.iter().rev() {
write!(f, " | ")?;
frame.fmt(f)?;
writeln!(f)?;
}
Ok(())
}
}
|