use std::{rc::Rc, error::Error, fmt}; pub mod token; pub mod expr; pub mod lexer; pub mod parser; pub mod value; pub mod eval; pub mod interpreter; pub mod env; #[derive(Clone, Debug)] pub struct Position { pub pos: usize, pub line: usize, pub col: usize, pub file: Option> } impl fmt::Display for Position { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}:{}:{}", self.file.as_ref().map(|x| x.as_ref()).unwrap_or(""), self.line, self.col ) } } #[derive(Debug)] pub struct ParserError { pub message: String, pub pos: Position } #[derive(Debug)] pub struct Stackframe { pub pos: Option, pub fn_name: Option>, } #[derive(Debug)] pub struct RuntimeError { pub message: String, pub stacktrace: Vec, pub last_pos: Option, } impl RuntimeError { pub fn new(message: S, pos: Position) -> Self where S: Into { Self { message: message.into(), stacktrace: vec![], last_pos: Some(pos) } } pub fn new_no_pos(message: S) -> Self where S: Into { Self { message: message.into(), stacktrace: vec![], last_pos: None } } pub fn exit_fn(mut self, fn_name: Option>, pos: Position) -> Self { self.stacktrace.push(Stackframe { pos: self.last_pos, fn_name }); self.last_pos = Some(pos); self } pub fn finish(mut self, ctx_name: Option>) -> Self { self.stacktrace.push(Stackframe { pos: self.last_pos, fn_name: ctx_name }); self.last_pos = None; self } } impl From for RuntimeError { fn from(s: String) -> Self { Self::new_no_pos(s) } } impl From<&str> for RuntimeError { fn from(s: &str) -> Self { Self::new_no_pos(s) } } impl fmt::Display for ParserError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}\n In {} at {},{}", self.message, self.pos.file.as_ref().map(|o| o.as_ref()).unwrap_or(""), self.pos.line, self.pos.col ) } } impl fmt::Display for RuntimeError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.message)?; for frame in &self.stacktrace { let fn_name = frame.fn_name.as_ref().map(|o| o.as_ref()).unwrap_or(""); match &frame.pos { Some(pos) => write!(f, "\n In {} at {}", fn_name, pos)?, None => write!(f, "\n In {} at ", fn_name)?, } } Ok(()) } } impl Error for ParserError {} impl Error for RuntimeError {}