feat(parser): chained assignment with attribute and subscript targets - #142
Merged
Conversation
…rgets The parser only chained bare names (x = y = 1); attribute targets (self.prev = self.next = None), name/subscript mixes (v = d['k'] = 1), and nested subscripts all failed with "unexpected token" at the second '='. A separate half-implementation for subscript chains desugared to a block while duplicating the RHS AST, so a[0] = b = f() called f() twice. Generalize collect_chained_assign to accept any valid target (name, getattr, subscript) at each link, and route every assignment entry point (attr, subscript, slice, nested-subscript, expression-statement) through a shared parse_assign_value helper so any of them can continue a chain. Single-target assignments still emit their exact old AST nodes. Chains emit one :chained_assign node with mixed targets; eval_chained_assign evaluates the RHS exactly once and binds left to right by reusing bind_assignment_pairs, with a slice-key clause so a[:2] = b = x keeps routing through the name-form slice splicer. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KuxYKoh8pXEna5ohZUgJsn
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.
Summary
Real Python chains assignments through any valid target —
self.prev = self.next = None,v = d['k'] = compute(),a[0] = a[1] = False— but pyex only chained bare names (x = y = 1). Everything else died withunexpected tokenat the second=. This is the parser gap that broke an idiomatic LRU cache (Node.__init__withself.prev = self.next = None) in the WasmGC demo.lib/pyex/parser.ex):collect_chained_assignnow accepts any valid target (name,getattr,subscript) at each link, and a sharedparse_assign_valuehelper lets every assignment entry point — attr, subscript, slice, nested-subscript, expression-statement — continue a chain from its own target. Single-target assignments still emit their exact old AST nodes, so nothing downstream sees a new shape unless a chain is present.lib/pyex/interpreter/bindings.ex):eval_chained_assigngeneralizes from[String.t()]to mixedunpack_target()lists, evaluating the RHS exactly once and binding left-to-right by reusingbind_assignment_pairs(the tuple-unpack machinery). A new slice-key clause keepsa[:2] = b = xrouted through the name-form slice splicer.parse_subscript_assign_valueblock-desugar, which duplicated the RHS AST across the block —a[0] = b = f()used to callf()twice. The unified path fixes that class of bug.assignments.ex(eval_name_subscript_assignaccepts{:__evaluated__, v}), demanded by Dialyzer.Semantics verified
RHS evaluated exactly once across the chain;
a = b = []aliases (a is b→True); assignment order is left-to-right;x = 1 == 2still parses as comparison;f() = x = 1is still a syntax error. Eleven new tests intest/pyex/interpreter_test.exsunder "chained assignment", including a linked-list pointer-splice case mirroring the LRU's_remove.Test plan
mix format --check-formattedmix compile --warnings-as-errors(modulo the three pre-existing 1.20.2-local warnings on main)mix test— 6512/6513 (the one failure is the known local-OTP zipfile CRC-message artifact, present on main)mix dialyzer— clean🤖 Generated with Claude Code
https://claude.ai/code/session_01KuxYKoh8pXEna5ohZUgJsn