Skip to content

Preserve grouping and typing in TA reset length lowering#41

Merged
luisleo526 merged 1 commit into
mainfrom
fix/stable-ta-length-expr-lowering
Jul 5, 2026
Merged

Preserve grouping and typing in TA reset length lowering#41
luisleo526 merged 1 commit into
mainfrom
fix/stable-ta-length-expr-lowering

Conversation

@luisleo526

Copy link
Copy Markdown
Contributor

Summary

  • The stable-runtime-TA-length reset path (PR Support stable runtime TA lengths #40) re-materialized length-defining expressions via a lossy AST->infix serializer: no grouping parentheses, no numeric coercion. C++ precedence re-associated the expression and int/int division truncated; a derived EMA length collapsed through sqrt(negative)->NaN->max(1, int(round(NaN))) to 1, silently degrading every TA instance built from it (strategy traded zero times).
  • Fix: parenthesize non-atomic operands in both serializers so the expanded expression re-parses to the same tree, then lower the reset expression through the same expression visitor used for scalar statements — grouping and Pine numeric typing correct by construction. Input-backed vars render as override-aware get_input_*() reads in reset context (resets may run before input member init). Legacy renderer kept as fallback only.

Validation

  • Full suite: 1443 passed / 0 failed / 2 pre-existing skips (incl. test_compile_corpus.py 254).
  • New regressions: grouping-across-division; float division of two int operands in derived lengths.
  • Independent fresh-context R7 gate: PASS (diff inspection, full suite re-run, e2e on the exposing strategy — derived length now 21 as Pine computes, 996 trades vs prior 0; an unaffected strategy transpiles byte-identical to main).

🤖 Generated with Claude Code

The stable-runtime-TA-length reset path re-materialized length-defining
expressions through a lossy AST->infix serializer: BinOp/UnaryOp operands
were joined without grouping parentheses and without the analyzer's
numeric coercions, so C++ operator precedence re-associated the
expression and int/int division truncated. A derived length like
2 / (-(beta) + sqrt(beta*beta + 2*beta)) could collapse through
sqrt(negative) -> NaN -> max(1, int(round(NaN))) to a constant length 1,
silently degrading every TA instance built from it.

Fix: parenthesize non-atomic operands in both serializers so the
expanded expression re-parses to the same tree, then lower the reset
expression through the same expression visitor used for scalar
statements, making grouping and Pine numeric typing (always-float
division, (double) coercions) correct by construction. Input-backed
variables render as override-aware get_input_*() reads in reset context
because resets can run before input members are initialized. The legacy
token-substitution renderer remains only as a fallback.

Adds regressions for grouping-across-division and float division of two
int operands in derived lengths.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@luisleo526 luisleo526 merged commit eb04eb7 into main Jul 5, 2026
9 checks passed
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