Skip to content

feat(expr): add 1-D array indexing to the binding evaluator (#142)#169

Merged
jscott3201 merged 2 commits into
developmentfrom
claude/expr-array-indexing
Jul 21, 2026
Merged

feat(expr): add 1-D array indexing to the binding evaluator (#142)#169
jscott3201 merged 2 commits into
developmentfrom
claude/expr-array-indexing

Conversation

@jscott3201

Copy link
Copy Markdown
Owner

Fourth PR of the issue-#142 array lane.

Scope

Postfix A[i] indexing in oce-expr: ExprAst::Index, ExprError::{IndexOutOfBounds{index,size}, NonIntegerIndex{found}} (the sanctioned PR-2 deferral lands here). Grammar: postfix binds tighter than unary sign (-A[i] == -(A[i])); slicing A[a:b] (even parenthesized) and empty brackets are typed parse rejections; A[i,j] parses then defers at eval (multi-dim); the leading-[ matrix-constructor rejection is byte-unchanged.

Safety policy

1-based bounds checked on the i64 subscript before any offset math (i64::MAX/MIN safe by construction); access via checked conversion + .get() with a deliberately distinct DomainError backstop so a bounds-check mutation cannot be masked; A[1.0] is NonIntegerIndex — no Real coercion (rounding-trap rationale in-test).

Tests

20 new (oce-expr 115; workspace 1151), including −0.0/NaN bit pass-through goldens, size(A)[1] composition, chained-index scalar-base error, extreme-subscript wrap traps, and two implementer-run mutation self-checks (off-by-one bounds; floor-coerced subscript) confirmed failing before revert.

Gates (implementer + independent lead verification at ae18257)

fmt ✓ · clippy -D warnings ✓ · nextest 1151/1151 ✓ · doctests ✓ · file-size ✓ · determinism mirror 410/410 ✓ · diff scope = oce-expr only ✓

🤖 Generated with Claude Code

jscott3201 and others added 2 commits July 21, 2026 15:03
Postfix subscripts A[i] now parse and evaluate. Grammar: a new postfix
production sits between unary and primary, so a subscript binds tighter
than the unary sign (-A[i] == -(A[i])) and chains (A[1][2]) parse as
nested Index nodes. Inside the brackets each subscript is a full range
expression grammatically, but one that parses to a range is array
slicing — rejected at parse with a typed error — and empty brackets are
malformed; the primary-position '[' matrix-constructor rejection is
byte-unchanged. Comma-separated subscripts parse into one Index node
and defer at evaluation with a typed DomainError naming the
multi-dimensional deferral.

Eval policy: the base must evaluate to an array (scalar base is a
TypeError naming the found type — which also covers chained indexing,
since A[1] is a scalar). Subscripts must be Integer scalars: Real
(including whole-valued 1.0), Boolean, String, and Enum subscripts are
the new NonIntegerIndex error — no integer()-style floor coercion, so a
0.999999 rounding artifact fails loudly instead of reading the wrong
element. Bounds are 1-based (CDL) and checked on the i64 subscript
against the length widened to i64 before any usize conversion, so
i64::MAX/i64::MIN subscripts report the new IndexOutOfBounds
{index, size} without wrap or saturation; every subscript of an empty
array is out of bounds with size 0. The element read is a clone of the
already-canonicalized stored value, so -0.0 and canonical-NaN bits pass
through bit-identical (golden-pinned).

Canary flip: tests.rs pinned a[1] as a parse rejection; it now parses
and fails as UnknownIdent at evaluation. The malformed-syntax list in
eval_array_tests drops its "a[1]" row for the same reason ("a[" stays).
The leading-'[' and comprehension parse rejections keep their pins.

Mutation self-checks (applied locally, confirmed failing, reverted):
an off-by-one bounds check (i < 0) fails
subscript_zero_negative_and_past_the_end_are_out_of_bounds and
every_subscript_of_an_empty_array_is_out_of_bounds; a floor-coercion
subscript fails non_integer_subscripts_are_rejected_without_coercion.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…essage tighten

Adds the Enumeration case to the subscript type-gate matrix: an enum
value in subscript position is NonIntegerIndex{found: "Enumeration"}
(the test scope now resolves enum references, mirroring tests.rs), and
the module rustdoc says "Enumeration" to match eval::type_name. Drops
the doubled "; oce-expr arrays are 1-D" from the multi-subscript
deferral message and updates its pinned golden.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jscott3201
jscott3201 merged commit b446775 into development Jul 21, 2026
14 checks passed
@jscott3201
jscott3201 deleted the claude/expr-array-indexing branch July 21, 2026 19:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant