about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/error.rs80
-rw-r--r--src/lex/token.rs60
-rw-r--r--src/main.rs18
-rw-r--r--src/parse/macros.rs22
-rw-r--r--src/parse/mod.rs2
-rw-r--r--src/parse/parser.rs107
6 files changed, 248 insertions, 41 deletions
diff --git a/src/error.rs b/src/error.rs
new file mode 100644
index 0000000..7493681
--- /dev/null
+++ b/src/error.rs
@@ -0,0 +1,80 @@
+use crate::{interpret::walker::WalkerError, lex::token::Location, parse::parser::ParserError};
+use colored::Colorize;
+use std::fmt::Display;
+pub struct RHError {
+    pub at: ErrorLocation,
+    pub kind: RHErrorKind,
+}
+
+impl RHError {
+    pub fn hydrate_source<'s>(self, source: &'s str) -> RHErrorWithSource<'s> {
+        RHErrorWithSource {
+            error: self,
+            source,
+        }
+    }
+}
+
+pub enum RHErrorKind {
+    Parse(ParserError),
+    Run(WalkerError),
+}
+
+pub enum ErrorLocation {
+    Specific(Location),
+    Eof,
+}
+
+pub struct RHErrorWithSource<'source> {
+    error: RHError,
+    source: &'source str,
+}
+
+impl Display for RHErrorWithSource<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let (error_title, error_string) = match &self.error.kind {
+            RHErrorKind::Parse(parser_error) => (
+                "Encountered error during parsing",
+                format!("{}", parser_error),
+            ),
+            RHErrorKind::Run(walker_error) => {
+                ("Encountered runtime error", format!("{}", walker_error))
+            }
+        };
+
+        let weird_source_error_msg =
+            "Found error but could not get it's location in source, how does this even happen?";
+
+        let (line_number, line_column, source_line) = match self.error.at {
+            ErrorLocation::Specific(location) => (
+                location.row,
+                location.col,
+                self.source
+                    .lines()
+                    .nth(location.row)
+                    .expect(weird_source_error_msg),
+            ),
+            ErrorLocation::Eof => {
+                let lines = self.source.lines();
+                let (line_count, _) = lines.size_hint();
+                let last_line = lines.last().expect(weird_source_error_msg);
+
+                (line_count, last_line.len(), last_line)
+            }
+        };
+
+        let arrow_pad_len = line_column + 3 + line_number.to_string().len();
+
+        writeln!(f, "{} {}:\n", " Error ".on_red(), error_title)?;
+        writeln!(
+            f,
+            "{}{}",
+            format!("{} | ", line_number).dimmed(),
+            source_line
+        )?;
+        writeln!(f, "{}{}", " ".repeat(arrow_pad_len), "^".red())?;
+        writeln!(f, "{}", error_string)?;
+
+        Ok(())
+    }
+}
diff --git a/src/lex/token.rs b/src/lex/token.rs
index f3dafa7..9d6ded0 100644
--- a/src/lex/token.rs
+++ b/src/lex/token.rs
@@ -1,3 +1,5 @@
+use std::fmt::{write, Display};
+
 #[derive(Clone, Copy, Debug)]
 pub struct Location {
     pub col: usize,
@@ -81,3 +83,61 @@ pub enum TokenKind {
     Unknown(char),
     Eof,
 }
+
+impl Display for TokenKind {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            TokenKind::OpPlus => write!(f, "+"),
+            TokenKind::OpMinus => write!(f, "-"),
+            TokenKind::OpStar => write!(f, "*"),
+            TokenKind::OpSlash => write!(f, "/"),
+            TokenKind::OpEq => write!(f, "=="),
+            TokenKind::OpNot => write!(f, "!"),
+            TokenKind::OpNeq => write!(f, "!="),
+            TokenKind::OpLt => write!(f, "<"),
+            TokenKind::OpGt => write!(f, ">"),
+            TokenKind::OpLte => write!(f, "<="),
+            TokenKind::OpGte => write!(f, ">="),
+            TokenKind::OpAnd => write!(f, "&&"),
+            TokenKind::OpOr => write!(f, "||"),
+            TokenKind::Dot => write!(f, "."),
+            TokenKind::Comma => write!(f, ","),
+            TokenKind::Colon => write!(f, ":"),
+            TokenKind::SemiColon => write!(f, ";"),
+            TokenKind::Assign => write!(f, "="),
+            TokenKind::ConstAssign => write!(f, ":="),
+            TokenKind::Arrow => write!(f, "->"),
+            TokenKind::GroupOpen => write!(f, "("),
+            TokenKind::GroupClose => write!(f, ")"),
+            // {{ Escapes a single {
+            TokenKind::BlockOpen => write!(f, "{{"),
+            TokenKind::BlockClose => write!(f, "}}"),
+            TokenKind::ArrayOpen => write!(f, "["),
+            TokenKind::ArrayClose => write!(f, "]"),
+            TokenKind::Int(v) => write!(f, "{}", v),
+            TokenKind::Float(v) => write!(f, "{}", v),
+            // These are a bit weird, because they aren't direct mappi
+            TokenKind::Str(v) => write!(f, "\"{}\"", v),
+            TokenKind::StrOpen => write!(f, "\""),
+            TokenKind::StrClose => write!(f, "\""),
+            TokenKind::StrEmbed(v) => write!(f, "{{{}}}", v),
+            TokenKind::Ident(v) => write!(f, "{}", v),
+            TokenKind::KeywordFn => write!(f, "fn"),
+            TokenKind::KeywordIf => write!(f, "if"),
+            TokenKind::KeywordElif => write!(f, "elif"),
+            TokenKind::KeywordElse => write!(f, "else"),
+            TokenKind::KeywordLoop => write!(f, "loop"),
+            TokenKind::KeywordForm => write!(f, "form"),
+            TokenKind::KeywordType => write!(f, "type"),
+            TokenKind::KeywordTrue => write!(f, "true"),
+            TokenKind::KeywordFalse => write!(f, "false"),
+            TokenKind::KeywordSelf => write!(f, "self"),
+            TokenKind::KeywordBreak => write!(f, "break"),
+            TokenKind::KeywordContinue => write!(f, "continue"),
+            TokenKind::KeywordReturn => write!(f, "return"),
+            TokenKind::KeywordPrint => write!(f, "print"),
+            TokenKind::Unknown(v) => write!(f, "{}", v),
+            TokenKind::Eof => write!(f, "end of file"),
+        }
+    }
+}
diff --git a/src/main.rs b/src/main.rs
index 0df0483..63f2347 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,10 +1,12 @@
-use std::{env, fs, path::Path};
+use std::{env, fs, path::Path, process::exit};
 
+mod error;
 mod interpret;
 mod lex;
 mod parse;
 mod types;
 
+use error::RHError;
 use lex::lexer::Lexer;
 
 use interpret::walker::Walker;
@@ -27,7 +29,7 @@ fn file(filename: impl AsRef<Path>) {
     let lexer = Lexer::new(&contents);
     let mut parser = Parser::new(lexer);
 
-    let node = parser.parse().expect("Failed parsing.");
+    let node = handle_error(parser.parse(), &contents);
     let mut walker = Walker::root();
 
     walker.walk(&node);
@@ -52,9 +54,19 @@ fn repl() {
         let lexer = Lexer::new(input_buffer.trim());
         let mut parser = Parser::new(lexer);
 
-        let node = parser.expression().expect("Failed parsing.");
+        let node = handle_error(parser.expression(), &input_buffer);
         let result = walker.walk_expression(&node).expect("Failed interpreting.");
 
         println!("🥕: {:?}\n", result);
     }
 }
+
+fn handle_error<T>(result: Result<T, RHError>, source: &str) -> T {
+    match result {
+        Ok(x) => x,
+        Err(error) => {
+            print!("{}", error.hydrate_source(&source));
+            exit(1);
+        }
+    }
+}
diff --git a/src/parse/macros.rs b/src/parse/macros.rs
index 97e0104..9cf995c 100644
--- a/src/parse/macros.rs
+++ b/src/parse/macros.rs
@@ -16,15 +16,15 @@ macro_rules! consume {
             if let Token {kind: $( $kind )|+, ..} = token {
                 Ok(token)
             } else {
-                Err(anyhow!(
-                    // Make a better error message
-                    "Received unexpected token: '{:?}'.",
-                    token.kind
-                ))
+                Err(parser_error(ErrorLocation::Specific(token.location), ParserError::UnexpectedToken {
+                    received: token.kind,
+                    expected: merge_token_names!($($kind),+),
+                }))
             }
         } else {
-            // Here too
-            Err(anyhow!("Expected a token."))
+            Err(parser_error(ErrorLocation::Eof, ParserError::UnexpectedEof {
+                expected: merge_token_names!($($kind),+),
+            }))
         }
     };
 }
@@ -49,3 +49,11 @@ macro_rules! inner {
         }
     };
 }
+
+// TODO: Better names for the tokens.
+#[macro_export]
+macro_rules! merge_token_names {
+    ($($kind:pat_param),+) => {
+        vec![$( stringify!($kind) ),+].join(", ")
+    };
+}
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index e45e6fa..9ddca42 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -1,3 +1,3 @@
 pub mod ast;
 mod macros;
-pub mod parser;
+pub mod parser;
\ No newline at end of file
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
index 8b43a74..76bbab7 100644
--- a/src/parse/parser.rs
+++ b/src/parse/parser.rs
@@ -1,15 +1,17 @@
+use thiserror::Error;
+
 use super::ast::expression::Expression;
 use super::ast::nodes::{ArrayNode, LoopNode, StrNode, UnaryOperator};
 use super::ast::statement::Statement;
 use super::ast::Program;
+use crate::error::{ErrorLocation, RHError, RHErrorKind};
 use crate::lex::lexer::Lexer;
-use crate::lex::token::TokenKind::*;
+use crate::lex::token::TokenKind::{self, *};
 use crate::parse::ast::nodes::{
     ArrayAccessNode, BinaryOperator, BlockNode, CallNode, ConditionalBlock, FnHeader, FnNode,
     IfNode, MemberAccessNode, SimpleLiteral, StrPart, TypedIdentifier,
 };
-use crate::{check, consume, consume_if, inner, lex::token::Token};
-use anyhow::{anyhow, Result};
+use crate::{check, consume, consume_if, inner, lex::token::Token, merge_token_names};
 use std::iter::Peekable;
 
 pub struct Parser<T: Iterator> {
@@ -23,7 +25,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         }
     }
 
-    pub fn parse(&mut self) -> Result<Program> {
+    pub fn parse(&mut self) -> Result<Program, RHError> {
         let mut statements = Vec::new();
 
         while !check!(self, Eof) {
@@ -33,7 +35,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         Ok(Program { statements })
     }
 
-    fn statement(&mut self) -> Result<Statement> {
+    fn statement(&mut self) -> Result<Statement, RHError> {
         let token = self.tokens.peek().expect("Expected token.");
         match token.kind {
             KeywordPrint => self.print_statement(),
@@ -44,14 +46,14 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         }
     }
 
-    fn return_statement(&mut self) -> Result<Statement> {
+    fn return_statement(&mut self) -> Result<Statement, RHError> {
         consume!(self, KeywordReturn)?;
         let expression = self.expression()?;
         consume!(self, SemiColon)?;
         Ok(Statement::Return(expression))
     }
 
-    fn break_statement(&mut self) -> Result<Statement> {
+    fn break_statement(&mut self) -> Result<Statement, RHError> {
         consume!(self, KeywordBreak)?;
         let returned_on_break = if consume_if!(self, SemiColon).is_none() {
             let expression = self.expression()?;
@@ -63,30 +65,30 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         Ok(Statement::Break(returned_on_break))
     }
 
-    fn continue_statement(&mut self) -> Result<Statement> {
+    fn continue_statement(&mut self) -> Result<Statement, RHError> {
         consume!(self, KeywordContinue)?;
         consume!(self, SemiColon)?;
         Ok(Statement::Continue)
     }
 
-    fn print_statement(&mut self) -> Result<Statement> {
+    fn print_statement(&mut self) -> Result<Statement, RHError> {
         consume!(self, KeywordPrint)?;
         let expression = self.expression()?;
         consume!(self, SemiColon)?;
         Ok(Statement::Print(expression))
     }
 
-    fn expression_statement(&mut self) -> Result<Statement> {
+    fn expression_statement(&mut self) -> Result<Statement, RHError> {
         let expression = self.expression()?;
         consume!(self, SemiColon)?;
         Ok(Statement::Expression(expression))
     }
 
-    pub fn expression(&mut self) -> Result<Expression> {
+    pub fn expression(&mut self) -> Result<Expression, RHError> {
         self.assignment_expression()
     }
 
-    fn assignment_expression(&mut self) -> Result<Expression> {
+    fn assignment_expression(&mut self) -> Result<Expression, RHError> {
         // Parse any expressions as l-values for now.
         let left = self.or_expression()?;
 
@@ -103,7 +105,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         }
     }
 
-    fn or_expression(&mut self) -> Result<Expression> {
+    fn or_expression(&mut self) -> Result<Expression, RHError> {
         let mut left = self.and_expression()?;
 
         while let Some(op) = consume_if!(self, OpAnd) {
@@ -119,7 +121,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         Ok(left)
     }
 
-    fn and_expression(&mut self) -> Result<Expression> {
+    fn and_expression(&mut self) -> Result<Expression, RHError> {
         let mut left = self.equality_expression()?;
 
         while let Some(op) = consume_if!(self, OpOr) {
@@ -135,7 +137,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         Ok(left)
     }
 
-    fn equality_expression(&mut self) -> Result<Expression> {
+    fn equality_expression(&mut self) -> Result<Expression, RHError> {
         let mut left = self.comparison_expression()?;
 
         while let Some(op) = consume_if!(self, OpEq | OpNeq) {
@@ -151,7 +153,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         Ok(left)
     }
 
-    fn comparison_expression(&mut self) -> Result<Expression> {
+    fn comparison_expression(&mut self) -> Result<Expression, RHError> {
         let mut left = self.term_expression()?;
 
         while let Some(op) = consume_if!(self, OpGt | OpGte | OpLt | OpLte) {
@@ -167,7 +169,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         Ok(left)
     }
 
-    fn term_expression(&mut self) -> Result<Expression> {
+    fn term_expression(&mut self) -> Result<Expression, RHError> {
         let mut left = self.factor_expression()?;
 
         while let Some(op) = consume_if!(self, OpPlus | OpMinus) {
@@ -183,7 +185,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         Ok(left)
     }
 
-    fn factor_expression(&mut self) -> Result<Expression> {
+    fn factor_expression(&mut self) -> Result<Expression, RHError> {
         let mut left = self.unary_expression()?;
 
         while let Some(op) = consume_if!(self, OpSlash | OpStar) {
@@ -199,7 +201,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         Ok(left)
     }
 
-    fn unary_expression(&mut self) -> Result<Expression> {
+    fn unary_expression(&mut self) -> Result<Expression, RHError> {
         let expression = if check!(self, OpPlus | OpMinus | OpNot) {
             Expression::Unary {
                 op: UnaryOperator::from_token(self.tokens.next().unwrap()),
@@ -212,7 +214,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         Ok(expression)
     }
 
-    fn postfix_expression(&mut self) -> Result<Expression> {
+    fn postfix_expression(&mut self) -> Result<Expression, RHError> {
         let mut left = self.unit_expression()?;
 
         while let Some(token) = consume_if!(self, GroupOpen | ArrayOpen | Dot) {
@@ -255,7 +257,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         Ok(left)
     }
 
-    fn unit_expression(&mut self) -> Result<Expression> {
+    fn unit_expression(&mut self) -> Result<Expression, RHError> {
         if let Some(token) = self.tokens.peek() {
             match token.kind {
                 Int(_) | Float(_) | Str(_) | KeywordTrue | KeywordFalse => {
@@ -275,21 +277,47 @@ impl<T: Iterator<Item = Token>> Parser<T> {
                 KeywordFn => Ok(Expression::FnLiteral(Box::new(self.function()?))),
                 KeywordIf => Ok(Expression::If(Box::new(self.conditional()?))),
                 KeywordLoop => Ok(Expression::Loop(Box::new(self.repeating()?))),
-                _ => Err(anyhow!("Unexpected token: {:?}", token.kind)),
+                _ => Err(parser_error(
+                    ErrorLocation::Specific(token.location),
+                    ParserError::UnexpectedToken {
+                        received: token.kind.clone(),
+                        expected: merge_token_names!(
+                            Int(_),
+                            Float(_),
+                            Str(_),
+                            KeywordTrue,
+                            KeywordFalse,
+                            Ident(_),
+                            StrOpen,
+                            GroupOpen,
+                            BlockOpen,
+                            ArrayOpen,
+                            KeywordFn,
+                            KeywordIf,
+                            KeywordLoop
+                        ),
+                    },
+                )),
             }
         } else {
-            Err(anyhow!("Expected expression."))
+            Err(parser_error(
+                ErrorLocation::Eof,
+                ParserError::UnexpectedEof {
+                    // Well sure this works.
+                    expected: "expression".into(),
+                },
+            ))
         }
     }
 
-    fn group(&mut self) -> Result<Expression> {
+    fn group(&mut self) -> Result<Expression, RHError> {
         consume!(self, GroupOpen)?;
         let expression = self.expression()?;
         consume!(self, GroupClose)?;
         Ok(expression)
     }
 
-    fn array(&mut self) -> Result<ArrayNode> {
+    fn array(&mut self) -> Result<ArrayNode, RHError> {
         consume!(self, ArrayOpen)?;
         let mut elements = Vec::new();
 
@@ -305,7 +333,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         Ok(ArrayNode { elements })
     }
 
-    fn str(&mut self) -> Result<StrNode> {
+    fn str(&mut self) -> Result<StrNode, RHError> {
         let mut parts = Vec::new();
 
         consume!(self, StrOpen)?;
@@ -333,7 +361,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         Ok(StrNode { parts })
     }
 
-    fn function(&mut self) -> Result<FnNode> {
+    fn function(&mut self) -> Result<FnNode, RHError> {
         consume!(self, KeywordFn)?;
 
         let header = {
@@ -382,7 +410,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         Ok(FnNode { header, body })
     }
 
-    fn conditional(&mut self) -> Result<IfNode> {
+    fn conditional(&mut self) -> Result<IfNode, RHError> {
         consume!(self, KeywordIf)?;
 
         let mut conditionals = Vec::new();
@@ -418,7 +446,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         })
     }
 
-    fn repeating(&mut self) -> Result<LoopNode> {
+    fn repeating(&mut self) -> Result<LoopNode, RHError> {
         consume!(self, KeywordLoop)?;
 
         let condition = if consume_if!(self, KeywordIf).is_some() {
@@ -432,7 +460,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         Ok(LoopNode { body, condition })
     }
 
-    fn generic_block(&mut self) -> Result<BlockNode> {
+    fn generic_block(&mut self) -> Result<BlockNode, RHError> {
         consume!(self, BlockOpen)?;
 
         let mut statements = Vec::new();
@@ -467,3 +495,22 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         })
     }
 }
+
+fn parser_error(at: ErrorLocation, parse_error: ParserError) -> RHError {
+    RHError {
+        at,
+        kind: RHErrorKind::Parse(parse_error),
+    }
+}
+
+#[derive(Error, Debug)]
+pub enum ParserError {
+    #[error("Received unexpected '{received}', expected: {expected}.'")]
+    UnexpectedToken {
+        received: TokenKind,
+        // Stringified expected tokens
+        expected: String,
+    },
+    #[error("Unexpected end of file, expected: {expected}")]
+    UnexpectedEof { expected: String },
+}