Browse Source

start to thread MatzoError

Getty Ritter 1 year ago
parent
commit
6882a52f76
4 changed files with 85 additions and 32 deletions
  1. 4 0
      src/ast.rs
  2. 24 4
      src/interp.rs
  3. 55 28
      src/lexer.rs
  4. 2 0
      src/lib.rs

+ 4 - 0
src/ast.rs

@@ -77,6 +77,10 @@ impl ASTArena {
         FileRef { idx }
     }
 
+    pub fn get_file(&self, file: FileRef) -> &str {
+        &self.files[file.idx]
+    }
+
     pub fn get_line(&self, file: FileRef, span: Span) -> String {
         let mut line_number = 1;
         let mut start_of_line = 0;

+ 24 - 4
src/interp.rs

@@ -1,4 +1,6 @@
 use crate::ast::*;
+use crate::errors::MatzoError;
+use crate::lexer;
 use crate::lexer::Span;
 use crate::rand::*;
 
@@ -259,15 +261,33 @@ impl State {
     /// Evaluate this string as a standalone program, writing the
     /// results to stdout.
     pub fn run(&self, src: &str) -> Result<(), Error> {
-        let lexed = crate::lexer::tokens(src);
         let file = self.ast.borrow_mut().add_file(src.to_string());
+        if let Err(mtz) = self.run_file(src, file) {
+            let mut buf = String::new();
+            buf.push_str(&mtz.message);
+            buf.push('\n');
+            buf.push_str(&self.ast.borrow().get_line(file, mtz.span));
+            for ctx in mtz.context {
+                buf.push('\n');
+                buf.push_str(&ctx.message);
+                buf.push_str(&self.ast.borrow().get_line(file, ctx.span));
+            }
+            bail!("{}", buf);
+        }
+        Ok(())
+    }
+
+    fn run_file(&self, src: &str, file: FileRef) -> Result<(), MatzoError> {
+        let lexed = crate::lexer::tokens(src);
         let stmts = self
             .parser
-            .parse(&mut self.ast.borrow_mut(), file, lexed)
-            .map_err(|err| anyhow!("Got {:?}", err))?;
+            .parse(&mut self.ast.borrow_mut(), file, lexed);
+        let stmts = stmts
+            .map_err(MatzoError::from_parse_error)?;
         let mut stdout = io::stdout();
         for stmt in stmts {
-            self.execute(&stmt, &mut stdout)?;
+            self.execute(&stmt, &mut stdout)
+                .map_err(|err| MatzoError::new(Span::empty(), format!("{:?}", err)))?;
         }
         Ok(())
     }

+ 55 - 28
src/lexer.rs

@@ -1,29 +1,5 @@
 use logos::{Lexer, Logos};
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct FileRef {
-    pub idx: usize,
-}
-
-/// A location in a source file
-#[derive(Debug, Clone, Copy)]
-pub struct Span {
-    pub start: u32,
-    pub end: u32,
-}
-
-impl Span {
-    pub fn empty() -> Span {
-        Span {
-            start: u32::MAX,
-            end: u32::MAX,
-        }
-    }
-
-    pub fn exists(&self) -> bool {
-        self.start != u32::MAX && self.end != u32::MAX
-    }
-}
+pub use crate::core::{Span, FileRef};
 
 #[derive(Debug, Clone, Copy)]
 pub struct Located<T> {
@@ -159,12 +135,58 @@ pub enum Token<'a> {
     Error,
 }
 
+impl<'a> Token<'a> {
+    pub fn token_name(&self) -> String {
+        match self {
+            Token::Var(v) => format!("variable `{}`", v),
+            Token::Atom(a) => format!("atom `{}`", a),
+            Token::Num(n) => format!("number `{}`", n),
+            Token::Str(s) => format!("string `{}`", s),
+
+            Token::LAngle => "`<`".to_string(),
+            Token::RAngle => "`>`".to_string(),
+
+            Token::LPar => "`(`".to_string(),
+            Token::RPar => "`)`".to_string(),
+
+            Token::LCurl => "`{`".to_string(),
+            Token::RCurl => "`}`".to_string(),
+
+            Token::LBrac => "`[`".to_string(),
+            Token::RBrac => "`]`".to_string(),
+
+            Token::Pipe => "`|`".to_string(),
+
+            Token::Colon => "`:`".to_string(),
+            Token::Comma => "`,`".to_string(),
+            Token::Semi => "`;`".to_string(),
+
+            Token::Dot => "`.`".to_string(),
+            Token::Underscore => "`_`".to_string(),
+            Token::DotDot => "`..`".to_string(),
+            Token::Arrow => "`=>`".to_string(),
+            Token::Assn => "`:=`".to_string(),
+
+            Token::LitAssn => "`::=`".to_string(),
+            Token::Puts => "`puts`".to_string(),
+            Token::Case => "`case`".to_string(),
+            Token::Let => "`let`".to_string(),
+            Token::In => "`in`".to_string(),
+            Token::Fix => "`fix`".to_string(),
+
+            Token::Error => "error".to_string(),
+        }
+    }
+}
+
 #[derive(Debug)]
-pub struct LexerError;
+pub struct LexerError {
+    pub range: Span,
+}
 
 impl std::fmt::Display for LexerError {
     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
-        write!(f, "LexerError")
+        write!(f, "LexerError({}..{})", self.range.start, self.range.end)
     }
 }
 
@@ -174,7 +196,12 @@ pub fn tokens(source: &str) -> impl Iterator<Item = Spanned<Token<'_>, usize, Le
     Token::lexer(source)
         .spanned()
         .map(move |(token, range)| match token {
-            Token::Error => Err(LexerError),
+            Token::Error => Err(LexerError {
+                range: Span {
+                    start: range.start as u32,
+                    end: range.end as u32,
+                },
+            }),
             token => Ok((range.start, token, range.end)),
         })
 }

+ 2 - 0
src/lib.rs

@@ -3,6 +3,8 @@ extern crate lalrpop_util;
 
 pub mod ast;
 pub mod builtins;
+pub mod core;
+pub mod errors;
 pub mod interp;
 pub mod lexer;
 pub mod rand;