Impl. more expr types in parser
- Impl. unary bool not "!"
- Impl. relational exprs (">", ">=", "<", "<=")
- Impl. equality exprs ("==", "!=")
- Impl. bool and, or, xor ("&&", "||", "^^")
- Changed bool xor lexing from "^" to "^^" in order to keep "^"
reserved for bitwise xor
- Prepared Ast for if, while & fn_def statements
This commit is contained in:
parent
cfc585426d
commit
1712dac6d6
@ -3,18 +3,51 @@ use crate::token::Literal;
|
|||||||
/// Binary Operator Types. For operations that have two operands
|
/// Binary Operator Types. For operations that have two operands
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum BinOpType {
|
pub enum BinOpType {
|
||||||
|
/// Addition "+"
|
||||||
Add,
|
Add,
|
||||||
|
/// Subtraction "-"
|
||||||
Sub,
|
Sub,
|
||||||
|
|
||||||
|
/// Multiplication "*"
|
||||||
Mul,
|
Mul,
|
||||||
|
/// Division "/"
|
||||||
Div,
|
Div,
|
||||||
|
/// Modulo "%"
|
||||||
Mod,
|
Mod,
|
||||||
|
|
||||||
|
// Equality
|
||||||
|
/// Equal "=="
|
||||||
|
Eq,
|
||||||
|
/// Not equal "!="
|
||||||
|
Neq,
|
||||||
|
|
||||||
|
/// Greater than ">"
|
||||||
|
Gt,
|
||||||
|
/// Lesser than "<"
|
||||||
|
Lt,
|
||||||
|
/// Greater or equal ">="
|
||||||
|
Ge,
|
||||||
|
/// Lesser or equal "<="
|
||||||
|
Le,
|
||||||
|
|
||||||
|
// Boolean
|
||||||
|
/// Boolean And "&&"
|
||||||
|
And,
|
||||||
|
/// Boolean Or "||"
|
||||||
|
Or,
|
||||||
|
/// Boolean Not "!"
|
||||||
|
Not,
|
||||||
|
/// Boolean Xor "^^"
|
||||||
|
Xor,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unary Operator Types. For operations that have one operand
|
/// Unary Operator Types. For operations that have one operand
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum UnOpType {
|
pub enum UnOpType {
|
||||||
|
/// Negation "-"
|
||||||
Neg,
|
Neg,
|
||||||
|
/// Boolean Not "!"
|
||||||
|
Not,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
@ -24,6 +57,27 @@ pub struct FnCall {
|
|||||||
pub args: Vec<Expr>,
|
pub args: Vec<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct FnDef {
|
||||||
|
pub fn_name: String,
|
||||||
|
/// Argument names
|
||||||
|
pub args: Vec<String>,
|
||||||
|
pub body: Vec<Statement>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct IfStmt {
|
||||||
|
pub condition: Expr,
|
||||||
|
pub body_true: Vec<Statement>,
|
||||||
|
pub body_false: Vec<Statement>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct WhileStmt {
|
||||||
|
pub condition: Expr,
|
||||||
|
pub body: Vec<Statement>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
Literal(Literal),
|
Literal(Literal),
|
||||||
@ -39,6 +93,9 @@ pub enum Statement {
|
|||||||
Expr(Expr),
|
Expr(Expr),
|
||||||
LetBinding(String, Expr),
|
LetBinding(String, Expr),
|
||||||
Assignment(String, Expr),
|
Assignment(String, Expr),
|
||||||
|
FnDef(FnDef),
|
||||||
|
IfStmt(IfStmt),
|
||||||
|
WhileStmt(WhileStmt),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{ast::{Statement, Expr, Ast}, token::Literal};
|
use crate::{ast::{Statement, Expr, Ast, BinOpType, UnOpType}, token::Literal};
|
||||||
|
|
||||||
pub struct Interpreter {
|
pub struct Interpreter {
|
||||||
prog: Vec<Statement>,
|
prog: Vec<Statement>,
|
||||||
@ -44,6 +44,9 @@ impl Interpreter {
|
|||||||
let rhs = self.execute_expr(expr);
|
let rhs = self.execute_expr(expr);
|
||||||
*self.variables.get_mut(&var_name).expect("Assigning variable before declaration") = rhs;
|
*self.variables.get_mut(&var_name).expect("Assigning variable before declaration") = rhs;
|
||||||
},
|
},
|
||||||
|
Statement::FnDef(_) => todo!(),
|
||||||
|
Statement::IfStmt(_) => todo!(),
|
||||||
|
Statement::WhileStmt(_) => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,18 +67,31 @@ impl Interpreter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let res = match bot {
|
let res = match bot {
|
||||||
crate::ast::BinOpType::Add => lhs + rhs,
|
BinOpType::Add => lhs + rhs,
|
||||||
crate::ast::BinOpType::Sub => lhs - rhs,
|
BinOpType::Sub => lhs - rhs,
|
||||||
crate::ast::BinOpType::Mul => lhs * rhs,
|
|
||||||
crate::ast::BinOpType::Div => lhs / rhs,
|
BinOpType::Mul => lhs * rhs,
|
||||||
crate::ast::BinOpType::Mod => lhs % rhs,
|
BinOpType::Div => lhs / rhs,
|
||||||
|
BinOpType::Mod => lhs % rhs,
|
||||||
|
|
||||||
|
BinOpType::Eq => todo!(),
|
||||||
|
BinOpType::Neq => todo!(),
|
||||||
|
BinOpType::Gt => todo!(),
|
||||||
|
BinOpType::Lt => todo!(),
|
||||||
|
BinOpType::Ge => todo!(),
|
||||||
|
BinOpType::Le => todo!(),
|
||||||
|
|
||||||
|
BinOpType::And => todo!(),
|
||||||
|
BinOpType::Or => todo!(),
|
||||||
|
BinOpType::Not => todo!(),
|
||||||
|
BinOpType::Xor => todo!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Literal::Int64(res)
|
Literal::Int64(res)
|
||||||
}
|
}
|
||||||
Expr::UnOp(uot, expr) => {
|
Expr::UnOp(uot, expr) => {
|
||||||
match uot {
|
match uot {
|
||||||
crate::ast::UnOpType::Neg => {
|
UnOpType::Neg => {
|
||||||
let mut res = self.execute_expr(*expr);
|
let mut res = self.execute_expr(*expr);
|
||||||
match &mut res {
|
match &mut res {
|
||||||
Literal::Boolean(_) => panic!("Can't negate bool"),
|
Literal::Boolean(_) => panic!("Can't negate bool"),
|
||||||
@ -85,6 +101,7 @@ impl Interpreter {
|
|||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
UnOpType::Not => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -97,6 +97,10 @@ impl<'a> Lexer<'a> {
|
|||||||
self.advance();
|
self.advance();
|
||||||
tokens.push(Token::Op(Op::Or));
|
tokens.push(Token::Op(Op::Or));
|
||||||
}
|
}
|
||||||
|
'^' if matches!(ch_nxt, Some('^')) => {
|
||||||
|
self.advance();
|
||||||
|
tokens.push(Token::Op(Op::Xor));
|
||||||
|
}
|
||||||
|
|
||||||
// Lex tokens with 1 char length. This just matches the current char
|
// Lex tokens with 1 char length. This just matches the current char
|
||||||
'+' => tokens.push(Token::Op(Op::Add)),
|
'+' => tokens.push(Token::Op(Op::Add)),
|
||||||
@ -118,7 +122,6 @@ impl<'a> Lexer<'a> {
|
|||||||
',' => tokens.push(Token::Comma),
|
',' => tokens.push(Token::Comma),
|
||||||
'.' => tokens.push(Token::Dot),
|
'.' => tokens.push(Token::Dot),
|
||||||
'!' => tokens.push(Token::Op(Op::Not)),
|
'!' => tokens.push(Token::Op(Op::Not)),
|
||||||
'^' => tokens.push(Token::Op(Op::Xor)),
|
|
||||||
'#' => tokens.push(Token::Hashtag),
|
'#' => tokens.push(Token::Hashtag),
|
||||||
|
|
||||||
// A quote represents a string start, so lex a string token here
|
// A quote represents a string start, so lex a string token here
|
||||||
@ -301,7 +304,7 @@ mod test {
|
|||||||
* / %
|
* / %
|
||||||
== != > < >= <=
|
== != > < >= <=
|
||||||
= ->
|
= ->
|
||||||
&& || ^ !
|
&& || ^^ !
|
||||||
([{)]}
|
([{)]}
|
||||||
4564 "a string" false true
|
4564 "a string" false true
|
||||||
an_5ident6
|
an_5ident6
|
||||||
|
|||||||
@ -3,6 +3,7 @@ use crate::{
|
|||||||
token::{Group, Keyword, Op, Token, TokenStream},
|
token::{Group, Keyword, Op, Token, TokenStream},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// TODO: Real parsing errors instead of panics in the Parser
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ParseErr;
|
pub struct ParseErr;
|
||||||
|
|
||||||
@ -12,41 +13,31 @@ type PRes<T> = Result<T, ParseErr>;
|
|||||||
///
|
///
|
||||||
/// ## Grammar
|
/// ## Grammar
|
||||||
/// ### Statements
|
/// ### Statements
|
||||||
/// `stmt_let = "let" ident "=" expr_add` \
|
/// `stmt_let = "let" IDENT "=" expr` \
|
||||||
/// `stmt_assign = ident "=" expr_add` \
|
/// `stmt_assign = IDENT "=" expr` \
|
||||||
/// `stmt = ( stmt_let | stmt_assign | expr_add ) ";"` \
|
/// `stmt_fn_def = "fn" IDENT "(" IDENT? ( "," IDENT)* ")" "{" stmt* "}"` \
|
||||||
|
/// `stmt_if = "if" expr "{" stmt* "}" ( "else" "{" stmt* "}" )?` \
|
||||||
|
/// `stmt_while = "while" expr "{" stmt* "}"`
|
||||||
|
/// `stmt = ( stmt_let | stmt_assign | expr | stmt_fn_def | stmt_if | stmt_while | ) ";"` \
|
||||||
///
|
///
|
||||||
/// ### Expressions
|
/// ### Expressions
|
||||||
/// `expr_literal = LITERAL` \
|
/// `expr_literal = LITERAL` \
|
||||||
/// `expr_fn_call = IDENT "(" expr_add? ( "," expr_add )* ")"` \
|
/// `expr_fn_call = IDENT "(" expr? ( "," expr )* ")"` \
|
||||||
/// `expr_varibale = IDENT` \
|
/// `expr_varibale = IDENT` \
|
||||||
/// `expr_value = expr_literal | expr_fn_call | expr_variable` \
|
/// `expr_value = expr_literal | expr_fn_call | expr_variable` \
|
||||||
/// `expr_term = "-" expr_term | "(" expr_add ")" | expr_value` \
|
/// `expr_term = "-" expr_term | "!" expr_term | "(" expr ")" | expr_value` \
|
||||||
/// `expr_mul = expr_term (("*"|"/"|"%") expr_term)*` \
|
/// `expr_mul = expr_term (("*"|"/"|"%") expr_term)*` \
|
||||||
/// `expr_add = expr_mul (("+"|"-") expr_mul)*` \
|
/// `expr_add = expr_mul (("+"|"-") expr_mul)*` \
|
||||||
|
/// `expr_rel = expr_add ((">"|"<"|">="|"<=") expr_add)*`
|
||||||
|
/// `expr_equal = expr_rel (("=="|"!=") expr_rel)*`
|
||||||
|
/// `expr_and = expr_equal ("&&" expr_equal)*`
|
||||||
|
/// `expr_xor = expr_and ("^^" expr_and)*`
|
||||||
|
/// `expr_or = expr_xor ("||" expr_xor)*`
|
||||||
|
/// `expr = expr_or`
|
||||||
pub struct Parser {
|
pub struct Parser {
|
||||||
tokens: TokenStream,
|
tokens: TokenStream,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
# GRAMMAR
|
|
||||||
## expressions
|
|
||||||
|
|
||||||
expr_literal = LITERAL
|
|
||||||
expr_fn_call = IDENT "(" expr_add? ( "," expr_add )* ")"
|
|
||||||
expr_varibale = IDENT
|
|
||||||
expr_value = expr_literal | expr_fn_call | expr_variable
|
|
||||||
expr_term = "-" expr_term | "(" expr_add ")" | expr_value
|
|
||||||
expr_mul = expr_term (("*"|"/"|"%") expr_term)*
|
|
||||||
expr_add = expr_mul (("+"|"-") expr_mul)*
|
|
||||||
|
|
||||||
## statements
|
|
||||||
stmt_let = "let" ident "=" expr_add
|
|
||||||
stmt_assign = ident "=" expr_add
|
|
||||||
stmt = ( stmt_let | stmt_assign | expr_add ) ";"
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
impl Parser {
|
impl Parser {
|
||||||
/// Create a new parser from a TokenStream
|
/// Create a new parser from a TokenStream
|
||||||
pub fn new(tokens: TokenStream) -> Self {
|
pub fn new(tokens: TokenStream) -> Self {
|
||||||
@ -91,7 +82,7 @@ impl Parser {
|
|||||||
/// an assignment.
|
/// an assignment.
|
||||||
///
|
///
|
||||||
/// ### Grammar
|
/// ### Grammar
|
||||||
/// `stmt = ( stmt_let | stmt_assign | expr_add ) ";"`
|
/// `stmt = ( stmt_let | stmt_assign | expr ) ";"`
|
||||||
pub fn parse_statement(&mut self) -> PRes<Statement> {
|
pub fn parse_statement(&mut self) -> PRes<Statement> {
|
||||||
// Check the current and next char to decide what kind of statement is being parsed
|
// Check the current and next char to decide what kind of statement is being parsed
|
||||||
let stmt = match self.curr() {
|
let stmt = match self.curr() {
|
||||||
@ -102,7 +93,7 @@ impl Parser {
|
|||||||
self.parse_stmt_assign()
|
self.parse_stmt_assign()
|
||||||
}
|
}
|
||||||
// Otherwise -> A simple expression
|
// Otherwise -> A simple expression
|
||||||
_ => self.parse_expr_add().map(|expr| Statement::Expr(expr)),
|
_ => self.parse_expr().map(|expr| Statement::Expr(expr)),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check that the statement is terminated with a semicolon.
|
// Check that the statement is terminated with a semicolon.
|
||||||
@ -118,7 +109,7 @@ impl Parser {
|
|||||||
/// an equal sign "=" and an expression.
|
/// an equal sign "=" and an expression.
|
||||||
///
|
///
|
||||||
/// ### Grammar
|
/// ### Grammar
|
||||||
/// `stmt_let = "let" ident "=" expr_add`
|
/// `stmt_let = "let" ident "=" expr`
|
||||||
pub fn parse_stmt_let(&mut self) -> PRes<Statement> {
|
pub fn parse_stmt_let(&mut self) -> PRes<Statement> {
|
||||||
// Check if the let token is there
|
// Check if the let token is there
|
||||||
if !matches!(self.advance(), Some(Token::Keyword(Keyword::Let))) {
|
if !matches!(self.advance(), Some(Token::Keyword(Keyword::Let))) {
|
||||||
@ -137,7 +128,7 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse the right hand side of the let statement
|
// Parse the right hand side of the let statement
|
||||||
let rhs = self.parse_expr_add()?;
|
let rhs = self.parse_expr()?;
|
||||||
|
|
||||||
let let_binding = Statement::LetBinding(var_name, rhs);
|
let let_binding = Statement::LetBinding(var_name, rhs);
|
||||||
|
|
||||||
@ -148,7 +139,7 @@ impl Parser {
|
|||||||
/// equal sign "=" and an expression.
|
/// equal sign "=" and an expression.
|
||||||
///
|
///
|
||||||
/// ### Grammar
|
/// ### Grammar
|
||||||
/// `stmt_assign = ident "=" expr_add`
|
/// `stmt_assign = ident "=" expr`
|
||||||
pub fn parse_stmt_assign(&mut self) -> PRes<Statement> {
|
pub fn parse_stmt_assign(&mut self) -> PRes<Statement> {
|
||||||
// Fetch the variable name
|
// Fetch the variable name
|
||||||
let var_name = match self.advance() {
|
let var_name = match self.advance() {
|
||||||
@ -162,16 +153,140 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse the right hand side of the assignment
|
// Parse the right hand side of the assignment
|
||||||
let rhs = self.parse_expr_add()?;
|
let rhs = self.parse_expr()?;
|
||||||
|
|
||||||
let let_binding = Statement::Assignment(var_name, rhs);
|
let let_binding = Statement::Assignment(var_name, rhs);
|
||||||
|
|
||||||
Ok(let_binding)
|
Ok(let_binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The main expression parsing function. This can be a multiplication expression and 0 or more
|
/// The main expression parsing function.
|
||||||
/// further multiplication expressions separated by addition precedence operators (add '+',
|
pub fn parse_expr(&mut self) -> PRes<Expr> {
|
||||||
/// sub '-').
|
self.parse_expr_or()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_expr_or(&mut self) -> PRes<Expr> {
|
||||||
|
// Parse the left hand side / the main expression if there is nothing on the right
|
||||||
|
let mut lhs = self.parse_expr_xor()?;
|
||||||
|
|
||||||
|
// Parse 0 or more expressions to the right side of the or operators
|
||||||
|
while matches!(self.curr(), Some(Token::Op(Op::Or))) {
|
||||||
|
// We successfully matched curr against Some already in the while condition, so unwrap
|
||||||
|
// is fine
|
||||||
|
let tok_op = self.advance().unwrap().clone();
|
||||||
|
|
||||||
|
let rhs = self.parse_expr_xor()?;
|
||||||
|
|
||||||
|
let op_type = match tok_op {
|
||||||
|
Token::Op(Op::Or) => BinOpType::Or,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
lhs = Expr::BinOp(op_type, lhs.into(), rhs.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(lhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_expr_xor(&mut self) -> PRes<Expr> {
|
||||||
|
// Parse the left hand side / the main expression if there is nothing on the right
|
||||||
|
let mut lhs = self.parse_expr_and()?;
|
||||||
|
|
||||||
|
// Parse 0 or more expressions to the right side of the xor operators
|
||||||
|
while matches!(self.curr(), Some(Token::Op(Op::Xor))) {
|
||||||
|
// We successfully matched curr against Some already in the while condition, so unwrap
|
||||||
|
// is fine
|
||||||
|
let tok_op = self.advance().unwrap().clone();
|
||||||
|
|
||||||
|
let rhs = self.parse_expr_and()?;
|
||||||
|
|
||||||
|
let op_type = match tok_op {
|
||||||
|
Token::Op(Op::Xor) => BinOpType::Xor,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
lhs = Expr::BinOp(op_type, lhs.into(), rhs.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(lhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_expr_and(&mut self) -> PRes<Expr> {
|
||||||
|
// Parse the left hand side / the main expression if there is nothing on the right
|
||||||
|
let mut lhs = self.parse_expr_equal()?;
|
||||||
|
|
||||||
|
// Parse 0 or more expressions to the right side of the and operators
|
||||||
|
while matches!(self.curr(), Some(Token::Op(Op::And))) {
|
||||||
|
// We successfully matched curr against Some already in the while condition, so unwrap
|
||||||
|
// is fine
|
||||||
|
let tok_op = self.advance().unwrap().clone();
|
||||||
|
|
||||||
|
let rhs = self.parse_expr_equal()?;
|
||||||
|
|
||||||
|
let op_type = match tok_op {
|
||||||
|
Token::Op(Op::And) => BinOpType::And,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
lhs = Expr::BinOp(op_type, lhs.into(), rhs.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(lhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_expr_equal(&mut self) -> PRes<Expr> {
|
||||||
|
// Parse the left hand side / the main expression if there is nothing on the right
|
||||||
|
let mut lhs = self.parse_expr_rel()?;
|
||||||
|
|
||||||
|
// Parse 0 or more expressions to the right side of the equality operators
|
||||||
|
while matches!(self.curr(), Some(Token::Op(Op::Eq | Op::Neq))) {
|
||||||
|
// We successfully matched curr against Some already in the while condition, so unwrap
|
||||||
|
// is fine
|
||||||
|
let tok_op = self.advance().unwrap().clone();
|
||||||
|
|
||||||
|
let rhs = self.parse_expr_rel()?;
|
||||||
|
|
||||||
|
let op_type = match tok_op {
|
||||||
|
Token::Op(Op::Eq) => BinOpType::Eq,
|
||||||
|
Token::Op(Op::Neq) => BinOpType::Neq,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
lhs = Expr::BinOp(op_type, lhs.into(), rhs.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(lhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_expr_rel(&mut self) -> PRes<Expr> {
|
||||||
|
// Parse the left hand side / the main expression if there is nothing on the right
|
||||||
|
let mut lhs = self.parse_expr_add()?;
|
||||||
|
|
||||||
|
// Parse 0 or more expressions to the right side of the relational operators
|
||||||
|
while matches!(self.curr(), Some(Token::Op(Op::Gt | Op::Lt | Op::Ge | Op::Le))) {
|
||||||
|
// We successfully matched curr against Some already in the while condition, so unwrap
|
||||||
|
// is fine
|
||||||
|
let tok_op = self.advance().unwrap().clone();
|
||||||
|
|
||||||
|
let rhs = self.parse_expr_add()?;
|
||||||
|
|
||||||
|
let op_type = match tok_op {
|
||||||
|
Token::Op(Op::Gt) => BinOpType::Gt,
|
||||||
|
Token::Op(Op::Lt) => BinOpType::Lt,
|
||||||
|
Token::Op(Op::Ge) => BinOpType::Ge,
|
||||||
|
Token::Op(Op::Le) => BinOpType::Le,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
lhs = Expr::BinOp(op_type, lhs.into(), rhs.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(lhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse an add expression from the TokenStream. This can be a multiplication expression and
|
||||||
|
/// 0 or more further multiplication expressions separated by addition precedence operators
|
||||||
|
/// (add '+', sub '-').
|
||||||
///
|
///
|
||||||
/// Add is the operator with the lowest precedence which is why this recursively handles all
|
/// Add is the operator with the lowest precedence which is why this recursively handles all
|
||||||
/// other kinds of expressions.
|
/// other kinds of expressions.
|
||||||
@ -236,7 +351,7 @@ impl Parser {
|
|||||||
/// expression enclosed by parentheses or a value.
|
/// expression enclosed by parentheses or a value.
|
||||||
///
|
///
|
||||||
/// ### Grammar
|
/// ### Grammar
|
||||||
/// `"-" expr_term | "(" expr_add ")" | expr_value`
|
/// `"-" expr_term | "!" expr_term | "(" expr_add ")" | expr_value`
|
||||||
pub fn parse_expr_term(&mut self) -> PRes<Expr> {
|
pub fn parse_expr_term(&mut self) -> PRes<Expr> {
|
||||||
let term = match self.curr() {
|
let term = match self.curr() {
|
||||||
// Current token is an opening parentheses '(' -> Must be an enclosed expr_add
|
// Current token is an opening parentheses '(' -> Must be an enclosed expr_add
|
||||||
@ -244,7 +359,7 @@ impl Parser {
|
|||||||
// Skip the '('
|
// Skip the '('
|
||||||
self.advance();
|
self.advance();
|
||||||
|
|
||||||
let expr = self.parse_expr_add()?;
|
let expr = self.parse_expr()?;
|
||||||
|
|
||||||
// After the expression must be closing parentheses ')'
|
// After the expression must be closing parentheses ')'
|
||||||
if !matches!(self.advance(), Some(Token::Close(Group::Paren))) {
|
if !matches!(self.advance(), Some(Token::Close(Group::Paren))) {
|
||||||
@ -261,6 +376,14 @@ impl Parser {
|
|||||||
// Parse an expr_term in a Negation Node
|
// Parse an expr_term in a Negation Node
|
||||||
Expr::UnOp(UnOpType::Neg, self.parse_expr_term()?.into())
|
Expr::UnOp(UnOpType::Neg, self.parse_expr_term()?.into())
|
||||||
}
|
}
|
||||||
|
// Current token is a not '!' -> Must be a not expr_term
|
||||||
|
Some(Token::Op(Op::Not)) => {
|
||||||
|
// Skip the '!'
|
||||||
|
self.advance();
|
||||||
|
|
||||||
|
// Parse an expr_term in a Not Node
|
||||||
|
Expr::UnOp(UnOpType::Not, self.parse_expr_term()?.into())
|
||||||
|
}
|
||||||
// Nothing special in the current -> Must be an expr_value
|
// Nothing special in the current -> Must be an expr_value
|
||||||
_ => self.parse_expr_value()?,
|
_ => self.parse_expr_value()?,
|
||||||
};
|
};
|
||||||
@ -309,13 +432,13 @@ impl Parser {
|
|||||||
// one add expression
|
// one add expression
|
||||||
// TODO: This is *suboptimal* code
|
// TODO: This is *suboptimal* code
|
||||||
if !matches!(self.curr(), Some(Token::Close(Group::Paren))) {
|
if !matches!(self.curr(), Some(Token::Close(Group::Paren))) {
|
||||||
args.push(self.parse_expr_add()?);
|
args.push(self.parse_expr()?);
|
||||||
|
|
||||||
// As long as there are commas after the expressions, parse more expressions as
|
// As long as there are commas after the expressions, parse more expressions as
|
||||||
// parameters
|
// parameters
|
||||||
while matches!(self.curr(), Some(Token::Comma)) {
|
while matches!(self.curr(), Some(Token::Comma)) {
|
||||||
self.advance();
|
self.advance();
|
||||||
args.push(self.parse_expr_add()?);
|
args.push(self.parse_expr()?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -467,7 +590,7 @@ mod tests {
|
|||||||
// let res = parse_str(input);
|
// let res = parse_str(input);
|
||||||
|
|
||||||
let mut parser = Parser::new(TokenStream::new(input_toks));
|
let mut parser = Parser::new(TokenStream::new(input_toks));
|
||||||
let res = parser.parse_expr_add().unwrap();
|
let res = parser.parse_expr().unwrap();
|
||||||
|
|
||||||
assert_eq!(expected, res);
|
assert_eq!(expected, res);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,13 +39,13 @@ pub enum Op {
|
|||||||
|
|
||||||
// Boolean
|
// Boolean
|
||||||
|
|
||||||
/// And "&&"
|
/// Boolean And "&&"
|
||||||
And,
|
And,
|
||||||
/// Or "||"
|
/// Boolean Or "||"
|
||||||
Or,
|
Or,
|
||||||
/// Not "!"
|
/// Boolean Not "!"
|
||||||
Not,
|
Not,
|
||||||
/// Xor "^"
|
/// Boolean Xor "^^"
|
||||||
Xor,
|
Xor,
|
||||||
|
|
||||||
/// Arrow "->"
|
/// Arrow "->"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user