From 933b6e052d3348a9f35b977328142eaa42edaa1c Mon Sep 17 00:00:00 2001 From: Seymur Bagirov Date: Sat, 15 Feb 2025 14:00:16 +0400 Subject: [PATCH] refactor(function): improve error handling for native functions --- src/interpreter.rs | 31 ++++++++++++++++++++----------- src/lib.rs | 4 +--- src/parser.rs | 2 +- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/interpreter.rs b/src/interpreter.rs index c3ceceb..8ac4582 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -16,7 +16,7 @@ type InterpreterResult = Result; #[derive(Debug)] pub struct RuntimeError { - pub token: Option, + 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 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)) }; diff --git a/src/lib.rs b/src/lib.rs index 1b474ca..c570929 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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); } diff --git a/src/parser.rs b/src/parser.rs index d56c021..12427a8 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -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 }) }