aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCody <cody@codyq.dev>2023-06-27 02:25:09 -0500
committerCody <cody@codyq.dev>2023-06-27 02:25:09 -0500
commit9f7f0f925f9304ac46499caf0fef245083a78828 (patch)
tree188fc3ac91de2e90581a3e193b5a85b3ebb3a4b4
parent29bdd10ee3621ed875bfa34a0faa42c35a1e39ed (diff)
downloadsloth-9f7f0f925f9304ac46499caf0fef245083a78828.tar.gz
Slightly improve error reporting
-rw-r--r--examples/hello.sloth1
-rw-r--r--sloth/src/lexer.rs81
-rw-r--r--sloth/src/main.rs13
-rw-r--r--sloth/src/parser/expr.rs2
-rw-r--r--sloth/src/parser/mod.rs26
-rw-r--r--sloth/src/parser/stmt.rs4
6 files changed, 115 insertions, 12 deletions
diff --git a/examples/hello.sloth b/examples/hello.sloth
index 619a5a0..8abb65c 100644
--- a/examples/hello.sloth
+++ b/examples/hello.sloth
@@ -1,5 +1,4 @@
fn main() Int {
print("Hello World\n");
- var x: F = 2;
return 0;
}
diff --git a/sloth/src/lexer.rs b/sloth/src/lexer.rs
index 20379a3..01eeb46 100644
--- a/sloth/src/lexer.rs
+++ b/sloth/src/lexer.rs
@@ -2,6 +2,7 @@
//! TODO: Lexing Regex Literals
+use std::fmt::Display;
use std::str::Chars;
use thiserror::Error;
@@ -112,6 +113,86 @@ pub enum TokenType {
Error(LexerError),
}
+impl Display for TokenType {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let s = match self {
+ TokenType::DocComment => "##",
+ TokenType::Comment => "#",
+ TokenType::OpeningParen => "(",
+ TokenType::ClosingParen => ")",
+ TokenType::OpeningBracket => "[",
+ TokenType::ClosingBracket => "]",
+ TokenType::OpeningBrace => "{",
+ TokenType::ClosingBrace => "}",
+ TokenType::Plus => "+",
+ TokenType::PlusPlus => "++",
+ TokenType::Minus => "-",
+ TokenType::Star => "*",
+ TokenType::StarStar => "**",
+ TokenType::Slash => "/",
+ TokenType::Perc => "%",
+ TokenType::Tilde => "~",
+ TokenType::PlusEq => "+=",
+ TokenType::PlusPlusEq => "++=",
+ TokenType::MinusEq => "-=",
+ TokenType::StarEq => "*=",
+ TokenType::StarStarEq => "**=",
+ TokenType::SlashEq => "/=",
+ TokenType::PercEq => "%=",
+ TokenType::TildeEq => "~=",
+ TokenType::Amp => "&",
+ TokenType::AmpAmp => "&&",
+ TokenType::Pipe => "|",
+ TokenType::PipePipe => "||",
+ TokenType::Caret => "^",
+ TokenType::Eq => "=",
+ TokenType::EqEq => "==",
+ TokenType::Bang => "!",
+ TokenType::BangBang => "!!",
+ TokenType::BangEq => "!=",
+ TokenType::Lt => "<",
+ TokenType::LtLt => "<<",
+ TokenType::LtEq => "<=",
+ TokenType::LtLtEq => "<<=",
+ TokenType::Gt => ">",
+ TokenType::GtGt => ">>",
+ TokenType::GtEq => ">=",
+ TokenType::GtGtEq => ">>=",
+ TokenType::Comma => ",",
+ TokenType::Question => "?",
+ TokenType::QuestionDot => "?.",
+ TokenType::QuestionQuestion => "??",
+ TokenType::Dot => ".",
+ TokenType::DotDot => "..",
+ TokenType::Colon => ":",
+ TokenType::ColonColon => "::",
+ TokenType::SemiColon => ";",
+ TokenType::Arrow => "->",
+ TokenType::FatArrow => "=>",
+ TokenType::Const => "const",
+ TokenType::Val => "val",
+ TokenType::Var => "var",
+ TokenType::Fn => "fn",
+ TokenType::Return => "return",
+ TokenType::If => "if",
+ TokenType::Else => "else",
+ TokenType::While => "while",
+ TokenType::For => "for",
+ TokenType::In => "in",
+ TokenType::Loop => "loop",
+ TokenType::Break => "break",
+ TokenType::Continue => "continue",
+ TokenType::As => "as",
+ TokenType::Foreign => "foreign",
+ TokenType::Literal(_) => "literal",
+ TokenType::Identifier(_) => "identifier",
+ TokenType::Error(_) => "error",
+ };
+
+ write!(f, "{s}")
+ }
+}
+
#[derive(Debug, Clone, PartialEq)]
pub enum Literal {
Integer(i32),
diff --git a/sloth/src/main.rs b/sloth/src/main.rs
index 421bbea..a1a4756 100644
--- a/sloth/src/main.rs
+++ b/sloth/src/main.rs
@@ -54,7 +54,18 @@ fn main() {
// Parsing
let tokens = Lexer::new(&source).collect_vec();
let global_symtable = mk_symtable();
- let mut ast = AstParser::parse(tokens, global_symtable).unwrap();
+
+ let mut ast = match AstParser::parse(tokens, global_symtable) {
+ Ok(node) => node,
+ Err(error) => {
+ eprintln!(
+ "Error in file {} on line {}: {error}",
+ args[1 + (error.line() / 1_000) as usize],
+ error.line() % 1000 + 1,
+ );
+ return;
+ }
+ };
if let Err(error) = analyze(&mut ast) {
eprintln!(
diff --git a/sloth/src/parser/expr.rs b/sloth/src/parser/expr.rs
index 3decf5d..ac7a19e 100644
--- a/sloth/src/parser/expr.rs
+++ b/sloth/src/parser/expr.rs
@@ -87,7 +87,7 @@ impl<'a> AstParser<'a> {
ExprKind::Grouping(Box::new(expr))
}
- _ => return Err(ParsingError::UnexpectedToken),
+ tt => return Err(ParsingError::UnexpectedToken(self.line, tt, "")),
};
Ok(Expr::new(
diff --git a/sloth/src/parser/mod.rs b/sloth/src/parser/mod.rs
index a1f251e..09a26fd 100644
--- a/sloth/src/parser/mod.rs
+++ b/sloth/src/parser/mod.rs
@@ -11,8 +11,17 @@ use crate::symtable::SymbolTable;
pub enum ParsingError {
#[error("Invalid operation")]
InvalidOp,
- #[error("Unexpected token")]
- UnexpectedToken,
+ #[error("Unexpected token '{1}'. {2}")]
+ UnexpectedToken(u32, TokenType, &'static str),
+}
+
+impl ParsingError {
+ pub fn line(&self) -> u32 {
+ match &self {
+ ParsingError::InvalidOp => 0,
+ ParsingError::UnexpectedToken(x, _, _) => *x,
+ }
+ }
}
#[derive(Debug)]
@@ -92,10 +101,13 @@ impl<'a> AstParser<'a> {
self.advance_if(|it| it.tt == *next)
}
- pub fn consume(&mut self, next: TokenType, error: &str) -> Result<&Token, ParsingError> {
+ pub fn consume(
+ &mut self,
+ next: TokenType,
+ error: &'static str,
+ ) -> Result<&Token, ParsingError> {
if std::mem::discriminant(&self.peek().tt) != std::mem::discriminant(&next) {
- println!("{error} at index {:?}", self.index);
- return Err(ParsingError::UnexpectedToken);
+ return Err(ParsingError::UnexpectedToken(self.line, next, error));
}
Ok(self.advance().unwrap())
@@ -103,7 +115,7 @@ impl<'a> AstParser<'a> {
pub fn consume_literal(&mut self) -> Result<Literal, ParsingError> {
let Some(TokenType::Literal(literal)) = self.advance().map(|it| it.tt.clone()) else {
- return Err(ParsingError::UnexpectedToken);
+ return Err(ParsingError::UnexpectedToken(self.line, self.peek().tt.clone(), "Expected literal"));
};
Ok(literal.into())
@@ -111,7 +123,7 @@ impl<'a> AstParser<'a> {
pub fn consume_identifier(&mut self) -> Result<String, ParsingError> {
let Some(TokenType::Identifier(identifier)) = self.advance().map(|it| it.tt.clone()) else {
- return Err(ParsingError::UnexpectedToken);
+ return Err(ParsingError::UnexpectedToken(self.line, self.peek().tt.clone(), "Expected identifier"));
};
Ok(identifier)
diff --git a/sloth/src/parser/stmt.rs b/sloth/src/parser/stmt.rs
index d8a0509..6af4634 100644
--- a/sloth/src/parser/stmt.rs
+++ b/sloth/src/parser/stmt.rs
@@ -24,10 +24,10 @@ impl<'a> AstParser<'a> {
// Consume the foreign token
self.consume(TokenType::Foreign, "Expected foreign")?;
- match self.peek().tt {
+ match &self.peek().tt {
TokenType::Fn => self.define_function(true),
- _ => Err(ParsingError::UnexpectedToken),
+ tt => Err(ParsingError::UnexpectedToken(self.line, tt.clone(), "")),
}
}