0%

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 × ALL parse.md §PR-5 operators = / += / -= / *= / /= / %= / **= / @= / &= / |= / ^= / <<= / >>= / &&= / ||=. 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) AND tests/spec/expressions/index_assignment_syntax.ori (#compile_fail pins).
  • Add AssignTarget AST node in ori_ir/src/ast/expr.rs as an ADDITIVE ExprKind variant — 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 — target resolves to the new ExprKind::AssignTarget node for chain targets (DD-1 resolution; not a field-type change, not a parallel struct).
    • Rust Tests: ori_ir/src/ast/tests.rs
  • Keep ExprKind::Assign consumers + incremental copier compiling: add an ExprKind::AssignTarget arm to ori_parse/src/incremental/copier/expr.rs (additive copier variant, mirrors the existing per-variant pattern near line 251); audit ExprKind::Assign match sites in ori_types / ori_canon / ori_eval / ori_arc / ori_fmt / oric — they match Assign (shape unchanged) so stay compiling; any site that must route a chain target hands ExprKind::AssignTarget to section-03’s desugar (no eval/canon/AIMS handling here — parser stays syntax-only).
    • Rust Tests: ori_parse/src/incremental/copier/expr.rs copier round-trip tests
  • Extend parser to accept assignment_target on 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 ONE AssignTarget node; reject non-identifier roots + non-index/field postfix.
    • Rust Tests: ori_parse/src/grammar/expr/mod.rs parser tests
    • Ori Tests: tests/spec/expressions/index_assignment_syntax.ori
  • Compound-operator LHS: verify ALL parse.md §PR-5 compound operators (+= -= *= /= %= **= @= &= |= ^= <<= >>= &&= ||=) accept the extended target (no subset deferral); compound expand stays the parse-time rewrite (parse.md §PR-5) over the extended target (per typeck.md §EX-17 — compound desugars to x = 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 rhs over a chain target MUST give the read-copy (x[i] on the RHS) and the write-copy (x[i] LHS, the AssignTarget) the SAME chain identity, so section-03 desugars read-copy via Index (read) and write-copy via IndexSet (write) into their correct roles (per typeck.md §EX-17 + parse.md §PR-5). Pin a parser test asserting both copies carry the structurally-identical chain for state.items[i] += 1; banned: two independently-resolved chain targets that section-03 could desugar inconsistently.
    • Rust Tests: ori_parse/src/grammar/expr/mod.rs compound-chain-identity test
  • 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.ebnf production (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.