refactor(function): improve error handling for native functions

This commit is contained in:
Seymur Bagirov 2025-02-15 14:00:16 +04:00
parent 42cf268899
commit 933b6e052d
3 changed files with 22 additions and 15 deletions

View File

@ -16,7 +16,7 @@ type InterpreterResult = Result<LiteralType, InterpreterSignal>;
#[derive(Debug)] #[derive(Debug)]
pub struct RuntimeError { pub struct RuntimeError {
pub token: Option<Token>, pub token: Token,
pub message: String, pub message: String,
} }
@ -28,14 +28,7 @@ pub struct InterpreterEnvironment {
impl RuntimeError { impl RuntimeError {
pub fn new(token: &Token, message: String) -> Self { pub fn new(token: &Token, message: String) -> Self {
RuntimeError { RuntimeError {
token: Some(token.clone()), token: token.clone(),
message: message.to_string(),
}
}
pub fn no_token(message: String) -> Self {
RuntimeError {
token: None,
message: message.to_string(), message: message.to_string(),
} }
} }
@ -43,6 +36,7 @@ impl RuntimeError {
pub enum InterpreterSignal { pub enum InterpreterSignal {
RuntimeError(RuntimeError), RuntimeError(RuntimeError),
NativeRuntimeError { msg: String },
Break, Break,
Return(LiteralType), Return(LiteralType),
} }
@ -64,6 +58,7 @@ impl From<InterpreterSignal> for RuntimeError {
InterpreterSignal::RuntimeError(runtime_error) => runtime_error, InterpreterSignal::RuntimeError(runtime_error) => runtime_error,
InterpreterSignal::Break => panic!("Not a runtime error"), InterpreterSignal::Break => panic!("Not a runtime error"),
InterpreterSignal::Return(_) => panic!("Not a runtime error"), InterpreterSignal::Return(_) => panic!("Not a runtime error"),
InterpreterSignal::NativeRuntimeError { .. } => panic!("Not a runtime error"),
} }
} }
} }
@ -270,7 +265,17 @@ fn evaluate(expr: &Expr, environment: &InterpreterEnvironment) -> InterpreterRes
), ),
))? ))?
} }
Ok(function.call(&arguments, environment)?) let call_result = function.call(&arguments, environment).map_err(|x| match x {
InterpreterSignal::NativeRuntimeError { msg } => {
InterpreterSignal::RuntimeError(RuntimeError {
token: paren.clone(),
message: msg,
})
}
_ => x,
});
Ok(call_result?)
} }
_ => Err(RuntimeError::new( _ => Err(RuntimeError::new(
paren, paren,
@ -358,7 +363,11 @@ fn read_input_function() -> NativeFunction {
let mut buf = String::new(); let mut buf = String::new();
io::stdin() io::stdin()
.read_line(&mut buf) .read_line(&mut buf)
.map_err(|_| RuntimeError::no_token("Error reading from stdin".to_string()))?; .map_err(|_| InterpreterSignal::NativeRuntimeError {
msg: "Error reading from stdin".to_string(),
})?;
buf.truncate(buf.trim_end().len());
Ok(LiteralType::String(buf)) Ok(LiteralType::String(buf))
}; };

View File

@ -107,7 +107,5 @@ fn error(ParseError { token, msg }: &ParseError) {
} }
fn runtime_error(err: &RuntimeError) { fn runtime_error(err: &RuntimeError) {
if let Some(token) = &err.token { eprintln!("{}\n[line {}]", err.message, err.token.line);
eprintln!("{}\n[line {}]", err.message, token.line);
}
} }

View File

@ -276,7 +276,7 @@ impl Parser<'_> {
None None
}; };
self.consume(TokenType::Semicolon, "Expect ';' after return value."); self.consume(TokenType::Semicolon, "Expect ';' after return value.")?;
Ok(Stmt::Return { keyword, value }) Ok(Stmt::Return { keyword, value })
} }