diff --git a/core/src/parser/grammar.lalrpop b/core/src/parser/grammar.lalrpop index eb9f197fc..c13d9607d 100644 --- a/core/src/parser/grammar.lalrpop +++ b/core/src/parser/grammar.lalrpop @@ -111,11 +111,19 @@ AsType: Type<'ast> = > =>? // Repeat a rule zero times or more with a separator interspersed, such that the last // separator is optional: for example, Delimiter will both accept // `1,2` and `1,2,`. -RepeatSep: Vec = Sep)*> Sep? => { +RepeatSep: Vec = Sep)*> => { + elems.extend(last); + elems +}; + +// Same as `RepeatSep`, but repeat the rule at least once (one or more), instead of zero or +// more. +RepeatSep1: Vec = )*> Sep? => { elems.push(last); elems }; + AsUniTerm: UniTerm<'ast> = > => UniTerm::from(ut); // Macro repeating a rule producing some form of annotation (that can be @@ -271,7 +279,7 @@ UniTerm: UniTerm<'ast> = { AsUniTerm>, "let" - > + > "in" =>? { Ok(UniTerm::from(mk_let( alloc, @@ -709,7 +717,21 @@ ConstantPatternData: ConstantPatternData<'ast> = { }; RecordPattern: RecordPattern<'ast> = { - "{" ",")*> "}" =>? { + "{" ",")*> "}" =>? { + let tail = match last { + Some(LastPattern::Normal(m)) => { + field_pats.push(m); + TailPattern::Empty + }, + Some(LastPattern::Ellipsis(Some(captured))) => { + TailPattern::Capture(captured) + } + Some(LastPattern::Ellipsis(None)) => { + TailPattern::Open + } + None => TailPattern::Empty, + }; + let pattern = RecordPattern { patterns: alloc.field_patterns(field_pats), tail, @@ -718,11 +740,25 @@ RecordPattern: RecordPattern<'ast> = { pattern.check_dup()?; Ok(pattern) - }, + } }; ArrayPattern: ArrayPattern<'ast> = { - "[" ",")*> "]" => { + "[" ",")*> "]" => { + let tail = match last { + Some(LastPattern::Normal(m)) => { + patterns.push(m); + TailPattern::Empty + }, + Some(LastPattern::Ellipsis(Some(captured))) => { + TailPattern::Capture(captured) + } + Some(LastPattern::Ellipsis(None)) => { + TailPattern::Open + } + None => TailPattern::Empty, + }; + ArrayPattern { patterns: alloc.patterns(patterns), tail, @@ -898,18 +934,21 @@ FieldPattern: FieldPattern<'ast> = { }, }; -// Potential ellipsis at the end of an array or a record pattern. This rule also -// account for the presence of a trailing -TailPattern: TailPattern = { - "," ".." => { - if let Some(captured) = <> { - TailPattern::Capture(captured) - } - else { - TailPattern::Open - } - }, - ","? => TailPattern::Empty, +// Last field pattern of a record pattern. We need this rule (together with +// `LastElemPat`) combining both a field and a potential ellipsis because +// putting the ellipsis in a separate rule AND handling the case of zero fields +// (`{..}`) isn't possible: the fact that the ellipsis will need a "," separator +// before it will depend on the presence of zero or more fields. A stand-alone +// ellipsis rule would have no way to know that. +LastFieldPat: LastPattern> = { + FieldPattern => LastPattern::Normal(<>), + ".." => LastPattern::Ellipsis(<>), +}; + +// Last pattern of an array pattern. See `LastFieldPat`. +LastElemPat: LastPattern> = { + Pattern => LastPattern::Normal(<>), + ".." => LastPattern::Ellipsis(<>), } // A default annotation in a pattern.