Skip to content

Commit

Permalink
Fix Github issue 855 - fail to parse with statement
Browse files Browse the repository at this point in the history
When we added support for parenthesized with statements, the
grammar on the with itself was correct (it's a right and left
parenthesis around a comma-separated list of with-items, with
a possible trailing comma).

But inside of the "as" variation of the with_item rule we have a peek at
the next character, which was allowing for a comma or a colon. That peek
needs to also accept right parentheses - otherwise, if the last item
contains an `as` and has no trailing comma we fail to parse.

The bug is exercisecd by, for example, this code snippet:
```
with (foo, bar as bar,):
    pass
```

The with_wickedness test fixture has been revised to include both
the plain and async variations of this example snippet with and without
trailing comma, and tests pass after the peek rule fix.
  • Loading branch information
stroxler committed Feb 15, 2023
1 parent 8652974 commit f09498a
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 4 deletions.
2 changes: 1 addition & 1 deletion native/libcst/src/parser/grammar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ parser! {
}

rule with_item() -> WithItem<'a>
= e:expression() a:lit("as") t:star_target() &(lit(",") / lit(":")) {
= e:expression() a:lit("as") t:star_target() &(lit(",") / lit(":") / rpar()) {
make_with_item(e, Some(a), Some(t))
}
/ e:expression() {
Expand Down
27 changes: 24 additions & 3 deletions native/libcst/tests/fixtures/with_wickedness.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,34 @@
# with_wickedness

with foo : ...
with foo :
pass

with foo, bar as bar:
pass

with (foo, bar as bar):
pass

with (foo, bar as bar,):
pass

async def f():
async with foo as bar:
async with foo:

with bar:
pass

async with foo(1+1) as bar , 1 as (a, b, ) , 2 as [a, b] , 3 as a[b] :
async with foo :
pass

async with foo, bar as bar:
pass

async with (foo, bar as bar):
pass

async with (foo, bar as bar,):
pass

async with foo(1+1) as bar , 1 as (a, b, ) , 2 as [a, b] , 3 as a[b] :
pass

0 comments on commit f09498a

Please sign in to comment.