diff options
Diffstat (limited to '')
-rw-r--r-- | dhall_core/src/parser.rs | 923 |
1 files changed, 479 insertions, 444 deletions
diff --git a/dhall_core/src/parser.rs b/dhall_core/src/parser.rs index 66581a3..896a93f 100644 --- a/dhall_core/src/parser.rs +++ b/dhall_core/src/parser.rs @@ -2,27 +2,62 @@ use pest::iterators::Pair; use pest::Parser; use std::collections::BTreeMap; use std::path::PathBuf; -use std::rc::Rc; use dhall_parser::{DhallParser, Rule}; -use crate::core; -use crate::core::*; +use crate::*; // This file consumes the parse tree generated by pest and turns it into // our own AST. All those custom macros should eventually moved into // their own crate because they are quite general and useful. For now they // are here and hopefully you can figure out how they work. -pub type ParsedExpr = Expr<X, Import>; -pub type ParsedText = InterpolatedText<X, Import>; -pub type ParsedTextContents<'a> = InterpolatedTextContents<'a, X, Import>; -pub type RcExpr = Rc<ParsedExpr>; +type ParsedExpr = crate::ParsedExpr<X>; +type ParsedText = InterpolatedText<X, Import>; +type ParsedTextContents<'a> = InterpolatedTextContents<'a, X, Import>; pub type ParseError = pest::error::Error<Rule>; pub type ParseResult<T> = Result<T, ParseError>; +impl Builtin { + pub fn parse(s: &str) -> Option<Self> { + use self::Builtin::*; + match s { + "Bool" => Some(Bool), + "Natural" => Some(Natural), + "Integer" => Some(Integer), + "Double" => Some(Double), + "Text" => Some(Text), + "List" => Some(List), + "Optional" => Some(Optional), + "Some" => Some(OptionalSome), + "None" => Some(OptionalNone), + "Natural/build" => Some(NaturalBuild), + "Natural/fold" => Some(NaturalFold), + "Natural/isZero" => Some(NaturalIsZero), + "Natural/even" => Some(NaturalEven), + "Natural/odd" => Some(NaturalOdd), + "Natural/toInteger" => Some(NaturalToInteger), + "Natural/show" => Some(NaturalShow), + "Integer/toDouble" => Some(IntegerToDouble), + "Integer/show" => Some(IntegerShow), + "Double/show" => Some(DoubleShow), + "List/build" => Some(ListBuild), + "List/fold" => Some(ListFold), + "List/length" => Some(ListLength), + "List/head" => Some(ListHead), + "List/last" => Some(ListLast), + "List/indexed" => Some(ListIndexed), + "List/reverse" => Some(ListReverse), + "Optional/fold" => Some(OptionalFold), + "Optional/build" => Some(OptionalBuild), + "Text/show" => Some(TextShow), + _ => None, + } + } +} + pub fn custom_parse_error(pair: &Pair<Rule>, msg: String) -> ParseError { let msg = format!("{} while matching on:\n{}", msg, debug_pair(pair.clone())); @@ -221,466 +256,466 @@ fn can_be_shortcutted(rule: Rule) -> bool { } make_parser! { -rule!(EOI<()>; raw_pair!(_) => ()); + rule!(EOI<()>; raw_pair!(_) => ()); -rule!(label_raw<Label>; captured_str!(s) => Label::from(s.trim().to_owned())); + rule!(label_raw<Label>; captured_str!(s) => Label::from(s.trim().to_owned())); -rule!(double_quote_literal<ParsedText>; children!( - [double_quote_chunk(chunks..)] => { - chunks.collect() - } -)); - -rule!(double_quote_chunk<ParsedTextContents<'a>>; children!( - [interpolation(e)] => { - InterpolatedTextContents::Expr(e) - }, - [double_quote_escaped(s)] => { - InterpolatedTextContents::Text(s) - }, - [double_quote_char(s)] => { - InterpolatedTextContents::Text(s) - }, -)); -rule!(double_quote_escaped<&'a str>; - // TODO: parse all escapes - captured_str!(s) => { - match s { - "\"" => "\"", - "$" => "$", - "\\" => "\\", - "/" => "/", - // "b" => "\b", - // "f" => "\f", - "n" => "\n", - "r" => "\r", - "t" => "\t", - // "uXXXX" - _ => unimplemented!(), + rule!(double_quote_literal<ParsedText>; children!( + [double_quote_chunk(chunks..)] => { + chunks.collect() } - } -); -rule!(double_quote_char<&'a str>; - captured_str!(s) => s -); + )); + + rule!(double_quote_chunk<ParsedTextContents<'a>>; children!( + [interpolation(e)] => { + InterpolatedTextContents::Expr(e) + }, + [double_quote_escaped(s)] => { + InterpolatedTextContents::Text(s) + }, + [double_quote_char(s)] => { + InterpolatedTextContents::Text(s) + }, + )); + rule!(double_quote_escaped<&'a str>; + // TODO: parse all escapes + captured_str!(s) => { + match s { + "\"" => "\"", + "$" => "$", + "\\" => "\\", + "/" => "/", + // "b" => "\b", + // "f" => "\f", + "n" => "\n", + "r" => "\r", + "t" => "\t", + // "uXXXX" + _ => unimplemented!(), + } + } + ); + rule!(double_quote_char<&'a str>; + captured_str!(s) => s + ); -rule!(end_of_line<()>; raw_pair!(_) => ()); + rule!(end_of_line<()>; raw_pair!(_) => ()); -rule!(single_quote_literal<ParsedText>; children!( - [end_of_line(eol), single_quote_continue(contents)] => { - contents.into_iter().rev().collect::<ParsedText>() - } -)); -rule!(single_quote_char<&'a str>; - captured_str!(s) => s -); -rule!(escaped_quote_pair<&'a str>; - raw_pair!(_) => "''" -); -rule!(escaped_interpolation<&'a str>; - raw_pair!(_) => "${" -); -rule!(interpolation<RcExpr>; children!( - [expression(e)] => e -)); - -rule!(single_quote_continue<Vec<ParsedTextContents<'a>>>; children!( - [interpolation(c), single_quote_continue(rest)] => { - let mut rest = rest; - rest.push(InterpolatedTextContents::Expr(c)); rest - }, - [escaped_quote_pair(c), single_quote_continue(rest)] => { - let mut rest = rest; - rest.push(InterpolatedTextContents::Text(c)); rest - }, - [escaped_interpolation(c), single_quote_continue(rest)] => { - let mut rest = rest; - rest.push(InterpolatedTextContents::Text(c)); rest - }, - [single_quote_char(c), single_quote_continue(rest)] => { - let mut rest = rest; - rest.push(InterpolatedTextContents::Text(c)); rest - }, - [] => { - vec![] - }, -)); - -rule!(NaN_raw<()>; raw_pair!(_) => ()); -rule!(minus_infinity_literal<()>; raw_pair!(_) => ()); -rule!(plus_infinity_literal<()>; raw_pair!(_) => ()); - -rule!(double_literal_raw<core::Double>; - raw_pair!(pair) => { - pair.as_str().trim() - .parse() - .map_err(|e: std::num::ParseFloatError| custom_parse_error(&pair, format!("{}", e)))? - } -); + rule!(single_quote_literal<ParsedText>; children!( + [end_of_line(eol), single_quote_continue(contents)] => { + contents.into_iter().rev().collect::<ParsedText>() + } + )); + rule!(single_quote_char<&'a str>; + captured_str!(s) => s + ); + rule!(escaped_quote_pair<&'a str>; + raw_pair!(_) => "''" + ); + rule!(escaped_interpolation<&'a str>; + raw_pair!(_) => "${" + ); + rule!(interpolation<ParsedExpr>; children!( + [expression(e)] => e + )); + + rule!(single_quote_continue<Vec<ParsedTextContents<'a>>>; children!( + [interpolation(c), single_quote_continue(rest)] => { + let mut rest = rest; + rest.push(InterpolatedTextContents::Expr(c)); rest + }, + [escaped_quote_pair(c), single_quote_continue(rest)] => { + let mut rest = rest; + rest.push(InterpolatedTextContents::Text(c)); rest + }, + [escaped_interpolation(c), single_quote_continue(rest)] => { + let mut rest = rest; + rest.push(InterpolatedTextContents::Text(c)); rest + }, + [single_quote_char(c), single_quote_continue(rest)] => { + let mut rest = rest; + rest.push(InterpolatedTextContents::Text(c)); rest + }, + [] => { + vec![] + }, + )); + + rule!(NaN_raw<()>; raw_pair!(_) => ()); + rule!(minus_infinity_literal<()>; raw_pair!(_) => ()); + rule!(plus_infinity_literal<()>; raw_pair!(_) => ()); + + rule!(double_literal_raw<core::Double>; + raw_pair!(pair) => { + pair.as_str().trim() + .parse() + .map_err(|e: std::num::ParseFloatError| custom_parse_error(&pair, format!("{}", e)))? + } + ); -rule!(natural_literal_raw<core::Natural>; - raw_pair!(pair) => { - pair.as_str().trim() - .parse() - .map_err(|e: std::num::ParseIntError| custom_parse_error(&pair, format!("{}", e)))? - } -); + rule!(natural_literal_raw<core::Natural>; + raw_pair!(pair) => { + pair.as_str().trim() + .parse() + .map_err(|e: std::num::ParseIntError| custom_parse_error(&pair, format!("{}", e)))? + } + ); -rule!(integer_literal_raw<core::Integer>; - raw_pair!(pair) => { - pair.as_str().trim() - .parse() - .map_err(|e: std::num::ParseIntError| custom_parse_error(&pair, format!("{}", e)))? - } -); - -rule!(path<PathBuf>; - captured_str!(s) => (".".to_owned() + s).into() -); - -rule_group!(local_raw<(FilePrefix, PathBuf)>); - -rule!(parent_path<(FilePrefix, PathBuf)> as local_raw; children!( - [path(p)] => (FilePrefix::Parent, p) -)); - -rule!(here_path<(FilePrefix, PathBuf)> as local_raw; children!( - [path(p)] => (FilePrefix::Here, p) -)); - -rule!(home_path<(FilePrefix, PathBuf)> as local_raw; children!( - [path(p)] => (FilePrefix::Home, p) -)); - -rule!(absolute_path<(FilePrefix, PathBuf)> as local_raw; children!( - [path(p)] => (FilePrefix::Absolute, p) -)); - -// TODO: other import types -rule!(import_type_raw<ImportLocation>; children!( - // [missing_raw(_e)] => { - // ImportLocation::Missing - // } - // [env_raw(e)] => { - // ImportLocation::Env(e) - // } - // [http(url)] => { - // ImportLocation::Remote(url) - // } - [local_raw((prefix, path))] => { - ImportLocation::Local(prefix, path) - } -)); - -rule!(import_hashed_raw<(ImportLocation, Option<()>)>; children!( - // TODO: handle hash - [import_type_raw(import)] => (import, None) -)); - -rule_group!(expression<RcExpr>); - -rule!(import_raw<RcExpr> as expression; children!( - // TODO: handle "as Text" - [import_hashed_raw((location, hash))] => { - bx(Expr::Embed(Import { - mode: ImportMode::Code, - hash, - location, - })) - } -)); + rule!(integer_literal_raw<core::Integer>; + raw_pair!(pair) => { + pair.as_str().trim() + .parse() + .map_err(|e: std::num::ParseIntError| custom_parse_error(&pair, format!("{}", e)))? + } + ); -rule!(lambda_expression<RcExpr> as expression; children!( - [label_raw(l), expression(typ), expression(body)] => { - bx(Expr::Lam(l, typ, body)) - } -)); + rule!(path<PathBuf>; + captured_str!(s) => (".".to_owned() + s).into() + ); -rule!(ifthenelse_expression<RcExpr> as expression; children!( - [expression(cond), expression(left), expression(right)] => { - bx(Expr::BoolIf(cond, left, right)) - } -)); + rule_group!(local_raw<(FilePrefix, PathBuf)>); + + rule!(parent_path<(FilePrefix, PathBuf)> as local_raw; children!( + [path(p)] => (FilePrefix::Parent, p) + )); + + rule!(here_path<(FilePrefix, PathBuf)> as local_raw; children!( + [path(p)] => (FilePrefix::Here, p) + )); + + rule!(home_path<(FilePrefix, PathBuf)> as local_raw; children!( + [path(p)] => (FilePrefix::Home, p) + )); + + rule!(absolute_path<(FilePrefix, PathBuf)> as local_raw; children!( + [path(p)] => (FilePrefix::Absolute, p) + )); + + // TODO: other import types + rule!(import_type_raw<ImportLocation>; children!( + // [missing_raw(_e)] => { + // ImportLocation::Missing + // } + // [env_raw(e)] => { + // ImportLocation::Env(e) + // } + // [http(url)] => { + // ImportLocation::Remote(url) + // } + [local_raw((prefix, path))] => { + ImportLocation::Local(prefix, path) + } + )); + + rule!(import_hashed_raw<(ImportLocation, Option<()>)>; children!( + // TODO: handle hash + [import_type_raw(import)] => (import, None) + )); + + rule_group!(expression<ParsedExpr>); + + rule!(import_raw<ParsedExpr> as expression; children!( + // TODO: handle "as Text" + [import_hashed_raw((location, hash))] => { + bx(Expr::Embed(Import { + mode: ImportMode::Code, + hash, + location, + })) + } + )); -rule!(let_expression<RcExpr> as expression; children!( - [let_binding(bindings..), expression(final_expr)] => { - bindings.fold(final_expr, |acc, x| bx(Expr::Let(x.0, x.1, x.2, acc))) - } -)); + rule!(lambda_expression<ParsedExpr> as expression; children!( + [label_raw(l), expression(typ), expression(body)] => { + bx(Expr::Lam(l, typ, body)) + } + )); -rule!(let_binding<(Label, Option<RcExpr>, RcExpr)>; children!( - [label_raw(name), expression(annot), expression(expr)] => (name, Some(annot), expr), - [label_raw(name), expression(expr)] => (name, None, expr), -)); + rule!(ifthenelse_expression<ParsedExpr> as expression; children!( + [expression(cond), expression(left), expression(right)] => { + bx(Expr::BoolIf(cond, left, right)) + } + )); -rule!(forall_expression<RcExpr> as expression; children!( - [label_raw(l), expression(typ), expression(body)] => { - bx(Expr::Pi(l, typ, body)) - } -)); + rule!(let_expression<ParsedExpr> as expression; children!( + [let_binding(bindings..), expression(final_expr)] => { + bindings.fold(final_expr, |acc, x| bx(Expr::Let(x.0, x.1, x.2, acc))) + } + )); -rule!(arrow_expression<RcExpr> as expression; children!( - [expression(typ), expression(body)] => { - bx(Expr::Pi("_".into(), typ, body)) - } -)); - -rule!(merge_expression<RcExpr> as expression; children!( - [expression(x), expression(y), expression(z)] => bx(Expr::Merge(x, y, Some(z))), - [expression(x), expression(y)] => bx(Expr::Merge(x, y, None)), -)); - -rule!(List<()>; raw_pair!(_) => ()); -rule!(Optional<()>; raw_pair!(_) => ()); - -rule!(empty_collection<RcExpr> as expression; children!( - [List(_), expression(y)] => { - bx(Expr::EmptyListLit(y)) - }, - [Optional(_), expression(y)] => { - bx(Expr::OptionalLit(Some(y), None)) - }, -)); - -rule!(non_empty_optional<RcExpr> as expression; children!( - [expression(x), Optional(_), expression(z)] => { - bx(Expr::OptionalLit(Some(z), Some(x))) - } -)); - -rule!(import_alt_expression<RcExpr> as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest..)] => { - rest.fold(first, |acc, e| bx(Expr::BinOp(BinOp::ImportAlt, acc, e))) - }, -)); -rule!(or_expression<RcExpr> as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest..)] => { - rest.fold(first, |acc, e| bx(Expr::BinOp(BinOp::BoolOr, acc, e))) - }, -)); -rule!(plus_expression<RcExpr> as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest..)] => { - rest.fold(first, |acc, e| bx(Expr::BinOp(BinOp::NaturalPlus, acc, e))) - }, -)); -rule!(text_append_expression<RcExpr> as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest..)] => { - rest.fold(first, |acc, e| bx(Expr::BinOp(BinOp::TextAppend, acc, e))) - }, -)); -rule!(list_append_expression<RcExpr> as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest..)] => { - rest.fold(first, |acc, e| bx(Expr::BinOp(BinOp::ListAppend, acc, e))) - }, -)); -rule!(and_expression<RcExpr> as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest..)] => { - rest.fold(first, |acc, e| bx(Expr::BinOp(BinOp::BoolAnd, acc, e))) - }, -)); -rule!(combine_expression<RcExpr> as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest..)] => { - rest.fold(first, |acc, e| bx(Expr::BinOp(BinOp::Combine, acc, e))) - }, -)); -rule!(prefer_expression<RcExpr> as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest..)] => { - rest.fold(first, |acc, e| bx(Expr::BinOp(BinOp::Prefer, acc, e))) - }, -)); -rule!(combine_types_expression<RcExpr> as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest..)] => { - rest.fold(first, |acc, e| bx(Expr::BinOp(BinOp::CombineTypes, acc, e))) - }, -)); -rule!(times_expression<RcExpr> as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest..)] => { - rest.fold(first, |acc, e| bx(Expr::BinOp(BinOp::NaturalTimes, acc, e))) - }, -)); -rule!(equal_expression<RcExpr> as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest..)] => { - rest.fold(first, |acc, e| bx(Expr::BinOp(BinOp::BoolEQ, acc, e))) - }, -)); -rule!(not_equal_expression<RcExpr> as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest..)] => { - rest.fold(first, |acc, e| bx(Expr::BinOp(BinOp::BoolNE, acc, e))) - }, -)); - -rule!(annotated_expression<RcExpr> as expression; children!( - [expression(e), expression(annot)] => { - bx(Expr::Annot(e, annot)) - }, - [expression(e)] => e, -)); - -rule!(application_expression<RcExpr> as expression; children!( - [expression(first), expression(rest..)] => { - let rest: Vec<_> = rest.collect(); - if rest.is_empty() { - first - } else { - bx(Expr::App(first, rest)) + rule!(let_binding<(Label, Option<ParsedExpr>, ParsedExpr)>; children!( + [label_raw(name), expression(annot), expression(expr)] => (name, Some(annot), expr), + [label_raw(name), expression(expr)] => (name, None, expr), + )); + + rule!(forall_expression<ParsedExpr> as expression; children!( + [label_raw(l), expression(typ), expression(body)] => { + bx(Expr::Pi(l, typ, body)) } - } -)); + )); -rule!(selector_expression_raw<RcExpr> as expression; children!( - [expression(first), selector_raw(rest..)] => { - rest.fold(first, |acc, e| bx(Expr::Field(acc, e))) - } -)); - -// TODO: handle record projection -rule!(selector_raw<Label>; children!( - [label_raw(l)] => l -)); - -rule!(literal_expression_raw<RcExpr> as expression; children!( - [double_literal_raw(n)] => bx(Expr::DoubleLit(n)), - [minus_infinity_literal(n)] => bx(Expr::DoubleLit(std::f64::NEG_INFINITY)), - [plus_infinity_literal(n)] => bx(Expr::DoubleLit(std::f64::INFINITY)), - [NaN_raw(n)] => bx(Expr::DoubleLit(std::f64::NAN)), - [natural_literal_raw(n)] => bx(Expr::NaturalLit(n)), - [integer_literal_raw(n)] => bx(Expr::IntegerLit(n)), - [double_quote_literal(s)] => bx(Expr::TextLit(s)), - [single_quote_literal(s)] => bx(Expr::TextLit(s)), - [expression(e)] => e, -)); - -rule!(identifier_raw<RcExpr> as expression; children!( - [label_raw(l), natural_literal_raw(idx)] => { - let name = String::from(l.clone()); - match Builtin::parse(name.as_str()) { - Some(b) => bx(Expr::Builtin(b)), - None => match name.as_str() { - "True" => bx(Expr::BoolLit(true)), - "False" => bx(Expr::BoolLit(false)), - "Type" => bx(Expr::Const(Const::Type)), - "Kind" => bx(Expr::Const(Const::Kind)), - _ => bx(Expr::Var(V(l, idx))), + rule!(arrow_expression<ParsedExpr> as expression; children!( + [expression(typ), expression(body)] => { + bx(Expr::Pi("_".into(), typ, body)) + } + )); + + rule!(merge_expression<ParsedExpr> as expression; children!( + [expression(x), expression(y), expression(z)] => bx(Expr::Merge(x, y, Some(z))), + [expression(x), expression(y)] => bx(Expr::Merge(x, y, None)), + )); + + rule!(List<()>; raw_pair!(_) => ()); + rule!(Optional<()>; raw_pair!(_) => ()); + + rule!(empty_collection<ParsedExpr> as expression; children!( + [List(_), expression(y)] => { + bx(Expr::EmptyListLit(y)) + }, + [Optional(_), expression(y)] => { + bx(Expr::OptionalLit(Some(y), None)) + }, + )); + + rule!(non_empty_optional<ParsedExpr> as expression; children!( + [expression(x), Optional(_), expression(z)] => { + bx(Expr::OptionalLit(Some(z), Some(x))) + } + )); + + rule!(import_alt_expression<ParsedExpr> as expression; children!( + [expression(e)] => e, + [expression(first), expression(rest..)] => { + rest.fold(first, |acc, e| bx(Expr::BinOp(BinOp::ImportAlt, acc, e))) + }, + )); + rule!(or_expression<ParsedExpr> as expression; children!( + [expression(e)] => e, + [expression(first), expression(rest..)] => { + rest.fold(first, |acc, e| bx(Expr::BinOp(BinOp::BoolOr, acc, e))) + }, + )); + rule!(plus_expression<ParsedExpr> as expression; children!( + [expression(e)] => e, + [expression(first), expression(rest..)] => { + rest.fold(first, |acc, e| bx(Expr::BinOp(BinOp::NaturalPlus, acc, e))) + }, + )); + rule!(text_append_expression<ParsedExpr> as expression; children!( + [expression(e)] => e, + [expression(first), expression(rest..)] => { + rest.fold(first, |acc, e| bx(Expr::BinOp(BinOp::TextAppend, acc, e))) + }, + )); + rule!(list_append_expression<ParsedExpr> as expression; children!( + [expression(e)] => e, + [expression(first), expression(rest..)] => { + rest.fold(first, |acc, e| bx(Expr::BinOp(BinOp::ListAppend, acc, e))) + }, + )); + rule!(and_expression<ParsedExpr> as expression; children!( + [expression(e)] => e, + [expression(first), expression(rest..)] => { + rest.fold(first, |acc, e| bx(Expr::BinOp(BinOp::BoolAnd, acc, e))) + }, + )); + rule!(combine_expression<ParsedExpr> as expression; children!( + [expression(e)] => e, + [expression(first), expression(rest..)] => { + rest.fold(first, |acc, e| bx(Expr::BinOp(BinOp::Combine, acc, e))) + }, + )); + rule!(prefer_expression<ParsedExpr> as expression; children!( + [expression(e)] => e, + [expression(first), expression(rest..)] => { + rest.fold(first, |acc, e| bx(Expr::BinOp(BinOp::Prefer, acc, e))) + }, + )); + rule!(combine_types_expression<ParsedExpr> as expression; children!( + [expression(e)] => e, + [expression(first), expression(rest..)] => { + rest.fold(first, |acc, e| bx(Expr::BinOp(BinOp::CombineTypes, acc, e))) + }, + )); + rule!(times_expression<ParsedExpr> as expression; children!( + [expression(e)] => e, + [expression(first), expression(rest..)] => { + rest.fold(first, |acc, e| bx(Expr::BinOp(BinOp::NaturalTimes, acc, e))) + }, + )); + rule!(equal_expression<ParsedExpr> as expression; children!( + [expression(e)] => e, + [expression(first), expression(rest..)] => { + rest.fold(first, |acc, e| bx(Expr::BinOp(BinOp::BoolEQ, acc, e))) + }, + )); + rule!(not_equal_expression<ParsedExpr> as expression; children!( + [expression(e)] => e, + [expression(first), expression(rest..)] => { + rest.fold(first, |acc, e| bx(Expr::BinOp(BinOp::BoolNE, acc, e))) + }, + )); + + rule!(annotated_expression<ParsedExpr> as expression; children!( + [expression(e), expression(annot)] => { + bx(Expr::Annot(e, annot)) + }, + [expression(e)] => e, + )); + + rule!(application_expression<ParsedExpr> as expression; children!( + [expression(first), expression(rest..)] => { + let rest: Vec<_> = rest.collect(); + if rest.is_empty() { + first + } else { + bx(Expr::App(first, rest)) } } - }, - [label_raw(l)] => { - let name = String::from(l.clone()); - match Builtin::parse(name.as_str()) { - Some(b) => bx(Expr::Builtin(b)), - None => match name.as_str() { - "True" => bx(Expr::BoolLit(true)), - "False" => bx(Expr::BoolLit(false)), - "Type" => bx(Expr::Const(Const::Type)), - "Kind" => bx(Expr::Const(Const::Kind)), - _ => bx(Expr::Var(V(l, 0))), + )); + + rule!(selector_expression_raw<ParsedExpr> as expression; children!( + [expression(first), selector_raw(rest..)] => { + rest.fold(first, |acc, e| bx(Expr::Field(acc, e))) + } + )); + + // TODO: handle record projection + rule!(selector_raw<Label>; children!( + [label_raw(l)] => l + )); + + rule!(literal_expression_raw<ParsedExpr> as expression; children!( + [double_literal_raw(n)] => bx(Expr::DoubleLit(n)), + [minus_infinity_literal(n)] => bx(Expr::DoubleLit(std::f64::NEG_INFINITY)), + [plus_infinity_literal(n)] => bx(Expr::DoubleLit(std::f64::INFINITY)), + [NaN_raw(n)] => bx(Expr::DoubleLit(std::f64::NAN)), + [natural_literal_raw(n)] => bx(Expr::NaturalLit(n)), + [integer_literal_raw(n)] => bx(Expr::IntegerLit(n)), + [double_quote_literal(s)] => bx(Expr::TextLit(s)), + [single_quote_literal(s)] => bx(Expr::TextLit(s)), + [expression(e)] => e, + )); + + rule!(identifier_raw<ParsedExpr> as expression; children!( + [label_raw(l), natural_literal_raw(idx)] => { + let name = String::from(l.clone()); + match Builtin::parse(name.as_str()) { + Some(b) => bx(Expr::Builtin(b)), + None => match name.as_str() { + "True" => bx(Expr::BoolLit(true)), + "False" => bx(Expr::BoolLit(false)), + "Type" => bx(Expr::Const(Const::Type)), + "Kind" => bx(Expr::Const(Const::Kind)), + _ => bx(Expr::Var(V(l, idx))), + } } + }, + [label_raw(l)] => { + let name = String::from(l.clone()); + match Builtin::parse(name.as_str()) { + Some(b) => bx(Expr::Builtin(b)), + None => match name.as_str() { + "True" => bx(Expr::BoolLit(true)), + "False" => bx(Expr::BoolLit(false)), + "Type" => bx(Expr::Const(Const::Type)), + "Kind" => bx(Expr::Const(Const::Kind)), + _ => bx(Expr::Var(V(l, 0))), + } + } + }, + )); + + rule!(empty_record_literal<ParsedExpr> as expression; + raw_pair!(_) => bx(Expr::RecordLit(BTreeMap::new())) + ); + + rule!(empty_record_type<ParsedExpr> as expression; + raw_pair!(_) => bx(Expr::Record(BTreeMap::new())) + ); + + rule!(non_empty_record_type_or_literal<ParsedExpr> as expression; children!( + [label_raw(first_label), non_empty_record_type(rest)] => { + let (first_expr, mut map) = rest; + map.insert(first_label, first_expr); + bx(Expr::Record(map)) + }, + [label_raw(first_label), non_empty_record_literal(rest)] => { + let (first_expr, mut map) = rest; + map.insert(first_label, first_expr); + bx(Expr::RecordLit(map)) + }, + )); + + rule!(non_empty_record_type<(ParsedExpr, BTreeMap<Label, ParsedExpr>)>; children!( + [expression(expr), record_type_entry(entries..)] => { + (expr, entries.collect()) } - }, -)); - -rule!(empty_record_literal<RcExpr> as expression; - raw_pair!(_) => bx(Expr::RecordLit(BTreeMap::new())) -); - -rule!(empty_record_type<RcExpr> as expression; - raw_pair!(_) => bx(Expr::Record(BTreeMap::new())) -); - -rule!(non_empty_record_type_or_literal<RcExpr> as expression; children!( - [label_raw(first_label), non_empty_record_type(rest)] => { - let (first_expr, mut map) = rest; - map.insert(first_label, first_expr); - bx(Expr::Record(map)) - }, - [label_raw(first_label), non_empty_record_literal(rest)] => { - let (first_expr, mut map) = rest; - map.insert(first_label, first_expr); - bx(Expr::RecordLit(map)) - }, -)); - -rule!(non_empty_record_type<(RcExpr, BTreeMap<Label, RcExpr>)>; children!( - [expression(expr), record_type_entry(entries..)] => { - (expr, entries.collect()) - } -)); + )); -rule!(record_type_entry<(Label, RcExpr)>; children!( - [label_raw(name), expression(expr)] => (name, expr) -)); + rule!(record_type_entry<(Label, ParsedExpr)>; children!( + [label_raw(name), expression(expr)] => (name, expr) + )); -rule!(non_empty_record_literal<(RcExpr, BTreeMap<Label, RcExpr>)>; children!( - [expression(expr), record_literal_entry(entries..)] => { - (expr, entries.collect()) - } -)); - -rule!(record_literal_entry<(Label, RcExpr)>; children!( - [label_raw(name), expression(expr)] => (name, expr) -)); - -rule!(union_type_or_literal<RcExpr> as expression; children!( - [empty_union_type(_)] => { - bx(Expr::Union(BTreeMap::new())) - }, - [non_empty_union_type_or_literal((Some((l, e)), entries))] => { - bx(Expr::UnionLit(l, e, entries)) - }, - [non_empty_union_type_or_literal((None, entries))] => { - bx(Expr::Union(entries)) - }, -)); - -rule!(empty_union_type<()>; raw_pair!(_) => ()); - -rule!(non_empty_union_type_or_literal - <(Option<(Label, RcExpr)>, BTreeMap<Label, RcExpr>)>; children!( - [label_raw(l), expression(e), union_type_entries(entries)] => { - (Some((l, e)), entries) - }, - [label_raw(l), expression(e), non_empty_union_type_or_literal(rest)] => { - let (x, mut entries) = rest; - entries.insert(l, e); - (x, entries) - }, - [label_raw(l), expression(e)] => { - let mut entries = BTreeMap::new(); - entries.insert(l, e); - (None, entries) - }, -)); - -rule!(union_type_entries<BTreeMap<Label, RcExpr>>; children!( - [union_type_entry(entries..)] => entries.collect() -)); - -rule!(union_type_entry<(Label, RcExpr)>; children!( - [label_raw(name), expression(expr)] => (name, expr) -)); - -rule!(non_empty_list_literal_raw<RcExpr> as expression; children!( - [expression(items..)] => bx(Expr::NEListLit(items.collect())) -)); - -rule!(final_expression<RcExpr> as expression; children!( - [expression(e), EOI(_eoi)] => e -)); + rule!(non_empty_record_literal<(ParsedExpr, BTreeMap<Label, ParsedExpr>)>; children!( + [expression(expr), record_literal_entry(entries..)] => { + (expr, entries.collect()) + } + )); + + rule!(record_literal_entry<(Label, ParsedExpr)>; children!( + [label_raw(name), expression(expr)] => (name, expr) + )); + + rule!(union_type_or_literal<ParsedExpr> as expression; children!( + [empty_union_type(_)] => { + bx(Expr::Union(BTreeMap::new())) + }, + [non_empty_union_type_or_literal((Some((l, e)), entries))] => { + bx(Expr::UnionLit(l, e, entries)) + }, + [non_empty_union_type_or_literal((None, entries))] => { + bx(Expr::Union(entries)) + }, + )); + + rule!(empty_union_type<()>; raw_pair!(_) => ()); + + rule!(non_empty_union_type_or_literal + <(Option<(Label, ParsedExpr)>, BTreeMap<Label, ParsedExpr>)>; children!( + [label_raw(l), expression(e), union_type_entries(entries)] => { + (Some((l, e)), entries) + }, + [label_raw(l), expression(e), non_empty_union_type_or_literal(rest)] => { + let (x, mut entries) = rest; + entries.insert(l, e); + (x, entries) + }, + [label_raw(l), expression(e)] => { + let mut entries = BTreeMap::new(); + entries.insert(l, e); + (None, entries) + }, + )); + + rule!(union_type_entries<BTreeMap<Label, ParsedExpr>>; children!( + [union_type_entry(entries..)] => entries.collect() + )); + + rule!(union_type_entry<(Label, ParsedExpr)>; children!( + [label_raw(name), expression(expr)] => (name, expr) + )); + + rule!(non_empty_list_literal_raw<ParsedExpr> as expression; children!( + [expression(items..)] => bx(Expr::NEListLit(items.collect())) + )); + + rule!(final_expression<ParsedExpr> as expression; children!( + [expression(e), EOI(_eoi)] => e + )); } -pub fn parse_expr(s: &str) -> ParseResult<RcExpr> { +pub fn parse_expr(s: &str) -> ParseResult<crate::ParsedExpr<X>> { let mut pairs = DhallParser::parse(Rule::final_expression, s)?; let expr = parse_any(pairs.next().unwrap())?; assert_eq!(pairs.next(), None); |