use smol_str::SmolStr;
use thiserror::Error;
use crate::{Ident, Token, number::Number};
use super::module::error::ModuleError;
type FunctionName = String;
type ArgType = Vec<SmolStr>;
type ErrorToken = Token;
#[derive(Error, Debug, PartialEq)]
pub enum RuntimeError {
#[error("{}", message)]
UserDefined { message: String, token: ErrorToken },
#[error("Invalid base64 string")]
InvalidBase64String(ErrorToken, String),
#[error("\"{1}\" is not defined")]
NotDefined(ErrorToken, FunctionName),
#[error("Unable to format date time, {1}")]
DateTimeFormatError(ErrorToken, String),
#[error("Index out of bounds {1}")]
IndexOutOfBounds(ErrorToken, Number),
#[error("Invalid definition for \"{1}\"")]
InvalidDefinition(ErrorToken, String),
#[error("Maximum recursion depth exceeded ({0})")]
RecursionError(u32),
#[error(r#"Invalid types for "{}", got {}"#, name, args.join(", "))]
InvalidTypes {
token: ErrorToken,
name: FunctionName,
args: ArgType,
},
#[error("Invalid number of arguments in \"{name}\", expected {expected}, got {actual}")]
InvalidNumberOfArguments {
token: ErrorToken,
name: FunctionName,
expected: u8,
actual: u8,
},
#[error("Invalid regular expression \"{1}\"")]
InvalidRegularExpression(ErrorToken, String),
#[error("Internal error")]
InternalError(ErrorToken),
#[error("Failed to load module \"{0}\"")]
ModuleLoadError(#[from] ModuleError),
#[error("Runtime error: {1}")]
Runtime(ErrorToken, String),
#[error("Division by zero")]
ZeroDivision(ErrorToken),
#[error("Unexpected break outside of loop")]
UnexpectedBreak(ErrorToken),
#[error("Unexpected continue outside of loop")]
UnexpectedContinue(ErrorToken),
#[error("Environment variable `{1}` not found")]
EnvNotFound(Token, SmolStr),
#[error("Cannot assign to immutable variable \"{1}\"")]
AssignToImmutable(Token, String),
#[error("Undefined variable \"{1}\"")]
UndefinedVariable(Token, String),
#[error("quote() is not allowed in runtime context, it should only appear inside macros")]
QuoteNotAllowedInRuntimeContext(Token),
#[error("unquote() can only be used inside quote()")]
UnquoteNotAllowedOutsideQuote(Token),
#[error("Undefined macro: {0}")]
UndefinedMacro(Ident),
#[error("Macro {macro_name} expects {expected} arguments, got {got}")]
ArityMismatch {
macro_name: Ident,
expected: usize,
got: usize,
},
#[error("Maximum macro recursion depth exceeded")]
RecursionLimit,
#[error("Invalid macro result AST")]
InvalidMacroResultAst(Token),
#[error("Invalid macro result: expected AST value")]
InvalidMacroResult(Token),
#[error("Invalid convert: {1}")]
InvalidConvert(Token, String),
#[error("Destructuring pattern did not match value")]
DestructuringFailed(Token),
}
impl RuntimeError {
#[cold]
pub fn token(&self) -> Option<&Token> {
match self {
RuntimeError::UserDefined { token, .. } => Some(token),
RuntimeError::InvalidBase64String(token, _) => Some(token),
RuntimeError::NotDefined(token, _) => Some(token),
RuntimeError::DateTimeFormatError(token, _) => Some(token),
RuntimeError::IndexOutOfBounds(token, _) => Some(token),
RuntimeError::InvalidDefinition(token, _) => Some(token),
RuntimeError::RecursionError(_) => None,
RuntimeError::InvalidTypes { token, .. } => Some(token),
RuntimeError::InvalidNumberOfArguments { token, .. } => Some(token),
RuntimeError::InvalidRegularExpression(token, _) => Some(token),
RuntimeError::InternalError(token) => Some(token),
RuntimeError::ModuleLoadError(err) => err.token(),
RuntimeError::Runtime(token, _) => Some(token),
RuntimeError::ZeroDivision(token) => Some(token),
RuntimeError::UnexpectedBreak(token) => Some(token),
RuntimeError::UnexpectedContinue(token) => Some(token),
RuntimeError::EnvNotFound(token, _) => Some(token),
RuntimeError::AssignToImmutable(token, _) => Some(token),
RuntimeError::UndefinedVariable(token, _) => Some(token),
RuntimeError::QuoteNotAllowedInRuntimeContext(token) => Some(token),
RuntimeError::UnquoteNotAllowedOutsideQuote(token) => Some(token),
RuntimeError::UndefinedMacro(_) => None,
RuntimeError::ArityMismatch { .. } => None,
RuntimeError::RecursionLimit => None,
RuntimeError::InvalidMacroResultAst(token) => Some(token),
RuntimeError::InvalidMacroResult(token) => Some(token),
RuntimeError::InvalidConvert(token, _) => Some(token),
RuntimeError::DestructuringFailed(token) => Some(token),
}
}
}