Replace panics with errors in parser
This commit is contained in:
parent
2312deec5b
commit
235eb460dc
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
182
src/parser.rs
182
src/parser.rs
@ -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()?;
|
||||||
|
|
||||||
|
validate_next!(self, T!['}'], "}");
|
||||||
}
|
}
|
||||||
|
|
||||||
body_false = self.parse_scoped_block();
|
Ok(If {
|
||||||
|
|
||||||
if self.next() != T!['}'] {
|
|
||||||
panic!("Error lexing if: Expected '}}'")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
tok => return Err(ParseErr::UnexpectedToken(tok, ";\" or \"{".to_string())),
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => panic!("Error lexing loop: Expected ';' or '{{'"),
|
validate_next!(self, T!['}'], "}");
|
||||||
}
|
|
||||||
|
|
||||||
if self.next() != T!['}'] {
|
Ok(Loop {
|
||||||
panic!("Error lexing loop: Expected '}}'")
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user