fix: longestMatch at trailing parsers

Before this commit, if we execut `longestMatch [p1, p2]` in a
trailing parser where both `p1` and `p2` succeed, then an incorrect
syntax tree is generated by `p2`. The issue is that before executing
`p2`, the trailing stack is of the form
`#[..., left, syntax-by-p1]`
Then, the trailing parser `p2` incorrectly assumes that `syntax-by-p1`
was the "left" syntax node.
This commit fix this issue by storing the `left` node at the
`ParserContext` at `trailingLoop`

@Kha This bug was introduced when we unified leading and trailing
parsers. I think this is the simplest solution.
We can observe the bug before this commit by using
```
set_option syntaxMaxDepth 1000
set_option trace.Elab true
```
at `choiceMacroRules.lean`.

It is funny the correct result was produced even with the bug.
It was working because the `macro_rules` was matching the
buggy syntax with the nested `syntax-by-p1` there :)
This commit is contained in:
Leonardo de Moura 2020-06-08 14:34:50 -07:00
parent 8b1cb0fcb8
commit 52c7709cb3

View file

@ -145,6 +145,7 @@ instance InputContext.inhabited : Inhabited InputContext :=
structure ParserContext extends InputContext :=
(rbp : Nat)
(left : Syntax := Syntax.missing)
(env : Environment)
(tokens : TokenTable)
@ -236,10 +237,10 @@ match s with
let stack := stack.push newNode;
⟨stack, pos, cache, err⟩
def mkTrailingNode (s : ParserState) (k : SyntaxNodeKind) (iniStackSz : Nat) : ParserState :=
def mkTrailingNode (s : ParserState) (k : SyntaxNodeKind) (left : Syntax) (iniStackSz : Nat) : ParserState :=
match s with
| ⟨stack, pos, cache, err⟩ =>
let newNode := Syntax.node k (stack.extract (iniStackSz - 1) stack.size);
let newNode := Syntax.node k (#[left] ++ stack.extract iniStackSz stack.size);
let stack := stack.shrink iniStackSz;
let stack := stack.push newNode;
⟨stack, pos, cache, err⟩
@ -363,7 +364,7 @@ instance hasAndthen : HasAndthen Parser :=
| c, s =>
let iniSz := s.stackSize;
let s := p c s;
s.mkTrailingNode n iniSz
s.mkTrailingNode n c.left iniSz
@[noinline] def nodeInfo (n : SyntaxNodeKind) (p : ParserInfo) : ParserInfo :=
{ collectTokens := p.collectTokens,
@ -1601,6 +1602,7 @@ partial def trailingLoop (tables : PrattParsingTables) (c : ParserContext) : Par
let (s, lbp) := currLbp left c s;
if c.rbp ≥ lbp then s
else
let c := { c with left := s.stxStack.back };
let iniSz := s.stackSize;
let identAsSymbol := false;
let (s, ps) := indexed tables.trailingTable c s identAsSymbol;