Section 02: Parser — assignment_target + AssignTarget AST
Goal
See frontmatter. Proposal Phase 2. Parser accepts the extended LHS and emits a single chain-capturing node; all desugaring is deferred to the type checker (section-03).
Implementation Sketch
The current grammar restricts assignment LHS to a bare identifier. This section extends the assignment-target dispatcher to accept an identifier followed by any combination of [expr] (index) and .ident (field) suffixes, emitting one AssignTarget node. The parser does NOT decide spread-vs-updated (that needs types); it records the raw chain. The root must remain a bare identifier (mutability is checked in section-03).
02.1 assignment_target Grammar + AssignTarget AST Node
- TDD-first: failing parser test matrix — target shapes
x/x[i]/x.f/x.f[i]/x[i].f/x.f.g[i].h× ALLparse.md §PR-5operators=/+=/-=/*=//=/%=/**=/@=/&=/|=/^=/<<=/>>=/&&=/||=. Negative (non-identifier root / non-target postfix rejection):f()[0] = x,(a+b)[0] = x,a?.b = x,a.m() = x,a.m()[0] = x,(a as T).f = x— method-call LHS and cast LHS rejected. Negatives live in BOTH the Rust parser tests (ori_parse/src/grammar/expr/mod.rs) ANDtests/spec/expressions/index_assignment_syntax.ori(#compile_failpins). - Add
AssignTargetAST node inori_ir/src/ast/expr.rsas an ADDITIVEExprKindvariant —ExprKind::AssignTarget { root: ExprId, steps: Vec<AccessStep> },AccessStep::Index(ExprId)/AccessStep::Field(Name); Salsa derives matching siblings (Clone/Eq/Hash/Debug).ExprKind::Assign { target: ExprId, value: ExprId }field shape is UNCHANGED —targetresolves to the newExprKind::AssignTargetnode for chain targets (DD-1 resolution; not a field-type change, not a parallel struct).- Rust Tests:
ori_ir/src/ast/tests.rs
- Rust Tests:
- Keep
ExprKind::Assignconsumers + incremental copier compiling: add anExprKind::AssignTargetarm toori_parse/src/incremental/copier/expr.rs(additive copier variant, mirrors the existing per-variant pattern near line 251); auditExprKind::Assignmatch sites inori_types/ori_canon/ori_eval/ori_arc/ori_fmt/oric— they matchAssign(shape unchanged) so stay compiling; any site that must route a chain target handsExprKind::AssignTargetto section-03’s desugar (no eval/canon/AIMS handling here — parser stays syntax-only).- Rust Tests:
ori_parse/src/incremental/copier/expr.rscopier round-trip tests
- Rust Tests:
- Extend parser to accept
assignment_targeton the LHS of=+ compound operators —ori_parse/src/grammar/expr/mod.rs(assignment-target dispatcher) +ori_parse/src/grammar/expr/postfix.rs(chain resolution). Emit ONEAssignTargetnode; reject non-identifier roots + non-index/field postfix.- Rust Tests:
ori_parse/src/grammar/expr/mod.rsparser tests - Ori Tests:
tests/spec/expressions/index_assignment_syntax.ori
- Rust Tests:
- Compound-operator LHS: verify ALL
parse.md §PR-5compound operators (+= -= *= /= %= **= @= &= |= ^= <<= >>= &&= ||=) accept the extended target (no subset deferral); compound expand stays the parse-time rewrite (parse.md §PR-5) over the extended target (pertypeck.md §EX-17— compound desugars tox = x op y, then section-03 desugars the index/field target). - Compound chain-target shared-identity invariant (AR-1 / DD-2): the PR-5 parse-time expansion of
x[i] op= rhs->x[i] = x[i] op rhsover a chain target MUST give the read-copy (x[i]on the RHS) and the write-copy (x[i]LHS, theAssignTarget) the SAME chain identity, so section-03 desugars read-copy viaIndex(read) and write-copy viaIndexSet(write) into their correct roles (pertypeck.md §EX-17+parse.md §PR-5). Pin a parser test asserting both copies carry the structurally-identical chain forstate.items[i] += 1; banned: two independently-resolved chain targets that section-03 could desugar inconsistently.- Rust Tests:
ori_parse/src/grammar/expr/mod.rscompound-chain-identity test
- Rust Tests:
- Verify: parser matrix green; no regression in
cargo t -p ori_parse+./test-all.sh.
Intelligence Reconnaissance
2026-06-01 — feature-mode scaffold; proposal is the research artifact. Verify the exact module against the shipped tree before editing — do NOT trust a guessed path.
scripts/intel-query.sh file-symbols "ori_parse/src/grammar/expr" --repo ori— assignment-target dispatcher + chain resolution[ori:ori_parse/src/grammar/expr/].scripts/intel-query.sh symbols "Assign" --repo ori --kind type— existing assignment AST node to extend[ori:ori_ir/src/ast/expr.rs].scripts/intel-query.sh callers "parse_assignment" --repo ori— assignment dispatch entry.
Spec References
- Proposal §Grammar Changes, §Implementation Note: Type-Directed Desugaring (parser is syntax-only).
grammar.ebnfproduction (synced in section-04):assignment_target = identifier { "[" expression "]" | "." identifier }.parse.md §PR-5(compound-assignment parse-time rewrite).
Tests
tests/spec/expressions/index_assignment_syntax.ori + Rust parser/AST unit tests per items.