diff --git a/src/errors.rs b/src/errors.rs index 7d9db21..c67869d 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,25 +1,36 @@ use crate::tokens::{Token, TokenType}; +/// The type of an error. +#[derive(Clone, Copy, Debug)] +pub enum ErrorType { + /// The error occurred while parsing the source code. + Parse, + /// The error occurred while trying to run the program. + Runtime, +} + /// Error handler. Can be used to print error messages; will also retain the /// current error status. #[derive(Default, Debug)] pub struct ErrorHandler { - had_error: bool, + had_error: Option, } impl ErrorHandler { /// Check whether this handler reported an error. - pub fn had_error(&self) -> bool { + pub fn had_error(&self) -> Option { self.had_error } /// Report an error. - pub fn error(&mut self, line: usize, message: &str) { - self.report(line, "", message) + pub fn error(&mut self, err_type: ErrorType, line: usize, message: &str) { + self.report(err_type, line, "", message) } - fn report(&mut self, line: usize, pos: &str, message: &str) { - self.had_error = true; + fn report(&mut self, err_type: ErrorType, line: usize, pos: &str, message: &str) { + if self.had_error.is_none() { + self.had_error = Option::Some(err_type); + } println!("[line {line}] Error{pos}: {message}") } } @@ -49,11 +60,10 @@ impl ParserError { /// Report the error to an error handler. pub fn report(&self, err_hdl: &mut ErrorHandler) { - err_hdl.report(self.line, &self.pos, &self.message); + err_hdl.report(ErrorType::Parse, self.line, &self.pos, &self.message); } } - /// An error that occurred while trying to evaluate the code. #[derive(Debug, Clone)] pub struct InterpreterError { @@ -72,6 +82,6 @@ impl InterpreterError { /// Report the error to an error handler. pub fn report(&self, err_hdl: &mut ErrorHandler) { - err_hdl.report(self.line, "", &self.message); + err_hdl.report(ErrorType::Runtime, self.line, "", &self.message); } } diff --git a/src/main.rs b/src/main.rs index c3e7a7a..7ba4541 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,7 @@ use std::{ }; use ast::AstDumper; -use errors::ErrorHandler; +use errors::{ErrorHandler, ErrorType}; use interpreter::evaluate; use parser::Parser; use scanner::Scanner; @@ -72,13 +72,16 @@ fn main() -> Result<(), ExitCode> { let args: Vec = env::args().skip(1).collect(); let n_args = args.len(); if n_args == 0 { - run_prompt() + run_prompt(); + Ok(()) } else if n_args == 1 { - if run_file(&args[0]).had_error() { - return Err(ExitCode::from(65)); + match run_file(&args[0]).had_error() { + None => Ok(()), + Some(ErrorType::Parse) => Err(ExitCode::from(65)), + Some(ErrorType::Runtime) => Err(ExitCode::from(70)), } } else { println!("Usage: slox [script]"); + Err(ExitCode::from(1)) } - Ok(()) } diff --git a/src/scanner.rs b/src/scanner.rs index 5228002..f9dcf38 100644 --- a/src/scanner.rs +++ b/src/scanner.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use lazy_static::lazy_static; use crate::{ + errors::ErrorType, tokens::{Token, TokenType}, ErrorHandler, }; @@ -135,7 +136,11 @@ impl Scanner { // Identifiers ch if ch.is_ascii_alphabetic() => self.identifier(), // Anything else is an error - ch => err_hdl.error(self.line, &format!("unexpected character {:#?}", ch)), + ch => err_hdl.error( + ErrorType::Parse, + self.line, + &format!("unexpected character {:#?}", ch), + ), } } @@ -153,7 +158,7 @@ impl Scanner { } if self.is_at_end() { - err_hdl.error(self.line, "unterminated string"); + err_hdl.error(ErrorType::Parse, self.line, "unterminated string"); } else { self.current += 1; // Last '"' let value = self.get_substring(self.start + 1, self.current - 1); @@ -177,6 +182,7 @@ impl Scanner { match tok_string.parse::() { Err(e) => { err_hdl.error( + ErrorType::Parse, self.line, &format!( "Could not parse {} as a floating point number: {:?}", @@ -207,7 +213,7 @@ impl Scanner { let mut depth = 1; loop { if self.is_at_end() { - err_hdl.error(self.line, "unterminated block comment"); + err_hdl.error(ErrorType::Parse, self.line, "unterminated block comment"); return; }