use thiserror::Error; use crate::interpreter::Primitive; use crate::lexer::Token; use crate::misc::CodePos; use crate::parser::expr::{BinaryOp, UnaryOp}; #[derive(Error, Debug)] pub enum LexerError { #[error("Unexpected character '{c}' at {code_pos}.")] UnexpectedCharacter { c: char, code_pos: CodePos }, #[error("Unterminated string literal starting at {code_pos}.")] UnterminatedStringLiteral { code_pos: CodePos }, #[error("Unterminated block comment starting at {code_pos}.")] UnterminatedBlockComment { code_pos: CodePos }, #[error("Invalid number literal {lexeme} at {code_pos}: {msg}")] InvalidNumberLiteral { lexeme: String, msg: String, code_pos: CodePos, }, } #[derive(Error, Debug)] pub enum ParserError { #[error("Token stream ended unexpectedly.")] TokenStreamEnded, #[error("Unexpected token {token} at {0}.", token.code_pos())] UnexpectedToken { token: Token }, } #[derive(Error, Debug)] pub enum EvalError { #[error("Unary operator {op} had invalid argument {arg}")] UnaryOpInvalidArgument { op: UnaryOp, arg: Primitive }, #[error("Binary operator {op} had invalid arguments {left} and {right}")] BinaryOpInvalidArguments { left: Primitive, op: BinaryOp, right: Primitive, }, #[error("Division by zero")] DivisionByZero, } #[derive(Error, Debug)] pub enum LoxError { #[error("{0}", format_lexer_errors(inner))] LexerError { inner: Vec }, #[error("{inner}")] ParserError { inner: ParserError }, #[error("{inner}")] EvalError { inner: EvalError }, } fn format_lexer_errors(lexer_errs: &Vec) -> String { let msg = if lexer_errs.len() == 1 { format!("{}", lexer_errs[0]) } else { let msgs: Vec = lexer_errs.iter().map(|err| format!("{}", err)).collect(); msgs.join("\n") }; msg } impl From> for LoxError { fn from(lexer_errs: Vec) -> Self { LoxError::LexerError { inner: lexer_errs } } } impl From for LoxError { fn from(parser_err: ParserError) -> Self { LoxError::ParserError { inner: parser_err } } } impl From for LoxError { fn from(eval_err: EvalError) -> Self { LoxError::EvalError { inner: eval_err } } }