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);
}
let ast = parse(tokens);
let ast = parse(tokens).unwrap();
self.run_ast(ast);
}

View File

@ -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<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
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);
parser.parse()
}
@ -32,17 +52,17 @@ impl<T: Iterator<Item = Token>> Parser<T> {
}
}
pub fn parse(mut self) -> Ast {
let main = self.parse_scoped_block();
Ast {
pub fn parse(mut self) -> ResPE<Ast> {
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<BlockScope> {
let framepointer = self.var_stack.len();
let mut prog = Vec::new();
@ -55,45 +75,42 @@ impl<T: Iterator<Item = Token>> Parser<T> {
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<Statement> {
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<T: Iterator<Item = Token>> Parser<T> {
*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<T: Iterator<Item = Token>> Parser<T> {
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<If> {
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()?;
validate_next!(self, T!['}'], "}");
}
body_false = self.parse_scoped_block();
if self.next() != T!['}'] {
panic!("Error lexing if: Expected '}}'")
}
}
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<Loop> {
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();
tok => return Err(ParseErr::UnexpectedToken(tok, ";\" or \"{".to_string())),
}
_ => panic!("Error lexing loop: Expected ';' or '{{'"),
}
validate_next!(self, T!['}'], "}");
if self.next() != T!['}'] {
panic!("Error lexing loop: Expected '}}'")
}
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<Expression> {
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<Expression> {
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<T: Iterator<Item = Token>> Parser<T> {
// 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<Expression> {
let primary = match self.next() {
// Literal i64
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
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<T: Iterator<Item = Token>> Parser<T> {
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<T: Iterator<Item = Token>> Parser<T> {
// 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);
}
}