From ee7c269301f84bd5c7c942900aaa2d96d17d886f Mon Sep 17 00:00:00 2001 From: David Li Date: Sat, 4 Nov 2017 19:06:13 -0400 Subject: Parse binary operators with precedence --- src/ast.rs | 22 ++++++++++++++++++++++ src/main.rs | 2 +- src/taiga.lalrpop | 25 +++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/ast.rs b/src/ast.rs index 3863ce9..2814ef9 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -18,12 +18,34 @@ impl WithLocation { location: self.location, } } + + pub fn join_map(self, other: WithLocation, f: F) -> WithLocation + where F: FnOnce(WithLocation, WithLocation) -> V + { + let loc1 = self.location; + let loc2 = other.location; + WithLocation { + value: f(self, other), + location: (loc1.0, loc2.1), + } + } } #[derive(Debug)] pub struct Program(pub Box>); +#[derive(Debug)] +pub enum BinOp { + Add, + Sub, + Mul, + Div, + FloorDiv, +} + #[derive(Debug)] pub enum Expression { + BinOp(BinOp, Box>, Box>), Number(u64), + Nil, } diff --git a/src/main.rs b/src/main.rs index 5b343ec..bd4659b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,5 +2,5 @@ pub mod ast; pub mod taiga; fn main() { - println!("{:?}", taiga::parse_Program("5")); + println!("{:?}", taiga::parse_Program("(3 + 5) * 7")); } diff --git a/src/taiga.lalrpop b/src/taiga.lalrpop index 08c3cd3..0182a04 100644 --- a/src/taiga.lalrpop +++ b/src/taiga.lalrpop @@ -8,7 +8,32 @@ pub Program: ast::Program = { }; Expression: Box> = { + "+" => Box::new(e1.join_map(*e2, |v1, v2| { + ast::Expression::BinOp(ast::BinOp::Add, Box::new(v1), Box::new(v2)) + })), + "-" => Box::new(e1.join_map(*e2, |v1, v2| { + ast::Expression::BinOp(ast::BinOp::Sub, Box::new(v1), Box::new(v2)) + })), + => <>, +}; + +ExpressionMul: Box> = { + "*" => Box::new(e1.join_map(*e2, |v1, v2| { + ast::Expression::BinOp(ast::BinOp::Mul, Box::new(v1), Box::new(v2)) + })), + "/" => Box::new(e1.join_map(*e2, |v1, v2| { + ast::Expression::BinOp(ast::BinOp::Div, Box::new(v1), Box::new(v2)) + })), + "//" => Box::new(e1.join_map(*e2, |v1, v2| { + ast::Expression::BinOp(ast::BinOp::FloorDiv, Box::new(v1), Box::new(v2)) + })), + => <>, +}; + +ExpressionBase: Box> = { Num => Box::new(<>.map(|v| ast::Expression::Number(v))), + Spanned => Box::new(<>.map(|v| ast::Expression::Nil)), + "(" ")" => <>, }; Num: WithLocation = > => e.map(|v| u64::from_str(v).unwrap()); -- cgit v1.2.3