From 3f19f1b34386875def0e6124fe550baefc81f65a Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 3 Mar 2019 00:14:08 +0100 Subject: Write macros to streamline parsing --- dhall/src/lib.rs | 1 + dhall/src/parser.rs | 83 +++++++++++++++++++++++++++++++++++++---------------- 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) { 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) -> BoxExpr { - let mut inner = pair.into_inner().map(parse_expression); - inner.next().unwrap() + parse!(pair; (expr: expression) => { + expr + }) } fn parse_str(pair: Pair) -> &str { pair.as_str().trim() } -fn parse_natural(pair: Pair) -> Result { - parse_str(pair).parse() +// fn parse_natural(pair: Pair) -> Result { +fn parse_natural(pair: Pair) -> usize { + parse_str(pair).parse().unwrap() } fn parse_expression(pair: Pair) -> 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) -> 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) -> 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")); -- cgit v1.2.3