summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNadrieril2019-03-03 00:14:08 +0100
committerNadrieril2019-03-03 00:26:23 +0100
commit3f19f1b34386875def0e6124fe550baefc81f65a (patch)
treee3f556f8554c5acd3e38ff40c693fddb6d9971e5
parentb7ce3e60770be41d8ccf773541c586c75d2a4e38 (diff)
Write macros to streamline parsing
-rw-r--r--dhall/src/lib.rs1
-rw-r--r--dhall/src/parser.rs83
2 files changed, 59 insertions, 25 deletions
diff --git a/dhall/src/lib.rs b/dhall/src/lib.rs
index 9dbd3a6..ad10cc5 100644
--- a/dhall/src/lib.rs
+++ b/dhall/src/lib.rs
@@ -1,4 +1,5 @@
#![feature(box_patterns)]
+#![feature(concat_idents)]
pub mod context;
mod core;
diff --git a/dhall/src/parser.rs b/dhall/src/parser.rs
index 9259dfd..40272e0 100644
--- a/dhall/src/parser.rs
+++ b/dhall/src/parser.rs
@@ -48,29 +48,62 @@ fn debug_pair(pair: Pair<Rule>) {
aux(0, "".into(), pair)
}
+macro_rules! parse_aux {
+ ($inner:expr, true, $x:ident : $ty:ident $($rest:tt)*) => {
+ let $x = concat_idents!(parse_, $ty)($inner.next().unwrap());
+ parse_aux!($inner, true $($rest)*)
+ };
+ ($inner:expr, true, $x:ident? : $ty:ident $($rest:tt)*) => {
+ let $x = $inner.next().map(concat_idents!(parse_, $ty));
+ parse_aux!($inner, true $($rest)*)
+ };
+ ($inner:expr, true, $x:ident* : $ty:ident $($rest:tt)*) => {
+ let $x = $inner.map(concat_idents!(parse_, $ty));
+ parse_aux!($inner, false $($rest)*)
+ };
+ ($inner:expr, false) => {};
+ ($inner:expr, true) => {
+ $inner.next().ok_or(()).expect_err("Some parsed values remain unused")
+ };
+}
+
+macro_rules! parse {
+ ($pair:expr; ($($args:tt)*) => $body:expr) => {
+ {
+ #[allow(unused_mut)]
+ let mut inner = $pair.into_inner();
+ parse_aux!(inner, true, $($args)*);
+ $body
+ }
+ };
+}
+
+
fn parse_binop<'a, F>(pair: Pair<'a, Rule>, mut f: F) -> BoxExpr<'a>
where F: FnMut(BoxExpr<'a>, BoxExpr<'a>) -> ParsedExpr<'a> {
- let mut inner = pair.into_inner().map(parse_expression);
- let first_expr = inner.next().unwrap();
- inner.fold(first_expr, |acc, e| bx(f(acc, e)))
+ parse!(pair; (first: expression, rest*: expression) => {
+ rest.fold(first, |acc, e| bx(f(acc, e)))
+ })
}
fn skip_expr(pair: Pair<Rule>) -> BoxExpr {
- let mut inner = pair.into_inner().map(parse_expression);
- inner.next().unwrap()
+ parse!(pair; (expr: expression) => {
+ expr
+ })
}
fn parse_str(pair: Pair<Rule>) -> &str {
pair.as_str().trim()
}
-fn parse_natural(pair: Pair<Rule>) -> Result<usize, std::num::ParseIntError> {
- parse_str(pair).parse()
+// fn parse_natural(pair: Pair<Rule>) -> Result<usize, std::num::ParseIntError> {
+fn parse_natural(pair: Pair<Rule>) -> usize {
+ parse_str(pair).parse().unwrap()
}
fn parse_expression(pair: Pair<Rule>) -> BoxExpr {
match pair.as_rule() {
- Rule::natural_literal_raw => bx(Expr::NaturalLit(parse_natural(pair).unwrap())),
+ Rule::natural_literal_raw => bx(Expr::NaturalLit(parse_natural(pair))),
Rule::annotated_expression => { parse_binop(pair, Expr::Annot) }
Rule::import_alt_expression => { skip_expr(pair) }
@@ -87,18 +120,20 @@ fn parse_expression(pair: Pair<Rule>) -> BoxExpr {
Rule::not_equal_expression => { parse_binop(pair, Expr::BoolNE) }
Rule::application_expression => { parse_binop(pair, Expr::App) }
- Rule::selector_expression_raw => {
- let mut inner = pair.into_inner();
- let first_expr = parse_expression(inner.next().unwrap());
- inner.fold(first_expr, |acc, e| bx(Expr::Field(acc, e.as_str())))
- }
+ Rule::selector_expression_raw =>
+ parse!(pair; (first: expression, rest*: str) => {
+ rest.fold(first, |acc, e| bx(Expr::Field(acc, e)))
+ }),
- Rule::identifier_raw => {
- let mut inner = pair.into_inner();
- let name = parse_str(inner.next().unwrap());
- let idx = inner.next().map(parse_natural).unwrap_or(Ok(0)).unwrap();
- bx(Expr::Var(V(name, idx)))
- }
+ Rule::identifier_raw =>
+ parse!(pair; (name: str, idx?: natural) => {
+ bx(Expr::Var(V(name, idx.unwrap_or(0))))
+ }),
+
+ Rule::ifthenelse_expression =>
+ parse!(pair; (cond: expression, left: expression, right: expression) => {
+ bx(Expr::BoolIf(cond, left, right))
+ }),
// Rule::record_type_or_literal => {
@@ -107,13 +142,11 @@ fn parse_expression(pair: Pair<Rule>) -> BoxExpr {
// inner.fold(first_expr, |acc, e| bx(Expr::Field(acc, e.as_str())))
// }
- // r => panic!("{:?}", r),
- // _ => bx(Expr::BoolLit(false)),
-
_ => {
let rulename = format!("{:?}", pair.as_rule());
- let mut inner = pair.into_inner().map(parse_expression).map(|x| *x);
- bx(Expr::FailedParse(rulename, inner.collect()))
+ parse!(pair; (exprs*: expression) => {
+ bx(Expr::FailedParse(rulename, exprs.map(|x| *x).collect()))
+ })
}
}
}
@@ -142,7 +175,7 @@ fn test_parse() {
},
ok => println!("{:?}", ok),
}
- // assert_eq!(parse_expr_pest(expr).unwrap(), parse_expr(expr).unwrap());
+ assert_eq!(parse_expr_pest(expr).unwrap(), parse_expr_lalrpop(expr).unwrap());
assert!(false);
println!("test {:?}", parse_expr_lalrpop("3 + 5 * 10"));