pineforge-codegen 0.9.0__tar.gz → 0.10.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/PKG-INFO +1 -1
- pineforge_codegen-0.10.0/VERSION +1 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/codegen/base.py +220 -22
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/codegen/emit_top.py +5 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/codegen/security.py +77 -25
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/codegen/types.py +53 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/codegen/visit_expr.py +87 -1
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/codegen/visit_stmt.py +11 -2
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_codegen_ta_derived_length.py +169 -0
- pineforge_codegen-0.10.0/tests/test_na_reassign_retype.py +183 -0
- pineforge_codegen-0.10.0/tests/test_na_relational_lowering.py +219 -0
- pineforge_codegen-0.10.0/tests/test_security_tf_input_derived.py +175 -0
- pineforge_codegen-0.9.0/VERSION +0 -1
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/.github/dependabot.yml +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/.github/workflows/gate.yml +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/.github/workflows/publish-pyodide.yml +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/.github/workflows/release.yml +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/.github/workflows/test.yml +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/.gitignore +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/CLAUDE.md +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/LEGAL.md +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/LICENSE +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/PYODIDE_TARGET +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/README.md +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/docs/codegen-coverage-gaps.md +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/gate/compare.mjs +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/gate/glue.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/gate/oracle.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/gate/run-gate.mjs +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/gate/selftest.mjs +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/npm/README.md +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/npm/index.mjs +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/npm/package.json +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/package-lock.json +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/package.json +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/__init__.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/analyzer/__init__.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/analyzer/base.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/analyzer/call_handlers.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/analyzer/contracts.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/analyzer/diagnostics.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/analyzer/tables.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/analyzer/types.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/ast_nodes.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/codegen/__init__.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/codegen/drawing.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/codegen/helpers.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/codegen/helpers_syminfo.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/codegen/input.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/codegen/ta.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/codegen/tables.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/codegen/visit_call.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/errors.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/lexer.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/parser.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/pragmas.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/signatures.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/support_checker.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/symbols.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/tokens.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/tv_input_choices.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pyproject.toml +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/scripts/build-npm-package.mjs +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/scripts/dump-tables.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/scripts/worker-template.mjs +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/__init__.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/_compile.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/err/const_ns_plot_style_free.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/err/const_ns_shape_free.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/err/divergent_last_bar_index.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/err/export_func.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/err/footprint_new.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/err/hard_reject_dividends.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/err/matrix_unknown_elem.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/err/multi_error_one_line.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/err/sec_tf_invalid.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/err/unknown_color.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/err/unknown_math.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/err/unknown_str.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/err/unknown_strategy_fn.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/err/unknown_syminfo.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/err/unknown_ta.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/AAPL__session-ismarket-nyse-rth-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/AAPL__time-tradingday-daily-reset-counter-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/QQQ__session-ispremarket-nasdaq-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/SPY__session-firstbar-vwap-anchor-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/SPY__session-lastbar-flatten-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/chart_bg_color.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/crypto-htf__mtf-htf-monthly-ema-cross-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/crypto-leverage__leverage-margin-call-perp-5x-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/forex__symbol-fx-5dp-eurusd-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/futures__symbol-futures-pointvalue-es-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/tutorial__macd__strategy.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/tutorial__mtf__strategy_htf.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/tutorial__mtf__strategy_ltf.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/us-equity__symbol-equity-rth-gaps-aapl-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/us-equity__us-equity-exchange-tz-intraday-cap-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__analyzer-parity-choch-bos-isolator-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__analyzer-parity-edge-margin-50-pct-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__analyzer-parity-percent-of-equity-sizing-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__analyzer-parity-small-equity-fraction-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__analyzer-parity-stop-limit-timing-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__analyzer-self-test-multi-mode-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__anomaly-equity-mirror-strategy-equity-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__barstate-isconfirmed-magnifier-off-01b.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__barstate-isconfirmed-magnifier-on-01a.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__bracket-atr-trail-series-int-points-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__bracket-atr-trailing-stop-state-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__bracket-entry-exit-same-pass-attach-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__bracket-exit-stop-limit-trail-same-bar-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__bracket-exit-three-way-set-once-entry-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__bracket-exit-tp-sl-fixed-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__bracket-narrow-stop-limit-with-trail8-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__bracket-partial-exit-qty-percent-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__bracket-same-id-exit-replace-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__bracket-tp-sl-oca-reduce-isolate-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__bracket-trail-points-no-offset-explicit-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__bracket-trail-points-with-offset-only-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__bracket-trailing-activation-offset-path-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__cap-max-intraday-filled-orders-isolate-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__cap-risk-gates-allow-max-intraday-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-4emarsi-integration-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-4emarsi-quad-ema-stack-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-4emarsi-rsi-pullback-latch-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-4emarsi-session-window-nbar-exit-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-boscurv-integration-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-boscurv-linreg-slope-channel-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-boscurv-pivot-bos-trigger-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-bracket-cap-range-pending-stop-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-ies-adx-regime-classify-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-ies-bb-kc-squeeze-release-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-ies-cooldown-daily-cap-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-ies-equity-feedback-sizing-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-ies-integration-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-ies-pivot-liquidity-sweep-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-ies-pressure-gauge-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-ies-rsi-macd-momentum-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-ies-three-ema-bias-score-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-kanuck-calc-on-every-tick-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-kanuck-integration-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-kanuck-kama-state-recurrence-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-kanuck-max-bars-back-500-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-kkb-ema-atr-breakout-band-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-kkb-integration-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-kkb-kalman-filter-1d-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-kkb-margin-100-pct-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-liqsweep-integration-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-liqsweep-pivot-hh-ll-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-liqsweep-wait-one-continuation-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-liqsweep-wick-pierce-close-back-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-marketshift-integration-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-marketshift-pivot-state-machine-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-marketshift-rolling-highest-lowest-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-marketshift-state-edge-detector-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-scalping-fast-ma-cross-trigger-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-scalping-integration-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-scalping-tight-tp-sl-points-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-trendmaster-integration-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-trendmaster-line-new-projection-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-trendmaster-pivot-anchored-bracket-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-trendmaster-three-tier-ema-state-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-trendmaster-trend-momentum-structure-gate-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-vcp-cumulative-volume-delta-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-vcp-fvg-active-zones-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-vcp-integration-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-vcp-manual-adx-regime-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-vcp-pivot-strength-5-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-vcp-rsi-smooth-divergence-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-vcp-session-tz-newyork-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-vcp-vol-zscore-anomaly-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-wunderscalper-alert-templates-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-wunderscalper-explicit-reverse-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__composite-wunderscalper-integration-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__input-source-runtime-override-high-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__input-source-subscript-hl2-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ltf-bool-array-bull-majority-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ltf-numeric-float-ratio15-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__magnifier-tick-dist-endpoints-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__magnifier-tick-dist-endpoints-rsi-cross-08a.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__magnifier-tick-dist-volume-weighted-on-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__matrix-bool-mask-explicit-utc-tz-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__matrix-bool-mask-no-transpose-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__matrix-bool-mask-transpose-roundtrip-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__matrix-bool-regime-mask-24x7-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__matrix-covariance-eigen-pca-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__matrix-eigen-rank-deficient-cov-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__max-bars-back-function-call-deep-history-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__mtf-daily-array-median-percentrank-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__mtf-daily-ema26-warmup-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__mtf-daily-prev-high-break-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__mtf-dual-tf-60-240-rising-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__mtf-htf-60-close-change-baseline-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__mtf-htf-60-close-roll-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__mtf-htf-60-gaps-on-roll-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__mtf-htf-60-rsi14-inside-security-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__mtf-htf-60-sma20-inside-security-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__mtf-htf-60-volume-spike-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__mtf-htf-confluence-manual-trail-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__mtf-htf-confluence-static-bracket-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__mtf-htf-weekly-sma-cross-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__mtf-roll-state-60-240-d-minimal-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__mtf-triple-tf-close-confluence-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__mtf-triple-tf-macd-hist-confluence-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__na-deep-history-int-na-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__na-nz-fixnan-history-chain-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__oca-exit-bracket-internal-cancel-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__oca-multi-bracket-isolation-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__oca-raw-strategy-order-reduce-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-close-all-cancel-all-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-close-immediate-vs-next-bar-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-cross-entry-cancel-same-pass-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-cross-entry-close-same-pass-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-cross-exit-close-same-pass-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-deferred-flip-guaranteed-gap-stops-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-deferred-flip-pooc-cross-bar-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-dual-four-bar-stop-no-close-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-dual-side-same-id-stop-no-cancel-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-dual-stop-both-touch-priority-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-dual-stop-cancel-rotation-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-dual-stop-far-only-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-dual-stop-near-only-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-dual-stop-open-high-first-path-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-dual-stop-open-low-first-path-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-dual-stop-open-tie-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-dual-stop-source-order-long-first-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-dual-stop-source-order-short-first-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-entry-implicit-reversal-exit-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-flip-stop-no-paired-close-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-market-close-fill-basis-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-one-side-four-bar-far-opposite-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-opposite-entry-close-same-pass-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-percent-equity-cash-commission-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-process-on-close-false-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-process-on-close-true-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-range-expansion-pending-stop-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-same-id-entry-close-same-bar-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-same-id-market-entry-repeat-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-same-id-stop-after-flat-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-same-id-stop-cross-before-modify-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-same-id-stop-minute-zero-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-same-id-stop-modification-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-same-id-stop-raise-only-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-same-id-stop-window-four-bars-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-stale-stop-after-close-no-cancel-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-stop-cancel-no-regime-close-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-stop-entry-cancel-opposite-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-stop-entry-reversal-grouping-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__order-stop-entry-touch-boundary-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__pyramid-cash-fractional-commission-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__pyramid-close-id-grouping-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__pyramid-deferred-flip-close-all-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__pyramid-flip-stop-pyramiding-2-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__recompute-alma-sar-corr-magnifier-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__recompute-mtf-rsi-macd-bb-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__risk-max-contracts-held-gate-pyramid-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__session-hour-minute-pulse-filter-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__session-ny-spring-forward-dst-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__stats-eventrades-zero-pnl-count-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-accdist-ema-cross-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-bb-kc-squeeze-breakout-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-bb-rsi-mean-reversion-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-cci-threshold-cross-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-chandelier-exit-direction-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-closedtrades-risk-introspection-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-cmo-9-zero-cross-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-cog-10-signal-cross-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-dmi-adx-di-cross-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-donchian-channel-breakout-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-dual-ma-switch-dispatch-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-dual-thrust-open-anchored-range-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-elder-ray-bull-bear-power-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-ema-ribbon-stack-transition-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-engulfing-candle-pattern-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-highestbars-lowestbars-breakout-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-hma-55-close-cross-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-hma-fast-slow-cross-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-inside-bar-engulfing-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-kama-style-efficiency-ratio-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-keltner-channel-break-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-linreg-stdev-channel-revert-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-macd-12-26-9-line-signal-cross-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-macd-histogram-reversal-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-macd-line-gt-signal-continuous-state-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-map-regime-threshold-lookup-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-median-vs-ema-cross-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-mfi-14-bands-20-80-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-momentum-roc-zero-cross-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-multi-indicator-score-composite-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-nvi-pvi-cross-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-obv-ema-cross-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-percentrank-mean-reversion-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-pivot-array-unshift-pop-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-pivot-atr-stop-target-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-pivot-confirmed-break-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-pivot-point-levels-break-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-pvt-ema-cross-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-range-filter-var-band-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-rci-14-zero-cross-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-rsi-bb-self-bands-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-rsi-ema-signal-cross-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-rsi-macd-and-continuous-state-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-rsi14-bands-30-70-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-rsi14-cross-50-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-rsi14-gt-50-continuous-state-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-rsi14-gt60-lt45-no-matrix-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-sar-flip-entry-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-sma-152-close-cross-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-sma-dual-cross-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-stdev-sma-expansion-break-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-stoch-slow-k-d-cross-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-stochastic-rsi-cross-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-str-match-regex-filter-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-supertrend-adx-filter-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-supertrend-direction-flip-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-triple-sma-stack-latch-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-tsi-25-13-signal-cross-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-volume-spike-atr-breakout-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-vwma-vs-sma-divergence-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__ta-wpr-14-bands-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__timeframe-main-period-self-adaptive-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__udt-method-calls-sibling-cumulative-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__udt-method-default-param-kwargs-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__udt-method-drives-strategy-entry-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__udt-method-extra-primitive-args-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__udt-method-feeds-strategy-exit-prices-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__udt-method-in-for-loop-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__udt-method-in-if-else-branch-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__udt-method-in-switch-arms-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__udt-method-in-while-loop-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__udt-method-mutating-self-ref-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__udt-method-on-array-element-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__udt-method-reads-strategy-state-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__udt-method-receives-ta-series-param-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__udt-method-scalar-return-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__udt-method-tuple-return-destructure-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__udt-method-udt-return-from-func-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__udt-method-uses-history-globals-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__udt-method-uses-math-funcs-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__udt-method-uses-na-nz-fixnan-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__udt-method-var-instance-streak-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__udt-method-windowed-method-chain-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__udt-regime-stack-stress-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__vwap-bands-breakout-1sigma-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/gate-corpus/ok/validation__vwap-bands-mean-reversion-2sigma-01.pine +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/golden/matrix_eigen_pca.cpp +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_analyzer.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_analyzer_matrix_inference.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_analyzer_ta_return_types.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_calc_on_order_fills_codegen.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_codegen_audit_fixes.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_codegen_determinism.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_codegen_drawing_data.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_codegen_drawing_handles.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_codegen_fallthrough_guards.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_codegen_golden.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_codegen_input_getters.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_codegen_matrix_typed.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_codegen_new.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_codegen_string_escape.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_codegen_validation_fixes.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_compile_corpus.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_compile_smoke.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_errors.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_extract_inputs.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_glue_smoke.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_import_all.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_input_time_int64.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_int64_reassign_promotion.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_int64_time_storage.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_lexer.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_official_surface.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_parser.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_security_math_reducer.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_security_ohlc_hist_is_complete.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_security_tf_literal.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_signatures.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_support_checker.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_support_checker_chart_visible_bar_time.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_support_checker_color_cast.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_support_checker_const_namespaces.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_support_checker_dividends_earnings.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_support_checker_footprint.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_support_checker_input_color.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_support_checker_input_source.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_support_checker_matrix.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_support_checker_security_adjustment.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_support_checker_syminfo_gap_fields.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_support_checker_timeframe_from_seconds.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_support_checker_varip.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_support_checker_volume_row.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_symbols.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_ta_official_surface.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_transpile_division.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_transpile_enum_order.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_transpile_pf_trace.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_transpile_tr_handle_na.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_transpiler_matrix_kwargs.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_typespec_matrix.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_udt_drawing_field_cleanup.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_udt_lvalue_alias.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_unsupported_reporting.py +0 -0
- {pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/tests/test_vwap_tuple_unpack.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pineforge-codegen
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.0
|
|
4
4
|
Summary: PineScript v6 to C++ transpiler that targets the pineforge-engine runtime.
|
|
5
5
|
Project-URL: Homepage, https://github.com/pineforge-4pass/pineforge-codegen-oss
|
|
6
6
|
Project-URL: Issues, https://github.com/pineforge-4pass/pineforge-codegen-oss/issues
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.10.0
|
|
@@ -1262,6 +1262,11 @@ class CodeGen(CallVisitor, ExprVisitor, StmtVisitor, TopLevelEmitter, SecurityEm
|
|
|
1262
1262
|
# First, find all variables that are reassigned anywhere in the AST.
|
|
1263
1263
|
# These cannot be inlined as constants since their value changes at runtime.
|
|
1264
1264
|
reassigned = self._find_reassigned_vars()
|
|
1265
|
+
# Register never-reassigned ``var``/``varip`` scalars with a stable
|
|
1266
|
+
# init FIRST — a later derived var (or a UDF body) may reference such a
|
|
1267
|
+
# scalar as a stable length component, so it must be classified stable
|
|
1268
|
+
# before those exprs are evaluated below.
|
|
1269
|
+
self._collect_stable_var_scalars(reassigned)
|
|
1265
1270
|
for stmt in self.ctx.ast.body:
|
|
1266
1271
|
if isinstance(stmt, VarDecl) and stmt.name not in reassigned:
|
|
1267
1272
|
self._collect_known_var(stmt)
|
|
@@ -1274,6 +1279,48 @@ class CodeGen(CallVisitor, ExprVisitor, StmtVisitor, TopLevelEmitter, SecurityEm
|
|
|
1274
1279
|
# dependent reassignments are left untracked (rejected by the guard).
|
|
1275
1280
|
self._collect_reassigned_stable_scalars(reassigned)
|
|
1276
1281
|
|
|
1282
|
+
def _collect_stable_var_scalars(self, reassigned: set[str]) -> None:
|
|
1283
|
+
"""Track top-level ``var``/``varip`` scalars declared exactly once (never
|
|
1284
|
+
reassigned) from a stable init expression.
|
|
1285
|
+
|
|
1286
|
+
A ``var`` scalar's one-shot initializer runs once and the value never
|
|
1287
|
+
changes across bars, so a never-reassigned ``var`` over a stable init
|
|
1288
|
+
(``var int _tfSec = timeframe.in_seconds()``) is a bar-invariant scalar —
|
|
1289
|
+
safe to embed in a TA ctor runtime-reset expression. Recording it in
|
|
1290
|
+
``_derived_input_expr`` + ``_stable_runtime_vars`` lets the reset path
|
|
1291
|
+
expand the name and lets ``_expr_is_stable`` classify it (the
|
|
1292
|
+
``_stable_runtime_vars`` check precedes the ``_var_names`` rejection).
|
|
1293
|
+
|
|
1294
|
+
A ``var`` that is reassigned anywhere (``:=`` in ``reassigned``), is a
|
|
1295
|
+
series var, or is initialized from a non-stable value stays untracked —
|
|
1296
|
+
so a TA length fed by genuinely-mutable persistent state is still
|
|
1297
|
+
rejected by the constructor guard. Names are NOT folded into
|
|
1298
|
+
``_known_vars`` (no use-site inlining): only the length-analysis path is
|
|
1299
|
+
affected, and the ``var`` member still emits and initializes normally.
|
|
1300
|
+
"""
|
|
1301
|
+
for stmt in (self.ctx.ast.body or []):
|
|
1302
|
+
if not isinstance(stmt, VarDecl):
|
|
1303
|
+
continue
|
|
1304
|
+
if not (stmt.is_var or stmt.is_varip):
|
|
1305
|
+
continue
|
|
1306
|
+
if stmt.name in reassigned:
|
|
1307
|
+
continue
|
|
1308
|
+
if stmt.name in self.ctx.series_vars:
|
|
1309
|
+
continue
|
|
1310
|
+
if stmt.value is None or not self._expr_is_stable(stmt.value):
|
|
1311
|
+
continue
|
|
1312
|
+
expr_str = self._arith_expr_to_str(stmt.value)
|
|
1313
|
+
if expr_str is None:
|
|
1314
|
+
continue
|
|
1315
|
+
self._derived_input_expr[stmt.name] = expr_str
|
|
1316
|
+
self._stable_runtime_vars.add(stmt.name)
|
|
1317
|
+
# Mark input-backed iff the init references an input, so the reset
|
|
1318
|
+
# emits override-aware get_input_*() reads for it.
|
|
1319
|
+
import re as _re
|
|
1320
|
+
toks = set(_re.findall(r"[A-Za-z_][A-Za-z_0-9]*", expr_str))
|
|
1321
|
+
if any(t in self._input_backed_vars for t in toks):
|
|
1322
|
+
self._input_backed_vars.add(stmt.name)
|
|
1323
|
+
|
|
1277
1324
|
def _collect_reassigned_stable_scalars(self, reassigned: set[str]) -> None:
|
|
1278
1325
|
"""Track class-scope scalars that are reassigned but only along stable
|
|
1279
1326
|
if/elif paths (see ``test_stable_reassigned_class_scope_length``).
|
|
@@ -1438,7 +1485,117 @@ class CodeGen(CallVisitor, ExprVisitor, StmtVisitor, TopLevelEmitter, SecurityEm
|
|
|
1438
1485
|
"ismonthly", "isdwm", "isseconds", "in_seconds", "isticks",
|
|
1439
1486
|
})
|
|
1440
1487
|
|
|
1441
|
-
|
|
1488
|
+
# Depth ceiling for inlining nested single-expression user functions while
|
|
1489
|
+
# classifying a TA length's stability. Pine forbids recursion, so any real
|
|
1490
|
+
# chain is shallow; the cap is a backstop against pathological input and is
|
|
1491
|
+
# enforced together with a name-stack cycle guard.
|
|
1492
|
+
_UDF_INLINE_MAX_DEPTH = 16
|
|
1493
|
+
|
|
1494
|
+
def _get_udf_def(self, name: str):
|
|
1495
|
+
"""Return the top-level single-name ``FuncDef`` for ``name`` (or None).
|
|
1496
|
+
|
|
1497
|
+
Built lazily and cached. UDT ``MethodDef``s are intentionally excluded —
|
|
1498
|
+
only a free function can appear as a bare-name TA length call.
|
|
1499
|
+
"""
|
|
1500
|
+
cache = getattr(self, "_udf_def_cache", None)
|
|
1501
|
+
if cache is None:
|
|
1502
|
+
cache = {}
|
|
1503
|
+
for stmt in (self.ctx.ast.body or []):
|
|
1504
|
+
if isinstance(stmt, FuncDef):
|
|
1505
|
+
# Last definition wins; a name map is all the length path needs.
|
|
1506
|
+
cache[stmt.name] = stmt
|
|
1507
|
+
self._udf_def_cache = cache
|
|
1508
|
+
return cache.get(name)
|
|
1509
|
+
|
|
1510
|
+
def _inline_single_expr_udf(self, node, _udf_stack: frozenset = frozenset(),
|
|
1511
|
+
_depth: int = 0):
|
|
1512
|
+
"""If ``node`` is a call to a user-defined SINGLE-EXPRESSION function,
|
|
1513
|
+
return its body expression with each parameter substituted by the
|
|
1514
|
+
corresponding call-argument node. Returns None when the call is not such
|
|
1515
|
+
a function, the arity/kwargs do not match, the body is not a single
|
|
1516
|
+
expression, the body contains a shape we do not clone, or the call would
|
|
1517
|
+
recurse (cycle / depth-limit).
|
|
1518
|
+
|
|
1519
|
+
Purely structural: it does NOT judge stability (the caller does, via
|
|
1520
|
+
``_expr_is_stable`` on the returned node). The conservative None keeps
|
|
1521
|
+
the TA-ctor guard intact.
|
|
1522
|
+
"""
|
|
1523
|
+
if not isinstance(node, FuncCall):
|
|
1524
|
+
return None
|
|
1525
|
+
func_name, namespace = self._resolve_callee(node.callee)
|
|
1526
|
+
if namespace is not None or func_name is None:
|
|
1527
|
+
return None
|
|
1528
|
+
if func_name in _udf_stack or _depth >= self._UDF_INLINE_MAX_DEPTH:
|
|
1529
|
+
return None
|
|
1530
|
+
fdef = self._get_udf_def(func_name)
|
|
1531
|
+
if fdef is None:
|
|
1532
|
+
return None
|
|
1533
|
+
# A body that is exactly ONE expression statement is inlinable, whether
|
|
1534
|
+
# written inline after ``=>`` (``is_single_expr=True``) or as a one-line
|
|
1535
|
+
# indented block (``f(x) =>`` then a single indented expr, which the
|
|
1536
|
+
# parser records as ``is_single_expr=False`` with a one-ExprStmt body —
|
|
1537
|
+
# the gonzowiththewind-sisyphus ``f_bars`` shape). A multi-statement
|
|
1538
|
+
# body (len != 1, or a non-ExprStmt) is conservatively refused.
|
|
1539
|
+
body = fdef.body
|
|
1540
|
+
if not body or len(body) != 1 or not isinstance(body[0], ExprStmt):
|
|
1541
|
+
return None
|
|
1542
|
+
# Require a plain positional call: one arg per param, no kwargs, no
|
|
1543
|
+
# default-parameter fill-in — anything else is conservatively refused.
|
|
1544
|
+
if node.kwargs or len(node.args) != len(fdef.params):
|
|
1545
|
+
return None
|
|
1546
|
+
subst = dict(zip(fdef.params, node.args))
|
|
1547
|
+
return self._subst_params(body[0].expr, subst)
|
|
1548
|
+
|
|
1549
|
+
def _subst_params(self, node, subst: dict):
|
|
1550
|
+
"""Return a copy of ``node`` with every ``Identifier`` whose name is a
|
|
1551
|
+
key in ``subst`` replaced by the mapped argument node. Returns None for
|
|
1552
|
+
any node outside the small arithmetic/call grammar we fold (an
|
|
1553
|
+
unrecognised construct — e.g. a history ``Subscript`` — conservatively
|
|
1554
|
+
aborts the inline). ``dataclasses.replace`` preserves ``loc``/
|
|
1555
|
+
``annotations`` so diagnostics still point at real source spans."""
|
|
1556
|
+
import dataclasses as _dc
|
|
1557
|
+
if isinstance(node, (NumberLiteral, StringLiteral, BoolLiteral, NaLiteral)):
|
|
1558
|
+
return node
|
|
1559
|
+
if isinstance(node, Identifier):
|
|
1560
|
+
return subst.get(node.name, node)
|
|
1561
|
+
if isinstance(node, MemberAccess):
|
|
1562
|
+
obj = self._subst_params(node.object, subst)
|
|
1563
|
+
if obj is None:
|
|
1564
|
+
return None
|
|
1565
|
+
return _dc.replace(node, object=obj)
|
|
1566
|
+
if isinstance(node, Ternary):
|
|
1567
|
+
c = self._subst_params(node.condition, subst)
|
|
1568
|
+
t = self._subst_params(node.true_val, subst)
|
|
1569
|
+
f = self._subst_params(node.false_val, subst)
|
|
1570
|
+
if c is None or t is None or f is None:
|
|
1571
|
+
return None
|
|
1572
|
+
return _dc.replace(node, condition=c, true_val=t, false_val=f)
|
|
1573
|
+
if isinstance(node, BinOp):
|
|
1574
|
+
l = self._subst_params(node.left, subst)
|
|
1575
|
+
r = self._subst_params(node.right, subst)
|
|
1576
|
+
if l is None or r is None:
|
|
1577
|
+
return None
|
|
1578
|
+
return _dc.replace(node, left=l, right=r)
|
|
1579
|
+
if isinstance(node, UnaryOp):
|
|
1580
|
+
o = self._subst_params(node.operand, subst)
|
|
1581
|
+
if o is None:
|
|
1582
|
+
return None
|
|
1583
|
+
return _dc.replace(node, operand=o)
|
|
1584
|
+
if isinstance(node, FuncCall):
|
|
1585
|
+
if node.kwargs:
|
|
1586
|
+
return None
|
|
1587
|
+
new_args = []
|
|
1588
|
+
for a in node.args:
|
|
1589
|
+
sa = self._subst_params(a, subst)
|
|
1590
|
+
if sa is None:
|
|
1591
|
+
return None
|
|
1592
|
+
new_args.append(sa)
|
|
1593
|
+
return _dc.replace(node, args=new_args)
|
|
1594
|
+
# Subscript (history read) and anything else: not a stable-length shape.
|
|
1595
|
+
return None
|
|
1596
|
+
|
|
1597
|
+
def _expr_is_stable(self, node, _udf_stack: frozenset = frozenset(),
|
|
1598
|
+
_depth: int = 0) -> bool:
|
|
1442
1599
|
"""True iff ``node``'s value is a bar-invariant scalar.
|
|
1443
1600
|
|
|
1444
1601
|
A stable expression depends only on: literals, ``input.*`` values,
|
|
@@ -1496,13 +1653,14 @@ class CodeGen(CallVisitor, ExprVisitor, StmtVisitor, TopLevelEmitter, SecurityEm
|
|
|
1496
1653
|
# History read (``close[1]``) or indexed access — per-bar.
|
|
1497
1654
|
return False
|
|
1498
1655
|
if isinstance(node, Ternary):
|
|
1499
|
-
return (self._expr_is_stable(node.condition)
|
|
1500
|
-
and self._expr_is_stable(node.true_val)
|
|
1501
|
-
and self._expr_is_stable(node.false_val))
|
|
1656
|
+
return (self._expr_is_stable(node.condition, _udf_stack, _depth)
|
|
1657
|
+
and self._expr_is_stable(node.true_val, _udf_stack, _depth)
|
|
1658
|
+
and self._expr_is_stable(node.false_val, _udf_stack, _depth))
|
|
1502
1659
|
if isinstance(node, BinOp):
|
|
1503
|
-
return self._expr_is_stable(node.left
|
|
1660
|
+
return (self._expr_is_stable(node.left, _udf_stack, _depth)
|
|
1661
|
+
and self._expr_is_stable(node.right, _udf_stack, _depth))
|
|
1504
1662
|
if isinstance(node, UnaryOp):
|
|
1505
|
-
return self._expr_is_stable(node.operand)
|
|
1663
|
+
return self._expr_is_stable(node.operand, _udf_stack, _depth)
|
|
1506
1664
|
if isinstance(node, FuncCall):
|
|
1507
1665
|
func_name, namespace = self._resolve_callee(node.callee)
|
|
1508
1666
|
if namespace == "ta":
|
|
@@ -1510,20 +1668,40 @@ class CodeGen(CallVisitor, ExprVisitor, StmtVisitor, TopLevelEmitter, SecurityEm
|
|
|
1510
1668
|
if namespace == "math":
|
|
1511
1669
|
if func_name not in self._MATH_STABLE_MEMBERS:
|
|
1512
1670
|
return False
|
|
1513
|
-
return all(self._expr_is_stable(a
|
|
1671
|
+
return all(self._expr_is_stable(a, _udf_stack, _depth)
|
|
1672
|
+
for a in node.args)
|
|
1514
1673
|
if namespace == "timeframe":
|
|
1515
1674
|
# ``timeframe.in_seconds()`` (and any other function-form
|
|
1516
1675
|
# timeframe member) is a stable per-run scalar — it reflects
|
|
1517
1676
|
# the script's resolution, not a per-bar value.
|
|
1518
1677
|
if func_name not in self._TF_STABLE_MEMBERS:
|
|
1519
1678
|
return False
|
|
1520
|
-
return all(self._expr_is_stable(a
|
|
1679
|
+
return all(self._expr_is_stable(a, _udf_stack, _depth)
|
|
1680
|
+
for a in node.args)
|
|
1521
1681
|
if namespace == "input":
|
|
1522
1682
|
return True
|
|
1523
1683
|
if namespace is None and func_name in ("int", "float", "bool", "string"):
|
|
1524
|
-
return all(self._expr_is_stable(a
|
|
1525
|
-
|
|
1526
|
-
#
|
|
1684
|
+
return all(self._expr_is_stable(a, _udf_stack, _depth)
|
|
1685
|
+
for a in node.args)
|
|
1686
|
+
# A user-defined single-expression function is stable iff every
|
|
1687
|
+
# argument is stable AND its body (with the params bound to those
|
|
1688
|
+
# args) is stable — i.e. the body references only stable scalars
|
|
1689
|
+
# (inputs / consts / timeframe.* / math.* / never-reassigned var
|
|
1690
|
+
# scalars) and no series / strategy state / ta.* results. Inlining
|
|
1691
|
+
# the body (params substituted by the arg nodes) lets the ordinary
|
|
1692
|
+
# classifier decide; the name-stack + depth guard refuses recursion
|
|
1693
|
+
# so a cyclic / malformed UDF is rejected, not looped forever.
|
|
1694
|
+
if namespace is None and func_name is not None:
|
|
1695
|
+
inlined = self._inline_single_expr_udf(node, _udf_stack, _depth)
|
|
1696
|
+
if inlined is not None:
|
|
1697
|
+
if not all(self._expr_is_stable(a, _udf_stack, _depth)
|
|
1698
|
+
for a in node.args):
|
|
1699
|
+
return False
|
|
1700
|
+
return self._expr_is_stable(
|
|
1701
|
+
inlined, _udf_stack | {func_name}, _depth + 1)
|
|
1702
|
+
# Any other call (multi-statement user functions, str.*, array.*,
|
|
1703
|
+
# ...) — series by default; the conservative answer keeps the guard
|
|
1704
|
+
# honest.
|
|
1527
1705
|
return False
|
|
1528
1706
|
return False
|
|
1529
1707
|
|
|
@@ -1536,22 +1714,28 @@ class CodeGen(CallVisitor, ExprVisitor, StmtVisitor, TopLevelEmitter, SecurityEm
|
|
|
1536
1714
|
# re-parsed and lowered through the expression visitor).
|
|
1537
1715
|
_ATOMIC_ARITH_NODES = (NumberLiteral, Identifier, MemberAccess, FuncCall)
|
|
1538
1716
|
|
|
1539
|
-
def _arith_operand_to_str(self, node
|
|
1717
|
+
def _arith_operand_to_str(self, node, _udf_stack: frozenset = frozenset(),
|
|
1718
|
+
_depth: int = 0) -> str | None:
|
|
1540
1719
|
"""Serialize ``node`` for use as an operand: parenthesize it unless its
|
|
1541
1720
|
serialized form is already self-delimiting, so grouping survives a
|
|
1542
1721
|
round-trip through the parser."""
|
|
1543
|
-
s = self._arith_expr_to_str(node)
|
|
1722
|
+
s = self._arith_expr_to_str(node, _udf_stack, _depth)
|
|
1544
1723
|
if s is None:
|
|
1545
1724
|
return None
|
|
1546
1725
|
if isinstance(node, self._ATOMIC_ARITH_NODES):
|
|
1547
1726
|
return s
|
|
1548
1727
|
return f"({s})"
|
|
1549
1728
|
|
|
1550
|
-
def _arith_expr_to_str(self, node
|
|
1729
|
+
def _arith_expr_to_str(self, node, _udf_stack: frozenset = frozenset(),
|
|
1730
|
+
_depth: int = 0) -> str | None:
|
|
1551
1731
|
"""Render a numeric arithmetic-over-identifiers expression to a string
|
|
1552
1732
|
that re-parses to the SAME tree (grouping preserved via
|
|
1553
1733
|
``_arith_operand_to_str``). Returns None for any node shape we don't
|
|
1554
1734
|
fold (series subscripts, etc.) so the caller leaves the var untracked.
|
|
1735
|
+
|
|
1736
|
+
``_udf_stack``/``_depth`` guard the single-expression-UDF inlining below
|
|
1737
|
+
against recursion cycles (Pine forbids recursion, but a malformed source
|
|
1738
|
+
must be refused, not looped forever).
|
|
1555
1739
|
"""
|
|
1556
1740
|
if isinstance(node, NumberLiteral):
|
|
1557
1741
|
v = node.value
|
|
@@ -1563,30 +1747,44 @@ class CodeGen(CallVisitor, ExprVisitor, StmtVisitor, TopLevelEmitter, SecurityEm
|
|
|
1563
1747
|
if isinstance(node, MemberAccess) and isinstance(node.object, Identifier):
|
|
1564
1748
|
return f"{node.object.name}.{node.member}"
|
|
1565
1749
|
if isinstance(node, BinOp):
|
|
1566
|
-
l = self._arith_operand_to_str(node.left)
|
|
1567
|
-
r = self._arith_operand_to_str(node.right)
|
|
1750
|
+
l = self._arith_operand_to_str(node.left, _udf_stack, _depth)
|
|
1751
|
+
r = self._arith_operand_to_str(node.right, _udf_stack, _depth)
|
|
1568
1752
|
if l is None or r is None:
|
|
1569
1753
|
return None
|
|
1570
1754
|
return f"{l} {node.op} {r}"
|
|
1571
1755
|
if isinstance(node, UnaryOp):
|
|
1572
|
-
o = self._arith_operand_to_str(node.operand)
|
|
1756
|
+
o = self._arith_operand_to_str(node.operand, _udf_stack, _depth)
|
|
1573
1757
|
if o is None:
|
|
1574
1758
|
return None
|
|
1575
1759
|
return f"{node.op}{o}"
|
|
1576
1760
|
if isinstance(node, Ternary):
|
|
1577
|
-
c = self._arith_operand_to_str(node.condition)
|
|
1578
|
-
t = self._arith_operand_to_str(node.true_val)
|
|
1579
|
-
f = self._arith_operand_to_str(node.false_val)
|
|
1761
|
+
c = self._arith_operand_to_str(node.condition, _udf_stack, _depth)
|
|
1762
|
+
t = self._arith_operand_to_str(node.true_val, _udf_stack, _depth)
|
|
1763
|
+
f = self._arith_operand_to_str(node.false_val, _udf_stack, _depth)
|
|
1580
1764
|
if c is None or t is None or f is None:
|
|
1581
1765
|
return None
|
|
1582
1766
|
return f"{c} ? {t} : {f}"
|
|
1583
1767
|
if isinstance(node, FuncCall):
|
|
1584
|
-
|
|
1768
|
+
# A bare-name call to a single-expression user function has no C++
|
|
1769
|
+
# counterpart at class scope — inline its body (params substituted
|
|
1770
|
+
# by the arg expressions) so the rendered string is pure
|
|
1771
|
+
# math/timeframe/input arithmetic the ctor-reset path can expand.
|
|
1772
|
+
# Namespaced calls (math.*/timeframe.*/int(...)) fall through to the
|
|
1773
|
+
# ordinary ``callee(args)`` rendering below. The stack/depth guard
|
|
1774
|
+
# refuses a recursive UDF (returns None -> caller leaves it untracked
|
|
1775
|
+
# -> the ctor guard rejects it loudly) instead of recursing forever.
|
|
1776
|
+
fn, ns = self._resolve_callee(node.callee)
|
|
1777
|
+
if ns is None and fn is not None and self._get_udf_def(fn) is not None:
|
|
1778
|
+
inlined = self._inline_single_expr_udf(node, _udf_stack, _depth)
|
|
1779
|
+
if inlined is None:
|
|
1780
|
+
return None
|
|
1781
|
+
return self._arith_expr_to_str(inlined, _udf_stack | {fn}, _depth + 1)
|
|
1782
|
+
callee = self._arith_expr_to_str(node.callee, _udf_stack, _depth)
|
|
1585
1783
|
if callee is None:
|
|
1586
1784
|
return None
|
|
1587
1785
|
parts = []
|
|
1588
1786
|
for a in node.args:
|
|
1589
|
-
s = self._arith_expr_to_str(a)
|
|
1787
|
+
s = self._arith_expr_to_str(a, _udf_stack, _depth)
|
|
1590
1788
|
if s is None:
|
|
1591
1789
|
return None
|
|
1592
1790
|
parts.append(s)
|
|
@@ -1216,6 +1216,11 @@ class TopLevelEmitter:
|
|
|
1216
1216
|
if (is_drawing or is_udt) and isinstance(init_ast, NaLiteral):
|
|
1217
1217
|
continue
|
|
1218
1218
|
init_cpp = self._visit_expr(init_ast)
|
|
1219
|
+
# A bare-``na`` initializer for an int/int64_t/bool ``var`` member
|
|
1220
|
+
# must be typed (``na<int>()``), mirroring the class-scope ctor
|
|
1221
|
+
# init (``_typed_na_init`` at _emit_constructor); a raw ``na<double>()``
|
|
1222
|
+
# NaN stored into an int member is UB and defeats is_na<T>().
|
|
1223
|
+
init_cpp = self._typed_na_init(init_cpp, name, ptype)
|
|
1219
1224
|
init_lines.append(f" {target} = {init_cpp};")
|
|
1220
1225
|
if not init_lines:
|
|
1221
1226
|
return
|
|
@@ -140,42 +140,91 @@ class SecurityEmitter:
|
|
|
140
140
|
: inputTf`` must be expanded to their source expression with direct
|
|
141
141
|
``get_input_*`` reads. Emitting the member name would register with its
|
|
142
142
|
default-constructed value (usually an empty string).
|
|
143
|
+
|
|
144
|
+
Delegates to :meth:`_substitute_tf_input_reads`, which rewrites the
|
|
145
|
+
input-derived *leaves* of the expression tree — including leaves buried
|
|
146
|
+
inside a ternary CONDITION or any BinOp / UnaryOp / FuncCall — and then
|
|
147
|
+
renders the substituted tree through the normal expression visitor.
|
|
143
148
|
"""
|
|
144
149
|
if node is None:
|
|
145
150
|
return None
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
151
|
+
substituted = self._substitute_tf_input_reads(node, resolving or set())
|
|
152
|
+
return self._visit_expr(substituted)
|
|
153
|
+
|
|
154
|
+
def _substitute_tf_input_reads(self, node, resolving: set[str]):
|
|
155
|
+
"""Return ``node`` with input-derived leaves rewritten to expressions
|
|
156
|
+
that are valid at security-registration time (before ``on_bar()``
|
|
157
|
+
assigns members from their inputs):
|
|
158
|
+
|
|
159
|
+
* an input-backed var -> its ``input.*()`` source call (``get_input_*``);
|
|
160
|
+
* a ``timeframe.period`` alias var -> ``timeframe.period`` (``script_tf_``);
|
|
161
|
+
* a known compile-time string var -> that string literal;
|
|
162
|
+
* a global alias -> its defining expression, expanded recursively.
|
|
163
|
+
|
|
164
|
+
The walk descends through Ternary / BinOp / UnaryOp / FuncCall /
|
|
165
|
+
Subscript, so an input-backed identifier nested inside e.g. a ternary
|
|
166
|
+
condition (``mode == "15" ? "240" : "60"``) resolves to its input read
|
|
167
|
+
instead of the uninitialised member. A subtree containing no
|
|
168
|
+
input-derived leaf is returned unchanged (same object) so unaffected
|
|
169
|
+
timeframe expressions render byte-identically to before the fix.
|
|
170
|
+
MemberAccess and literals are left verbatim: ``timeframe.period`` is
|
|
171
|
+
already lowered to ``script_tf_`` by the expression visitor.
|
|
172
|
+
"""
|
|
173
|
+
if not isinstance(node, ASTNode):
|
|
174
|
+
return node
|
|
149
175
|
if isinstance(node, Identifier):
|
|
150
176
|
name = node.name
|
|
151
177
|
if name in self._timeframe_period_vars:
|
|
152
|
-
return "
|
|
178
|
+
return MemberAccess(object=Identifier(name="timeframe"), member="period")
|
|
153
179
|
if name in self._input_backed_vars and name in self._input_var_to_call:
|
|
154
|
-
return self.
|
|
180
|
+
return self._input_var_to_call[name]
|
|
155
181
|
if (name in self._known_vars and name not in self._input_backed_vars
|
|
156
182
|
and isinstance(self._known_vars[name], str)):
|
|
157
|
-
return
|
|
183
|
+
return StringLiteral(value=self._known_vars[name])
|
|
158
184
|
global_expr_map = getattr(self.ctx, "global_expr_map", {}) or {}
|
|
159
185
|
if name in global_expr_map and name not in resolving:
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
return out
|
|
164
|
-
return self._visit_expr(node)
|
|
165
|
-
if (
|
|
166
|
-
isinstance(node, MemberAccess)
|
|
167
|
-
and isinstance(node.object, Identifier)
|
|
168
|
-
and node.object.name == "timeframe"
|
|
169
|
-
and node.member == "period"
|
|
170
|
-
):
|
|
171
|
-
return "script_tf_"
|
|
186
|
+
return self._substitute_tf_input_reads(
|
|
187
|
+
global_expr_map[name], resolving | {name})
|
|
188
|
+
return node
|
|
172
189
|
if isinstance(node, Ternary):
|
|
173
|
-
cond = self.
|
|
174
|
-
tv = self.
|
|
175
|
-
fv = self.
|
|
176
|
-
if cond is
|
|
177
|
-
return
|
|
178
|
-
|
|
190
|
+
cond = self._substitute_tf_input_reads(node.condition, resolving)
|
|
191
|
+
tv = self._substitute_tf_input_reads(node.true_val, resolving)
|
|
192
|
+
fv = self._substitute_tf_input_reads(node.false_val, resolving)
|
|
193
|
+
if cond is node.condition and tv is node.true_val and fv is node.false_val:
|
|
194
|
+
return node
|
|
195
|
+
return Ternary(condition=cond, true_val=tv, false_val=fv)
|
|
196
|
+
if isinstance(node, BinOp):
|
|
197
|
+
left = self._substitute_tf_input_reads(node.left, resolving)
|
|
198
|
+
right = self._substitute_tf_input_reads(node.right, resolving)
|
|
199
|
+
if left is node.left and right is node.right:
|
|
200
|
+
return node
|
|
201
|
+
return BinOp(left=left, op=node.op, right=right)
|
|
202
|
+
if isinstance(node, UnaryOp):
|
|
203
|
+
operand = self._substitute_tf_input_reads(node.operand, resolving)
|
|
204
|
+
if operand is node.operand:
|
|
205
|
+
return node
|
|
206
|
+
return UnaryOp(op=node.op, operand=operand)
|
|
207
|
+
if isinstance(node, FuncCall):
|
|
208
|
+
new_args = [self._substitute_tf_input_reads(a, resolving) for a in node.args]
|
|
209
|
+
new_kwargs = {
|
|
210
|
+
k: (self._substitute_tf_input_reads(v, resolving)
|
|
211
|
+
if isinstance(v, ASTNode) else v)
|
|
212
|
+
for k, v in node.kwargs.items()
|
|
213
|
+
}
|
|
214
|
+
unchanged = (
|
|
215
|
+
all(a is b for a, b in zip(new_args, node.args))
|
|
216
|
+
and all(new_kwargs[k] is node.kwargs[k] for k in node.kwargs)
|
|
217
|
+
)
|
|
218
|
+
if unchanged:
|
|
219
|
+
return node
|
|
220
|
+
return FuncCall(callee=node.callee, args=new_args, kwargs=new_kwargs)
|
|
221
|
+
if isinstance(node, Subscript):
|
|
222
|
+
obj = self._substitute_tf_input_reads(node.object, resolving)
|
|
223
|
+
idx = self._substitute_tf_input_reads(node.index, resolving)
|
|
224
|
+
if obj is node.object and idx is node.index:
|
|
225
|
+
return node
|
|
226
|
+
return Subscript(object=obj, index=idx)
|
|
227
|
+
return node
|
|
179
228
|
|
|
180
229
|
def _resolve_param_tf_from_callsites(self, func_name: str, param_name: str):
|
|
181
230
|
"""For a ``request.security`` whose tf is function parameter ``param_name``
|
|
@@ -2226,7 +2275,10 @@ class SecurityEmitter:
|
|
|
2226
2275
|
op = cpp_ops.get(expr_node.op, expr_node.op)
|
|
2227
2276
|
if expr_node.op == "%":
|
|
2228
2277
|
return f"std::fmod((double)({left}), (double)({right}))"
|
|
2229
|
-
|
|
2278
|
+
# KI-71: honour Pine's falsy-on-na relational rule inside
|
|
2279
|
+
# request.security expressions too (this builder is a second
|
|
2280
|
+
# relational emission site independent of _visit_binop).
|
|
2281
|
+
return self._lower_relational(op, expr_node.left, expr_node.right, left, right)
|
|
2230
2282
|
|
|
2231
2283
|
if isinstance(expr_node, UnaryOp):
|
|
2232
2284
|
operand = self._build_security_expr(
|
|
@@ -552,6 +552,59 @@ class TypeInferer:
|
|
|
552
552
|
return True
|
|
553
553
|
return name in self._int64_reassign_targets()
|
|
554
554
|
|
|
555
|
+
def _na_reassign_cpp_type(self, name: str) -> str | None:
|
|
556
|
+
"""Declared scalar C++ type of a ``:=`` reassignment target ``name``, so a
|
|
557
|
+
bare-``na`` RHS (``x := na``) can be spelled ``na<T>()`` matching the
|
|
558
|
+
member/local type instead of the default ``na<double>()``.
|
|
559
|
+
|
|
560
|
+
Assigning a double quiet-NaN into an ``int``/``int64_t``/``bool`` member is
|
|
561
|
+
undefined behaviour (NaN->int is unspecified; on ARM64 it saturates to 0,
|
|
562
|
+
which is not the ``na<T>()`` sentinel) and defeats ``is_na<T>()``. Mirrors
|
|
563
|
+
the member-declaration type logic (``base._emit_class_members`` /
|
|
564
|
+
``_typed_na_init``): ``PINE_TYPE_TO_CPP`` plus the int->int64_t epoch
|
|
565
|
+
promotion. Returns ``None`` for collections / UDT / drawing handles and
|
|
566
|
+
for ``double`` (already the default lowering), so those paths are
|
|
567
|
+
unchanged.
|
|
568
|
+
"""
|
|
569
|
+
# Collections / UDT / drawing handles never take a scalar ``na<T>()``:
|
|
570
|
+
# leave them to the drawing-na / default lowering in _visit_rhs_value.
|
|
571
|
+
if (name in self._array_vars
|
|
572
|
+
or name in self._map_vars
|
|
573
|
+
or name in getattr(self, "_matrix_specs", {})
|
|
574
|
+
or name in self._udt_var_types):
|
|
575
|
+
return None
|
|
576
|
+
cpp_type: str | None = None
|
|
577
|
+
# 1. ``var`` member (class-scope OR function-local: both are recorded in
|
|
578
|
+
# ctx.var_members). This is the authoritative declaration source.
|
|
579
|
+
for vname, ptype, _init in self.ctx.var_members:
|
|
580
|
+
if vname == name:
|
|
581
|
+
cpp_type = PINE_TYPE_TO_CPP.get(ptype, "double")
|
|
582
|
+
break
|
|
583
|
+
# 2. Function-local plain (non-``var``) scalar: its declared type was
|
|
584
|
+
# remembered at the VarDecl (``_type_for_decl``).
|
|
585
|
+
if cpp_type is None:
|
|
586
|
+
cpp_type = getattr(self, "_current_func_local_types", {}).get(name)
|
|
587
|
+
# 3. Function parameter.
|
|
588
|
+
if cpp_type is None:
|
|
589
|
+
cpp_type = getattr(self, "_current_func_param_types", {}).get(name)
|
|
590
|
+
# 4. Global-scope non-``var`` class member.
|
|
591
|
+
if cpp_type is None:
|
|
592
|
+
for gname, gptype in self.ctx.global_var_decls:
|
|
593
|
+
if gname == name:
|
|
594
|
+
cpp_type = PINE_TYPE_TO_CPP.get(gptype, "double")
|
|
595
|
+
break
|
|
596
|
+
if cpp_type is None:
|
|
597
|
+
return None
|
|
598
|
+
# int -> int64_t promotion for epoch-ms builtins, mirroring the member
|
|
599
|
+
# declaration so the na sentinel width matches the storage width.
|
|
600
|
+
if cpp_type == "int" and self._is_int64_builtin_init(name):
|
|
601
|
+
cpp_type = "int64_t"
|
|
602
|
+
# Only the retypeable scalar types are meaningful; ``double`` already
|
|
603
|
+
# lowers to ``na<double>()`` and everything else is left untouched.
|
|
604
|
+
if cpp_type in ("int", "int64_t", "bool", "std::string"):
|
|
605
|
+
return cpp_type
|
|
606
|
+
return None
|
|
607
|
+
|
|
555
608
|
# ------------------------------------------------------------------
|
|
556
609
|
# BUG C: user-defined-UDT lvalue aliasing
|
|
557
610
|
# ------------------------------------------------------------------
|
{pineforge_codegen-0.9.0 → pineforge_codegen-0.10.0}/pineforge_codegen/codegen/visit_expr.py
RENAMED
|
@@ -166,6 +166,20 @@ _BUILTIN_NAMESPACE_NAMES: frozenset[str] = frozenset({
|
|
|
166
166
|
})
|
|
167
167
|
|
|
168
168
|
|
|
169
|
+
# KI-71: Pine relational comparisons (``==`` ``!=`` ``<`` ``>`` ``<=`` ``>=``)
|
|
170
|
+
# with an ``na`` operand evaluate *falsy*. Naive C++ relationals do not honour
|
|
171
|
+
# this for the engine's na sentinels, so these ops route through na-aware
|
|
172
|
+
# lowering when an operand can be na (see ``_visit_binop`` / ``_operand_na_kind``).
|
|
173
|
+
_RELATIONAL_OPS: frozenset[str] = frozenset({"==", "!=", "<", ">", "<=", ">="})
|
|
174
|
+
|
|
175
|
+
# C++ scalar types carrying a detectable ``na`` sentinel via ``is_na``:
|
|
176
|
+
# ``double`` -> NaN (IEEE), ``int``/``int64_t`` -> ``numeric_limits<T>::min()``.
|
|
177
|
+
# Only these route through the na-aware relational lowering — ``is_na`` has no
|
|
178
|
+
# overload for ``bool``/``std::string``/vector/UDT-value operands, and Pine's
|
|
179
|
+
# na-bool is engine-indistinguishable from ``false`` (na<bool>() == false).
|
|
180
|
+
_NA_SCALAR_CPP: frozenset[str] = frozenset({"int", "int64_t", "double"})
|
|
181
|
+
|
|
182
|
+
|
|
169
183
|
class ExprVisitor:
|
|
170
184
|
"""Expression-level visitor methods shared across the codegen.
|
|
171
185
|
|
|
@@ -760,6 +774,78 @@ class ExprVisitor:
|
|
|
760
774
|
return f'std::string("{node.member}")'
|
|
761
775
|
return f"{obj}.{node.member}"
|
|
762
776
|
|
|
777
|
+
def _operand_na_kind(self, node, cpp_type: str) -> str | None:
|
|
778
|
+
"""Classify a relational operand by the ``na`` sentinel it can carry.
|
|
779
|
+
|
|
780
|
+
Returns:
|
|
781
|
+
|
|
782
|
+
* ``"int"`` — an ``int``/``int64_t`` expression that can hold the
|
|
783
|
+
``INT_MIN`` sentinel. Because that sentinel is a *finite* very-negative
|
|
784
|
+
integer (not NaN), naive C++ diverges from Pine's falsy-on-na rule for
|
|
785
|
+
EVERY relational — ordered (``<`` ``>`` ``<=`` ``>=``) and equality
|
|
786
|
+
(``==`` ``!=``) alike.
|
|
787
|
+
* ``"float"`` — a ``double`` expression that can hold NaN. IEEE already
|
|
788
|
+
yields ``false`` for ``==`` ``<`` ``>`` ``<=`` ``>=`` against NaN
|
|
789
|
+
(matching Pine's falsy), so the ONLY diverging float cell is ``!=``
|
|
790
|
+
(IEEE ``NaN != x`` is true; Pine is falsy).
|
|
791
|
+
* ``None`` — provably not na (numeric/bool literal, inlined
|
|
792
|
+
compile-time constant) or a non-scalar type with no ``is_na`` overload;
|
|
793
|
+
the naive emission is already correct.
|
|
794
|
+
"""
|
|
795
|
+
if cpp_type not in _NA_SCALAR_CPP:
|
|
796
|
+
return None
|
|
797
|
+
# Literals are never na.
|
|
798
|
+
if isinstance(node, (NumberLiteral, BoolLiteral)):
|
|
799
|
+
return None
|
|
800
|
+
# A bare ``na`` lowers to ``na<double>()`` — a real NaN, i.e. it IS na.
|
|
801
|
+
if self._is_na_expr(node):
|
|
802
|
+
return "float"
|
|
803
|
+
# Inlined compile-time constants (non-input known vars) never hold na.
|
|
804
|
+
if (isinstance(node, Identifier)
|
|
805
|
+
and node.name in self._known_vars
|
|
806
|
+
and node.name not in self._input_backed_vars):
|
|
807
|
+
return None
|
|
808
|
+
return "int" if cpp_type in ("int", "int64_t") else "float"
|
|
809
|
+
|
|
810
|
+
def _emit_na_relational(self, op: str, left: str, right: str) -> str:
|
|
811
|
+
"""Emit an na-aware relational: ``false`` when either operand is ``na``.
|
|
812
|
+
|
|
813
|
+
Mirrors the ``nz()`` lambda idiom (``visit_call``): each operand is
|
|
814
|
+
hoisted to a temporary so a stateful operand expression is evaluated
|
|
815
|
+
exactly once (no double-step), then compared only when neither side is
|
|
816
|
+
na. ``is_na`` resolves via the emitted ``using namespace pineforge;``
|
|
817
|
+
(``double`` -> ``isnan``; integral -> ``== numeric_limits<T>::min()``).
|
|
818
|
+
"""
|
|
819
|
+
return (f"([&]{{ auto _pna_l = ({left}); auto _pna_r = ({right}); "
|
|
820
|
+
f"return !is_na(_pna_l) && !is_na(_pna_r) && "
|
|
821
|
+
f"(_pna_l {op} _pna_r); }}())")
|
|
822
|
+
|
|
823
|
+
def _lower_relational(self, op: str, left_node, right_node,
|
|
824
|
+
left_cpp: str, right_cpp: str) -> str:
|
|
825
|
+
"""Lower a Pine relational to C++, applying KI-71 na-aware wrapping.
|
|
826
|
+
|
|
827
|
+
Shared by ``_visit_binop`` and the ``request.security`` expression
|
|
828
|
+
builder so EVERY relational emission site honours Pine's falsy-on-na
|
|
829
|
+
rule. Wraps only the diverging cells: any na-capable *integer* operand
|
|
830
|
+
(the INT_MIN sentinel poisons all six operators) or a ``!=`` with an
|
|
831
|
+
na-capable *float* operand (the sole IEEE-diverging float cell). Pure
|
|
832
|
+
``double`` ``==`` ``<`` ``>`` ``<=`` ``>=`` keep the naive emission —
|
|
833
|
+
IEEE is already falsy-on-NaN there, so wrapping would be a pure no-op.
|
|
834
|
+
Non-relational ``op`` (or non-scalar operands with no ``is_na``) fall
|
|
835
|
+
through to the naive ``(left op right)`` form unchanged.
|
|
836
|
+
"""
|
|
837
|
+
if op in _RELATIONAL_OPS:
|
|
838
|
+
lt = self._infer_type(left_node)
|
|
839
|
+
rt = self._infer_type(right_node)
|
|
840
|
+
if lt in _NA_SCALAR_CPP and rt in _NA_SCALAR_CPP:
|
|
841
|
+
lk = self._operand_na_kind(left_node, lt)
|
|
842
|
+
rk = self._operand_na_kind(right_node, rt)
|
|
843
|
+
int_na = "int" in (lk, rk)
|
|
844
|
+
float_na = "float" in (lk, rk)
|
|
845
|
+
if int_na or (op == "!=" and float_na):
|
|
846
|
+
return self._emit_na_relational(op, left_cpp, right_cpp)
|
|
847
|
+
return f"({left_cpp} {op} {right_cpp})"
|
|
848
|
+
|
|
763
849
|
def _visit_binop(self, node: BinOp) -> str:
|
|
764
850
|
left = self._visit_expr(node.left)
|
|
765
851
|
right = self._visit_expr(node.right)
|
|
@@ -786,7 +872,7 @@ class ExprVisitor:
|
|
|
786
872
|
# Ref: https://www.tradingview.com/pine-script-docs/concepts/operators/
|
|
787
873
|
if node.op == "/":
|
|
788
874
|
return f"((double)({left}) / (double)({right}))"
|
|
789
|
-
return
|
|
875
|
+
return self._lower_relational(op, node.left, node.right, left, right)
|
|
790
876
|
|
|
791
877
|
def _visit_unaryop(self, node: UnaryOp) -> str:
|
|
792
878
|
operand = self._visit_expr(node.operand)
|