use itertools::Itertools; use rlox2_frontend::lexer::LexerError; use thiserror::Error; use crate::{Opcode, Value}; #[derive(Error, Debug)] pub enum CompileError {} #[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 InterpretError { #[error("{0}", format_multiple_errors(inner))] LexerError { inner: Vec }, #[error("{inner}")] CompileError { inner: CompileError }, #[error("{inner}")] RuntimeError { inner: RuntimeError }, #[error("Called exit() with exit code {exit_code}")] Exit { exit_code: i32 }, } impl From> for InterpretError { fn from(lexer_errs: Vec) -> Self { InterpretError::LexerError { inner: lexer_errs } } } impl From for InterpretError { fn from(compile_err: CompileError) -> Self { InterpretError::CompileError { inner: compile_err } } } impl From for InterpretError { fn from(runtime_err: RuntimeError) -> Self { InterpretError::RuntimeError { inner: runtime_err } } } fn format_multiple_errors(errs: &Vec) -> String { let msg = if errs.len() == 1 { errs[0].to_string() } else { errs.iter().map(|err| err.to_string()).join("\n") }; msg }