Parse var and fn calls in expr

- Parse variable values in expressions
- Parse function calls in expressions
This commit is contained in:
Daniel M 2021-12-24 01:25:04 +01:00
parent 8de6e990b4
commit 5be3fd5bbc
3 changed files with 116 additions and 53 deletions

View File

@ -4,7 +4,7 @@ use plang2_lib::*;
fn main() { fn main() {
let code = r#" let code = r#"
-( -5 + 2 ) * -( 2 * -5 ) + -( 2 - 6 ) (-(-5+2)*-(2*-sqrt(9))+-(a-6)) % 30
"#; "#;
let mut lexer = Lexer::new(code); let mut lexer = Lexer::new(code);

View File

@ -17,9 +17,18 @@ pub enum UnOpType {
Neg Neg
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FnCall {
pub fn_name: String,
pub args: Vec<Expr>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Expr { pub enum Expr {
Literal(Literal), Literal(Literal),
// contains variable name
Variable(String),
FnCall(FnCall),
BinOp(BinOpType, Box<Expr>, Box<Expr>), BinOp(BinOpType, Box<Expr>, Box<Expr>),
UnOp(UnOpType, Box<Expr>), UnOp(UnOpType, Box<Expr>),
} }

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
ast::{BinOpType, Expr, UnOpType}, ast::{BinOpType, Expr, FnCall, UnOpType},
token::{Group, Op, Token, TokenStream}, token::{Group, Op, Token, TokenStream},
}; };
@ -15,7 +15,10 @@ pub struct Parser {
/* /*
GRAMMAR GRAMMAR
expr_literal = "-" Literal | Literal expr_literal = Literal
expr_fn_call = FnCall
expr_varibale = Variable
expr_value = expr_literal | expr_fn_call | expr_variable
expr_term = "-" expr_term | "(" expr_add ")" | expr_literal expr_term = "-" expr_term | "(" expr_add ")" | expr_literal
expr_mul = expr_term (("*"|"/") expr_term)* expr_mul = expr_term (("*"|"/") expr_term)*
expr_add = expr_mul (("+"|"-") expr_mul)* expr_add = expr_mul (("+"|"-") expr_mul)*
@ -99,15 +102,64 @@ impl Parser {
self.advance(); self.advance();
Expr::UnOp(UnOpType::Neg, self.parse_expr_term()?.into()) Expr::UnOp(UnOpType::Neg, self.parse_expr_term()?.into())
} }
_ => self.parse_expr_literal()?, _ => self.parse_expr_value()?,
}; };
Ok(term) Ok(term)
} }
pub fn parse_expr_value(&mut self) -> PRes<Expr> {
match self.curr() {
Some(Token::Literal(_)) => self.parse_expr_literal(),
Some(Token::Ident(_)) if matches!(self.peek(), Some(Token::Open(Group::Paren))) => {
self.parse_expr_fn_call()
}
Some(Token::Ident(_)) => self.parse_expr_varibale(),
_ => panic!("Expected value (literal, variable or function call)"),
}
}
pub fn parse_expr_fn_call(&mut self) -> PRes<Expr> {
// The first 2 checks are not really necessary for internal calls since parse_expr_value
// verifies the tokens already
let fn_name = match self.advance() {
Some(Token::Ident(ident)) => ident.clone(),
_ => panic!("Unexpected token while parsing function call. Expected identifier"),
};
if !matches!(self.advance(), Some(Token::Open(Group::Paren))) {
panic!("Unexpected token while parsing function call. Expected '('");
}
let mut args = Vec::new();
// TODO: This is *suboptimal* code
if !matches!(self.curr(), Some(Token::Close(Group::Paren))) {
args.push(self.parse_expr_add()?);
while matches!(self.curr(), Some(Token::Comma)) {
self.advance();
args.push(self.parse_expr_add()?);
}
}
if !matches!(self.advance(), Some(Token::Close(Group::Paren))) {
panic!("Unexpected token while parsing function call. Expected '('");
}
Ok(Expr::FnCall(FnCall { fn_name, args }))
}
pub fn parse_expr_varibale(&mut self) -> PRes<Expr> {
match self.advance() {
Some(Token::Ident(ident)) => Ok(Expr::Variable(ident.clone())),
_ => panic!("Unexpected token while parsing variable. Expected identifier"),
}
}
pub fn parse_expr_literal(&mut self) -> PRes<Expr> { pub fn parse_expr_literal(&mut self) -> PRes<Expr> {
match self.advance() { match self.advance() {
Some(Token::Literal(lit)) => Ok(Expr::Literal(lit.clone())), Some(Token::Literal(lit)) => Ok(Expr::Literal(lit.clone())),
_ => panic!("Unexpected token. Expected literal"), _ => panic!("Unexpected token while parsing literal. Expected literal"),
} }
} }
} }
@ -115,51 +167,49 @@ impl Parser {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use crate::{
ast::{BinOpType, Expr, UnOpType}, ast::{BinOpType, Expr, FnCall, UnOpType},
token::{Group, Literal, Op, Token, TokenStream}, token::{Group, Literal, Op, Token, TokenStream},
Parser, Parser,
}; };
// fn parse_str(code: &str) -> Expr {
// let mut lexer = Lexer::new(code);
// let tokens = lexer.tokenize().unwrap();
// let mut parser = Parser::new(tokens);
// parser.parse().unwrap()
// }
#[test] #[test]
fn test_groupings_neg() { fn test_groupings_neg() {
// let input = "(-(-5+2)*-(2*-5)+-(2-6)) % 30"; // let input = "(-(-5+2)*-(2*-sqrt(9))+-(a-6)) % 30";
// (-(-5+2)*-(2*-5)+-(2-6)) % 30 let fn_name = "sqrt".to_string();
let var_name = "a".to_string();
// (-(-5+2)*-(2*-sqrt(9))+-(a-6)) % 30
let input_toks = vec![ let input_toks = vec![
Token::Open(Group::Paren), Token::Open(Group::Paren), // (
Token::Op(Op::Sub), Token::Op(Op::Sub), // -
Token::Open(Group::Paren), Token::Open(Group::Paren), // (
Token::Op(Op::Sub), Token::Op(Op::Sub), // -
Token::Literal(Literal::Int64(5)), Token::Literal(Literal::Int64(5)), // 5
Token::Op(Op::Add), Token::Op(Op::Add), // +
Token::Literal(Literal::Int64(2)), Token::Literal(Literal::Int64(2)), // 2
Token::Close(Group::Paren), Token::Close(Group::Paren), // )
Token::Op(Op::Mul), Token::Op(Op::Mul), // *
Token::Op(Op::Sub), Token::Op(Op::Sub), // -
Token::Open(Group::Paren), Token::Open(Group::Paren), // (
Token::Literal(Literal::Int64(2)), Token::Literal(Literal::Int64(2)), // 2
Token::Op(Op::Mul), Token::Op(Op::Mul), // *
Token::Op(Op::Sub), Token::Op(Op::Sub), // -
Token::Literal(Literal::Int64(5)), Token::Ident(fn_name.clone()), // sqrt
Token::Close(Group::Paren), Token::Open(Group::Paren), // (
Token::Op(Op::Add), Token::Literal(Literal::Int64(9)), // 9
Token::Op(Op::Sub), Token::Close(Group::Paren), // )
Token::Open(Group::Paren), Token::Close(Group::Paren), // )
Token::Literal(Literal::Int64(2)), Token::Op(Op::Add), // +
Token::Op(Op::Sub), Token::Op(Op::Sub), // -
Token::Literal(Literal::Int64(6)), Token::Open(Group::Paren), // (
Token::Close(Group::Paren), Token::Ident(var_name.clone()), // a
Token::Close(Group::Paren), Token::Op(Op::Sub), // -
Token::Op(Op::Mod), Token::Literal(Literal::Int64(6)), // 6
Token::Literal(Literal::Int64(30)), Token::Close(Group::Paren), // )
Token::Close(Group::Paren), // )
Token::Op(Op::Mod), // %
Token::Literal(Literal::Int64(30)), // 30
]; ];
// -(-5+2) // -(-5+2)
@ -175,40 +225,44 @@ mod tests {
)), )),
); );
// -(2*-5) // -(2*-sqrt(9))
let neg_grp_2_mul_neg_2 = Expr::UnOp( let neg_grp_2_mul_neg_sqrt = Expr::UnOp(
UnOpType::Neg, UnOpType::Neg,
Box::new(Expr::BinOp( Box::new(Expr::BinOp(
BinOpType::Mul, BinOpType::Mul,
Expr::Literal(Literal::Int64(2)).into(), Expr::Literal(Literal::Int64(2)).into(),
Box::new(Expr::UnOp( Box::new(Expr::UnOp(
UnOpType::Neg, UnOpType::Neg,
Expr::Literal(Literal::Int64(5)).into(), Expr::FnCall(FnCall {
fn_name,
args: vec![Expr::Literal(Literal::Int64(9))],
})
.into(),
)), )),
)), )),
); );
// -(-5+2)*-(2*-5) // -(-5+2) * -(2*-sqrt(9))
let mul_first = Expr::BinOp( let mul_first = Expr::BinOp(
BinOpType::Mul, BinOpType::Mul,
neg_grp_neg_5_add_2.into(), neg_grp_neg_5_add_2.into(),
neg_grp_2_mul_neg_2.into(), neg_grp_2_mul_neg_sqrt.into(),
); );
// -(2-6) // -(a-6)
let neg_grp_2_sub_6 = Expr::UnOp( let neg_grp_a_sub_6 = Expr::UnOp(
UnOpType::Neg, UnOpType::Neg,
Box::new(Expr::BinOp( Box::new(Expr::BinOp(
BinOpType::Sub, BinOpType::Sub,
Expr::Literal(Literal::Int64(2)).into(), Expr::Variable(var_name).into(),
Expr::Literal(Literal::Int64(6)).into(), Expr::Literal(Literal::Int64(6)).into(),
)), )),
); );
// -(-5+2)*-(2*-5)+-(2-6) // -(-5+2)*-(2*-sqrt(9)) + -(a-6)
let left_of_mod = Expr::BinOp(BinOpType::Add, mul_first.into(), neg_grp_2_sub_6.into()); let left_of_mod = Expr::BinOp(BinOpType::Add, mul_first.into(), neg_grp_a_sub_6.into());
// (-(-5+2)*-(2*-5)+-(2-6)) % 30 // (-(-5+2) * -(2*-sqrt(9)) + -(a-6)) % 30
let expected = Expr::BinOp( let expected = Expr::BinOp(
BinOpType::Mod, BinOpType::Mod,
left_of_mod.into(), left_of_mod.into(),