summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Li <li.davidm96@gmail.com>2017-11-04 19:06:13 -0400
committerDavid Li <li.davidm96@gmail.com>2017-11-04 19:06:13 -0400
commitee7c269301f84bd5c7c942900aaa2d96d17d886f (patch)
tree6ecdae2104751db610526f9564c97177a5244db1
parent35bf004cc923c1bd61a75fa0ff9b336644f0c8b0 (diff)
Parse binary operators with precedence
-rw-r--r--src/ast.rs22
-rw-r--r--src/main.rs2
-rw-r--r--src/taiga.lalrpop25
3 files changed, 48 insertions, 1 deletions
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<T> WithLocation<T> {
location: self.location,
}
}
+
+ pub fn join_map<U, V, F>(self, other: WithLocation<U>, f: F) -> WithLocation<V>
+ where F: FnOnce(WithLocation<T>, WithLocation<U>) -> 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<WithLocation<Expression>>);
#[derive(Debug)]
+pub enum BinOp {
+ Add,
+ Sub,
+ Mul,
+ Div,
+ FloorDiv,
+}
+
+#[derive(Debug)]
pub enum Expression {
+ BinOp(BinOp, Box<WithLocation<Expression>>, Box<WithLocation<Expression>>),
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<ast::WithLocation<ast::Expression>> = {
+ <e1:Expression> "+" <e2:ExpressionMul> => Box::new(e1.join_map(*e2, |v1, v2| {
+ ast::Expression::BinOp(ast::BinOp::Add, Box::new(v1), Box::new(v2))
+ })),
+ <e1:Expression> "-" <e2:ExpressionMul> => Box::new(e1.join_map(*e2, |v1, v2| {
+ ast::Expression::BinOp(ast::BinOp::Sub, Box::new(v1), Box::new(v2))
+ })),
+ <ExpressionMul> => <>,
+};
+
+ExpressionMul: Box<ast::WithLocation<ast::Expression>> = {
+ <e1:ExpressionMul> "*" <e2:ExpressionBase> => Box::new(e1.join_map(*e2, |v1, v2| {
+ ast::Expression::BinOp(ast::BinOp::Mul, Box::new(v1), Box::new(v2))
+ })),
+ <e1:ExpressionMul> "/" <e2:ExpressionBase> => Box::new(e1.join_map(*e2, |v1, v2| {
+ ast::Expression::BinOp(ast::BinOp::Div, Box::new(v1), Box::new(v2))
+ })),
+ <e1:ExpressionMul> "//" <e2:ExpressionBase> => Box::new(e1.join_map(*e2, |v1, v2| {
+ ast::Expression::BinOp(ast::BinOp::FloorDiv, Box::new(v1), Box::new(v2))
+ })),
+ <ExpressionBase> => <>,
+};
+
+ExpressionBase: Box<ast::WithLocation<ast::Expression>> = {
Num => Box::new(<>.map(|v| ast::Expression::Number(v))),
+ Spanned<r"nil"> => Box::new(<>.map(|v| ast::Expression::Nil)),
+ "(" <Expression> ")" => <>,
};
Num: WithLocation<u64> = <e: Spanned<r"[0-9]+">> => e.map(|v| u64::from_str(v).unwrap());