|
|
The `AdvanceIfMatch()` method was introduced to the parser as a way to avoid infinite loops when parsing nested list structures (e.g., `()`-enclosed parameter lists). The basic idea is that it tries to detect if we have scanned "too far" looking for a closing token, and reports a match to whatever logic was doing the looping to break the statemate.
Unfortunately, the `TryRecoverBefore` logic was changed at some point so that it doesn't necessarily advance any tokens at all, because we generally don't want to skip over a `}` while searching for a `)`. As a result, we could still end up in an infinite loop where we didn't consume any additional tokens as part of recovery, but wouldn't bail out of the search for a match.
This change tries to introduce a slightly more systematic setup where `AdvanceIfMatch` is now parameterized on a type of matched token pair (not just the closing token), and each such matched token pair introduces a list of tokens where if we see them as our lookahead we should bail out (e.g., when looking for a `)` we should give up the search upon seeing a `}`).
After installing that fix I found that my simple test case still gave a surprising error because when mistakenly parsing a function body the parser would look for a `{` and then a `}` to close the body. The search for a closing `}` could accidentally consume a `}` meant for an outer scope, and lead to a cascading failure. I madea quick fix to the parsing of block statements so that we don't look for a closing `}` if we never had an opening `{`, but that isn't really a systematic solution like we truly need.
For now, these fixes will avoid the infinite-loop case, and should give a better diagnostic in the case a user ran into, but we need to take time to do some more top-down work on the parser sooner or later.
|