use std::fmt;
#[derive(Debug, Clone)]
pub struct SourceLocation {
pub line: usize,
pub column: usize,
}
impl fmt::Display for SourceLocation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "line {}, column {}", self.line, self.column)
}
}
#[derive(Debug, thiserror::Error)]
pub enum RobinPathError {
#[error("Lexer error at {location}: {message}")]
LexerError {
message: String,
location: SourceLocation,
},
#[error("Parse error at {location}: {message}")]
ParseError {
message: String,
location: SourceLocation,
},
#[error("Runtime error: {message}")]
RuntimeError { message: String },
#[error("Runtime error at {location}: {message}")]
RuntimeErrorAt {
message: String,
location: SourceLocation,
},
#[error("Type error: {message}")]
TypeError { message: String },
#[error("Unknown function: {name}")]
UnknownFunction {
name: String,
suggestions: Vec<String>,
},
#[error("Constant reassignment: cannot reassign constant '{name}'")]
ConstantReassignment { name: String },
#[error("Recursion limit exceeded for function '{name}' (max depth: {max_depth})")]
RecursionLimit { name: String, max_depth: usize },
#[error("Assertion failed: {message}")]
AssertionError { message: String },
#[error("Internal error: {0}")]
Internal(String),
}
impl RobinPathError {
pub fn lexer(message: impl Into<String>, line: usize, column: usize) -> Self {
Self::LexerError {
message: message.into(),
location: SourceLocation { line, column },
}
}
pub fn parse(message: impl Into<String>, line: usize, column: usize) -> Self {
Self::ParseError {
message: message.into(),
location: SourceLocation { line, column },
}
}
pub fn runtime(message: impl Into<String>) -> Self {
Self::RuntimeError {
message: message.into(),
}
}
pub fn runtime_at(message: impl Into<String>, line: usize, column: usize) -> Self {
Self::RuntimeErrorAt {
message: message.into(),
location: SourceLocation { line, column },
}
}
pub fn type_error(message: impl Into<String>) -> Self {
Self::TypeError {
message: message.into(),
}
}
pub fn unknown_function(name: impl Into<String>, suggestions: Vec<String>) -> Self {
Self::UnknownFunction {
name: name.into(),
suggestions,
}
}
}