From c5f099340bbfa83c2f6cb552e9e7e738bb02c44d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= <tseeker@nocternity.net>
Date: Wed, 4 Jan 2023 07:58:44 +0100
Subject: [PATCH] Errors refactoring - Code compiles.

---
 src/errors.rs                  |  7 +------
 src/interpreter/callable.rs    |  8 ++------
 src/interpreter/environment.rs | 31 +++++++++++++++++++------------
 src/interpreter/functions.rs   |  8 ++------
 src/interpreter/native_fn.rs   |  8 ++------
 src/parser.rs                  |  6 +++++-
 src/scanner.rs                 |  8 +++-----
 7 files changed, 34 insertions(+), 42 deletions(-)

diff --git a/src/errors.rs b/src/errors.rs
index 3766978..6f20f1f 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -114,11 +114,6 @@ pub struct ErrorHandler {
 }
 
 impl ErrorHandler {
-    /// Check whether this handler reported an error.
-    pub fn had_error(&self) -> Option<ErrorKind> {
-        self.had_error
-    }
-
     /// Report an error.
     pub fn report(&mut self, error: SloxError) {
         self.had_error = Some(error.kind);
@@ -131,8 +126,8 @@ impl ErrorHandler {
         match result {
             Ok(v) => Ok(v),
             Err(e) => {
-                self.report(e);
                 let fe = SloxError::stage_failed(e.kind);
+                self.report(e);
                 println!("{fe}");
                 Err(fe)
             }
diff --git a/src/interpreter/callable.rs b/src/interpreter/callable.rs
index 695f300..20ac38e 100644
--- a/src/interpreter/callable.rs
+++ b/src/interpreter/callable.rs
@@ -1,6 +1,6 @@
 use std::{cell::RefCell, fmt::Debug, rc::Rc};
 
-use crate::errors::InterpreterError;
+use crate::errors::SloxResult;
 
 use super::{EnvironmentRef, Value};
 
@@ -11,11 +11,7 @@ pub trait Callable: Debug + ToString {
 
     /// Run the callable in the execution environment with the specified
     /// arguments.
-    fn call(
-        &self,
-        environment: &EnvironmentRef,
-        arguments: Vec<Value>,
-    ) -> Result<Value, InterpreterError>;
+    fn call(&self, environment: &EnvironmentRef, arguments: Vec<Value>) -> SloxResult<Value>;
 }
 
 /// A reference to a callable.
diff --git a/src/interpreter/environment.rs b/src/interpreter/environment.rs
index eeaf8c7..f68d47a 100644
--- a/src/interpreter/environment.rs
+++ b/src/interpreter/environment.rs
@@ -1,6 +1,9 @@
 use std::{cell::RefCell, collections::HashMap, rc::Rc};
 
-use crate::{errors::InterpreterError, tokens::Token};
+use crate::{
+    errors::{ErrorKind, SloxError, SloxResult},
+    tokens::Token,
+};
 
 use super::{native_fn, CallableRef, Value};
 
@@ -45,11 +48,12 @@ impl Environment {
     }
 
     /// Define a new variable.
-    pub fn define(&mut self, name: &Token, value: Variable) -> Result<(), InterpreterError> {
+    pub fn define(&mut self, name: &Token, value: Variable) -> SloxResult<()> {
         if self.values.contains_key(&name.lexeme as &str) {
-            Err(InterpreterError::new(
+            Err(SloxError::with_token(
+                ErrorKind::Runtime,
                 name,
-                &format!("variable '{}' already defined in scope", name.lexeme),
+                format!("variable '{}' already defined in scope", name.lexeme),
             ))
         } else {
             self.values.insert(name.lexeme.clone(), value);
@@ -58,33 +62,36 @@ impl Environment {
     }
 
     /// Get the value of a variable.
-    pub fn get(&self, name: &Token) -> Result<Value, InterpreterError> {
+    pub fn get(&self, name: &Token) -> SloxResult<Value> {
         match self.values.get(&name.lexeme as &str) {
             None => match &self.enclosing {
-                None => Err(InterpreterError::new(
+                None => Err(SloxError::with_token(
+                    ErrorKind::Runtime,
                     name,
-                    &format!("undefined variable '{}'", name.lexeme),
+                    format!("undefined variable '{}'", name.lexeme),
                 )),
                 Some(parent) => parent.borrow().get(name),
             },
-            Some(None) => Err(InterpreterError::new(
+            Some(None) => Err(SloxError::with_token(
+                ErrorKind::Runtime,
                 name,
-                &format!("variable '{}' has not been initialized", name.lexeme),
+                format!("variable '{}' has not been initialized", name.lexeme),
             )),
             Some(Some(value)) => Ok(value.clone()),
         }
     }
 
     /// Assign a value to an existing variable.
-    pub fn assign(&mut self, name: &Token, value: Value) -> Result<(), InterpreterError> {
+    pub fn assign(&mut self, name: &Token, value: Value) -> SloxResult<()> {
         if self.values.contains_key(&name.lexeme as &str) {
             self.values.insert(name.lexeme.clone(), Some(value));
             Ok(())
         } else {
             match &mut self.enclosing {
-                None => Err(InterpreterError::new(
+                None => Err(SloxError::with_token(
+                    ErrorKind::Runtime,
                     name,
-                    &format!("undefined variable '{}'", name.lexeme),
+                    format!("undefined variable '{}'", name.lexeme),
                 )),
                 Some(parent) => parent.borrow_mut().assign(name, value),
             }
diff --git a/src/interpreter/functions.rs b/src/interpreter/functions.rs
index 40d7daa..5fab45c 100644
--- a/src/interpreter/functions.rs
+++ b/src/interpreter/functions.rs
@@ -4,7 +4,7 @@ use itertools::izip;
 
 use crate::{
     ast,
-    errors::InterpreterError,
+    errors::SloxResult,
     interpreter::{Environment, Interpretable, InterpreterFlowControl},
     tokens::Token,
 };
@@ -39,11 +39,7 @@ impl Callable for Function {
         self.params.len()
     }
 
-    fn call(
-        &self,
-        environment: &EnvironmentRef,
-        arguments: Vec<Value>,
-    ) -> Result<Value, InterpreterError> {
+    fn call(&self, environment: &EnvironmentRef, arguments: Vec<Value>) -> SloxResult<Value> {
         assert_eq!(arguments.len(), self.arity());
         let param_env = Environment::create_child(environment);
         for (arg, value) in izip!(self.params.iter(), arguments.into_iter()) {
diff --git a/src/interpreter/native_fn.rs b/src/interpreter/native_fn.rs
index 2a1ee18..988edb1 100644
--- a/src/interpreter/native_fn.rs
+++ b/src/interpreter/native_fn.rs
@@ -4,7 +4,7 @@ use std::{
     time::{SystemTime, UNIX_EPOCH},
 };
 
-use crate::errors::InterpreterError;
+use crate::errors::SloxResult;
 
 use super::{Callable, CallableRef, EnvironmentRef, Value};
 
@@ -20,11 +20,7 @@ impl Callable for Clock {
         0
     }
 
-    fn call(
-        &self,
-        _environment: &EnvironmentRef,
-        _arguments: Vec<Value>,
-    ) -> Result<Value, InterpreterError> {
+    fn call(&self, _environment: &EnvironmentRef, _arguments: Vec<Value>) -> SloxResult<Value> {
         let now = SystemTime::now();
         let since_epoch = now
             .duration_since(UNIX_EPOCH)
diff --git a/src/parser.rs b/src/parser.rs
index 6e66e6c..b5ca6e6 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -517,7 +517,11 @@ impl Parser {
                     value: Box::new(value),
                 })
             } else {
-                self.error("invalid assignment target")
+                Err(SloxError::with_token(
+                    ErrorKind::Parse,
+                    &equals,
+                    "invalid assignment target".to_owned(),
+                ))
             }
         } else {
             Ok(expr)
diff --git a/src/scanner.rs b/src/scanner.rs
index bd64dde..f49c782 100644
--- a/src/scanner.rs
+++ b/src/scanner.rs
@@ -145,7 +145,7 @@ impl Scanner {
             // Identifiers
             ch if ch.is_ascii_alphabetic() => self.identifier(),
             // Anything else is an error
-            ch => return self.error("unexpected character".to_owned()),
+            _ => return self.error("unexpected character".to_owned()),
         }
     }
 
@@ -167,8 +167,7 @@ impl Scanner {
         } else {
             self.current += 1; // Last '"'
             let value = self.get_substring(self.start + 1, self.current - 1);
-            self.add_token(TokenType::String(value));
-            Ok(())
+            self.add_token(TokenType::String(value))
         }
     }
 
@@ -187,8 +186,7 @@ impl Scanner {
         let tok_string = self.get_substring(self.start, self.current);
         match tok_string.parse::<f64>() {
             Ok(value) => {
-                self.add_token(TokenType::Number(value));
-                Ok(())
+                self.add_token(TokenType::Number(value))
             }
             Err(e) => self.error(format!(
                 "Could not parse {} as a floating point number: {:?}",