From f29f8e61adb359d12105fcc87a53137416519638 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 3 Mar 2019 03:21:32 +0100 Subject: Parse more AST nodes --- dhall/src/parser.rs | 133 +++++++++++++++++++++++++++++++++++++------------- dhall/tests/macros.rs | 7 ++- 2 files changed, 105 insertions(+), 35 deletions(-) (limited to 'dhall') diff --git a/dhall/src/parser.rs b/dhall/src/parser.rs index 022c964..21429b0 100644 --- a/dhall/src/parser.rs +++ b/dhall/src/parser.rs @@ -1,5 +1,6 @@ -use lalrpop_util; +use std::collections::BTreeMap; use itertools::*; +use lalrpop_util; use pest::Parser; use pest::iterators::Pair; @@ -8,7 +9,7 @@ use dhall_parser::{DhallParser, Rule}; use crate::grammar; use crate::grammar_util::{BoxExpr, ParsedExpr}; use crate::lexer::{Lexer, LexicalError, Tok}; -use crate::core::{bx, Expr, Builtin, V}; +use crate::core::{bx, Expr, Builtin, Const, V}; pub fn parse_expr_lalrpop(s: &str) -> Result> { grammar::ExprParser::new().parse(Lexer::new(s)) @@ -25,23 +26,34 @@ pub fn custom_parse_error(pair: &Pair, msg: String) -> ParseError { macro_rules! parse_aux { - ($inner:expr, true, $x:ident : $ty:ident $($rest:tt)*) => { + // Normal pattern + (0, $inner:expr, $x:ident : $ty:ident $($rest:tt)*) => { let $x = concat_idents!(parse_, $ty)($inner.next().unwrap())?; - parse_aux!($inner, true $($rest)*) + parse_aux!(0, $inner $($rest)*); }; - ($inner:expr, true, $x:ident? : $ty:ident $($rest:tt)*) => { + // Normal pattern after a variable length one: declare reversed and take from the end + ($w:expr, $inner:expr, $x:ident : $ty:ident $($rest:tt)*) => { + parse_aux!($w, $inner $($rest)*); + let $x = concat_idents!(parse_, $ty)($inner.next_back().unwrap())?; + }; + // Optional pattern + (0, $inner:expr, $x:ident? : $ty:ident $($rest:tt)*) => { + parse_aux!(1, $inner $($rest)*); let $x = $inner.next().map(concat_idents!(parse_, $ty)).transpose()?; - parse_aux!($inner, true $($rest)*) + $inner.next().ok_or(()).expect_err("Some parsed values remain unused"); }; - ($inner:expr, true, $x:ident* : $ty:ident $($rest:tt)*) => { + // Everything else pattern + (0, $inner:expr, $x:ident* : $ty:ident $($rest:tt)*) => { + parse_aux!(2, $inner $($rest)*); #[allow(unused_mut)] let mut $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") + + // Check no elements remain + (0, $inner:expr) => { + $inner.next().ok_or(()).expect_err("Some parsed values remain unused"); }; + ($_:expr, $inner:expr) => {}; } macro_rules! parse { @@ -49,7 +61,7 @@ macro_rules! parse { { #[allow(unused_mut)] let mut inner = $pair.into_inner(); - parse_aux!(inner, true, $($args)*); + parse_aux!(0, inner, $($args)*); Ok($body) } }; @@ -79,9 +91,73 @@ fn parse_natural(pair: Pair) -> ParseResult { .map_err(|e: std::num::ParseIntError| custom_parse_error(&pair, format!("{}", e))) } +fn parse_integer(pair: Pair) -> ParseResult { + parse_str(pair.clone())? + .parse() + .map_err(|e: std::num::ParseIntError| custom_parse_error(&pair, format!("{}", e))) +} + +fn parse_letbinding(pair: Pair) -> ParseResult<(&str, Option, BoxExpr)> { + parse!(pair; (name: str, annot?: expression, expr: expression) => { + (name, annot, expr) + }) +} + +fn parse_record_entry(pair: Pair) -> ParseResult<(&str, BoxExpr)> { + parse!(pair; (name: str, expr: expression) => { (name, expr) }) +} + +fn parse_partial_record_entries(pair: Pair) -> ParseResult<(Rule, BoxExpr, BTreeMap<&str, ParsedExpr>)> { + let rule = pair.as_rule(); + parse!(pair; (expr: expression, entries*: record_entry) => { + let mut map: BTreeMap<&str, ParsedExpr> = BTreeMap::new(); + for entry in entries { + let (n, e) = entry?; + map.insert(n, *e); + } + (rule, expr, map) + }) +} + +// TODO: handle stack manually fn parse_expression(pair: Pair) -> ParseResult { match pair.as_rule() { Rule::natural_literal_raw => Ok(bx(Expr::NaturalLit(parse_natural(pair)?))), + Rule::integer_literal_raw => Ok(bx(Expr::IntegerLit(parse_integer(pair)?))), + + Rule::identifier_raw => + parse!(pair; (name: str, idx?: natural) => { + match Builtin::parse(name) { + Some(b) => bx(Expr::Builtin(b)), + None => match name { + "True" => bx(Expr::BoolLit(true)), + "False" => bx(Expr::BoolLit(false)), + "Type" => bx(Expr::Const(Const::Type)), + "Kind" => bx(Expr::Const(Const::Kind)), + name => bx(Expr::Var(V(name, idx.unwrap_or(0)))), + } + } + }), + + Rule::lambda_expression => + parse!(pair; (label: str, typ: expression, body: expression) => { + bx(Expr::Lam(label, typ, body)) + }), + + Rule::ifthenelse_expression => + parse!(pair; (cond: expression, left: expression, right: expression) => { + bx(Expr::BoolIf(cond, left, right)) + }), + + Rule::let_expression => + parse!(pair; (bindings*: letbinding, final_expr: expression) => { + bindings.fold_results(final_expr, |acc, x| bx(Expr::Let(x.0, x.1, x.2, acc)))? + }), + + Rule::forall_expression => + parse!(pair; (label: str, typ: expression, body: expression) => { + bx(Expr::Pi(label, typ, body)) + }), Rule::annotated_expression => { parse_binop(pair, Expr::Annot) } Rule::import_alt_expression => { skip_expr(pair) } @@ -103,31 +179,22 @@ fn parse_expression(pair: Pair) -> ParseResult { rest.fold_results(first, |acc, e| bx(Expr::Field(acc, e)))? }), - Rule::identifier_raw => - parse!(pair; (name: str, idx?: natural) => { - match Builtin::parse(name) { - Some(b) => bx(Expr::Builtin(b)), - None => match name { - "True" => bx(Expr::BoolLit(true)), - "False" => bx(Expr::BoolLit(false)), - name => bx(Expr::Var(V(name, idx.unwrap_or(0)))), - } + Rule::empty_record_type => Ok(bx(Expr::Record(BTreeMap::new()))), + Rule::empty_record_literal => Ok(bx(Expr::RecordLit(BTreeMap::new()))), + Rule::non_empty_record_type_or_literal => + parse!(pair; (first_label: str, rest: partial_record_entries) => { + let (rule, first_expr, mut map) = rest; + map.insert(first_label, *first_expr); + match rule { + Rule::non_empty_record_type => bx(Expr::Record(map)), + Rule::non_empty_record_literal => bx(Expr::RecordLit(map)), + _ => unreachable!() } }), - Rule::ifthenelse_expression => - parse!(pair; (cond: expression, left: expression, right: expression) => { - bx(Expr::BoolIf(cond, left, right)) - }), - - - // Rule::record_type_or_literal => { - // 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()))) - // } _ => { + // panic!(); let rulename = format!("{:?}", pair.as_rule()); parse!(pair; (exprs*: expression) => { bx(Expr::FailedParse(rulename, exprs.map_results(|x| *x).collect::>()?)) @@ -158,7 +225,7 @@ fn test_parse() { ok => println!("{:?}", ok), } assert_eq!(parse_expr_pest(expr).unwrap(), parse_expr_lalrpop(expr).unwrap()); - assert!(false); + // assert!(false); println!("test {:?}", parse_expr_lalrpop("3 + 5 * 10")); assert!(parse_expr_lalrpop("22").is_ok()); diff --git a/dhall/tests/macros.rs b/dhall/tests/macros.rs index 6031a34..5dec825 100644 --- a/dhall/tests/macros.rs +++ b/dhall/tests/macros.rs @@ -18,8 +18,11 @@ macro_rules! run_spec_test { }; (parser, $path:expr) => { let expr_str = include_test_str!(concat!($path, "A")); - parser::parse_expr_pest(&expr_str).map_err(|e| println!("{}", e)).unwrap(); - // parser::parse_expr(&expr_str).unwrap(); + let pest_expr = parser::parse_expr_pest(&expr_str).map_err(|e| println!("{}", e)).unwrap(); + match parser::parse_expr_lalrpop(&expr_str) { + Ok(larlpop_expr) => assert_eq!(pest_expr, larlpop_expr), + Err(_) => {}, + }; }; (parser_failure, $path:expr) => { let expr_str = include_test_str!($path); -- cgit v1.2.3