use std::fmt; use std::fmt::Display; use std::io; #[cfg(feature = "compiler")] use std::num::ParseIntError; #[cfg(feature = "compiler")] use super::compiler::ArithmeticOp; #[cfg(feature = "compiler")] use super::vm::Position; use super::vm::VariableType; #[derive(Debug)] pub enum GenericError { StdIOError(io::Error), CorruptedBytecode, #[cfg(feature = "compiler")] SyntaxError(SyntaxError), #[cfg(feature = "compiler")] CompilerError(CompilerError), } impl From for GenericError { fn from(error: io::Error) -> Self { Self::StdIOError(error) } } #[cfg(feature = "compiler")] impl From for GenericError { fn from(error: SyntaxError) -> Self { Self::SyntaxError(error) } } #[cfg(feature = "compiler")] impl From for GenericError { fn from(error: CompilerError) -> Self { Self::CompilerError(error) } } impl Display for GenericError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let text = match self { GenericError::StdIOError(err) => format!("IO Error: {}", err), GenericError::CorruptedBytecode => { "Failed to read bytecode. Bytecode might be corrupted.".to_string() } #[cfg(feature = "compiler")] GenericError::SyntaxError(err) => format!("Syntax Error: {}", err), #[cfg(feature = "compiler")] GenericError::CompilerError(err) => format!("Compiler Error: {}", err), }; write!(f, "{}", text) } } #[derive(Debug)] #[cfg(feature = "compiler")] pub enum SyntaxError { #[allow(dead_code)] Fatal, ExpectedToken(Position, char), ExpectedExpression(Position, Option>), ExpectedIdent(Position), ExpectedStatement(Position, Option>), ExpectedPattern(Position), } #[cfg(feature = "compiler")] impl SyntaxError { fn from_opt(from: &Option>) -> String { if let Some(err) = from { format!("\n {}", err) } else { String::new() } } } #[cfg(feature = "compiler")] impl Display for SyntaxError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let text = match self { SyntaxError::Fatal => "Fatal error".to_string(), SyntaxError::ExpectedToken(pos, c) => format!("Expected token '{}' at {}", c, pos), SyntaxError::ExpectedExpression(pos, err) => format!( "Expected expression at {}{}", pos, SyntaxError::from_opt(err) ), SyntaxError::ExpectedIdent(pos) => format!("Expected ident at {}", pos), SyntaxError::ExpectedStatement(pos, err) => format!( "Expected statement at {}{}", pos, SyntaxError::from_opt(err) ), SyntaxError::ExpectedPattern(pos) => format!("Expected pattern at {}", pos), }; write!(f, "{}", text) } } #[derive(Debug)] #[cfg(feature = "compiler")] pub enum CompilerError { #[allow(dead_code)] Fatal, VariableExists(Position, String), VariableNotExists(Position, String), InvalidScopeExit(Position), LetFailed(Position, Box), CanNotAssignVoidType, FunctionNotFound(Position, String, Vec), ParseIntError(ParseIntError), ArithmeticExpressionFailed(Position, Box), InvalidArithmeticOperation(ArithmeticOp), } #[cfg(feature = "compiler")] impl Display for CompilerError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let text = match self { CompilerError::Fatal => "Fatal error".to_string(), CompilerError::VariableExists(pos, name) => { format!("Variable '{}' already exists, re-assign at {}", pos, name) } CompilerError::VariableNotExists(pos, name) => { format!("Variable '{}' does not exist, at {}", name, pos) } CompilerError::InvalidScopeExit(pos) => { format!("Attempted to escape a scope invalidly at {}", pos) } CompilerError::LetFailed(pos, error) => { format!("Let statement failed at {}:\n {}", pos, error) } CompilerError::CanNotAssignVoidType => "Can not assign void type here".to_string(), CompilerError::FunctionNotFound(pos, name, params) => format!( "Function with signature {}{} not found at {}", name, ParamList(params.clone()), pos ), CompilerError::ParseIntError(err) => format!("Failed to parse integer value: {}", err), CompilerError::ArithmeticExpressionFailed(pos, err) => { format!("Arithmetic expression failed at {}:\n {}", pos, err) } CompilerError::InvalidArithmeticOperation(op) => { let text = match op { ArithmeticOp::Add(t1, t2, _) => { format!("{} + {}", t1.to_string(), t2.to_string()) } ArithmeticOp::Subtract(t1, t2, _) => { format!("{} - {}", t1.to_string(), t2.to_string()) } ArithmeticOp::Mult(t1, t2, _) => { format!("{} * {}", t1.to_string(), t2.to_string()) } ArithmeticOp::Pow(t1, t2, _) => { format!("{} ** {}", t1.to_string(), t2.to_string()) } ArithmeticOp::Div(t1, t2, _) => { format!("{} / {}", t1.to_string(), t2.to_string()) } ArithmeticOp::Mod(t1, t2, _) => { format!("{} % {}", t1.to_string(), t2.to_string()) } }; format!("Invalid arithmetic operation: {}", text) } }; write!(f, "{}", text) } } struct ParamList(Vec); impl Display for ParamList { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut text = String::new(); text += "("; for (idx, vtype) in self.0.iter().enumerate() { if idx > 0 { text += ", "; } text += &vtype.to_string(); } text += ")"; write!(f, "{}", text) } } #[derive(Debug)] pub enum RuntimePanic { #[allow(dead_code)] Fatal, InvalidCommandIdx(usize), ScopeStackUnderflow, StackUnderflow, StackOverflow, RegistryNotDefined, InvalidHeapAddress, ValueNotInitialized, InvalidTypeAssign, InvalidFuncAddress, AttemptedInvalidArithmeticOperation, }