From 5bb44fa527fb4b7270fbe2be6c566a8236b88f58 Mon Sep 17 00:00:00 2001 From: Vedat Can Keklik Date: Wed, 22 Nov 2023 18:53:58 +0300 Subject: [PATCH] feat: Minimal scan errors --- examples/scan_err.ly | 7 ++++++ src/lang/ast.rs | 1 - src/lang/parser.rs | 8 ++---- src/lang/scanner.rs | 2 +- src/runtime/error.rs | 58 ++++++++++++++++++-------------------------- src/runtime/mod.rs | 9 +++++-- 6 files changed, 40 insertions(+), 45 deletions(-) create mode 100644 examples/scan_err.ly diff --git a/examples/scan_err.ly b/examples/scan_err.ly new file mode 100644 index 00000000..7f41d4c9 --- /dev/null +++ b/examples/scan_err.ly @@ -0,0 +1,7 @@ +// Define recursive Fibonacci function +fun fib($n) { + if ($n < 2) return $n; + return fib($n - 2) + fib($n - 1); +} + +"some unterminated string \ No newline at end of file diff --git a/src/lang/ast.rs b/src/lang/ast.rs index 56f106ea..d53ec644 100644 --- a/src/lang/ast.rs +++ b/src/lang/ast.rs @@ -122,7 +122,6 @@ pub enum Expr { Call(ExprId, Token, Vec), } - pub type ExprId = usize; pub type StmtId = usize; diff --git a/src/lang/parser.rs b/src/lang/parser.rs index daddad97..174e31ac 100644 --- a/src/lang/parser.rs +++ b/src/lang/parser.rs @@ -278,9 +278,7 @@ impl<'a> Parser<'a> { let value = self.assignment()?; match self.arena.get_expression(expr) { Variable(tok) => { - return Ok(self - .arena - .expression(Expr::Assignment(tok.clone(), value))); + return Ok(self.arena.expression(Expr::Assignment(tok.clone(), value))); } _ => { return Err(ParseError::InvalidAssignmentTarget { @@ -463,9 +461,7 @@ impl<'a> Parser<'a> { } let paren = self.expected(sym!(RightParen))?.clone(); - Ok(self - .arena - .expression(Expr::Call(callee, paren, arguments))) + Ok(self.arena.expression(Expr::Call(callee, paren, arguments))) } fn call(&mut self) -> ParseResult { diff --git a/src/lang/scanner.rs b/src/lang/scanner.rs index 268a2ed6..3865a477 100644 --- a/src/lang/scanner.rs +++ b/src/lang/scanner.rs @@ -97,7 +97,7 @@ impl Scanner { } if self.is_at_end() { - let err_span: String = self.chars[self.start + 1..self.current - 1] + let err_span: String = self.chars[self.start + 1..self.current] .iter() .collect(); return Err(ScanError::UnterminatedString { diff --git a/src/runtime/error.rs b/src/runtime/error.rs index c9dd8d11..1adf7674 100644 --- a/src/runtime/error.rs +++ b/src/runtime/error.rs @@ -7,43 +7,31 @@ pub enum ExecutionError { Parse(ParseError), Resolve(ResolveError), } -/* -fn report() { - use ariadne::{Color, ColorGenerator, Fmt, Label, Report, ReportKind, Source}; - let mut colors = ColorGenerator::new(); +pub fn report_error(filename: &str, source: &str, error: ScanError) { + use ariadne::{Color, Fmt, Label, Report, ReportKind, Source}; // Generate & choose some colours for each of our elements - let a = colors.next(); - let b = colors.next(); let out = Color::Fixed(81); - Report::build(ReportKind::Error, filename, 12) - .with_code(3) - .with_message(format!("Incompatible types")) - .with_label( - Label::new((filename, 12..13)) - .with_message(format!("This is of type {}", "Nat".fg(a))) - .with_color(a), - ) - .with_label( - Label::new((filename, 2..5)) - .with_message(format!("This is of type {}", "Str".fg(b))) - .with_color(b), - ) - .with_label( - Label::new((filename, 1..4)) - .with_message(format!( - "The values are outputs of this {} expression", - "match".fg(out), - )) - .with_color(out), - ) - .with_note(format!( - "Outputs of {} expressions must coerce to the same type", - "match".fg(out) - )) - .finish() - .print((filename, Source::from(filename))) - .unwrap(); -} */ + match error { + ScanError::UnexpectedCharacter { span, message }| + ScanError::UnterminatedString { span, message } | + ScanError::MalformedNumberLiteral { span, message } => { + Report::build(ReportKind::Error, filename, 12) + .with_code(3) + .with_message(message) + .with_label( + Label::new((filename, span.start..span.start + span.lexeme.len())) + .with_message(format!( + "The values are outputs of this {} expression", + "match".fg(out), + )) + .with_color(out), + ) + .finish() + .print((filename, Source::from(&source))) + .unwrap(); + } + } +} \ No newline at end of file diff --git a/src/runtime/mod.rs b/src/runtime/mod.rs index cda65b6f..e83ff37f 100644 --- a/src/runtime/mod.rs +++ b/src/runtime/mod.rs @@ -1,3 +1,4 @@ +use self::error::report_error; use self::resolver::Resolver; use crate::lang::ast::Visitor; use crate::lang::parser::Parser; @@ -84,8 +85,12 @@ impl Runtime { } pub fn interpret(&mut self, source: &str) { - let tokens = Scanner::scan(source).unwrap(); - let parsed = Parser::parse(&tokens); + let tokens = Scanner::scan(source); + if tokens.is_err() { + report_error("filename", source, tokens.err().unwrap()); + return; + } + let parsed = Parser::parse(&tokens.unwrap()); let arena = Rc::clone(&parsed.arena); // let mut resolver = Resolver::new(arena.clone());