2024-09-01 23:53:04 +02:00
|
|
|
use std::fmt::Display;
|
2023-01-28 14:19:12 +01:00
|
|
|
use std::rc::Rc;
|
|
|
|
|
|
2023-01-28 01:11:55 +01:00
|
|
|
use rlox2_frontend::lexer::LexerError;
|
|
|
|
|
use rlox2_frontend::parser::{BinaryOp, ParserError, UnaryOp};
|
2024-09-02 05:19:30 +02:00
|
|
|
use smol_str::SmolStr;
|
2023-01-28 01:11:55 +01:00
|
|
|
use thiserror::Error;
|
|
|
|
|
|
|
|
|
|
use crate::Value;
|
2023-01-28 14:19:12 +01:00
|
|
|
use crate::{LoxClass, ResolverError};
|
2023-01-28 01:11:55 +01:00
|
|
|
|
|
|
|
|
#[derive(Error, Debug)]
|
|
|
|
|
pub enum RuntimeError {
|
2024-09-01 23:53:04 +02:00
|
|
|
#[error("unary operator {op} had invalid argument {arg}")]
|
2023-01-28 01:11:55 +01:00
|
|
|
UnaryOpInvalidArgument { op: UnaryOp, arg: Value },
|
2024-09-01 23:53:04 +02:00
|
|
|
#[error("binary operator {op} had invalid arguments {left} and {right}")]
|
2024-09-01 19:16:30 +02:00
|
|
|
BinaryOpInvalidArguments {
|
|
|
|
|
left: Value,
|
|
|
|
|
op: BinaryOp,
|
|
|
|
|
right: Value,
|
|
|
|
|
},
|
2024-09-01 23:53:04 +02:00
|
|
|
#[error("division by zero")]
|
2023-01-28 01:11:55 +01:00
|
|
|
DivisionByZero,
|
2024-09-01 23:53:04 +02:00
|
|
|
#[error("local {name} is not defined")]
|
2023-01-28 01:11:55 +01:00
|
|
|
NameNotDefined { name: String },
|
2024-09-01 23:53:04 +02:00
|
|
|
#[error("global {name} is not defined")]
|
2023-01-28 01:11:55 +01:00
|
|
|
GlobalNotDefined { name: String },
|
2024-09-01 23:53:04 +02:00
|
|
|
#[error("{callee} is not callable")]
|
2023-01-28 01:11:55 +01:00
|
|
|
NotCallable { callee: Value },
|
2024-09-01 23:53:04 +02:00
|
|
|
#[error("{name}() takes {arity} args, but {given} were given.")]
|
2024-09-01 19:16:30 +02:00
|
|
|
WrongArity {
|
|
|
|
|
name: String,
|
|
|
|
|
arity: usize,
|
|
|
|
|
given: usize,
|
|
|
|
|
},
|
2024-09-01 23:53:04 +02:00
|
|
|
#[error("extern function call to {name} failed: {msg}")]
|
2023-01-28 01:11:55 +01:00
|
|
|
ExtFunCallFailed { name: String, msg: String },
|
2024-09-01 23:53:04 +02:00
|
|
|
#[error("uncaught break statement")]
|
2023-01-28 01:11:55 +01:00
|
|
|
Break,
|
2024-09-01 23:53:04 +02:00
|
|
|
#[error("uncaught return statement")]
|
2023-01-28 01:11:55 +01:00
|
|
|
Return { value: Value },
|
2024-09-01 23:53:04 +02:00
|
|
|
#[error("exit with exit code {exit_code}")]
|
2023-01-28 01:11:55 +01:00
|
|
|
Exit { exit_code: i32 },
|
2024-09-01 23:53:04 +02:00
|
|
|
#[error("only objects have attributes")]
|
2023-01-28 14:19:12 +01:00
|
|
|
InvalidGetTarget,
|
2024-09-01 23:53:04 +02:00
|
|
|
#[error("only objects have attributes")]
|
2023-01-28 14:19:12 +01:00
|
|
|
InvalidSetTarget,
|
2024-09-01 23:53:04 +02:00
|
|
|
#[error("class {0} has no property {name}", class.name())]
|
2024-09-02 05:19:30 +02:00
|
|
|
UndefinedAttribute { class: Rc<LoxClass>, name: SmolStr },
|
2024-09-01 23:53:04 +02:00
|
|
|
#[error("{value} is not a valid superclass")]
|
2023-01-28 14:19:12 +01:00
|
|
|
InvalidSuperclass { value: Value },
|
2024-09-01 23:53:04 +02:00
|
|
|
#[error("stack overflow")]
|
2024-09-01 20:47:42 +02:00
|
|
|
StackOverflow,
|
2023-01-28 01:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
2024-09-01 23:53:04 +02:00
|
|
|
#[derive(Debug)]
|
2023-01-28 01:11:55 +01:00
|
|
|
#[allow(clippy::enum_variant_names)]
|
|
|
|
|
pub enum LoxError {
|
2024-09-01 23:53:04 +02:00
|
|
|
LexerError { lexer_errors: Vec<LexerError> },
|
|
|
|
|
ParserError { parser_errors: Vec<ParserError> },
|
|
|
|
|
ResolverError { resolver_error: ResolverError },
|
|
|
|
|
RuntimeError { runtime_error: RuntimeError },
|
2023-01-28 01:11:55 +01:00
|
|
|
Exit { exit_code: i32 },
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-01 23:53:04 +02:00
|
|
|
impl Display for LoxError {
|
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
|
let plural = |len: usize| {
|
|
|
|
|
if len > 1 {
|
|
|
|
|
"s"
|
|
|
|
|
} else {
|
|
|
|
|
""
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
match self {
|
|
|
|
|
LoxError::LexerError { lexer_errors } => {
|
|
|
|
|
let len = lexer_errors.len();
|
|
|
|
|
|
|
|
|
|
writeln!(f, "{len} lexer error{}:", plural(len))?;
|
|
|
|
|
|
|
|
|
|
if len > 1 {
|
|
|
|
|
for lexer_error in lexer_errors[..len - 2].iter() {
|
|
|
|
|
writeln!(f, "{lexer_error}")?;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
write!(f, "{}", lexer_errors[len - 1])
|
|
|
|
|
}
|
|
|
|
|
LoxError::ParserError { parser_errors } => {
|
|
|
|
|
let len = parser_errors.len();
|
|
|
|
|
|
|
|
|
|
writeln!(f, "{len} parser error{}:", plural(len))?;
|
|
|
|
|
|
|
|
|
|
if len > 1 {
|
|
|
|
|
for lexer_error in parser_errors[..len - 2].iter() {
|
|
|
|
|
writeln!(f, "{lexer_error}")?;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-01-28 01:11:55 +01:00
|
|
|
|
2024-09-01 23:53:04 +02:00
|
|
|
write!(f, "{}", parser_errors[len - 1])
|
|
|
|
|
}
|
|
|
|
|
LoxError::ResolverError { resolver_error } => {
|
|
|
|
|
write!(f, "resolver error: {resolver_error}")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LoxError::RuntimeError { runtime_error } => {
|
|
|
|
|
write!(f, "runtime error: {runtime_error}")
|
|
|
|
|
}
|
|
|
|
|
LoxError::Exit { exit_code } => {
|
|
|
|
|
write!(f, "exited with code {exit_code}")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-01-28 01:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
2024-09-01 23:53:04 +02:00
|
|
|
impl std::error::Error for LoxError {}
|
|
|
|
|
|
2023-01-28 01:11:55 +01:00
|
|
|
impl From<Vec<LexerError>> for LoxError {
|
|
|
|
|
fn from(lexer_errs: Vec<LexerError>) -> Self {
|
2024-09-01 23:53:04 +02:00
|
|
|
LoxError::LexerError {
|
|
|
|
|
lexer_errors: lexer_errs,
|
|
|
|
|
}
|
2023-01-28 01:11:55 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<Vec<ParserError>> for LoxError {
|
|
|
|
|
fn from(parser_errs: Vec<ParserError>) -> Self {
|
2024-09-01 23:53:04 +02:00
|
|
|
LoxError::ParserError {
|
|
|
|
|
parser_errors: parser_errs,
|
|
|
|
|
}
|
2023-01-28 01:11:55 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<ResolverError> for LoxError {
|
|
|
|
|
fn from(resolver_err: ResolverError) -> Self {
|
2024-09-01 19:16:30 +02:00
|
|
|
LoxError::ResolverError {
|
2024-09-01 23:53:04 +02:00
|
|
|
resolver_error: resolver_err,
|
2024-09-01 19:16:30 +02:00
|
|
|
}
|
2023-01-28 01:11:55 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<RuntimeError> for LoxError {
|
|
|
|
|
fn from(runtime_err: RuntimeError) -> Self {
|
|
|
|
|
match runtime_err {
|
|
|
|
|
RuntimeError::Exit { exit_code } => LoxError::Exit { exit_code },
|
2024-09-01 23:53:04 +02:00
|
|
|
_ => LoxError::RuntimeError {
|
|
|
|
|
runtime_error: runtime_err,
|
|
|
|
|
},
|
2023-01-28 01:11:55 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|