Skip to content

fix: preserve dynamic array index on dotted property paths#704

Merged
killme2008 merged 1 commit into
masterfrom
fix/dotted-var-dynamic-index
Jul 19, 2026
Merged

fix: preserve dynamic array index on dotted property paths#704
killme2008 merged 1 commit into
masterfrom
fix/dotted-var-dynamic-index

Conversation

@killme2008

Copy link
Copy Markdown
Owner

Problem

The recent lexer/parser refactor for a.b.c property access (PR #693) made ExpressionLexer.scanVariable greedily absorb any [...] following a dotted name into the variable lexeme. That lexeme is then resolved via Reflector.fastGetProperty, whose bracket handling only supports integer-literal indices (Integer.valueOf). As a result, expressions that previously worked through the parser's array-access path regressed:

Expression Before this fix
a.b[i] NumberFormatException at runtime → "Could not find variable a.b[i]"
a.b[i + 1] compile-time ExpressionSyntaxErrorException
a.b[0][1] broken multi-dimensional index
foo.bars[0].name ✅ works (new feature)

Fix

scanVariable now only absorbs a mid-chain integer-literal index into the lexeme — a [digits] group immediately followed by another . (e.g. the [0] in foo.bars[0].name). That is the only case that cannot be expressed through the parser's array-access path.

Every other case — dynamic (a.b[i]), expression (a.b[i + 1]), trailing (a.b[0]) and multi-dimensional (a.b[0][1]) — stops before [ and is handled by the parser's getElement array access, which supports arbitrary index expressions. This restores the old behavior while keeping the new property-chain feature intact.

Position rollback uses StringCharacterIterator.setIndex.

Tests

  • ExpressionLexerUnitTest: tokenization tests asserting dynamic / trailing / multi-dimensional indices are not absorbed, and mid-chain literal indices are.
  • QuoteVarTest: end-to-end tests for dynamic and multi-dimensional indices on dotted paths.

Full suite passes locally (mvn test): 870 tests, 0 failures.

The lexer/parser refactor for `a.b.c` property access made scanVariable
greedily absorb any `[...]` following a dotted name into the variable
lexeme, which is then resolved via Reflector.fastGetProperty. That path
only supports integer-literal indices (Integer.valueOf), so it regressed
expressions that used to work through the parser's array-access path:

- `a.b[i]`      -> NumberFormatException at runtime (variable not found)
- `a.b[i + 1]`  -> compile-time syntax error
- `a.b[0][1]`   -> broken multi-dimensional index

scanVariable now only absorbs a mid-chain integer-literal index (a
`[digits]` group immediately followed by another `.`, e.g. the `[0]` in
`foo.bars[0].name`), which is the only case that cannot be expressed via
array access. Dynamic, expression, trailing and multi-dimensional indices
are left for the parser's getElement handling, restoring the old behavior
while keeping the new property-chain feature.

Add lexer tokenization tests and end-to-end tests covering dynamic and
multi-dimensional indices on dotted paths.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Restores pre-refactor behavior for dotted variables with array access by ensuring ExpressionLexer.scanVariable only absorbs mid-chain integer-literal indices (e.g. foo.bars[0].name) into the variable lexeme, while leaving dynamic/expression/trailing/multi-dimensional indices for the parser’s array-access path.

Changes:

  • Refines ExpressionLexer.scanVariable to stop before [ unless it’s a [digits] immediately followed by ..
  • Adds a focused lexer helper (tryAbsorbChainedIndex) with rollback via StringCharacterIterator.setIndex.
  • Adds/extends tests covering dynamic, trailing, and multi-dimensional indices on dotted paths (lexer-level + end-to-end).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/main/java/com/googlecode/aviator/lexer/ExpressionLexer.java Changes variable scanning to only absorb mid-chain [digits]. indices, preserving parser handling for dynamic/trailing/multi-dim indexing.
src/test/java/com/googlecode/aviator/lexer/ExpressionLexerUnitTest.java Adds tokenization assertions to ensure indices on dotted vars are (or aren’t) absorbed as intended.
src/test/java/com/googlecode/aviator/test/function/QuoteVarTest.java Adds end-to-end coverage for dynamic and multi-dimensional indices on dotted paths.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@killme2008
killme2008 merged commit b379d02 into master Jul 19, 2026
2 checks passed
@killme2008
killme2008 deleted the fix/dotted-var-dynamic-index branch July 19, 2026 16:27
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.

2 participants