From 235eb460dca78406e1e599cdb450e088970eb18a Mon Sep 17 00:00:00 2001 From: Daniel M Date: Wed, 9 Feb 2022 13:49:14 +0100 Subject: [PATCH] Replace panics with errors in parser --- src/interpreter.rs | 2 +- src/parser.rs | 176 ++++++++++++++++++++++----------------------- 2 files changed, 87 insertions(+), 91 deletions(-) diff --git a/src/interpreter.rs b/src/interpreter.rs index 6eb87e0..edac6db 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -53,7 +53,7 @@ impl Interpreter { println!("Tokens: {:?}", tokens); } - let ast = parse(tokens); + let ast = parse(tokens).unwrap(); self.run_ast(ast); } diff --git a/src/parser.rs b/src/parser.rs index 1f32d1f..8f8d707 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,4 +1,5 @@ use std::iter::Peekable; +use thiserror::Error; use crate::{ ast::{Ast, BinOpType, BlockScope, Expression, If, Loop, Statement, UnOpType}, @@ -7,8 +8,27 @@ use crate::{ T, }; +#[derive(Debug, Error)] +pub enum ParseErr { + #[error("Unexpected Token \"{0:?}\", expected \"{1}\"")] + UnexpectedToken(Token, String), + #[error("Left hand side of declaration is not a variable")] + DeclarationOfNonVar, +} + +type ResPE = Result; + +macro_rules! validate_next { + ($self:ident, $expected_tok:pat, $expected_str:expr) => { + match $self.next() { + $expected_tok => (), + tok => return Err(ParseErr::UnexpectedToken(tok, format!("{}", $expected_str))), + } + }; +} + /// Parse the given tokens into an abstract syntax tree -pub fn parse, A: IntoIterator>(tokens: A) -> Ast { +pub fn parse, A: IntoIterator>(tokens: A) -> ResPE { let parser = Parser::new(tokens); parser.parse() } @@ -32,17 +52,17 @@ impl> Parser { } } - pub fn parse(mut self) -> Ast { - let main = self.parse_scoped_block(); - Ast { + pub fn parse(mut self) -> ResPE { + let main = self.parse_scoped_block()?; + Ok(Ast { main, stringstore: self.string_store, - } + }) } /// Parse tokens into an abstract syntax tree. This will continuously parse statements until /// encountering end-of-file or a block end '}' . - fn parse_scoped_block(&mut self) -> BlockScope { + fn parse_scoped_block(&mut self) -> ResPE { let framepointer = self.var_stack.len(); let mut prog = Vec::new(); @@ -55,45 +75,42 @@ impl> Parser { T!['{'] => { self.next(); - prog.push(Statement::Block(self.parse_scoped_block())); - if self.next() != T!['}'] { - panic!("Error parsing block: Expectected closing braces '}}'"); - } + prog.push(Statement::Block(self.parse_scoped_block()?)); + + validate_next!(self, T!['}'], "}"); } // By default try to lex a statement - _ => prog.push(self.parse_stmt()), + _ => prog.push(self.parse_stmt()?), } } self.var_stack.truncate(framepointer); - prog + Ok(prog) } /// Parse a single statement from the tokens. - fn parse_stmt(&mut self) -> Statement { - match self.peek() { - T![loop] => Statement::Loop(self.parse_loop()), + fn parse_stmt(&mut self) -> ResPE { + let stmt = match self.peek() { + T![loop] => Statement::Loop(self.parse_loop()?), T![print] => { self.next(); - let expr = self.parse_expr(); + let expr = self.parse_expr()?; // After a statement, there must be a semicolon - if self.next() != T![;] { - panic!("Expected semicolon after statement"); - } + validate_next!(self, T![;], ";"); Statement::Print(expr) } - T![if] => Statement::If(self.parse_if()), + T![if] => Statement::If(self.parse_if()?), // If it is not a loop, try to lex as an expression _ => { - let mut expr = self.parse_expr(); + let mut expr = self.parse_expr()?; match &mut expr { Expression::BinOp(BinOpType::Declare, lhs, _) => match lhs.as_mut() { @@ -101,7 +118,7 @@ impl> Parser { *sp = self.var_stack.len(); self.var_stack.push(*sid); } - _ => panic!("Left hand side of declaration must be variable"), + _ => return Err(ParseErr::DeclarationOfNonVar), }, _ => (), } @@ -109,104 +126,87 @@ impl> Parser { let stmt = Statement::Expr(expr); // After a statement, there must be a semicolon - if self.next() != T![;] { - panic!("Expected semicolon after statement"); - } + validate_next!(self, T![;], ";"); stmt } - } + }; + Ok(stmt) } /// Parse an if statement from the tokens - fn parse_if(&mut self) -> If { - if self.next() != T![if] { - panic!("Error lexing if: Expected if token"); - } + fn parse_if(&mut self) -> ResPE { + validate_next!(self, T![if], "if"); - let condition = self.parse_expr(); + let condition = self.parse_expr()?; - if self.next() != T!['{'] { - panic!("Error lexing if: Expected '{{'") - } + validate_next!(self, T!['{'], "{"); - let body_true = self.parse_scoped_block(); + let body_true = self.parse_scoped_block()?; - if self.next() != T!['}'] { - panic!("Error lexing if: Expected '}}'") - } + validate_next!(self, T!['}'], "}"); let mut body_false = BlockScope::default(); if self.peek() == &T![else] { self.next(); - if self.next() != T!['{'] { - panic!("Error lexing if: Expected '{{'") - } + validate_next!(self, T!['{'], "{"); - body_false = self.parse_scoped_block(); + body_false = self.parse_scoped_block()?; - if self.next() != T!['}'] { - panic!("Error lexing if: Expected '}}'") - } + validate_next!(self, T!['}'], "}"); } - If { + Ok(If { condition, body_true, body_false, - } + }) } /// Parse a loop statement from the tokens - fn parse_loop(&mut self) -> Loop { - if self.next() != T![loop] { - panic!("Error lexing loop: Expected loop token"); - } + fn parse_loop(&mut self) -> ResPE { + validate_next!(self, T![loop], "loop"); - let condition = self.parse_expr(); + let condition = self.parse_expr()?; let mut advancement = None; let body; match self.next() { T!['{'] => { - body = self.parse_scoped_block(); + body = self.parse_scoped_block()?; } T![;] => { - advancement = Some(self.parse_expr()); + advancement = Some(self.parse_expr()?); - if self.next() != T!['{'] { - panic!("Error lexing loop: Expected '{{'") - } + validate_next!(self, T!['{'], "{"); - body = self.parse_scoped_block(); + body = self.parse_scoped_block()?; } - _ => panic!("Error lexing loop: Expected ';' or '{{'"), + tok => return Err(ParseErr::UnexpectedToken(tok, ";\" or \"{".to_string())), } - if self.next() != T!['}'] { - panic!("Error lexing loop: Expected '}}'") - } + validate_next!(self, T!['}'], "}"); - Loop { + Ok(Loop { condition, advancement, body, - } + }) } /// Parse a single expression from the tokens - fn parse_expr(&mut self) -> Expression { - let lhs = self.parse_primary(); + fn parse_expr(&mut self) -> ResPE { + let lhs = self.parse_primary()?; self.parse_expr_precedence(lhs, 0) } /// Parse binary expressions with a precedence equal to or higher than min_prec - fn parse_expr_precedence(&mut self, mut lhs: Expression, min_prec: u8) -> Expression { + fn parse_expr_precedence(&mut self, mut lhs: Expression, min_prec: u8) -> ResPE { while let Some(binop) = &self.peek().try_to_binop() { // Stop if the next operator has a lower binding power if !(binop.precedence() >= min_prec) { @@ -217,25 +217,25 @@ impl> Parser { // valid let binop = self.next().try_to_binop().unwrap(); - let mut rhs = self.parse_primary(); + let mut rhs = self.parse_primary()?; while let Some(binop2) = &self.peek().try_to_binop() { if !(binop2.precedence() > binop.precedence()) { break; } - rhs = self.parse_expr_precedence(rhs, binop.precedence() + 1); + rhs = self.parse_expr_precedence(rhs, binop.precedence() + 1)?; } lhs = Expression::BinOp(binop, lhs.into(), rhs.into()); } - lhs + Ok(lhs) } /// Parse a primary expression (for now only number) - fn parse_primary(&mut self) -> Expression { - match self.next() { + fn parse_primary(&mut self) -> ResPE { + let primary = match self.next() { // Literal i64 T![i64(val)] => Expression::I64(val), @@ -244,11 +244,9 @@ impl> Parser { // Array literal. Square brackets containing the array size as expression T!['['] => { - let size = self.parse_expr(); + let size = self.parse_expr()?; - if self.next() != T![']'] { - panic!("Error parsing array literal: Expected closing bracket") - } + validate_next!(self, T![']'], "]"); Expression::ArrayLiteral(size.into()) } @@ -261,11 +259,9 @@ impl> Parser { self.next(); - let index = self.parse_expr(); + let index = self.parse_expr()?; - if self.next() != T![']'] { - panic!("Error parsing array access: Expected closing bracket") - } + validate_next!(self, T![']'], "]"); Expression::ArrayAccess(sid, stackpos, index.into()) } @@ -278,36 +274,36 @@ impl> Parser { // Parentheses grouping T!['('] => { - let inner_expr = self.parse_expr(); + let inner_expr = self.parse_expr()?; // Verify that there is a closing parenthesis - if self.next() != T![')'] { - panic!("Error parsing primary expr: Exepected closing parenthesis ')'"); - } + validate_next!(self, T![')'], ")"); inner_expr } // Unary negation T![-] => { - let operand = self.parse_primary(); + let operand = self.parse_primary()?; Expression::UnOp(UnOpType::Negate, operand.into()) } // Unary bitwise not (bitflip) T![~] => { - let operand = self.parse_primary(); + let operand = self.parse_primary()?; Expression::UnOp(UnOpType::BNot, operand.into()) } // Unary logical not T![!] => { - let operand = self.parse_primary(); + let operand = self.parse_primary()?; Expression::UnOp(UnOpType::LNot, operand.into()) } - tok => panic!("Error parsing primary expr: Unexpected Token '{:?}'", tok), - } + tok => return Err(ParseErr::UnexpectedToken(tok, "primary".to_string())), + }; + + Ok(primary) } fn get_stackpos(&self, varid: Sid) -> usize { @@ -371,7 +367,7 @@ mod tests { let expected = vec![expected]; - let actual = parse(tokens); + let actual = parse(tokens).unwrap(); assert_eq!(expected, actual.main); } }