summaryrefslogtreecommitdiff
path: root/dhall_core/src/parser.rs
diff options
context:
space:
mode:
Diffstat (limited to 'dhall_core/src/parser.rs')
-rw-r--r--dhall_core/src/parser.rs923
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);