summaryrefslogtreecommitdiff
path: root/dhall
diff options
context:
space:
mode:
Diffstat (limited to 'dhall')
-rw-r--r--dhall/src/parser.rs133
-rw-r--r--dhall/tests/macros.rs7
2 files changed, 105 insertions, 35 deletions
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<BoxExpr, lalrpop_util::ParseError<usize, Tok, LexicalError>> {
grammar::ExprParser::new().parse(Lexer::new(s))
@@ -25,23 +26,34 @@ pub fn custom_parse_error(pair: &Pair<Rule>, 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<Rule>) -> ParseResult<usize> {
.map_err(|e: std::num::ParseIntError| custom_parse_error(&pair, format!("{}", e)))
}
+fn parse_integer(pair: Pair<Rule>) -> ParseResult<isize> {
+ parse_str(pair.clone())?
+ .parse()
+ .map_err(|e: std::num::ParseIntError| custom_parse_error(&pair, format!("{}", e)))
+}
+
+fn parse_letbinding(pair: Pair<Rule>) -> ParseResult<(&str, Option<BoxExpr>, BoxExpr)> {
+ parse!(pair; (name: str, annot?: expression, expr: expression) => {
+ (name, annot, expr)
+ })
+}
+
+fn parse_record_entry(pair: Pair<Rule>) -> ParseResult<(&str, BoxExpr)> {
+ parse!(pair; (name: str, expr: expression) => { (name, expr) })
+}
+
+fn parse_partial_record_entries(pair: Pair<Rule>) -> 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<Rule>) -> ParseResult<BoxExpr> {
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<Rule>) -> ParseResult<BoxExpr> {
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::<ParseResult<_>>()?))
@@ -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);