use itertools::Itertools; use rlox2_frontend::lexer::{CodePos, LexerError}; use thiserror::Error; use crate::{Opcode, Value}; #[derive(Error, Debug)] pub enum CompilerError { #[error("Missing closing parenthesis at {code_pos}")] MissingRightParen { code_pos: CodePos }, #[error("{msg}")] Todo { msg: String }, } #[derive(Error, Debug)] pub enum RuntimeError { #[error("Opcopde {opcode} had invalid operand {operand}")] UnaryInvalidOperand { opcode: Opcode, operand: Value }, #[error("Opcopde {opcode} had invalid operands {left} and {right}")] BinaryInvalidOperand { opcode: Opcode, left: Value, right: Value, }, #[error("Division by zero")] DivisionByZero, } #[derive(Error, Debug)] pub enum LoxError { #[error("{0}", format_multiple_errors(inner))] LexerError { inner: Vec }, #[error("{inner}")] CompileError { inner: CompilerError }, #[error("{inner}")] RuntimeError { inner: RuntimeError }, #[error("Called exit() with exit code {exit_code}")] Exit { exit_code: i32 }, } impl From> for LoxError { fn from(lexer_errs: Vec) -> Self { LoxError::LexerError { inner: lexer_errs } } } impl From for LoxError { fn from(compile_err: CompilerError) -> Self { LoxError::CompileError { inner: compile_err } } } impl From for LoxError { fn from(runtime_err: RuntimeError) -> Self { LoxError::RuntimeError { inner: runtime_err } } } fn format_multiple_errors(errs: &[impl std::error::Error]) -> String { let msg = if errs.len() == 1 { errs[0].to_string() } else { errs.iter().map(|err| err.to_string()).join("\n") }; msg }