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(-)
(limited to 'src')
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