Replace panics with errors in parser
This commit is contained in:
parent
2312deec5b
commit
235eb460dc
@ -53,7 +53,7 @@ impl Interpreter {
|
||||
println!("Tokens: {:?}", tokens);
|
||||
}
|
||||
|
||||
let ast = parse(tokens);
|
||||
let ast = parse(tokens).unwrap();
|
||||
|
||||
self.run_ast(ast);
|
||||
}
|
||||
|
||||
182
src/parser.rs
182
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<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);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user