diff --git a/src/interpreter/interpretable.rs b/src/interpreter/interpretable.rs
index 131f5c5..7f6c5c8 100644
--- a/src/interpreter/interpretable.rs
+++ b/src/interpreter/interpretable.rs
@@ -2,28 +2,16 @@ use std::{cell::RefCell, rc::Rc};
 
 use crate::{
     ast,
-    errors::{ErrorHandler, SloxError},
-    interpreter::{Environment, EnvironmentRef, Value},
+    errors::{ErrorKind, SloxError, SloxResult},
+    interpreter::{functions::Function, Environment, EnvironmentRef, Value},
     resolver::ResolvedVariables,
     tokens::{Token, TokenType},
 };
 
-use super::functions::Function;
-
 /// Evaluate an interpretable, returning its value.
-pub fn evaluate(
-    err_hdl: &mut ErrorHandler,
-    ast: &dyn Interpretable,
-    vars: ResolvedVariables,
-) -> Result<Value, SloxError> {
+pub fn evaluate(ast: &dyn Interpretable, vars: ResolvedVariables) -> SloxResult<Value> {
     let env = Rc::new(RefCell::new(Environment::default()));
-    match ast.interpret(&env) {
-        Ok(v) => Ok(v.result()),
-        Err(e) => {
-            err_hdl.report(e);
-            Err(e)
-        }
-    }
+    ast.interpret(&env).map(|v| v.result())
 }
 
 /* ------- *
@@ -43,7 +31,7 @@ pub enum InterpreterFlowControl {
 impl InterpreterFlowControl {
     /// Return the result's value. If the flow control value does not represent
     /// a result, panic.
-    pub(crate) fn result(self) -> Value {
+    pub fn result(self) -> Value {
         match self {
             Self::Result(v) => v,
             other => panic!("Result expected, {:?} found instead", other),
@@ -52,7 +40,7 @@ impl InterpreterFlowControl {
 
     /// Check whether a flow control value contains actual flow control
     /// information.
-    pub(crate) fn is_flow_control(&self) -> bool {
+    pub fn is_flow_control(&self) -> bool {
         matches!(self, Self::Break(_) | Self::Continue(_) | Self::Return(_))
     }
 }
@@ -70,13 +58,22 @@ impl From<Value> for InterpreterFlowControl {
 }
 
 /// A result returned by some part of the interpreter.
-pub type InterpreterResult = Result<InterpreterFlowControl, SloxError>;
+pub type InterpreterResult = SloxResult<InterpreterFlowControl>;
 
 /// An Interpretable can be evaluated and will return a value.
 pub trait Interpretable {
     fn interpret(&self, environment: &EnvironmentRef) -> InterpreterResult;
 }
 
+/// Generate an error with a static message.
+fn error<T>(token: &Token, message: &str) -> SloxResult<T> {
+    Err(SloxError::with_token(
+        ErrorKind::Runtime,
+        token,
+        message.to_owned(),
+    ))
+}
+
 /* ----------------------------- *
  * INTERPRETER FOR PROGRAM NODES *
  * ----------------------------- */
@@ -331,12 +328,12 @@ impl ast::ExprNode {
             TokenType::Plus => match (left_value, right_value) {
                 (Value::Number(a), Value::Number(b)) => Ok(Value::Number(a + b).into()),
                 (Value::String(a), Value::String(b)) => Ok(Value::String(a + &b).into()),
-                _ => Err(SloxError::new(operator, "type error")),
+                _ => error(operator, "type error"),
             },
 
             TokenType::Minus => match (left_value, right_value) {
                 (Value::Number(a), Value::Number(b)) => Ok(Value::Number(a - b).into()),
-                _ => Err(SloxError::new(operator, "type error")),
+                _ => error(operator, "type error"),
             },
 
             TokenType::Star => match (left_value, right_value) {
@@ -344,38 +341,38 @@ impl ast::ExprNode {
                 (Value::String(a), Value::Number(b)) => {
                     Ok(Value::String(a.repeat(b as usize)).into())
                 }
-                _ => Err(SloxError::new(operator, "type error")),
+                _ => error(operator, "type error"),
             },
 
             TokenType::Slash => match (left_value, right_value) {
                 (Value::Number(a), Value::Number(b)) => {
                     if b == 0. {
-                        Err(SloxError::new(operator, "division by zero"))
+                        error(operator, "division by zero")
                     } else {
                         Ok(Value::Number(a / b).into())
                     }
                 }
-                _ => Err(SloxError::new(operator, "type error")),
+                _ => error(operator, "type error"),
             },
 
             TokenType::Greater => match (left_value, right_value) {
                 (Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a > b).into()),
-                _ => Err(SloxError::new(operator, "type error")),
+                _ => error(operator, "type error"),
             },
 
             TokenType::GreaterEqual => match (left_value, right_value) {
                 (Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a >= b).into()),
-                _ => Err(SloxError::new(operator, "type error")),
+                _ => error(operator, "type error"),
             },
 
             TokenType::Less => match (left_value, right_value) {
                 (Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a < b).into()),
-                _ => Err(SloxError::new(operator, "type error")),
+                _ => error(operator, "type error"),
             },
 
             TokenType::LessEqual => match (left_value, right_value) {
                 (Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a <= b).into()),
-                _ => Err(SloxError::new(operator, "type error")),
+                _ => error(operator, "type error"),
             },
 
             TokenType::EqualEqual => Ok(Value::Boolean(left_value == right_value).into()),
@@ -401,7 +398,7 @@ impl ast::ExprNode {
                 if let Value::Number(n) = right_value {
                     Ok(Value::Number(-n).into())
                 } else {
-                    Err(SloxError::new(operator, "number expected"))
+                    error(operator, "number expected")
                 }
             }
 
@@ -446,9 +443,10 @@ impl ast::ExprNode {
         if let Value::Callable(callable_ref) = &callee {
             let callable = callable_ref.borrow();
             if callable.arity() != arg_values.len() {
-                Err(SloxError::new(
+                Err(SloxError::with_token(
+                    ErrorKind::Runtime,
                     right_paren,
-                    &format!(
+                    format!(
                         "expected {} arguments, found {}",
                         arg_values.len(),
                         callable.arity()
@@ -458,10 +456,7 @@ impl ast::ExprNode {
                 Ok(callable.call(environment, arg_values)?.into())
             }
         } else {
-            Err(SloxError::new(
-                right_paren,
-                "can only call functions and classes",
-            ))
+            error(right_paren, "can only call functions and classes")
         }
     }
 }
diff --git a/src/interpreter/value.rs b/src/interpreter/value.rs
index f337910..f27198b 100644
--- a/src/interpreter/value.rs
+++ b/src/interpreter/value.rs
@@ -1,4 +1,4 @@
-use std::{cell::RefCell, rc::Rc};
+use std::{cell::RefCell, fmt::Display, rc::Rc};
 
 use super::Callable;
 
@@ -24,6 +24,18 @@ impl PartialEq for Value {
     }
 }
 
+impl Display for Value {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Value::Nil => f.write_str("nil"),
+            Value::Boolean(b) => b.fmt(f),
+            Value::String(s) => s.fmt(f),
+            Value::Number(n) => n.fmt(f),
+            Value::Callable(c) => f.write_str(&c.borrow().to_string()),
+        }
+    }
+}
+
 impl Value {
     /// Check whether a value is truthy or not.
     pub fn is_truthy(&self) -> bool {
diff --git a/src/main.rs b/src/main.rs
index 9cb5f4b..e624fdd 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -15,7 +15,7 @@ use std::{
 #[cfg(feature = "dump_ast")]
 use ast::AstDumper;
 use errors::{ErrorHandler, SloxResult};
-use interpreter::evaluate;
+use interpreter::{evaluate, Value};
 use parser::Parser;
 use resolver::resolve_variables;
 use scanner::Scanner;
@@ -36,9 +36,12 @@ fn run(source: String) -> SloxResult<()> {
     #[cfg(feature = "dump_ast")]
     println!("AST generated ! {}", ast.dump());
 
-    let resolved_vars = error_handler.final_error(resolve_variables(&ast))?;
-    error_handler.final_error(evaluate(&ast, resolved_vars));
-
+    let resolved_vars = error_handler.report_or_continue(resolve_variables(&ast))?;
+    let value = error_handler.report_or_continue(evaluate(&ast, resolved_vars))?;
+    match value {
+        Value::Nil => (),
+        _ => println!("{value}"),
+    }
     Ok(())
 }