Repository navigation
feat: support unpacking in Python comprehensions - #19
Merged
Merged
Conversation
Co-authored-by: WillBooster (Codex CLI) <agent@willbooster.com>
Co-authored-by: WillBooster (Codex CLI) <agent@willbooster.com>
Co-authored-by: WillBooster (Codex CLI) <agent@willbooster.com>
Co-authored-by: WillBooster (Codex CLI) <agent@willbooster.com>
Co-authored-by: WillBooster (Codex CLI) <agent@willbooster.com>
Co-authored-by: WillBooster (Codex CLI) <agent@willbooster.com>
Co-authored-by: WillBooster (Codex CLI) <agent@willbooster.com>
…ions Co-authored-by: WillBooster (Codex CLI) <agent@willbooster.com>
Co-authored-by: WillBooster (Codex CLI) <agent@willbooster.com>
Python 3 reads `print >>sys.stderr, *a` as an expression list whose second element unpacks `a`, so the print statement arguments accept the same splats as expression lists. Co-authored-by: WillBooster (Claude Code) <agent@willbooster.com>
`:error` cases assert only that the input fails to parse, and the test runner never compares their trees, so the placeholder trees documented nothing. Co-authored-by: WillBooster (Claude Code) <agent@willbooster.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Python 3.15 permits unpacking comprehension bodies, but tuple operands and dictionary unpacking produce errors or incorrectly grouped trees. This addresses the feature proposed in
tree-sitter/tree-sitter-python#353, addressingtree-sitter/tree-sitter-python#352and the accepted PEP 798.Requirements
Customer Summary
List, set, dictionary, and generator comprehensions accept unpacking bodies, including tuple and call operands, async clauses, and filters. Invalid recursive splats and unparenthesized conditional display and list/set-comprehension operands produce parse errors. List literal splats contain their complete attribute or call operand. Single-element tuples containing unpacking require a trailing comma.
Technical Summary
Splats are explicit at collection, argument, subscript, expression-list, print-statement, match-subject, and type boundaries rather than general primary expressions. This prevents operators and parentheses from admitting invalid nested splats without duplicating the expression grammar. Tuple displays require a comma; parenthesized expressions remain separate. Call, subscript, generator-comprehension, and dictionary-comprehension unpacking retain conditional and lambda operands while rejecting unparenthesized walrus operands, including recursive operator and lambda variants. Starred types are confined to declaration parameters, generic arguments, and variadic positional annotations with their respective operand restrictions. Type aliases use declaration names, so ordinary type(...) assignments remain expressions. Starred types appear directly as splat_type nodes at their permitted boundaries. The compact parser and node metadata are regenerated, and the README identifies this fork's grammar, scanner, and highlighting changes.
Corpus coverage includes all four comprehension forms, parenthesized conditional operands, valid unpacking inside operands, expression lists, subscripts, starred match subjects, and independent rejection cases for direct and recursive invalid splats. The rejection cases use
:errorwithout a recorded tree, since the runner only checks that they fail to parse. Existing list-literal expectations assert correct grouping; invalid tuple/yield examples use valid syntax, with their invalid counterparts covered separately.Testing
The initial four comprehension cases reproduced failures against the base parser. Recursive invalid-splat reproducers parsed without errors before the repair.
TREE_SITTER_ITERATIONS=100 TREE_SITTER_EDITS=10 mise exec rust@1.99.1 -- bun wb verify --full test/unit/corpus.test.ts test/unit/incremental.test.tspasses, including linting, type checking, the native corpus, and incremental parsing. The pinned CPythonLib/test/test_typing.pyfile that failed in CI also parses successfully after restoring explicit starred type operands. Manual comparisons against CPython 3.15.0rc2 cover 192 expression-unpacking cases and 143 typing cases with no acceptance mismatches.print >>sys.stderr, *a, which CPython compiles as an expression list, parses as a print statement with alist_splatargument, as onmain. The full cross-platform, Wasm, and sanitizer suites run in PR CI.Notes
The shared expression repair is necessary because restricting only the direct comprehension operand leaves invalid nested splats reachable through operators and parentheses.
The generated parser contains generator-emitted trailing spaces and remains byte-compatible with regeneration. Code-gauge reports existing violations in scanner and example files; none are in code changed here.