Replace panics with errors in parser

This commit is contained in:
Daniel M 2022-02-09 13:49:14 +01:00
parent 2312deec5b
commit 235eb460dc
2 changed files with 87 additions and 91 deletions

View File

@ -53,7 +53,7 @@ impl Interpreter {
println!("Tokens: {:?}", tokens); println!("Tokens: {:?}", tokens);
} }
let ast = parse(tokens); let ast = parse(tokens).unwrap();
self.run_ast(ast); self.run_ast(ast);
} }

View File

@ -1,4 +1,5 @@
use std::iter::Peekable; use std::iter::Peekable;
use thiserror::Error;
use crate::{ use crate::{
ast::{Ast, BinOpType, BlockScope, Expression, If, Loop, Statement, UnOpType}, ast::{Ast, BinOpType, BlockScope, Expression, If, Loop, Statement, UnOpType},
@ -7,8 +8,27 @@ use crate::{
T, 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<T> = Result<T, ParseErr>;
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 /// Parse the given tokens into an abstract syntax tree
pub fn parse<T: Iterator<Item = Token>, A: IntoIterator<IntoIter = T>>(tokens: A) -> Ast { pub fn parse<T: Iterator<Item = Token>, A: IntoIterator<IntoIter = T>>(tokens: A) -> ResPE<Ast> {
let parser = Parser::new(tokens); let parser = Parser::new(tokens);
parser.parse() parser.parse()
} }
@ -32,17 +52,17 @@ impl<T: Iterator<Item = Token>> Parser<T> {
} }
} }
pub fn parse(mut self) -> Ast { pub fn parse(mut self) -> ResPE<Ast> {
let main = self.parse_scoped_block(); let main = self.parse_scoped_block()?;
Ast { Ok(Ast {
main, main,
stringstore: self.string_store, stringstore: self.string_store,
} })
} }
/// Parse tokens into an abstract syntax tree. This will continuously parse statements until /// Parse tokens into an abstract syntax tree. This will continuously parse statements until
/// encountering end-of-file or a block end '}' . /// encountering end-of-file or a block end '}' .
fn parse_scoped_block(&mut self) -> BlockScope { fn parse_scoped_block(&mut self) -> ResPE<BlockScope> {
let framepointer = self.var_stack.len(); let framepointer = self.var_stack.len();
let mut prog = Vec::new(); let mut prog = Vec::new();
@ -55,45 +75,42 @@ impl<T: Iterator<Item = Token>> Parser<T> {
T!['{'] => { T!['{'] => {
self.next(); self.next();
prog.push(Statement::Block(self.parse_scoped_block())); prog.push(Statement::Block(self.parse_scoped_block()?));
if self.next() != T!['}'] {
panic!("Error parsing block: Expectected closing braces '}}'"); validate_next!(self, T!['}'], "}");
}
} }
// By default try to lex a statement // By default try to lex a statement
_ => prog.push(self.parse_stmt()), _ => prog.push(self.parse_stmt()?),
} }
} }
self.var_stack.truncate(framepointer); self.var_stack.truncate(framepointer);
prog Ok(prog)
} }
/// Parse a single statement from the tokens. /// Parse a single statement from the tokens.
fn parse_stmt(&mut self) -> Statement { fn parse_stmt(&mut self) -> ResPE<Statement> {
match self.peek() { let stmt = match self.peek() {
T![loop] => Statement::Loop(self.parse_loop()), T![loop] => Statement::Loop(self.parse_loop()?),
T![print] => { T![print] => {
self.next(); self.next();
let expr = self.parse_expr(); let expr = self.parse_expr()?;
// After a statement, there must be a semicolon // After a statement, there must be a semicolon
if self.next() != T![;] { validate_next!(self, T![;], ";");
panic!("Expected semicolon after statement");
}
Statement::Print(expr) 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 // 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 { match &mut expr {
Expression::BinOp(BinOpType::Declare, lhs, _) => match lhs.as_mut() { Expression::BinOp(BinOpType::Declare, lhs, _) => match lhs.as_mut() {
@ -101,7 +118,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
*sp = self.var_stack.len(); *sp = self.var_stack.len();
self.var_stack.push(*sid); self.var_stack.push(*sid);
} }
_ => panic!("Left hand side of declaration must be variable"), _ => return Err(ParseErr::DeclarationOfNonVar),
}, },
_ => (), _ => (),
} }
@ -109,104 +126,87 @@ impl<T: Iterator<Item = Token>> Parser<T> {
let stmt = Statement::Expr(expr); let stmt = Statement::Expr(expr);
// After a statement, there must be a semicolon // After a statement, there must be a semicolon
if self.next() != T![;] { validate_next!(self, T![;], ";");
panic!("Expected semicolon after statement");
}
stmt stmt
} }
} };
Ok(stmt)
} }
/// Parse an if statement from the tokens /// Parse an if statement from the tokens
fn parse_if(&mut self) -> If { fn parse_if(&mut self) -> ResPE<If> {
if self.next() != T![if] { validate_next!(self, T![if], "if");
panic!("Error lexing if: Expected if token");
}
let condition = self.parse_expr(); let condition = self.parse_expr()?;
if self.next() != T!['{'] { validate_next!(self, T!['{'], "{");
panic!("Error lexing if: Expected '{{'")
}
let body_true = self.parse_scoped_block(); let body_true = self.parse_scoped_block()?;
if self.next() != T!['}'] { validate_next!(self, T!['}'], "}");
panic!("Error lexing if: Expected '}}'")
}
let mut body_false = BlockScope::default(); let mut body_false = BlockScope::default();
if self.peek() == &T![else] { if self.peek() == &T![else] {
self.next(); self.next();
if self.next() != T!['{'] { validate_next!(self, T!['{'], "{");
panic!("Error lexing if: Expected '{{'")
}
body_false = self.parse_scoped_block(); body_false = self.parse_scoped_block()?;
if self.next() != T!['}'] { validate_next!(self, T!['}'], "}");
panic!("Error lexing if: Expected '}}'")
}
} }
If { Ok(If {
condition, condition,
body_true, body_true,
body_false, body_false,
} })
} }
/// Parse a loop statement from the tokens /// Parse a loop statement from the tokens
fn parse_loop(&mut self) -> Loop { fn parse_loop(&mut self) -> ResPE<Loop> {
if self.next() != T![loop] { validate_next!(self, T![loop], "loop");
panic!("Error lexing loop: Expected loop token");
}
let condition = self.parse_expr(); let condition = self.parse_expr()?;
let mut advancement = None; let mut advancement = None;
let body; let body;
match self.next() { match self.next() {
T!['{'] => { T!['{'] => {
body = self.parse_scoped_block(); body = self.parse_scoped_block()?;
} }
T![;] => { T![;] => {
advancement = Some(self.parse_expr()); advancement = Some(self.parse_expr()?);
if self.next() != T!['{'] { validate_next!(self, T!['{'], "{");
panic!("Error lexing loop: Expected '{{'")
}
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!['}'] { validate_next!(self, T!['}'], "}");
panic!("Error lexing loop: Expected '}}'")
}
Loop { Ok(Loop {
condition, condition,
advancement, advancement,
body, body,
} })
} }
/// Parse a single expression from the tokens /// Parse a single expression from the tokens
fn parse_expr(&mut self) -> Expression { fn parse_expr(&mut self) -> ResPE<Expression> {
let lhs = self.parse_primary(); let lhs = self.parse_primary()?;
self.parse_expr_precedence(lhs, 0) self.parse_expr_precedence(lhs, 0)
} }
/// Parse binary expressions with a precedence equal to or higher than min_prec /// 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<Expression> {
while let Some(binop) = &self.peek().try_to_binop() { while let Some(binop) = &self.peek().try_to_binop() {
// Stop if the next operator has a lower binding power // Stop if the next operator has a lower binding power
if !(binop.precedence() >= min_prec) { if !(binop.precedence() >= min_prec) {
@ -217,25 +217,25 @@ impl<T: Iterator<Item = Token>> Parser<T> {
// valid // valid
let binop = self.next().try_to_binop().unwrap(); 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() { while let Some(binop2) = &self.peek().try_to_binop() {
if !(binop2.precedence() > binop.precedence()) { if !(binop2.precedence() > binop.precedence()) {
break; 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 = Expression::BinOp(binop, lhs.into(), rhs.into());
} }
lhs Ok(lhs)
} }
/// Parse a primary expression (for now only number) /// Parse a primary expression (for now only number)
fn parse_primary(&mut self) -> Expression { fn parse_primary(&mut self) -> ResPE<Expression> {
match self.next() { let primary = match self.next() {
// Literal i64 // Literal i64
T![i64(val)] => Expression::I64(val), T![i64(val)] => Expression::I64(val),
@ -244,11 +244,9 @@ impl<T: Iterator<Item = Token>> Parser<T> {
// Array literal. Square brackets containing the array size as expression // Array literal. Square brackets containing the array size as expression
T!['['] => { T!['['] => {
let size = self.parse_expr(); let size = self.parse_expr()?;
if self.next() != T![']'] { validate_next!(self, T![']'], "]");
panic!("Error parsing array literal: Expected closing bracket")
}
Expression::ArrayLiteral(size.into()) Expression::ArrayLiteral(size.into())
} }
@ -261,11 +259,9 @@ impl<T: Iterator<Item = Token>> Parser<T> {
self.next(); self.next();
let index = self.parse_expr(); let index = self.parse_expr()?;
if self.next() != T![']'] { validate_next!(self, T![']'], "]");
panic!("Error parsing array access: Expected closing bracket")
}
Expression::ArrayAccess(sid, stackpos, index.into()) Expression::ArrayAccess(sid, stackpos, index.into())
} }
@ -278,36 +274,36 @@ impl<T: Iterator<Item = Token>> Parser<T> {
// Parentheses grouping // Parentheses grouping
T!['('] => { T!['('] => {
let inner_expr = self.parse_expr(); let inner_expr = self.parse_expr()?;
// Verify that there is a closing parenthesis // Verify that there is a closing parenthesis
if self.next() != T![')'] { validate_next!(self, T![')'], ")");
panic!("Error parsing primary expr: Exepected closing parenthesis ')'");
}
inner_expr inner_expr
} }
// Unary negation // Unary negation
T![-] => { T![-] => {
let operand = self.parse_primary(); let operand = self.parse_primary()?;
Expression::UnOp(UnOpType::Negate, operand.into()) Expression::UnOp(UnOpType::Negate, operand.into())
} }
// Unary bitwise not (bitflip) // Unary bitwise not (bitflip)
T![~] => { T![~] => {
let operand = self.parse_primary(); let operand = self.parse_primary()?;
Expression::UnOp(UnOpType::BNot, operand.into()) Expression::UnOp(UnOpType::BNot, operand.into())
} }
// Unary logical not // Unary logical not
T![!] => { T![!] => {
let operand = self.parse_primary(); let operand = self.parse_primary()?;
Expression::UnOp(UnOpType::LNot, operand.into()) 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 { fn get_stackpos(&self, varid: Sid) -> usize {
@ -371,7 +367,7 @@ mod tests {
let expected = vec![expected]; let expected = vec![expected];
let actual = parse(tokens); let actual = parse(tokens).unwrap();
assert_eq!(expected, actual.main); assert_eq!(expected, actual.main);
} }
} }