diff options
| author | Tim Foley <tfoleyNV@users.noreply.github.com> | 2021-02-23 01:47:19 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-02-23 01:47:19 -0800 |
| commit | 4bf01b04cb6bf1df8d4fb2ec5eee0a912ec679dc (patch) | |
| tree | cb4e1ae5fa780de24e3320b41af3a4b83d59b19c /tests/parser | |
| parent | 025c0edc3fd3fb751b36058596a0733ac24b8939 (diff) | |
Some ad hoc parser fixes (#1723)
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.
Diffstat (limited to 'tests/parser')
| -rw-r--r-- | tests/parser/incomplete-member-decl.slang | 20 | ||||
| -rw-r--r-- | tests/parser/incomplete-member-decl.slang.expected | 8 |
2 files changed, 28 insertions, 0 deletions
diff --git a/tests/parser/incomplete-member-decl.slang b/tests/parser/incomplete-member-decl.slang new file mode 100644 index 000000000..67a722711 --- /dev/null +++ b/tests/parser/incomplete-member-decl.slang @@ -0,0 +1,20 @@ +// incomplete-member-decl.slang + +//DIAGNOSTIC_TEST:SIMPLE: + +// Regresion test to ensure parser doesn't go into infinite loop +// on incomplete/malformed member decalration + +struct Outer +{ + // Programmer was *trying* to declarae a field, but somehow + // ended up with two type specifiers. + // + // Parser sees the second (generic) type specifier and assumes + // it must represent a method declaration, at which point it + // fails to find a parameter list (no opening `(`), and then + // fails to find a body (no opening `{`), but finds a bare identifier + // instead. + // + int MyType<X> inner; +}
\ No newline at end of file diff --git a/tests/parser/incomplete-member-decl.slang.expected b/tests/parser/incomplete-member-decl.slang.expected new file mode 100644 index 000000000..ed5695977 --- /dev/null +++ b/tests/parser/incomplete-member-decl.slang.expected @@ -0,0 +1,8 @@ +result code = -1 +standard error = { +tests/parser/incomplete-member-decl.slang(19): error 20001: unexpected identifier, expected '(' + int MyType<X> inner; + ^~~~~ +} +standard output = { +} |
