mirror of
https://github.com/MorizzG/rlox.git
synced 2025-12-06 04:12:42 +00:00
85 lines
2.7 KiB
Rust
85 lines
2.7 KiB
Rust
|
|
use itertools::Itertools;
|
||
|
|
use rlox2_frontend::lexer::LexerError;
|
||
|
|
use rlox2_frontend::parser::{BinaryOp, ParserError, UnaryOp};
|
||
|
|
use thiserror::Error;
|
||
|
|
|
||
|
|
use crate::ResolverError;
|
||
|
|
use crate::Value;
|
||
|
|
|
||
|
|
#[derive(Error, Debug)]
|
||
|
|
pub enum RuntimeError {
|
||
|
|
#[error("Unary operator {op} had invalid argument {arg}")]
|
||
|
|
UnaryOpInvalidArgument { op: UnaryOp, arg: Value },
|
||
|
|
#[error("Binary operator {op} had invalid arguments {left} and {right}")]
|
||
|
|
BinaryOpInvalidArguments { left: Value, op: BinaryOp, right: Value },
|
||
|
|
#[error("Division by zero")]
|
||
|
|
DivisionByZero,
|
||
|
|
#[error("Name {name} is not defined")]
|
||
|
|
NameNotDefined { name: String },
|
||
|
|
#[error("Global {name} is not defined")]
|
||
|
|
GlobalNotDefined { name: String },
|
||
|
|
#[error("{callee} is not callable")]
|
||
|
|
NotCallable { callee: Value },
|
||
|
|
#[error("{name}() takes {arity} args, but {given} were given.")]
|
||
|
|
WrongArity { name: String, arity: usize, given: usize },
|
||
|
|
#[error("Extern function call to {name} failed: {msg}")]
|
||
|
|
ExtFunCallFailed { name: String, msg: String },
|
||
|
|
#[error("Uncaught break statement")]
|
||
|
|
Break,
|
||
|
|
#[error("Uncaught return statement")]
|
||
|
|
Return { value: Value },
|
||
|
|
#[error("Exit with exit code {exit_code}")]
|
||
|
|
Exit { exit_code: i32 },
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Error, Debug)]
|
||
|
|
#[allow(clippy::enum_variant_names)]
|
||
|
|
pub enum LoxError {
|
||
|
|
#[error("{0}", format_multiple_errors(inner))]
|
||
|
|
LexerError { inner: Vec<LexerError> },
|
||
|
|
#[error("{0}", format_multiple_errors(inner))]
|
||
|
|
ParserError { inner: Vec<ParserError> },
|
||
|
|
#[error("{inner}")]
|
||
|
|
ResolverError { inner: ResolverError },
|
||
|
|
#[error("{inner}")]
|
||
|
|
RuntimeError { inner: RuntimeError },
|
||
|
|
#[error("Called exit() with exit code {exit_code}")]
|
||
|
|
Exit { exit_code: i32 },
|
||
|
|
}
|
||
|
|
|
||
|
|
fn format_multiple_errors(errs: &Vec<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
|
||
|
|
}
|
||
|
|
|
||
|
|
impl From<Vec<LexerError>> for LoxError {
|
||
|
|
fn from(lexer_errs: Vec<LexerError>) -> Self {
|
||
|
|
LoxError::LexerError { inner: lexer_errs }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
impl From<Vec<ParserError>> for LoxError {
|
||
|
|
fn from(parser_errs: Vec<ParserError>) -> Self {
|
||
|
|
LoxError::ParserError { inner: parser_errs }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
impl From<ResolverError> for LoxError {
|
||
|
|
fn from(resolver_err: ResolverError) -> Self {
|
||
|
|
LoxError::ResolverError { inner: resolver_err }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
impl From<RuntimeError> for LoxError {
|
||
|
|
fn from(runtime_err: RuntimeError) -> Self {
|
||
|
|
match runtime_err {
|
||
|
|
RuntimeError::Exit { exit_code } => LoxError::Exit { exit_code },
|
||
|
|
_ => LoxError::RuntimeError { inner: runtime_err },
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|