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)]
pub struct RuntimeError {
pub token: Option<Token>,
pub token: Token,
pub message: String,
}
@ -28,14 +28,7 @@ pub struct InterpreterEnvironment {
impl RuntimeError {
pub fn new(token: &Token, message: String) -> Self {
RuntimeError {
token: Some(token.clone()),
message: message.to_string(),
}
}
pub fn no_token(message: String) -> Self {
RuntimeError {
token: None,
token: token.clone(),
message: message.to_string(),
}
}
@ -43,6 +36,7 @@ impl RuntimeError {
pub enum InterpreterSignal {
RuntimeError(RuntimeError),
NativeRuntimeError { msg: String },
Break,
Return(LiteralType),
}
@ -64,6 +58,7 @@ impl From<InterpreterSignal> for RuntimeError {
InterpreterSignal::RuntimeError(runtime_error) => runtime_error,
InterpreterSignal::Break => 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(
paren,
@ -358,7 +363,11 @@ fn read_input_function() -> NativeFunction {
let mut buf = String::new();
io::stdin()
.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))
};

View File

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

View File

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