Parse var and fn calls in expr
- Parse variable values in expressions - Parse function calls in expressions
This commit is contained in:
parent
8de6e990b4
commit
5be3fd5bbc
@ -4,7 +4,7 @@ use plang2_lib::*;
|
||||
fn main() {
|
||||
|
||||
let code = r#"
|
||||
-( -5 + 2 ) * -( 2 * -5 ) + -( 2 - 6 )
|
||||
(-(-5+2)*-(2*-sqrt(9))+-(a-6)) % 30
|
||||
"#;
|
||||
|
||||
let mut lexer = Lexer::new(code);
|
||||
|
||||
@ -17,9 +17,18 @@ pub enum UnOpType {
|
||||
Neg
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct FnCall {
|
||||
pub fn_name: String,
|
||||
pub args: Vec<Expr>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Expr {
|
||||
Literal(Literal),
|
||||
// contains variable name
|
||||
Variable(String),
|
||||
FnCall(FnCall),
|
||||
BinOp(BinOpType, Box<Expr>, Box<Expr>),
|
||||
UnOp(UnOpType, Box<Expr>),
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
ast::{BinOpType, Expr, UnOpType},
|
||||
ast::{BinOpType, Expr, FnCall, UnOpType},
|
||||
token::{Group, Op, Token, TokenStream},
|
||||
};
|
||||
|
||||
@ -15,7 +15,10 @@ pub struct Parser {
|
||||
/*
|
||||
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_mul = expr_term (("*"|"/") expr_term)*
|
||||
expr_add = expr_mul (("+"|"-") expr_mul)*
|
||||
@ -99,15 +102,64 @@ impl Parser {
|
||||
self.advance();
|
||||
Expr::UnOp(UnOpType::Neg, self.parse_expr_term()?.into())
|
||||
}
|
||||
_ => self.parse_expr_literal()?,
|
||||
_ => self.parse_expr_value()?,
|
||||
};
|
||||
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> {
|
||||
match self.advance() {
|
||||
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)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
ast::{BinOpType, Expr, UnOpType},
|
||||
ast::{BinOpType, Expr, FnCall, UnOpType},
|
||||
token::{Group, Literal, Op, Token, TokenStream},
|
||||
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]
|
||||
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![
|
||||
Token::Open(Group::Paren),
|
||||
Token::Op(Op::Sub),
|
||||
Token::Open(Group::Paren),
|
||||
Token::Op(Op::Sub),
|
||||
Token::Literal(Literal::Int64(5)),
|
||||
Token::Op(Op::Add),
|
||||
Token::Literal(Literal::Int64(2)),
|
||||
Token::Close(Group::Paren),
|
||||
Token::Op(Op::Mul),
|
||||
Token::Op(Op::Sub),
|
||||
Token::Open(Group::Paren),
|
||||
Token::Literal(Literal::Int64(2)),
|
||||
Token::Op(Op::Mul),
|
||||
Token::Op(Op::Sub),
|
||||
Token::Literal(Literal::Int64(5)),
|
||||
Token::Close(Group::Paren),
|
||||
Token::Op(Op::Add),
|
||||
Token::Op(Op::Sub),
|
||||
Token::Open(Group::Paren),
|
||||
Token::Literal(Literal::Int64(2)),
|
||||
Token::Op(Op::Sub),
|
||||
Token::Literal(Literal::Int64(6)),
|
||||
Token::Close(Group::Paren),
|
||||
Token::Close(Group::Paren),
|
||||
Token::Op(Op::Mod),
|
||||
Token::Literal(Literal::Int64(30)),
|
||||
Token::Open(Group::Paren), // (
|
||||
Token::Op(Op::Sub), // -
|
||||
Token::Open(Group::Paren), // (
|
||||
Token::Op(Op::Sub), // -
|
||||
Token::Literal(Literal::Int64(5)), // 5
|
||||
Token::Op(Op::Add), // +
|
||||
Token::Literal(Literal::Int64(2)), // 2
|
||||
Token::Close(Group::Paren), // )
|
||||
Token::Op(Op::Mul), // *
|
||||
Token::Op(Op::Sub), // -
|
||||
Token::Open(Group::Paren), // (
|
||||
Token::Literal(Literal::Int64(2)), // 2
|
||||
Token::Op(Op::Mul), // *
|
||||
Token::Op(Op::Sub), // -
|
||||
Token::Ident(fn_name.clone()), // sqrt
|
||||
Token::Open(Group::Paren), // (
|
||||
Token::Literal(Literal::Int64(9)), // 9
|
||||
Token::Close(Group::Paren), // )
|
||||
Token::Close(Group::Paren), // )
|
||||
Token::Op(Op::Add), // +
|
||||
Token::Op(Op::Sub), // -
|
||||
Token::Open(Group::Paren), // (
|
||||
Token::Ident(var_name.clone()), // a
|
||||
Token::Op(Op::Sub), // -
|
||||
Token::Literal(Literal::Int64(6)), // 6
|
||||
Token::Close(Group::Paren), // )
|
||||
Token::Close(Group::Paren), // )
|
||||
Token::Op(Op::Mod), // %
|
||||
Token::Literal(Literal::Int64(30)), // 30
|
||||
];
|
||||
|
||||
// -(-5+2)
|
||||
@ -175,40 +225,44 @@ mod tests {
|
||||
)),
|
||||
);
|
||||
|
||||
// -(2*-5)
|
||||
let neg_grp_2_mul_neg_2 = Expr::UnOp(
|
||||
// -(2*-sqrt(9))
|
||||
let neg_grp_2_mul_neg_sqrt = Expr::UnOp(
|
||||
UnOpType::Neg,
|
||||
Box::new(Expr::BinOp(
|
||||
BinOpType::Mul,
|
||||
Expr::Literal(Literal::Int64(2)).into(),
|
||||
Box::new(Expr::UnOp(
|
||||
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(
|
||||
BinOpType::Mul,
|
||||
neg_grp_neg_5_add_2.into(),
|
||||
neg_grp_2_mul_neg_2.into(),
|
||||
neg_grp_2_mul_neg_sqrt.into(),
|
||||
);
|
||||
|
||||
// -(2-6)
|
||||
let neg_grp_2_sub_6 = Expr::UnOp(
|
||||
// -(a-6)
|
||||
let neg_grp_a_sub_6 = Expr::UnOp(
|
||||
UnOpType::Neg,
|
||||
Box::new(Expr::BinOp(
|
||||
BinOpType::Sub,
|
||||
Expr::Literal(Literal::Int64(2)).into(),
|
||||
Expr::Variable(var_name).into(),
|
||||
Expr::Literal(Literal::Int64(6)).into(),
|
||||
)),
|
||||
);
|
||||
|
||||
// -(-5+2)*-(2*-5)+-(2-6)
|
||||
let left_of_mod = Expr::BinOp(BinOpType::Add, mul_first.into(), neg_grp_2_sub_6.into());
|
||||
// -(-5+2)*-(2*-sqrt(9)) + -(a-6)
|
||||
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(
|
||||
BinOpType::Mod,
|
||||
left_of_mod.into(),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user