diff options
-rw-r--r-- | dhall_generated_parser/src/dhall.pest.visibility | 2 | ||||
-rw-r--r-- | dhall_syntax/src/parser.rs | 200 | ||||
-rw-r--r-- | tests_buffer | 1 |
3 files changed, 95 insertions, 108 deletions
diff --git a/dhall_generated_parser/src/dhall.pest.visibility b/dhall_generated_parser/src/dhall.pest.visibility index 8235735..2ac7fe4 100644 --- a/dhall_generated_parser/src/dhall.pest.visibility +++ b/dhall_generated_parser/src/dhall.pest.visibility @@ -160,7 +160,7 @@ not_equal_expression equivalent_expression application_expression first_application_expression -# import_expression +import_expression selector_expression selector labels diff --git a/dhall_syntax/src/parser.rs b/dhall_syntax/src/parser.rs index d11eb18..2debc8b 100644 --- a/dhall_syntax/src/parser.rs +++ b/dhall_syntax/src/parser.rs @@ -174,12 +174,11 @@ macro_rules! make_parser { ); (@rule_alias, rule!( - $name:ident<$o:ty> - as $group:ident; + $name:ident<$o:ty>; $($args:tt)* ) ) => ({ - Rule::$group + Rule::$name }); (@rule_alias, token_rule!($name:ident<$o:ty>) @@ -190,8 +189,7 @@ macro_rules! make_parser { (@body, ($climbers:expr, $input:expr, $pair:expr), rule!( - $name:ident<$o:ty> - as $group:ident; + $name:ident<$o:ty>; $span:ident; captured_str!($x:pat) => $body:expr ) @@ -199,15 +197,14 @@ macro_rules! make_parser { let res: Result<_, String> = try { let $span = Span::make($input, $pair.as_span()); let $x = $pair.as_str(); - ParsedValue::$group($body) + ParsedValue::$name($body) }; res.map_err(|msg| custom_parse_error(&$pair, msg)) }); (@body, ($climbers:expr, $input:expr, $pair:expr), rule!( - $name:ident<$o:ty> - as $group:ident; + $name:ident<$o:ty>; $span:ident; children!( $( [$($args:tt)*] => $body:expr ),* $(,)* ) ) @@ -257,27 +254,33 @@ macro_rules! make_parser { }; let res = res.map_err(|msg| custom_parse_error(&$pair, msg))?; - Ok(ParsedValue::$group(res)) + Ok(ParsedValue::$name(res)) }); (@body, ($climbers:expr, $input:expr, $pair:expr), rule!( - $name:ident<$o:ty> - as $group:ident; - prec_climb!( $_climber:expr, $args:pat => $body:expr $(,)* ) + $name:ident<$o:ty>; + prec_climb!($other_name:ident, $_climber:expr, $args:pat => $body:expr $(,)* ) ) ) => ({ - let climber = $climbers.get(&Rule::$name).unwrap(); + let climber = $climbers.get(&Rule::$name).expect(&format!("UUUU: {:?}", $climbers)); climber.climb( $pair.clone().into_inner(), - |p| parse_any($climbers, $input.clone(), p), + |p| { + let parsed = parse_any($climbers, $input.clone(), p)?; + if let ParsedValue::$other_name(x) = parsed { + Ok(ParsedValue::$name(x)) + } else { + unreachable!() + } + }, |l, op, r| { let (l, r) = (l?, r?); let res: Result<_, String> = try { #[allow(unused_imports)] use ParsedValue::*; match (l, op, r) { - $args => ParsedValue::$group($body), + $args => ParsedValue::$name($body), children => Err( format!("Unexpected children: {:?}", children) )?, @@ -289,26 +292,13 @@ macro_rules! make_parser { }); (@body, ($($things:tt)*), - rule!( $name:ident<$o:ty>; $($args:tt)* ) - ) => ( - make_parser!(@body, - ($($things)*), - rule!( $name<$o> as $name; $($args)* ) - ) - ); - (@body, - ($($things:tt)*), - rule!( - $name:ident<$o:ty> - as $group:ident; - $($args:tt)* + rule!( $name:ident<$o:ty>; $($args:tt)* ) ) => ({ make_parser!(@body, ($($things)*), rule!( - $name<$o> - as $group; + $name<$o>; _span; $($args)* ) @@ -324,9 +314,8 @@ macro_rules! make_parser { (@construct_climber, ($map:expr), rule!( - $name:ident<$o:ty> - as $group:ident; - prec_climb!( $climber:expr, $($_rest:tt)* ) + $name:ident<$o:ty>; + prec_climb!( $other_name:ident, $climber:expr, $($_rest:tt)* ) ) ) => ({ $map.insert(Rule::$name, $climber) @@ -379,27 +368,8 @@ macro_rules! make_parser { fn parse_any<'a>( climbers: &HashMap<Rule, PrecClimber<Rule>>, input: Rc<str>, - mut pair: Pair<'a, Rule>, + pair: Pair<'a, Rule>, ) -> ParseResult<ParsedValue<'a>> { - // Avoid parsing while the pair has exactly one child that can be returned as-is - loop { - if can_be_shortcutted(pair.as_rule()) { - let mut i = pair.clone().into_inner(); - let first = i.next(); - let second = i.next(); - match (first, second) { - // If pair has exactly one child, just go on parsing that child - (Some(p), None) => { - pair = p; - continue; - } - // Otherwise parse normally - _ => break, - } - } - break; - } - match pair.as_rule() { $( Rule::$name => Parsers::$name(climbers, input, pair), @@ -418,20 +388,6 @@ fn do_parse<'a>( parse_any(&climbers, input, pair) } -// List of rules that can be shortcutted if they have a single child -fn can_be_shortcutted(rule: Rule) -> bool { - use Rule::*; - match rule { - expression - | operator_expression - | application_expression - | first_application_expression - | selector_expression - | annotated_expression => true, - _ => false, - } -} - // Trim the shared indent off of a vec of lines, as defined by the Dhall semantics of multiline // literals. fn trim_indent(lines: &mut Vec<ParsedText>) { @@ -591,10 +547,10 @@ make_parser! { rule!(single_quote_char<&'a str>; captured_str!(s) => s ); - rule!(escaped_quote_pair<&'a str> as single_quote_char; + rule!(escaped_quote_pair<&'a str>; captured_str!(_) => "''" ); - rule!(escaped_interpolation<&'a str> as single_quote_char; + rule!(escaped_interpolation<&'a str>; captured_str!(_) => "${" ); rule!(interpolation<ParsedSubExpr>; children!( @@ -609,6 +565,20 @@ make_parser! { lines.last_mut().unwrap().push(c); lines }, + [escaped_quote_pair(c), single_quote_continue(lines)] => { + let mut lines = lines; + // TODO: don't allocate for every char + let c = InterpolatedTextContents::Text(c.to_owned()); + lines.last_mut().unwrap().push(c); + lines + }, + [escaped_interpolation(c), single_quote_continue(lines)] => { + let mut lines = lines; + // TODO: don't allocate for every char + let c = InterpolatedTextContents::Text(c.to_owned()); + lines.last_mut().unwrap().push(c); + lines + }, [single_quote_char(c), single_quote_continue(lines)] => { let mut lines = lines; if c == "\n" || c == "\r\n" { @@ -682,7 +652,7 @@ make_parser! { } ); - rule!(identifier<ParsedSubExpr> as expression; span; children!( + rule!(identifier<ParsedSubExpr>; span; children!( [variable(v)] => { spanned(span, Var(v)) }, @@ -715,19 +685,22 @@ make_parser! { )); rule!(local<(FilePrefix, Vec<String>)>; children!( - [local(l)] => l + [parent_path(l)] => l, + [here_path(l)] => l, + [home_path(l)] => l, + [absolute_path(l)] => l, )); - rule!(parent_path<(FilePrefix, Vec<String>)> as local; children!( + rule!(parent_path<(FilePrefix, Vec<String>)>; children!( [path(p)] => (FilePrefix::Parent, p) )); - rule!(here_path<(FilePrefix, Vec<String>)> as local; children!( + rule!(here_path<(FilePrefix, Vec<String>)>; children!( [path(p)] => (FilePrefix::Here, p) )); - rule!(home_path<(FilePrefix, Vec<String>)> as local; children!( + rule!(home_path<(FilePrefix, Vec<String>)>; children!( [path(p)] => (FilePrefix::Home, p) )); - rule!(absolute_path<(FilePrefix, Vec<String>)> as local; children!( + rule!(absolute_path<(FilePrefix, Vec<String>)>; children!( [path(p)] => (FilePrefix::Absolute, p) )); @@ -760,7 +733,7 @@ make_parser! { rule!(http<URL<ParsedSubExpr>>; children!( [http_raw(url)] => url, - [http_raw(url), expression(e)] => + [http_raw(url), import_expression(e)] => URL { headers: Some(e), ..url }, )); @@ -828,7 +801,7 @@ make_parser! { token_rule!(Text<()>); token_rule!(Location<()>); - rule!(import<ParsedSubExpr> as expression; span; children!( + rule!(import<ParsedSubExpr>; span; children!( [import_hashed(imp)] => { spanned(span, Import(crate::Import { mode: ImportMode::Code, @@ -857,13 +830,13 @@ make_parser! { token_rule!(if_<()>); token_rule!(in_<()>); - rule!(empty_list_literal<ParsedSubExpr> as expression; span; children!( - [expression(e)] => { + rule!(empty_list_literal<ParsedSubExpr>; span; children!( + [application_expression(e)] => { spanned(span, EmptyListLit(e)) }, )); - rule!(expression<ParsedSubExpr> as expression; span; children!( + rule!(expression<ParsedSubExpr>; span; children!( [lambda(()), label(l), expression(typ), arrow(()), expression(body)] => { spanned(span, Lam(l, typ, body)) @@ -881,16 +854,17 @@ make_parser! { arrow(()), expression(body)] => { spanned(span, Pi(l, typ, body)) }, - [expression(typ), arrow(()), expression(body)] => { + [operator_expression(typ), arrow(()), expression(body)] => { spanned(span, Pi("_".into(), typ, body)) }, - [merge(()), expression(x), expression(y), expression(z)] => { + [merge(()), import_expression(x), import_expression(y), application_expression(z)] => { spanned(span, Merge(x, y, Some(z))) }, + [empty_list_literal(e)] => e, [assert(()), expression(x)] => { spanned(span, Assert(x)) }, - [expression(e)] => e, + [annotated_expression(e)] => e, )); rule!(let_binding<(Label, Option<ParsedSubExpr>, ParsedSubExpr)>; @@ -904,14 +878,14 @@ make_parser! { token_rule!(List<()>); token_rule!(Optional<()>); - rule!(annotated_expression<ParsedSubExpr> as expression; span; children!( - [expression(e)] => e, - [expression(e), expression(annot)] => { + rule!(annotated_expression<ParsedSubExpr>; span; children!( + [operator_expression(e)] => e, + [operator_expression(e), expression(annot)] => { spanned(span, Annot(e, annot)) }, )); - rule!(operator_expression<ParsedSubExpr> as expression; prec_climb!( + rule!(operator_expression<ParsedSubExpr>; prec_climb!(application_expression, { use Rule::*; // In order of precedence @@ -937,7 +911,7 @@ make_parser! { .collect(), ) }, - (expression(l), op, expression(r)) => { + (operator_expression(l), op, operator_expression(r)) => { use crate::BinOp::*; use Rule::*; let op = match op.as_rule() { @@ -966,32 +940,38 @@ make_parser! { token_rule!(Some_<()>); token_rule!(toMap<()>); - rule!(application_expression<ParsedSubExpr> as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest)..] => { + rule!(application_expression<ParsedSubExpr>; children!( + [first_application_expression(e)] => e, + [first_application_expression(first), import_expression(rest)..] => { rest.fold(first, |acc, e| unspanned(App(acc, e))) }, )); - rule!(first_application_expression<ParsedSubExpr> as expression; span; + rule!(first_application_expression<ParsedSubExpr>; span; children!( - [expression(e)] => e, - [Some_(()), expression(e)] => { + [Some_(()), import_expression(e)] => { spanned(span, SomeLit(e)) }, - [merge(()), expression(x), expression(y)] => { + [merge(()), import_expression(x), import_expression(y)] => { spanned(span, Merge(x, y, None)) }, + [import_expression(e)] => e, )); - rule!(selector_expression<ParsedSubExpr> as expression; children!( - [expression(e)] => e, - [expression(first), selector(rest)..] => { + rule!(import_expression<ParsedSubExpr>; span; + children!( + [selector_expression(e)] => e, + [import(e)] => e, + )); + + rule!(selector_expression<ParsedSubExpr>; children!( + [primitive_expression(e)] => e, + [primitive_expression(first), selector(rest)..] => { rest.fold(first, |acc, e| unspanned(match e { Either::Left(l) => Field(acc, l), Either::Right(ls) => Projection(acc, ls), })) - } + }, )); rule!(selector<Either<Label, DupTreeSet<Label>>>; children!( @@ -1004,24 +984,30 @@ make_parser! { [label(ls)..] => ls.collect(), )); - rule!(primitive_expression<ParsedSubExpr> as expression; span; children!( + rule!(primitive_expression<ParsedSubExpr>; span; children!( [double_literal(n)] => spanned(span, DoubleLit(n)), [natural_literal(n)] => spanned(span, NaturalLit(n)), [integer_literal(n)] => spanned(span, IntegerLit(n)), [double_quote_literal(s)] => spanned(span, TextLit(s)), [single_quote_literal(s)] => spanned(span, TextLit(s)), + [empty_record_type(e)] => e, + [empty_record_literal(e)] => e, + [non_empty_record_type_or_literal(e)] => e, + [union_type(e)] => e, + [non_empty_list_literal(e)] => e, + [identifier(e)] => e, [expression(e)] => e, )); - rule!(empty_record_literal<ParsedSubExpr> as expression; span; + rule!(empty_record_literal<ParsedSubExpr>; span; captured_str!(_) => spanned(span, RecordLit(Default::default())) ); - rule!(empty_record_type<ParsedSubExpr> as expression; span; + rule!(empty_record_type<ParsedSubExpr>; span; captured_str!(_) => spanned(span, RecordType(Default::default())) ); - rule!(non_empty_record_type_or_literal<ParsedSubExpr> as expression; span; + rule!(non_empty_record_type_or_literal<ParsedSubExpr>; span; children!( [label(first_label), non_empty_record_type(rest)] => { let (first_expr, mut map) = rest; @@ -1057,7 +1043,7 @@ make_parser! { [label(name), expression(expr)] => (name, expr) )); - rule!(union_type<ParsedSubExpr> as expression; span; children!( + rule!(union_type<ParsedSubExpr>; span; children!( [empty_union_type(_)] => { spanned(span, UnionType(Default::default())) }, @@ -1073,7 +1059,7 @@ make_parser! { [label(name)] => (name, None), )); - rule!(non_empty_list_literal<ParsedSubExpr> as expression; span; + rule!(non_empty_list_literal<ParsedSubExpr>; span; children!( [expression(items)..] => spanned( span, @@ -1081,7 +1067,7 @@ make_parser! { ) )); - rule!(final_expression<ParsedSubExpr> as expression; children!( + rule!(final_expression<ParsedSubExpr>; children!( [expression(e), EOI(_eoi)] => e )); } @@ -1092,7 +1078,7 @@ pub fn parse_expr(s: &str) -> ParseResult<ParsedSubExpr> { let expr = do_parse(rc_input, pairs.next().unwrap())?; assert_eq!(pairs.next(), None); match expr { - ParsedValue::expression(e) => Ok(e), + ParsedValue::final_expression(e) => Ok(e), _ => unreachable!(), } } diff --git a/tests_buffer b/tests_buffer index 1ad880e..67de9eb 100644 --- a/tests_buffer +++ b/tests_buffer @@ -9,6 +9,7 @@ success/ PrecedenceAll2 a b != c == d * e ⩓ f ⫽ g ∧ h && i # j ++ k + l || m ? n LetNoAnnot let x = y in e LetAnnot let x: T = y in e + EmptyRecordLiteral {=} failure/ AssertNoAnnotation assert |