Skip to content

feat(codegen): run named parser actions at committed positions - #287

Merged
tinovyatkin merged 13 commits into
mainfrom
issue-266-named-parser-actions
Aug 3, 2026
Merged

feat(codegen): run named parser actions at committed positions#287
tinovyatkin merged 13 commits into
mainfrom
issue-266-named-parser-actions

Conversation

@tinovyatkin

@tinovyatkin tinovyatkin commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Summary

  • map [[helper]] kind = "parser-action" calls to stable named typed-hook methods keyed by grammar action coordinates
  • allocate globally unique typed-hook method names after predicate/action suffixing without splitting repeated coordinates for one helper
  • execute non-embedded parser actions exactly once at their committed grammar positions across generated and interpreted paths
  • preserve nested-rule, repeated, left-recursive, recovery, and handled rule-init ordering while keeping speculative alternatives side-effect free
  • retain interpreted parser behavior in the committed fallback, including prediction modes and overrides, translated actions, legacy init-action replay, listeners, diagnostics, recursion limits, and recovery
  • honor indexed assume-* and hook action overrides before portable boolean lowering and propagate descendant EOF boundaries into parent contexts
  • derive parameterized action routing from grammar declarations, forward caller arguments into action hooks on both parser paths, and fail generation on unsupported argument expressions
  • scope fail-loud semantic misses across nested committed parses, prioritize sticky parser aborts, drain returned top-level misses, and report unrecovered bail errors without poisoning parser reuse
  • prevent adaptive retries from replaying effectful actions while keeping ANTLR-synthesized no-op actions eligible for adaptive routing
  • store prediction provenance once behind compact simulator-local IDs, verify hash-bucket collisions, and index provenance-aware ATN configs directly in O(1)
  • bump the generated-code API to revision 3, retain revisions 1 and 2, regenerate checked-in recognizers, and document the compatibility change
  • add strict semantic-manifest, generated/interpreted parity, recovery, left-recursion, receiver-alias, literal-argument, conflict, prediction, lifecycle, local-argument, EOF-boundary, and retry-safety coverage

Compatibility

Newly generated recognizers require codegen API revision 3 because parameterized generated rules call the argument-aware action hook. The runtime continues to accept revisions 1 and 2 because every runtime surface required by those generated sources remains available.

Performance

Same-machine Java parse benchmark against origin/main (f85c971d), using 20 iterations and five warmups:

Fixture Base Head Ratio
issue-174 return expression 0.0119 ms 0.0121 ms 1.022x
Mojang DataResult 2.7919 ms 2.9591 ms 1.060x
Bazel SkyValueRetriever 5.8551 ms 5.7358 ms 0.980x
Closure Property 0.7803 ms 0.7934 ms 1.017x
Trino FilterEvaluator 4.4181 ms 4.5564 ms 1.031x

All five comparisons pass the CI 1.15x regression threshold.

Validation

  • cargo test --locked --all-features --workspace (382 runtime, 3 testsuite-bin, 925 generator, and 72 CLI integration tests)
  • cargo clippy --locked --all-targets --all-features -- -D warnings
  • cargo fmt --all -- --check
  • ANTLR runtime conformance: 357/357 passed with --features codegen
  • self-hosted grammar frontend: Stage 1/2 byte-identical, both corpus checks passed, and checked-in hashes verified
  • direct-codegen fixture validation: 471 manifests and 2,840 hashed artifacts
  • parse benchmark comparison: 5/5 passed at the 1.15x threshold
  • pre-commit hooks: check, format, and Clippy

Fixes #266

Map parser-action helper calls to stable typed-hook methods keyed by grammar action coordinates, so integrations no longer switch on generated ATN states.

Execute non-embedded action hooks at their committed grammar positions on both generated and interpreted paths. The committed walker preserves nested, repeated, left-recursive, and recovery ordering while keeping speculative alternatives side-effect free.

Bump the generated-code API to revision 2 for the new indexed action surface while retaining revision 1 compatibility, regenerate checked-in recognizers, and add strict manifest and generated/interpreted parity coverage.
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The generator and runtime now preserve stable parser-action indexes, track semantic provenance during prediction, and execute indexed actions at committed ATN positions. Typed action hooks support indexed actions and parameterized arguments. Runtime API revision 3 remains compatible with revisions 1 and 2.

Changes

Parser action pipeline

Layer / File(s) Summary
Action contracts and generated dispatch
README.md, src/lib.rs, src/bin/antlr4-rust-gen.rs
Generated metadata and runtime options preserve stable action indexes. Typed parser-action hooks support indexed dispatch, normalized names, typed signatures, collision handling, and fallback routing.
Prediction semantic provenance
src/prediction.rs, src/atn/parser.rs
Prediction configurations retain rule-call and predicate-call provenance. The ATN simulator publishes semantic candidates across DFA, EOF, and full-context paths.
Committed ATN execution
src/parser.rs
Configured mappings select the committed walker. The walker evaluates decisions, enters rules, consumes tokens, evaluates predicates, dispatches indexed actions, and preserves recursion, recovery, listeners, and diagnostics.
Generator and runtime validation
tests/antlr4_rust_gen_cli.rs, tests/fixtures/antlr4-rust-gen/parser-action-hooks/*, src/bin/antlr4-rust-gen.rs, src/parser.rs, third_party/antlr-v4-grammar/self-hosted.sha256
Tests and fixtures cover API compatibility, typed hooks, parameterized arguments, action ordering, losing alternatives, recovery, semantic conflicts, generated/interpreted parity, and updated generated-file checksums.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GeneratedParser
  participant ParserRuntimeOptions
  participant ParserAtnSimulator
  participant CommittedParser
  participant SemanticHooks
  GeneratedParser->>ParserRuntimeOptions: pass indexed action mappings
  ParserRuntimeOptions->>CommittedParser: select committed execution
  CommittedParser->>ParserAtnSimulator: predict with semantic provenance
  ParserAtnSimulator-->>CommittedParser: return selected alternative and candidates
  CommittedParser->>SemanticHooks: dispatch indexed action at committed position
  SemanticHooks-->>CommittedParser: return handled status
  CommittedParser->>CommittedParser: evaluate subsequent predicates and transitions
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes implement named typed hooks, committed action timing, stable attribution, parity, recovery, provenance, fixtures, and compatibility requirements from issue #266.
Out of Scope Changes check ✅ Passed The changes support issue #266 through runtime, generator, compatibility, documentation, fixture, checksum, and test updates.
Docstring Coverage ✅ Passed Docstring coverage is 89.66% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: executing named parser actions at committed grammar positions.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-266-named-parser-actions

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@claude

claude Bot commented Aug 2, 2026

Copy link
Copy Markdown

Claude Code is working…

I'll analyze this and get back to you.

View job run

@codecov

codecov Bot commented Aug 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.40113% with 23 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/bin/antlr4-rust-gen.rs 97.40% 14 Missing ⚠️
src/prediction.rs 96.61% 7 Missing ⚠️
src/atn/parser.rs 98.55% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown

📊 Source Code Metrics (this PR vs main)

File Cyclomatic Cognitive Functions LLOC MI
src/parser.rs 2415 (main: 2168) 🔴 1598 (main: 1422) 🔴 772 (main: 704) 🔴 5407 (main: 4740) 🔴 0 ⚪
src/bin/antlr4-rust-gen.rs 3031 (main: 2956) 🔴 1963 (main: 1911) 🔴 634 (main: 625) 🔴 5317 (main: 5197) 🔴 0 ⚪
src/atn/parser.rs 415 (main: 391) 🔴 298 (main: 287) 🔴 136 (main: 129) 🔴 1173 (main: 1132) 🔴 0 ⚪
src/prediction.rs 301 (main: 265) 🔴 186 (main: 172) 🔴 119 (main: 98) 🔴 629 (main: 536) 🔴 0 ⚪
src/lib.rs 4 ⚪ 3 ⚪ 1 ⚪ 7 ⚪ 30.02 (main: 30.19) 🔴

Generated by mehen v1.8.0 — the code quality watcher.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/parser.rs`:
- Around line 13141-13146: Replace the linear scan in
CommittedAtnParser::action_index with an FxHashMap<usize, usize> built once from
options.action_indices during parser construction. Store the map on
CommittedAtnParser and have action_index perform a source-state lookup,
preserving the existing Option result and all callers’ behavior.
- Around line 12673-12679: Hoist a reusable scratch BTreeSet<usize> field onto
CommittedAtnParser and use it for predicate probes instead of constructing a new
set per transition or candidate. In the has_visible_predicate/transition_index
path and semantic_candidate_matches path, clear the shared set before each
probe, then pass it to transition_has_visible_predicate; preserve the existing
probe behavior.
- Around line 12470-12554: Update the committed parse path to preserve
parser-level behavior when action_indices is non-empty. In src/parser.rs lines
12470-12554, use parse_rule to enforce rule_depth_cap_violation before
child-rule recursion and dispatch parse_listener_enter_rule and
parse_listener_exit_rule around each rule body. In src/parser.rs lines
7905-7941, drain buffered recovery diagnostics via
report_generated_parser_diagnostics and dispatch prediction_diagnostics
consistently with the interpreted entry. In src/parser.rs lines 7951-7967,
either replay init_action_rules in the committed walker or restrict committed
routing so grammars with `@init` templates use the interpreted path.
- Around line 12762-12764: Update the ParserAtnSimulatorError handling around
no_viable_alternative_error so UnknownDecision, MissingAtnState, and
MissingDfaState return AntlrError::Unsupported containing the simulator error
text instead of being converted into parser syntax errors. Preserve the existing
no-viable-alternative mapping for input-driven failures.
- Around line 18852-18905: Add runtime tests alongside
committed_action_runs_before_later_predicate and
committed_walker_does_not_run_action_in_losing_alternative covering
action_indices on a committed action inside a * loop and on a left-recursive
precedence alternative. Build appropriate ATNs and parser inputs, invoke
parse_atn_rule_with_runtime_options with the relevant action indices, and assert
the resulting tree, deferred actions, and semantic hook events to exercise
entered_loops and push_new_recursion_context_with_previous.
- Around line 13124-13137: Align the committed `Transition::Precedence` handling
with the interpreted precedence-transition gate: either retain the
`self.parser.precpred(transition_precedence)` check in both paths or
intentionally narrow and document the committed semantics. Ensure both paths
apply the same `transition_precedence` versus `precedence` condition, updating
the corresponding interpreted transition logic alongside this match arm if
needed.

In `@tests/antlr4_rust_gen_cli.rs`:
- Around line 5263-5273: Update the Rust test function containing the
conflicting-hooks assertions to verify stderr has no temporary-directory paths,
normalizing any such paths before snapshotting if necessary, then replace the
substring assertion with insta::assert_snapshot! over the complete normalized
stderr. Add #[allow(clippy::disallowed_methods)] to this actual test function so
the snapshot macros compile cleanly, while preserving the failure and
no-partial-output assertions.

In `@tests/fixtures/antlr4-rust-gen/parser-action-hooks/ActionTiming.g4`:
- Around line 7-17: Update the force argument in the interpreted grammar rules,
particularly interpreted and recoverInterpreted, to use an i32-compatible value
instead of 2147483648. Preserve the existing rule structure and EOF behavior
while ensuring generated Rust compiles without overflowing_literals errors.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b6c5874d-f1da-43be-9199-3b6b31373c84

📥 Commits

Reviewing files that changed from the base of the PR and between f85c971 and ad11db9.

⛔ Files ignored due to path filters (12)
  • docs/migration.md is excluded by !**/docs/**
  • src/bin/snapshots/antlr4_rust_gen__tests__generated_decision_does_not_hoist_portable_predicate_past_local_action.snap is excluded by !**/*.snap
  • src/bin/snapshots/antlr4_rust_gen__tests__generated_module_file_header.snap is excluded by !**/*.snap
  • src/bin_support/grammar/generated/antlr_v4_lexer.rs is excluded by !**/generated/**
  • src/bin_support/grammar/generated/antlr_v4_parser.rs is excluded by !**/generated/**
  • src/bin_support/rust_syntax/generated/rust_lexer.rs is excluded by !**/generated/**
  • src/bin_support/rust_syntax/generated/rust_parser.rs is excluded by !**/generated/**
  • src/xpath/generated/x_path_lexer.rs is excluded by !**/generated/**
  • tests/snapshots/antlr4_rust_gen_cli__antlr4rust_compat_semantics_manifest.snap is excluded by !**/*.snap
  • tests/snapshots/antlr4_rust_gen_cli__generated_codegen_api_checks.snap is excluded by !**/*.snap
  • tests/snapshots/antlr4_rust_gen_cli__generated_codegen_api_mismatch_diagnostic.snap is excluded by !**/*.snap
  • tests/snapshots/antlr4_rust_gen_cli__named_parser_actions_semantics_manifest.snap is excluded by !**/*.snap
📒 Files selected for processing (7)
  • README.md
  • src/bin/antlr4-rust-gen.rs
  • src/lib.rs
  • src/parser.rs
  • tests/antlr4_rust_gen_cli.rs
  • tests/fixtures/antlr4-rust-gen/parser-action-hooks/ActionTiming.g4
  • tests/fixtures/antlr4-rust-gen/parser-action-hooks/patterns.toml

Comment thread src/parser.rs
Comment thread src/parser.rs Outdated
Comment thread src/parser.rs Outdated
Comment thread src/parser.rs
Comment thread src/parser.rs
Comment thread src/parser.rs
Comment thread tests/antlr4_rust_gen_cli.rs
Comment thread tests/fixtures/antlr4-rust-gen/parser-action-hooks/ActionTiming.g4

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ad11db91f2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/parser.rs Outdated
Comment thread src/parser.rs Outdated
Comment thread src/parser.rs Outdated
Comment thread src/parser.rs Outdated
Comment thread src/parser.rs Outdated
Comment thread src/parser.rs Outdated
Comment thread src/parser.rs
Comment thread src/parser.rs Outdated
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown

Copy/Paste Detection

Found 3169 duplication(s) across 11 changed Rust file(s) (threshold: 100 tokens).

Show duplications

Found a 364 line (1962 tokens) duplication in the following files:

  • Starting at line 170 of src/bin_support/grammar/generated/antlr_v4_parser.rs
  • Starting at line 360 of src/bin_support/rust_syntax/generated/rust_parser.rs
    &[None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
    &[],
    &[],
    &[],
);

pub fn metadata() -> &'static GrammarMetadata {
    &METADATA
}

pub fn rule_names() -> &'static [&'static str] {
    METADATA.rule_names()
}

fn parser_semantics() -> &'static antlr4_runtime::ParserSemantics {
    static SEMANTICS_CELL: OnceLock<antlr4_runtime::ParserSemantics> = OnceLock::new();
    SEMANTICS_CELL.get_or_init(|| {
        let mut ir = antlr4_runtime::semir::SemIr::new();
        let mut predicates = Vec::new();

        let actions = Vec::new();
        antlr4_runtime::ParserSemantics { ir, predicates, actions }
    })
}


#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs0 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs1 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs2 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs3 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs4 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs5 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs6 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs7 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs8 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs9 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs10 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs11 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs12 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs13 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs14 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs15 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs16 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs17 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs18 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs19 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs20 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs21 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs22 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs23 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs24 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs25 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs26 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs27 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs28 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs29 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs30 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs31 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs32 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs33 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs34 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs35 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs36 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs37 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs38 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs39 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs40 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs41 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs42 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs43 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs44 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs45 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs46 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs47 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs48 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs49 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs50 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs51 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs52 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs53 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs54 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs55 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs56 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs57 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs58 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs59 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs60 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs61 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs62 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs63 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs64 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs65 {
}

#[derive(Clone, Debug, Default)]
#[allow(non_snake_case, dead_code)]
pub struct __RuleAttrs66 {
}



#[allow(dead_code)]
```rust

---

Found a 295 line (1730 tokens) duplication in the following files:
* Starting at line 528 of src/bin_support/grammar/generated/antlr_v4_parser.rs
* Starting at line 1458 of src/bin_support/rust_syntax/generated/rust_parser.rs

```rust
pub struct __RuleAttrs66 {
}



#[allow(dead_code)]
pub struct __GeneratedInput<'a, L: TokenSource>(&'a mut CommonTokenStream<L>);

#[allow(dead_code)]
impl<L: TokenSource> __GeneratedInput<'_, L> {
    pub fn text(&mut self) -> String {
        self.0.text_all()
    }

    pub fn la(&mut self, offset: isize) -> i32 {
        antlr4_runtime::IntStream::la(self.0, offset)
    }

    pub fn lt(&mut self, offset: isize) -> __GeneratedTokenView {
        __GeneratedTokenView {
            text: self
                .0
                .lt(offset)
                .map(|token| token.text_or_empty().to_owned())
                .unwrap_or_default(),
        }
    }
}

#[allow(dead_code)]
pub struct __GeneratedTokenView {
    text: String,
}

#[allow(dead_code)]
impl __GeneratedTokenView {
    pub fn text(&self) -> &str {
        &self.text
    }
}
#[allow(dead_code)]
#[derive(Clone)]
pub struct TerminalNode<'a> {
    __node: RuntimeTerminalNode<'a>,
}

#[allow(dead_code)]
impl<'a> TerminalNode<'a> {
    fn new(node: RuntimeTerminalNode<'a>) -> Self {
        Self { __node: node }
    }

    pub fn symbol(&self) -> antlr4_runtime::TokenView<'a> {
        self.__node.symbol()
    }

    pub fn is_error(&self) -> bool {
        matches!(
            self.__node.node().kind(),
            antlr4_runtime::NodeKind::Error
        )
    }

    pub fn is_missing(&self) -> bool {
        self.symbol().is_synthetic()
    }
}

impl std::fmt::Display for TerminalNode<'_> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(self.__node.text())
    }
}

#[allow(dead_code)]
#[derive(Clone)]
pub struct ErrorNode<'a> {
    __node: RuntimeErrorNode<'a>,
}

#[allow(dead_code)]
impl<'a> ErrorNode<'a> {
    fn new(node: RuntimeErrorNode<'a>) -> Self {
        Self { __node: node }
    }

    pub fn symbol(&self) -> antlr4_runtime::TokenView<'a> {
        self.__node.symbol()
    }

    pub fn is_missing(&self) -> bool {
        self.symbol().is_synthetic()
    }
}

impl std::fmt::Display for ErrorNode<'_> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(self.__node.text())
    }
}

#[allow(dead_code)]
#[derive(Clone, Copy)]
enum __GeneratedRuleContext<'a> {
    Stored(RuleNodeView<'a>),
    Active {
        context: &'a antlr4_runtime::ParserRuleContext,
        storage: &'a antlr4_runtime::ParseTreeStorage,
        tokens: &'a antlr4_runtime::TokenStore,
    },
}

#[doc(hidden)]
#[derive(Clone, Copy, Debug)]
pub struct StoredTreeContext;

#[derive(Clone, Copy, Debug)]
struct __ActiveParserContext;

#[allow(dead_code)]
fn __context_children<'a>(
    source: __GeneratedRuleContext<'a>,
) -> impl Iterator<Item = antlr4_runtime::Node<'a>> + 'a {
    let mut stored = match source {
        __GeneratedRuleContext::Stored(node) => Some(node.children()),
        __GeneratedRuleContext::Active { .. } => None,
    };
    let mut active = match source {
        __GeneratedRuleContext::Stored(_) => None,
        __GeneratedRuleContext::Active {
            context,
            storage,
            tokens,
        } => Some(context.child_nodes(storage, tokens)),
    };
    std::iter::from_fn(move || {
        stored
            .as_mut()
            .and_then(Iterator::next)
            .or_else(|| active.as_mut().and_then(Iterator::next))
    })
}

#[allow(dead_code)]
fn __rule_children<'a>(
    source: __GeneratedRuleContext<'a>,
    rule_index: usize,
) -> impl Iterator<Item = RuleNodeView<'a>> + 'a {
    __context_children(source).filter_map(move |child| {
        let rule = child.as_rule()?;
        (rule.rule_index() == rule_index).then_some(rule)
    })
}

// Keep this triage aligned with runtime `RuleNodeView::terminal_children()` and
// `ParserRuleContext::terminal_children()`.
fn __terminal_children<'a>(
    source: __GeneratedRuleContext<'a>,
) -> impl Iterator<Item = RuntimeTerminalNode<'a>> + 'a {
    __context_children(source).filter_map(|child| match child.kind() {
        antlr4_runtime::NodeKind::Terminal => child.as_terminal(),
        antlr4_runtime::NodeKind::Error => {
            child.as_error().map(antlr4_runtime::ErrorNodeView::terminal)
        }
        antlr4_runtime::NodeKind::Rule => None,
    })
}

#[allow(dead_code)]
fn __token_children<'a>(
    source: __GeneratedRuleContext<'a>,
    token_type: i32,
) -> impl Iterator<Item = RuntimeTerminalNode<'a>> + 'a {
    __terminal_children(source)
        .filter(move |terminal| terminal.symbol().token_type() == token_type)
}

#[allow(dead_code)]
fn __token_children_matching<'a>(
    source: __GeneratedRuleContext<'a>,
    token_types: &'static [i32],
) -> impl Iterator<Item = RuntimeTerminalNode<'a>> + 'a {
    __terminal_children(source)
        .filter(move |terminal| token_types.contains(&terminal.symbol().token_type()))
}

#[allow(dead_code)]
fn __labeled_token_child(
    child: antlr4_runtime::Node<'_>,
) -> Option<RuntimeTerminalNode<'_>> {
    match child.kind() {
        antlr4_runtime::NodeKind::Terminal => child.as_terminal(),
        antlr4_runtime::NodeKind::Error => {
            let terminal = child
                .as_error()
                .map(antlr4_runtime::ErrorNodeView::terminal)?;
            terminal.symbol().is_synthetic().then_some(terminal)
        }
        antlr4_runtime::NodeKind::Rule => None,
    }
}

#[allow(dead_code)]
fn __labeled_token_children<'a>(
    source: __GeneratedRuleContext<'a>,
    token_type: i32,
) -> impl Iterator<Item = RuntimeTerminalNode<'a>> + 'a {
    __context_children(source).filter_map(move |child| {
        let terminal = __labeled_token_child(child)?;
        (terminal.symbol().token_type() == token_type).then_some(terminal)
    })
}

#[allow(dead_code)]
fn __labeled_token_children_matching<'a>(
    source: __GeneratedRuleContext<'a>,
    token_types: &'static [i32],
) -> impl Iterator<Item = RuntimeTerminalNode<'a>> + 'a {
    __context_children(source).filter_map(move |child| {
        let terminal = __labeled_token_child(child)?;
        token_types
            .contains(&terminal.symbol().token_type())
            .then_some(terminal)
    })
}

#[allow(dead_code)]
trait __FromActiveRuleContext<'a>: Sized {
    fn __from_active(
        context: &'a antlr4_runtime::ParserRuleContext,
        live_attrs: Option<&dyn std::any::Any>,
        invocation_states: Vec<isize>,
        storage: &'a antlr4_runtime::ParseTreeStorage,
        tokens: &'a antlr4_runtime::TokenStore,
    ) -> Option<Self>;
}

#[allow(dead_code)]
fn __active_context_view<'a, T: __FromActiveRuleContext<'a>>(
    context: &'a antlr4_runtime::ParserRuleContext,
    invocation_states: Vec<isize>,
    storage: &'a antlr4_runtime::ParseTreeStorage,
    tokens: &'a antlr4_runtime::TokenStore,
) -> Option<T> {
    T::__from_active(context, None, invocation_states, storage, tokens)
}

#[allow(dead_code)]
fn __active_context_view_with_attrs<'a, T: __FromActiveRuleContext<'a>>(
    context: &'a antlr4_runtime::ParserRuleContext,
    live_attrs: &dyn std::any::Any,
    invocation_states: Vec<isize>,
    storage: &'a antlr4_runtime::ParseTreeStorage,
    tokens: &'a antlr4_runtime::TokenStore,
) -> Option<T> {
    T::__from_active(
        context,
        Some(live_attrs),
        invocation_states,
        storage,
        tokens,
    )
}

#[allow(dead_code)]
fn __write_invocation_states(
    f: &mut std::fmt::Formatter<'_>,
    states: impl Iterator<Item = isize>,
) -> std::fmt::Result {
    f.write_str("[")?;
    let mut separator = "";
    for state in states {
        write!(f, "{separator}{state}")?;
        separator = " ";
    }
    f.write_str("]")
}

/// Marker carried by generated contexts whose required-child
/// invariants were checked after a syntax-clean parse.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ValidatedTreeContext {
    __private: (),
}

#[allow(dead_code)]
trait __RecoveryContextState {}

impl __RecoveryContextState for StoredTreeContext {}
impl __RecoveryContextState for __ActiveParserContext {}

/// A completed, syntax-clean parse tree whose generated child cardinalities
/// have been structurally validated.
#[derive(Debug)]
pub struct ANTLRv4ValidatedTree {

Found a 303 line (1655 tokens) duplication in the following files:

  • Starting at line 18280 of src/bin_support/grammar/generated/antlr_v4_parser.rs
  • Starting at line 54881 of src/bin_support/rust_syntax/generated/rust_parser.rs
impl<L, H> AntlRv4Parser<L, H>
where
    L: TokenSource,
    H: antlr4_runtime::SemanticHooks,
{
    pub fn with_hooks(input: CommonTokenStream<L>, hooks: H) -> Self {
        let grammar_metadata = metadata();
        let data = grammar_metadata.recognizer_data();
        let mut base = BaseParser::with_semantic_hooks(input, data, hooks);
        base.set_unknown_predicate_policy(antlr4_runtime::UnknownSemanticPolicy::Error);
        Self {
            base,
            simulator: None,
            generated_only: std::env::var_os("ANTLR4_RUST_GENERATED_ONLY").is_some(),
        }
    }

    pub fn metadata() -> &'static GrammarMetadata {
        metadata()
    }

    /// Adds a listener for parser diagnostics.
    pub fn add_error_listener<T>(&mut self, listener: T)
    where
        T: for<'a> antlr4_runtime::ErrorListener<dyn antlr4_runtime::Recognizer + 'a> + Send + 'static,
    {
        self.base.add_error_listener(listener);
    }

    /// Removes every parser error listener, including the default console listener.
    pub fn remove_error_listeners(&mut self) {
        self.base.remove_error_listeners();
    }


    /// Registers a listener for committed rule enter/exit events during
    /// recognition (ANTLR's `addParseListener`). See
    /// [`antlr4_runtime::ParseListener`] for the delivery contract.
    pub fn add_parse_listener<T>(&mut self, listener: T)
    where
        T: antlr4_runtime::ParseListener + 'static,
    {
        self.base.add_parse_listener(listener);
    }

    /// Removes every registered parse listener and returns them, dropping
    /// any sticky abort a removed listener had requested.
    pub fn remove_parse_listeners(&mut self) -> Vec<Box<dyn antlr4_runtime::ParseListener>> {
        self.base.remove_parse_listeners()
    }

    /// Fully resets parser-owned state and rewinds the current token stream.
    pub fn reset(&mut self) {
        self.base.reset();
        if let Some(simulator) = self.simulator.as_mut() {
            simulator.reset();
        }
    }

    /// Replaces the token stream and fully resets parser-owned state.
    pub fn set_token_stream(&mut self, input: CommonTokenStream<L>) {
        self.base.set_token_stream(input);
        if let Some(simulator) = self.simulator.as_mut() {
            simulator.reset();
        }
    }

    #[must_use]
    pub const fn token_stream(&self) -> &CommonTokenStream<L> {
        self.base.token_stream()
    }

    #[must_use]
    pub const fn token_stream_mut(&mut self) -> &mut CommonTokenStream<L> {
        self.base.token_stream_mut()
    }

    #[must_use]
    pub const fn token_store(&self) -> &antlr4_runtime::TokenStore {
        self.base.token_store()
    }

    #[must_use]
    pub const fn parse_tree_storage(&self) -> &antlr4_runtime::ParseTreeStorage {
        self.base.parse_tree_storage()
    }

    #[must_use]
    pub fn prediction_context_stats(&self) -> antlr4_runtime::PredictionContextStats {
        self.simulator.as_ref().map_or_else(
            antlr4_runtime::PredictionContextStats::default,
            antlr4_runtime::ParserAtnSimulator::prediction_context_stats,
        )
    }

    #[must_use]
    pub fn parser_dfa_stats(&self) -> antlr4_runtime::ParserDfaStats {
        self.simulator.as_ref().map_or_else(
            antlr4_runtime::ParserDfaStats::default,
            antlr4_runtime::ParserAtnSimulator::parser_dfa_stats,
        )
    }

    /// Clears this grammar's learned parser decision DFAs.
    pub fn clear_dfa(&mut self) {
        if let Some(simulator) = self.simulator.as_mut() {
            simulator.clear_dfa();
        } else {
            antlr4_runtime::ParserAtnSimulator::clear_shared_dfa(atn());
        }
    }

    #[must_use]
    pub fn node(&self, id: antlr4_runtime::NodeId) -> antlr4_runtime::Node<'_> {
        self.base.node(id)
    }

    #[must_use]
    pub fn into_token_stream(self) -> CommonTokenStream<L> {
        self.base.into_token_stream()
    }

    #[must_use]
    pub fn into_token_store(self) -> antlr4_runtime::TokenStore {
        self.base.into_token_store()
    }

    #[must_use]
    pub fn into_parsed_file(self, root: antlr4_runtime::NodeId) -> antlr4_runtime::ParsedFile {
        self.base.into_parsed_file(root)
    }

    /// Compiles a tree pattern rooted at parser rule `rule_index`.
    ///
    /// Mirrors ANTLR's `Parser.compileParseTreePattern`. Literal chunks of
    /// `pattern` are lexed with a fresh lexer built by `make_lexer` (pass this
    /// grammar's generated lexer constructor, e.g. `MyGrammarLexer::new`);
    /// `<tag>` placeholders become rule/token references matched over a
    /// rule-bypass ATN. The returned [`antlr4_runtime::ParseTreePattern`] can
    /// then match subtrees.
    ///
    /// Takes `&self` only to mirror ANTLR's instance method; the ATN and
    /// grammar metadata come from this module, so the parser's own state is
    /// untouched. The pattern compiler (and its rule-bypass ATN) is built once
    /// per process and shared by every call.
    ///
    /// # Errors
    ///
    /// Returns a [`antlr4_runtime::ParseTreePatternError`] for a malformed
    /// pattern, an unknown tag, a lexer failure, or a pattern the start rule
    /// does not parse cleanly and fully consume.
    pub fn compile_parse_tree_pattern<PL>(
        &self,
        pattern: &str,
        rule_index: usize,
        mut make_lexer: impl FnMut(antlr4_runtime::InputStream) -> PL,
    ) -> Result<antlr4_runtime::ParseTreePattern, antlr4_runtime::ParseTreePatternError>
    where
        PL: antlr4_runtime::TokenSource,
    {
        // The rule-bypass ATN derivation inside `ParseTreePatternMatcher::new`
        // is O(states + transitions), so — like ANTLR's
        // `Parser.bypassAltsAtnCache` — the matcher is built once per process
        // and shared by every subsequent compile. A failed build is not cached
        // and is retried (and re-reported) on the next call.
        static PATTERN_DATA: OnceLock<RecognizerData> = OnceLock::new();
        static PATTERN_MATCHER: OnceLock<antlr4_runtime::ParseTreePatternMatcher<'static>> =
            OnceLock::new();
        let matcher = match PATTERN_MATCHER.get() {
            Some(matcher) => matcher,
            None => {
                let data = PATTERN_DATA.get_or_init(|| {
                    let grammar_metadata = metadata();
                    grammar_metadata.recognizer_data()
                });
                let matcher = antlr4_runtime::ParseTreePatternMatcher::new(parser_atn(), data)?;
                PATTERN_MATCHER.get_or_init(|| matcher)
            }
        };
        matcher.compile(pattern, rule_index, move |text: &str| {
            antlr4_runtime::lex_pattern_chunk(text, &mut make_lexer)
        })
    }

    #[allow(dead_code)]
    fn simulator(&mut self) -> &mut antlr4_runtime::ParserAtnSimulator<'static> {
        self.simulator
            .get_or_insert_with(|| antlr4_runtime::ParserAtnSimulator::new_shared(atn()))
    }

    #[allow(dead_code)]
    fn generated_only(&self) -> bool {
        self.generated_only
    }

    #[allow(dead_code)]
    fn parse_rule(&mut self, rule_index: usize) -> Result<antlr4_runtime::ParseTree, antlr4_runtime::AntlrError> {
        self.parse_rule_precedence(rule_index, 0)
    }

    #[allow(dead_code)]
    fn parse_rule_precedence(&mut self, rule_index: usize, precedence: i32) -> Result<antlr4_runtime::ParseTree, antlr4_runtime::AntlrError> {
        self.parse_rule_precedence_inner(rule_index, precedence, true)
    }

    #[allow(dead_code)]
    fn parse_rule_precedence_from_generated(&mut self, rule_index: usize, precedence: i32) -> Result<antlr4_runtime::ParseTree, antlr4_runtime::AntlrError> {
        self.parse_rule_precedence_inner(rule_index, precedence, false)
    }

    #[allow(dead_code)]
    fn parse_rule_precedence_inner(&mut self, rule_index: usize, precedence: i32, allow_generated_fallback: bool) -> Result<antlr4_runtime::ParseTree, antlr4_runtime::AntlrError> {
        if allow_generated_fallback {
            // True top-level entry: drop any fail-loud coordinates left by a
            // previous parse so a reused parser starts clean. Mid-parse the hits
            // are preserved so a generated parent can surface a recovered child's
            // fail-loud coordinate at this boundary.
            self.base.reset_unknown_semantic_hits();
            // Likewise drop stale sticky aborts (depth-cap violation,
            // parse-listener abort): entry rules share one parser instance,
            // and the flags must not poison the next parse when the previous
            // one exited through an error path.
            let _ = self.base.take_parse_abort();
        }
        let __rule_start = antlr4_runtime::IntStream::index(self.base.input());
        let __generated_only = self.generated_only();
        let __tree = if let Some(result) = self.parse_generated_rule(rule_index, precedence, allow_generated_fallback) {
            match result {
                Ok(tree) => tree,
                Err(error) => {
                    antlr4_runtime::IntStream::seek(self.base.input(), __rule_start);
                    let __report_error =
                        matches!(&error, GeneratedRuleError::Fatal(_));
                    // A fatal unwind retains recovery diagnostics committed
                    // earlier in this entry. Dispatch them before a semantic
                    // or parser-abort override can return, or they would leak
                    // into the next entry on a reused parser.
                    if allow_generated_fallback && __report_error {
                        self.base.report_generated_parser_diagnostics();
                    }
                    if allow_generated_fallback {
                        // A sticky abort (depth cap, listener) wins over an
                        // error or semantic miss derived after recovery absorbed
                        // the aborted rule. Drain any masked semantic miss too,
                        // so neither condition poisons the next entry.
                        if let Some(abort) = self.base.take_parse_abort() {
                            let _ = self.base.take_unknown_semantic_error();
                            return Err(abort);
                        }
                        // A generated predicate that consulted an unimplemented
                        // hook fails the alternative and surfaces here as a generic
                        // failed-predicate/rule error. Prefer the recorded fail-loud
                        // semantic error when no parser abort occurred.
                        if let Some(semantic_error) = self.base.take_unknown_semantic_error() {
                            return Err(semantic_error);
                        }
                    }
                    let error = error.into_error();
                    if allow_generated_fallback && __report_error {
                        self.base.report_unrecovered_parser_error(&error);
                    }
                    return Err(error);
                }
            }
        } else if __generated_only {
            return Err(antlr4_runtime::AntlrError::Unsupported(format!("generated parser did not emit rule {}", rule_index)));
        } else {
            self.parse_interpreted_rule_precedence(rule_index, precedence)?
        };
        if allow_generated_fallback {
            self.base.report_generated_parser_diagnostics();
            // A sticky abort (depth-cap violation, listener abort) is not a
            // syntax error: rule-level recovery may have produced a tree
            // and semantic miss anyway, but the abort is the root cause. Drain
            // both sticky conditions before returning so parser reuse is clean.
            if let Some(error) = self.base.take_parse_abort() {
                let _ = self.base.take_unknown_semantic_error();
                return Err(error);
            }
            // Surface unknown predicate/action coordinates recorded under the
            // Error policy only after parser aborts have been ruled out.
            if let Some(error) = self.base.take_unknown_semantic_error() {
                return Err(error);
            }
        }
        Ok(__tree)
    }

    #[allow(dead_code)]
    fn parse_interpreted_rule(&mut self, rule_index: usize) -> Result<antlr4_runtime::ParseTree, antlr4_runtime::AntlrError> {
        self.parse_interpreted_rule_precedence(rule_index, 0)
    }

    #[allow(dead_code)]
    fn parse_interpreted_rule_precedence(&mut self, rule_index: usize, precedence: i32) -> Result<antlr4_runtime::ParseTree, antlr4_runtime::AntlrError> {
        if precedence == 0 && false && std::env::var_os("ANTLR4_RUST_ADAPTIVE_DIRECT").is_some() {
            let simulator = self
                .simulator
                .get_or_insert_with(|| antlr4_runtime::ParserAtnSimulator::new_shared(atn()));
            self.base
                .parse_atn_rule_adaptive_or_fallback(atn(), simulator, rule_index)
        } else {
        let (tree, actions) = self.base.parse_atn_rule_with_runtime_options_and_precedence(atn(), rule_index, precedence, antlr4_runtime::ParserRuntimeOptions { action_indices: &[], track_alt_numbers: false, track_context_alt_numbers: false, predicates: &[], semantics: Some(parser_semantics()), rule_args: &[], member_actions: &[], return_actions: &[], unknown_predicate_policy: antlr4_runtime::UnknownSemanticPolicy::Error , ..antlr4_runtime::ParserRuntimeOptions::default() })?;
```rust

---

Found a 5 line (1075 tokens) duplication in the following files:
* Starting at line 141 of src/bin_support/rust_syntax/generated/rust_lexer.rs
* Starting at line 357 of src/bin_support/rust_syntax/generated/rust_parser.rs

```rust
    &["T__0", "T__1", "T__2", "T__3", "T__4", "T__5", "T__6", "T__7", "T__8", "T__9", "T__10", "T__11", "T__12", "T__13", "T__14", "T__15", "T__16", "T__17", "T__18", "T__19", "T__20", "T__21", "T__22", "T__23", "T__24", "T__25", "T__26", "T__27", "T__28", "T__29", "T__30", "T__31", "T__32", "T__33", "T__34", "T__35", "T__36", "T__37", "T__38", "T__39", "T__40", "T__41", "T__42", "T__43", "T__44", "T__45", "T__46", "T__47", "T__48", "T__49", "T__50", "T__51", "T__52", "T__53", "T__54", "T__55", "T__56", "T__57", "T__58", "T__59", "T__60", "T__61", "T__62", "T__63", "T__64", "T__65", "T__66", "T__67", "T__68", "T__69", "T__70", "T__71", "T__72", "T__73", "T__74", "T__75", "T__76", "T__77", "T__78", "T__79", "T__80", "T__81", "T__82", "T__83", "T__84", "T__85", "T__86", "T__87", "T__88", "T__89", "T__90", "T__91", "T__92", "T__93", "T__94", "T__95", "T__96", "T__97", "T__98", "T__99", "XID_Start", "XID_Continue", "CashMoney", "RawIdentifier", "IDENT", "Lifetime", "Ident", "SIMPLE_ESCAPE", "CHAR", "CharLit", "OTHER_STRING_ELEMENT", "STRING_ELEMENT", "RAW_CHAR", "RAW_STRING_BODY", "StringLit", "C_STRING_CHAR", "C_BYTE_ESCAPE", "C_UNICODE_ESCAPE", "C_UNICODE_HEX_TAIL_5", "C_UNICODE_HEX_TAIL_4", "C_UNICODE_HEX_TAIL_3", "C_UNICODE_HEX_TAIL_2", "C_UNICODE_HEX_TAIL_1", "C_UNICODE_HEX_TAIL_0", "C_STRING_ELEMENT", "C_RAW_CHAR", "C_RAW_STRING_BODY", "CStringLit", "BYTE", "ByteLit", "BYTE_STRING_ELEMENT", "RAW_BYTE_STRING_BODY", "ByteStringLit", "DEC_DIGITS", "BareIntLit", "INT_SUFFIX", "FullIntLit", "EXPONENT", "FLOAT_SUFFIX", "FloatLit", "Whitespace", "LineComment", "BlockComment", "TupleIndex", "Shebang"],
    &[None, Some("\'pub\'"), Some("\'crate\'"), Some("\'(\'"), Some("\')\'"), Some("\'self\'"), Some("\'super\'"), Some("\'in\'"), Some("\'\\\'\'"), Some("\'extern\'"), Some("\';\'"), Some("\'use\'"), Some("\'::\'"), Some("\'{\'"), Some("\'}\'"), Some("\'*\'"), Some("\',\'"), Some("\'as\'"), Some("\'_\'"), Some("\'mod\'"), Some("\'unsafe\'"), Some("\'safe\'"), Some("\'static\'"), Some("\'mut\'"), Some("\':\'"), Some("\'=\'"), Some("\'type\'"), Some("\'default\'"), Some("\'const\'"), Some("\'macro\'"), Some("\'async\'"), Some("\'fn\'"), Some("\'...\'"), Some("\'&\'"), Some("\'impl\'"), Some("\'ref\'"), Some("\'&&\'"), Some("\'->\'"), Some("\'struct\'"), Some("\'enum\'"), Some("\'union\'"), Some("\'auto\'"), Some("\'trait\'"), Some("\'?\'"), Some("\'!\'"), Some("\'for\'"), Some("\'..\'"), Some("\'#\'"), Some("\'[\'"), Some("\']\'"), Some("\'<\'"), Some("\'>\'"), Some("\'Self\'"), Some("\'$crate\'"), Some("\'+\'"), Some("\'raw\'"), Some("\'where\'"), Some("\'dyn\'"), Some("\'true\'"), Some("\'false\'"), Some("\'-\'"), Some("\'|\'"), Some("\'@\'"), Some("\'..=\'"), Some("\'box\'"), Some("\'let\'"), Some("\'else\'"), Some("\'match\'"), Some("\'loop\'"), Some("\'try\'"), Some("\'if\'"), Some("\'while\'"), Some("\'=>\'"), Some("\'move\'"), Some("\'break\'"), Some("\'continue\'"), Some("\'return\'"), Some("\'yield\'"), Some("\'.\'"), Some("\'||\'"), Some("\'|_|\'"), Some("\'/\'"), Some("\'%\'"), Some("\'^\'"), Some("\'==\'"), Some("\'!=\'"), Some("\'<=\'"), Some("\'>=\'"), Some("\'*=\'"), Some("\'/=\'"), Some("\'%=\'"), Some("\'+=\'"), Some("\'-=\'"), Some("\'<<=\'"), Some("\'>>=\'"), Some("\'&=\'"), Some("\'^=\'"), Some("\'|=\'"), Some("\'macro_rules\'"), Some("\'\\\'static\'"), Some("\'\\\'_\'"), Some("\'$\'"), None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
    &[None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, Some("CashMoney"), Some("RawIdentifier"), Some("Lifetime"), Some("Ident"), Some("CharLit"), Some("StringLit"), Some("CStringLit"), Some("ByteLit"), Some("ByteStringLit"), Some("BareIntLit"), Some("FullIntLit"), Some("FloatLit"), Some("Whitespace"), Some("LineComment"), Some("BlockComment"), Some("TupleIndex"), Some("Shebang")],
    &[None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
    &["DEFAULT_TOKEN_CHANNEL", "HIDDEN"],

Found a 76 line (996 tokens) duplication in the following files:

  • Starting at line 18584 of src/bin_support/grammar/generated/antlr_v4_parser.rs
  • Starting at line 55185 of src/bin_support/rust_syntax/generated/rust_parser.rs
        Ok(tree)
        }
    }

    #[allow(dead_code)]
    fn parse_generated_rule(&mut self, rule_index: usize, precedence: i32, allow_fallback: bool) -> Option<Result<antlr4_runtime::ParseTree, GeneratedRuleError>> {
        let _ = precedence;
        let _ = allow_fallback;
        match rule_index {
            0 => Some(self.parse_generated_rule_0_dispatch(precedence, allow_fallback)),
            1 => Some(self.parse_generated_rule_1_dispatch(precedence, allow_fallback)),
            2 => Some(self.parse_generated_rule_2_dispatch(precedence, allow_fallback)),
            3 => Some(self.parse_generated_rule_3_dispatch(precedence, allow_fallback)),
            4 => Some(self.parse_generated_rule_4_dispatch(precedence, allow_fallback)),
            5 => Some(self.parse_generated_rule_5_dispatch(precedence, allow_fallback)),
            6 => Some(self.parse_generated_rule_6_dispatch(precedence, allow_fallback)),
            7 => Some(self.parse_generated_rule_7_dispatch(precedence, allow_fallback)),
            8 => Some(self.parse_generated_rule_8_dispatch(precedence, allow_fallback)),
            9 => Some(self.parse_generated_rule_9_dispatch(precedence, allow_fallback)),
            10 => Some(self.parse_generated_rule_10_dispatch(precedence, allow_fallback)),
            11 => Some(self.parse_generated_rule_11_dispatch(precedence, allow_fallback)),
            12 => Some(self.parse_generated_rule_12_dispatch(precedence, allow_fallback)),
            13 => Some(self.parse_generated_rule_13_dispatch(precedence, allow_fallback)),
            14 => Some(self.parse_generated_rule_14_dispatch(precedence, allow_fallback)),
            15 => Some(self.parse_generated_rule_15_dispatch(precedence, allow_fallback)),
            16 => Some(self.parse_generated_rule_16_dispatch(precedence, allow_fallback)),
            17 => Some(self.parse_generated_rule_17_dispatch(precedence, allow_fallback)),
            18 => Some(self.parse_generated_rule_18_dispatch(precedence, allow_fallback)),
            19 => Some(self.parse_generated_rule_19_dispatch(precedence, allow_fallback)),
            20 => Some(self.parse_generated_rule_20_dispatch(precedence, allow_fallback)),
            21 => Some(self.parse_generated_rule_21_dispatch(precedence, allow_fallback)),
            22 => Some(self.parse_generated_rule_22_dispatch(precedence, allow_fallback)),
            23 => Some(self.parse_generated_rule_23_dispatch(precedence, allow_fallback)),
            24 => Some(self.parse_generated_rule_24_dispatch(precedence, allow_fallback)),
            25 => Some(self.parse_generated_rule_25_dispatch(precedence, allow_fallback)),
            26 => Some(self.parse_generated_rule_26_dispatch(precedence, allow_fallback)),
            27 => Some(self.parse_generated_rule_27_dispatch(precedence, allow_fallback)),
            28 => Some(self.parse_generated_rule_28_dispatch(precedence, allow_fallback)),
            29 => Some(self.parse_generated_rule_29_dispatch(precedence, allow_fallback)),
            30 => Some(self.parse_generated_rule_30_dispatch(precedence, allow_fallback)),
            31 => Some(self.parse_generated_rule_31_dispatch(precedence, allow_fallback)),
            32 => Some(self.parse_generated_rule_32_dispatch(precedence, allow_fallback)),
            33 => Some(self.parse_generated_rule_33_dispatch(precedence, allow_fallback)),
            34 => Some(self.parse_generated_rule_34_dispatch(precedence, allow_fallback)),
            35 => Some(self.parse_generated_rule_35_dispatch(precedence, allow_fallback)),
            36 => Some(self.parse_generated_rule_36_dispatch(precedence, allow_fallback)),
            37 => Some(self.parse_generated_rule_37_dispatch(precedence, allow_fallback)),
            38 => Some(self.parse_generated_rule_38_dispatch(precedence, allow_fallback)),
            39 => Some(self.parse_generated_rule_39_dispatch(precedence, allow_fallback)),
            40 => Some(self.parse_generated_rule_40_dispatch(precedence, allow_fallback)),
            41 => Some(self.parse_generated_rule_41_dispatch(precedence, allow_fallback)),
            42 => Some(self.parse_generated_rule_42_dispatch(precedence, allow_fallback)),
            43 => Some(self.parse_generated_rule_43_dispatch(precedence, allow_fallback)),
            44 => Some(self.parse_generated_rule_44_dispatch(precedence, allow_fallback)),
            45 => Some(self.parse_generated_rule_45_dispatch(precedence, allow_fallback)),
            46 => Some(self.parse_generated_rule_46_dispatch(precedence, allow_fallback)),
            47 => Some(self.parse_generated_rule_47_dispatch(precedence, allow_fallback)),
            48 => Some(self.parse_generated_rule_48_dispatch(precedence, allow_fallback)),
            49 => Some(self.parse_generated_rule_49_dispatch(precedence, allow_fallback)),
            50 => Some(self.parse_generated_rule_50_dispatch(precedence, allow_fallback)),
            51 => Some(self.parse_generated_rule_51_dispatch(precedence, allow_fallback)),
            52 => Some(self.parse_generated_rule_52_dispatch(precedence, allow_fallback)),
            53 => Some(self.parse_generated_rule_53_dispatch(precedence, allow_fallback)),
            54 => Some(self.parse_generated_rule_54_dispatch(precedence, allow_fallback)),
            55 => Some(self.parse_generated_rule_55_dispatch(precedence, allow_fallback)),
            56 => Some(self.parse_generated_rule_56_dispatch(precedence, allow_fallback)),
            57 => Some(self.parse_generated_rule_57_dispatch(precedence, allow_fallback)),
            58 => Some(self.parse_generated_rule_58_dispatch(precedence, allow_fallback)),
            59 => Some(self.parse_generated_rule_59_dispatch(precedence, allow_fallback)),
            60 => Some(self.parse_generated_rule_60_dispatch(precedence, allow_fallback)),
            61 => Some(self.parse_generated_rule_61_dispatch(precedence, allow_fallback)),
            62 => Some(self.parse_generated_rule_62_dispatch(precedence, allow_fallback)),
            63 => Some(self.parse_generated_rule_63_dispatch(precedence, allow_fallback)),
            64 => Some(self.parse_generated_rule_64_dispatch(precedence, allow_fallback)),
            65 => Some(self.parse_generated_rule_65_dispatch(precedence, allow_fallback)),
            66 => Some(self.parse_generated_rule_66_dispatch(precedence, allow_fallback)),
```rust

---

Found a 122 line (949 tokens) duplication in the following files:
* Starting at line 14 of src/bin_support/rust_syntax/generated/rust_lexer.rs
* Starting at line 17 of src/bin_support/rust_syntax/generated/rust_parser.rs

```rust
use std::sync::OnceLock;

pub const EOF: i32 = antlr4_runtime::TOKEN_EOF;
pub const T__0: i32 = 1;
pub const T__1: i32 = 2;
pub const T__2: i32 = 3;
pub const T__3: i32 = 4;
pub const T__4: i32 = 5;
pub const T__5: i32 = 6;
pub const T__6: i32 = 7;
pub const T__7: i32 = 8;
pub const T__8: i32 = 9;
pub const T__9: i32 = 10;
pub const T__10: i32 = 11;
pub const T__11: i32 = 12;
pub const T__12: i32 = 13;
pub const T__13: i32 = 14;
pub const T__14: i32 = 15;
pub const T__15: i32 = 16;
pub const T__16: i32 = 17;
pub const T__17: i32 = 18;
pub const T__18: i32 = 19;
pub const T__19: i32 = 20;
pub const T__20: i32 = 21;
pub const T__21: i32 = 22;
pub const T__22: i32 = 23;
pub const T__23: i32 = 24;
pub const T__24: i32 = 25;
pub const T__25: i32 = 26;
pub const T__26: i32 = 27;
pub const T__27: i32 = 28;
pub const T__28: i32 = 29;
pub const T__29: i32 = 30;
pub const T__30: i32 = 31;
pub const T__31: i32 = 32;
pub const T__32: i32 = 33;
pub const T__33: i32 = 34;
pub const T__34: i32 = 35;
pub const T__35: i32 = 36;
pub const T__36: i32 = 37;
pub const T__37: i32 = 38;
pub const T__38: i32 = 39;
pub const T__39: i32 = 40;
pub const T__40: i32 = 41;
pub const T__41: i32 = 42;
pub const T__42: i32 = 43;
pub const T__43: i32 = 44;
pub const T__44: i32 = 45;
pub const T__45: i32 = 46;
pub const T__46: i32 = 47;
pub const T__47: i32 = 48;
pub const T__48: i32 = 49;
pub const T__49: i32 = 50;
pub const T__50: i32 = 51;
pub const T__51: i32 = 52;
pub const T__52: i32 = 53;
pub const T__53: i32 = 54;
pub const T__54: i32 = 55;
pub const T__55: i32 = 56;
pub const T__56: i32 = 57;
pub const T__57: i32 = 58;
pub const T__58: i32 = 59;
pub const T__59: i32 = 60;
pub const T__60: i32 = 61;
pub const T__61: i32 = 62;
pub const T__62: i32 = 63;
pub const T__63: i32 = 64;
pub const T__64: i32 = 65;
pub const T__65: i32 = 66;
pub const T__66: i32 = 67;
pub const T__67: i32 = 68;
pub const T__68: i32 = 69;
pub const T__69: i32 = 70;
pub const T__70: i32 = 71;
pub const T__71: i32 = 72;
pub const T__72: i32 = 73;
pub const T__73: i32 = 74;
pub const T__74: i32 = 75;
pub const T__75: i32 = 76;
pub const T__76: i32 = 77;
pub const T__77: i32 = 78;
pub const T__78: i32 = 79;
pub const T__79: i32 = 80;
pub const T__80: i32 = 81;
pub const T__81: i32 = 82;
pub const T__82: i32 = 83;
pub const T__83: i32 = 84;
pub const T__84: i32 = 85;
pub const T__85: i32 = 86;
pub const T__86: i32 = 87;
pub const T__87: i32 = 88;
pub const T__88: i32 = 89;
pub const T__89: i32 = 90;
pub const T__90: i32 = 91;
pub const T__91: i32 = 92;
pub const T__92: i32 = 93;
pub const T__93: i32 = 94;
pub const T__94: i32 = 95;
pub const T__95: i32 = 96;
pub const T__96: i32 = 97;
pub const T__97: i32 = 98;
pub const T__98: i32 = 99;
pub const T__99: i32 = 100;
pub const CASH_MONEY: i32 = 101;
pub const RAW_IDENTIFIER: i32 = 102;
pub const LIFETIME: i32 = 103;
pub const IDENT: i32 = 104;
pub const CHAR_LIT: i32 = 105;
pub const STRING_LIT: i32 = 106;
pub const C_STRING_LIT: i32 = 107;
pub const BYTE_LIT: i32 = 108;
pub const BYTE_STRING_LIT: i32 = 109;
pub const BARE_INT_LIT: i32 = 110;
pub const FULL_INT_LIT: i32 = 111;
pub const FLOAT_LIT: i32 = 112;
pub const WHITESPACE: i32 = 113;
pub const LINE_COMMENT: i32 = 114;
pub const BLOCK_COMMENT: i32 = 115;
pub const TUPLE_INDEX: i32 = 116;
pub const SHEBANG: i32 = 117;

pub const CHANNEL_DEFAULT_TOKEN_CHANNEL: i32 = 0;

Found a 5 line (823 tokens) duplication in the following files:

  • Starting at line 103 of src/bin_support/grammar/generated/antlr_v4_lexer.rs
  • Starting at line 167 of src/bin_support/grammar/generated/antlr_v4_parser.rs
    &["DOC_COMMENT", "BLOCK_COMMENT", "LINE_COMMENT", "INT", "STRING_LITERAL", "UNTERMINATED_STRING_LITERAL", "BEGIN_ARGUMENT", "ACTION", "NESTED_ACTION", "ApostropheIdentifier", "OPTIONS", "TOKENS", "CHANNELS", "IMPORT", "FRAGMENT", "LEXER", "PARSER", "GRAMMAR", "PROTECTED", "PUBLIC", "PRIVATE", "RETURNS", "LOCALS", "THROWS", "CATCH", "FINALLY", "MODE", "COLON", "COLONCOLON", "COMMA", "SEMI", "LPAREN", "RPAREN", "RBRACE", "RARROW", "LT", "GT", "ASSIGN", "QUESTION", "STAR", "PLUS_ASSIGN", "PLUS", "OR", "DOLLAR", "RANGE", "DOT", "AT", "POUND", "NOT", "ID", "WS", "NESTED_ARGUMENT", "ARGUMENT_ESCAPE", "ARGUMENT_STRING_LITERAL", "ARGUMENT_CHAR_LITERAL", "END_ARGUMENT", "UNTERMINATED_ARGUMENT", "ARGUMENT_CONTENT", "LEXER_CHAR_SET_BODY", "LEXER_CHAR_SET", "UNTERMINATED_CHAR_SET", "ESC_SEQUENCE", "HexDigit", "UnicodeESC", "DoubleQuoteLiteral", "TripleQuoteLiteral", "BacktickQuoteLiteral", "NameChar", "NameStartChar"],
    &[None, None, None, None, None, None, None, Some("\'=\'"), None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, Some("\'[\'"), None, None, None, Some("\'import\'"), Some("\'fragment\'"), Some("\'lexer\'"), Some("\'parser\'"), Some("\'grammar\'"), Some("\'protected\'"), Some("\'public\'"), Some("\'private\'"), Some("\'returns\'"), Some("\'locals\'"), Some("\'throws\'"), Some("\'catch\'"), Some("\'finally\'"), Some("\'mode\'"), Some("\':\'"), Some("\'::\'"), Some("\',\'"), Some("\';\'"), Some("\'(\'"), Some("\')\'"), Some("\'}\'"), Some("\'->\'"), Some("\'<\'"), Some("\'>\'"), Some("\'?\'"), Some("\'*\'"), Some("\'+=\'"), Some("\'+\'"), Some("\'|\'"), Some("\'$\'"), Some("\'..\'"), Some("\'.\'"), Some("\'@\'"), Some("\'#\'"), Some("\'~\'"), None, None, None, None, None],
    &[None, None, None, None, Some("ACTION"), Some("ARG_ACTION"), Some("ARG_OR_CHARSET"), Some("ASSIGN"), Some("LEXER_CHAR_SET"), Some("RULE_REF"), Some("SEMPRED"), Some("STRING_LITERAL"), Some("TOKEN_REF"), Some("UNICODE_ESC"), Some("UNICODE_EXTENDED_ESC"), Some("WS"), Some("ALT"), Some("BLOCK"), Some("CLOSURE"), Some("ELEMENT_OPTIONS"), Some("EPSILON"), Some("LEXER_ACTION_CALL"), Some("LEXER_ALT_ACTION"), Some("OPTIONAL"), Some("POSITIVE_CLOSURE"), Some("RULE"), Some("RULEMODIFIERS"), Some("RULES"), Some("SET"), Some("WILDCARD"), Some("DOC_COMMENT"), Some("BLOCK_COMMENT"), Some("LINE_COMMENT"), Some("INT"), Some("UNTERMINATED_STRING_LITERAL"), Some("BEGIN_ARGUMENT"), Some("OPTIONS"), Some("TOKENS"), Some("CHANNELS"), Some("IMPORT"), Some("FRAGMENT"), Some("LEXER"), Some("PARSER"), Some("GRAMMAR"), Some("PROTECTED"), Some("PUBLIC"), Some("PRIVATE"), Some("RETURNS"), Some("LOCALS"), Some("THROWS"), Some("CATCH"), Some("FINALLY"), Some("MODE"), Some("COLON"), Some("COLONCOLON"), Some("COMMA"), Some("SEMI"), Some("LPAREN"), Some("RPAREN"), Some("RBRACE"), Some("RARROW"), Some("LT"), Some("GT"), Some("QUESTION"), Some("STAR"), Some("PLUS_ASSIGN"), Some("PLUS"), Some("OR"), Some("DOLLAR"), Some("RANGE"), Some("DOT"), Some("AT"), Some("POUND"), Some("NOT"), Some("ID"), Some("END_ARGUMENT"), Some("UNTERMINATED_ARGUMENT"), Some("ARGUMENT_CONTENT"), Some("UNTERMINATED_CHAR_SET")],
    &[None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
    &["DEFAULT_TOKEN_CHANNEL", "HIDDEN", "OFF_CHANNEL", "COMMENT"],
```rust

---

Found a 80 line (613 tokens) duplication in the following files:
* Starting at line 14 of src/bin_support/grammar/generated/antlr_v4_lexer.rs
* Starting at line 17 of src/bin_support/grammar/generated/antlr_v4_parser.rs

```rust
use std::sync::OnceLock;

pub const EOF: i32 = antlr4_runtime::TOKEN_EOF;
pub const ACTION: i32 = 4;
pub const ARG_ACTION: i32 = 5;
pub const ARG_OR_CHARSET: i32 = 6;
pub const ASSIGN: i32 = 7;
pub const LEXER_CHAR_SET: i32 = 8;
pub const RULE_REF: i32 = 9;
pub const SEMPRED: i32 = 10;
pub const STRING_LITERAL: i32 = 11;
pub const TOKEN_REF: i32 = 12;
pub const UNICODE_ESC: i32 = 13;
pub const UNICODE_EXTENDED_ESC: i32 = 14;
pub const WS: i32 = 15;
pub const ALT: i32 = 16;
pub const BLOCK: i32 = 17;
pub const CLOSURE: i32 = 18;
pub const ELEMENT_OPTIONS: i32 = 19;
pub const EPSILON: i32 = 20;
pub const LEXER_ACTION_CALL: i32 = 21;
pub const LEXER_ALT_ACTION: i32 = 22;
pub const OPTIONAL: i32 = 23;
pub const POSITIVE_CLOSURE: i32 = 24;
pub const RULE: i32 = 25;
pub const RULEMODIFIERS: i32 = 26;
pub const RULES: i32 = 27;
pub const SET: i32 = 28;
pub const WILDCARD: i32 = 29;
pub const DOC_COMMENT: i32 = 30;
pub const BLOCK_COMMENT: i32 = 31;
pub const LINE_COMMENT: i32 = 32;
pub const INT: i32 = 33;
pub const UNTERMINATED_STRING_LITERAL: i32 = 34;
pub const BEGIN_ARGUMENT: i32 = 35;
pub const OPTIONS: i32 = 36;
pub const TOKENS: i32 = 37;
pub const CHANNELS: i32 = 38;
pub const IMPORT: i32 = 39;
pub const FRAGMENT: i32 = 40;
pub const LEXER: i32 = 41;
pub const PARSER: i32 = 42;
pub const GRAMMAR: i32 = 43;
pub const PROTECTED: i32 = 44;
pub const PUBLIC: i32 = 45;
pub const PRIVATE: i32 = 46;
pub const RETURNS: i32 = 47;
pub const LOCALS: i32 = 48;
pub const THROWS: i32 = 49;
pub const CATCH: i32 = 50;
pub const FINALLY: i32 = 51;
pub const MODE: i32 = 52;
pub const COLON: i32 = 53;
pub const COLONCOLON: i32 = 54;
pub const COMMA: i32 = 55;
pub const SEMI: i32 = 56;
pub const LPAREN: i32 = 57;
pub const RPAREN: i32 = 58;
pub const RBRACE: i32 = 59;
pub const RARROW: i32 = 60;
pub const LT: i32 = 61;
pub const GT: i32 = 62;
pub const QUESTION: i32 = 63;
pub const STAR: i32 = 64;
pub const PLUS_ASSIGN: i32 = 65;
pub const PLUS: i32 = 66;
pub const OR: i32 = 67;
pub const DOLLAR: i32 = 68;
pub const RANGE: i32 = 69;
pub const DOT: i32 = 70;
pub const AT: i32 = 71;
pub const POUND: i32 = 72;
pub const NOT: i32 = 73;
pub const ID: i32 = 74;
pub const END_ARGUMENT: i32 = 75;
pub const UNTERMINATED_ARGUMENT: i32 = 76;
pub const ARGUMENT_CONTENT: i32 = 77;
pub const UNTERMINATED_CHAR_SET: i32 = 78;

pub const CHANNEL_COMMENT: i32 = 3;

Found a 1 line (558 tokens) duplication in the following files:

  • Starting at line 109 of src/bin_support/grammar/generated/antlr_v4_lexer.rs
  • Starting at line 147 of src/bin_support/rust_syntax/generated/rust_lexer.rs
    &[4, 0, 78, 590, 6, -1, 6, -1, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 147, 8, 0, 10, 0, 12, 0, 150, 9, 0, 1, 0, 1, 0, 1, 0, 3, 0, 155, 8, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 163, 8, 1, 10, 1, 12, 1, 166, 9, 1, 1, 1, 1, 1, 1, 1, 3, 1, 171, 8, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 5, 2, 179, 8, 2, 10, 2, 12, 2, 182, 9, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 5, 3, 189, 8, 3, 10, 3, 12, 3, 192, 9, 3, 3, 3, 194, 8, 3, 1, 4, 1, 4, 1, 4, 5, 4, 199, 8, 4, 10, 4, 12, 4, 202, 9, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 5, 5, 209, 8, 5, 10, 5, 12, 5, 212, 9, 5, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 5, 8, 230, 8, 8, 10, 8, 12, 8, 233, 9, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 5, 8, 241, 8, 8, 10, 8, 12, 8, 244, 9, 8, 1, 8, 1, 8, 1, 8, 5, 8, 249, 8, 8, 10, 8, 12, 8, 252, 9, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 3, 9, 260, 8, 9, 1, 9, 1, 9, 5, 9, 264, 8, 9, 10, 9, 12, 9, 267, 9, 9, 3, 9, 269, 8, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 5, 10, 280, 8, 10, 10, 10, 12, 10, 283, 9, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 5, 11, 295, 8, 11, 10, 11, 12, 11, 298, 9, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 5, 12, 312, 8, 12, 10, 12, 12, 12, 315, 9, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 30, 1, 30, 1, 31, 1, 31, 1, 32, 1, 32, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 35, 1, 35, 1, 36, 1, 36, 1, 37, 1, 37, 1, 38, 1, 38, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 42, 1, 42, 1, 43, 1, 43, 1, 44, 1, 44, 1, 44, 1, 45, 1, 45, 1, 46, 1, 46, 1, 47, 1, 47, 1, 48, 1, 48, 1, 49, 1, 49, 5, 49, 472, 8, 49, 10, 49, 12, 49, 475, 9, 49, 1, 50, 4, 50, 478, 8, 50, 11, 50, 12, 50, 479, 1, 50, 1, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 58, 1, 58, 1, 58, 4, 58, 514, 8, 58, 11, 58, 12, 58, 515, 1, 58, 1, 58, 1, 59, 1, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 3, 61, 533, 8, 61, 1, 62, 1, 62, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 3, 63, 542, 8, 63, 3, 63, 544, 8, 63, 3, 63, 546, 8, 63, 3, 63, 548, 8, 63, 1, 64, 1, 64, 1, 64, 5, 64, 553, 8, 64, 10, 64, 12, 64, 556, 9, 64, 1, 64, 1, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 5, 65, 566, 8, 65, 10, 65, 12, 65, 569, 9, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 66, 1, 66, 1, 66, 5, 66, 578, 8, 66, 10, 66, 12, 66, 581, 9, 66, 1, 66, 1, 66, 1, 67, 1, 67, 3, 67, 587, 8, 67, 1, 68, 1, 68, 7, 148, 164, 231, 250, 554, 567, 579, 0, 69, 3, 30, 5, 31, 7, 32, 9, 33, 11, 11, 13, 34, 15, 35, 17, 4, 19, 0, 21, 0, 23, 36, 25, 37, 27, 38, 29, 39, 31, 40, 33, 41, 35, 42, 37, 43, 39, 44, 41, 45, 43, 46, 45, 47, 47, 48, 49, 49, 51, 50, 53, 51, 55, 52, 57, 53, 59, 54, 61, 55, 63, 56, 65, 57, 67, 58, 69, 59, 71, 60, 73, 61, 75, 62, 77, 7, 79, 63, 81, 64, 83, 65, 85, 66, 87, 67, 89, 68, 91, 69, 93, 70, 95, 71, 97, 72, 99, 73, 101, 74, 103, 15, 105, 0, 107, 0, 109, 0, 111, 0, 113, 75, 115, 76, 117, 77, 119, 0, 121, 8, 123, 78, 125, 0, 127, 0, 129, 0, 131, 0, 133, 0, 135, 0, 137, 0, 139, 0, 3, 0, 1, 2, 12, 2, 0, 10, 10, 13, 13, 1, 0, 49, 57, 1, 0, 48, 57, 4, 0, 10, 10, 13, 13, 39, 39, 92, 92, 5, 0, 34, 34, 39, 39, 92, 92, 96, 96, 123, 123, 4, 0, 9, 10, 12, 13, 32, 32, 65279, 65279, 1, 0, 92, 93, 8, 0, 34, 34, 39, 39, 92, 92, 98, 98, 102, 102, 110, 110, 114, 114, 116, 116, 3, 0, 48, 57, 65, 70, 97, 102, 4, 0, 10, 10, 13, 13, 34, 34, 92, 92, 5, 0, 48, 57, 95, 95, 183, 183, 768, 879, 8255, 8256, 14, 0, 65, 90, 97, 122, 192, 214, 216, 246, 248, 767, 880, 893, 895, 8191, 8204, 8205, 8304, 8591, 11264, 12271, 12289, 55295, 63744, 64975, 65008, 65278, 65280, 65533, 624, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, 0, 55, 1, 0, 0, 0, 0, 57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 61, 1, 0, 0, 0, 0, 63, 1, 0, 0, 0, 0, 65, 1, 0, 0, 0, 0, 67, 1, 0, 0, 0, 0, 69, 1, 0, 0, 0, 0, 71, 1, 0, 0, 0, 0, 73, 1, 0, 0, 0, 0, 75, 1, 0, 0, 0, 0, 77, 1, 0, 0, 0, 0, 79, 1, 0, 0, 0, 0, 81, 1, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 85, 1, 0, 0, 0, 0, 87, 1, 0, 0, 0, 0, 89, 1, 0, 0, 0, 0, 91, 1, 0, 0, 0, 0, 93, 1, 0, 0, 0, 0, 95, 1, 0, 0, 0, 0, 97, 1, 0, 0, 0, 0, 99, 1, 0, 0, 0, 0, 101, 1, 0, 0, 0, 0, 103, 1, 0, 0, 0, 1, 105, 1, 0, 0, 0, 1, 107, 1, 0, 0, 0, 1, 109, 1, 0, 0, 0, 1, 111, 1, 0, 0, 0, 1, 113, 1, 0, 0, 0, 1, 115, 1, 0, 0, 0, 1, 117, 1, 0, 0, 0, 2, 119, 1, 0, 0, 0, 2, 121, 1, 0, 0, 0, 2, 123, 1, 0, 0, 0, 3, 141, 1, 0, 0, 0, 5, 158, 1, 0, 0, 0, 7, 174, 1, 0, 0, 0, 9, 193, 1, 0, 0, 0, 11, 195, 1, 0, 0, 0, 13, 205, 1, 0, 0, 0, 15, 213, 1, 0, 0, 0, 17, 216, 1, 0, 0, 0, 19, 218, 1, 0, 0, 0, 21, 255, 1, 0, 0, 0, 23, 270, 1, 0, 0, 0, 25, 286, 1, 0, 0, 0, 27, 301, 1, 0, 0, 0, 29, 318, 1, 0, 0, 0, 31, 325, 1, 0, 0, 0, 33, 334, 1, 0, 0, 0, 35, 340, 1, 0, 0, 0, 37, 347, 1, 0, 0, 0, 39, 355, 1, 0, 0, 0, 41, 365, 1, 0, 0, 0, 43, 372, 1, 0, 0, 0, 45, 380, 1, 0, 0, 0, 47, 388, 1, 0, 0, 0, 49, 395, 1, 0, 0, 0, 51, 402, 1, 0, 0, 0, 53, 408, 1

_(report truncated; full output in workflow logs)_

The indexed-action walker must execute actions at committed positions without changing the parser behavior that selected the path.

Honor decision overrides and SLL mode, retain simulator-viable semantic configurations for predicate fallback (including predicates reached through rule calls), and preserve loop synchronization, translated action state, listeners, depth limits, init actions, and diagnostics.

Add focused runtime regressions and snapshot the affected diagnostics.
@tinovyatkin

Copy link
Copy Markdown
Contributor Author

@codex review

@coderabbitai coderabbitai Bot 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/parser.rs (1)

12657-12677: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fire the expansion exit event only after the depth probe succeeds.

The expansion path calls parse_listener_exit_rule at Line 12660, then probes the depth cap at Line 12661. If the probe returns an error, walk_rule returns Err, and parse_rule fires parse_listener_exit_rule again at Line 12585. A listener then receives two exit events for one enter event. The same imbalance occurs when parse_listener_enter_rule at Line 12674 returns a sticky abort.

Move the depth probe ahead of the exit dispatch so a rejected expansion leaves the enter/exit pairing intact.

🐛 Proposed reordering
-                self.parser.parse_listener_exit_rule(rule_index);
                 if let Some(error) = self.parser.rule_depth_cap_violation() {
                     return Err(error);
                 }
+                self.parser.parse_listener_exit_rule(rule_index);
                 self.parser.push_new_recursion_context_with_previous(
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/parser.rs` around lines 12657 - 12677, In the left-recursive expansion
block, probe rule_depth_cap_violation() before calling parse_listener_exit_rule.
Return the depth error immediately; only dispatch parse_listener_exit_rule after
the probe succeeds, and preserve the existing context push and
parse_listener_enter_rule flow so rejected expansions retain balanced listener
events.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/parser.rs`:
- Around line 12657-12677: In the left-recursive expansion block, probe
rule_depth_cap_violation() before calling parse_listener_exit_rule. Return the
depth error immediately; only dispatch parse_listener_exit_rule after the probe
succeeds, and preserve the existing context push and parse_listener_enter_rule
flow so rejected expansions retain balanced listener events.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 83b0d155-7b81-45e6-8064-933af6ea3038

📥 Commits

Reviewing files that changed from the base of the PR and between ad11db9 and da43783.

⛔ Files ignored due to path filters (3)
  • src/snapshots/antlr4_runtime__parser__tests__committed_predicate_star_loop_uses_single_token_deletion.snap is excluded by !**/*.snap
  • src/snapshots/antlr4_runtime__parser__tests__committed_walker_dispatches_recovery_diagnostics.snap is excluded by !**/*.snap
  • tests/snapshots/antlr4_rust_gen_cli__parser_action_hook_signature_conflict_diagnostic.snap is excluded by !**/*.snap
📒 Files selected for processing (3)
  • src/atn/parser.rs
  • src/parser.rs
  • tests/antlr4_rust_gen_cli.rs

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: da437838c5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/parser.rs Outdated
Comment thread src/parser.rs Outdated
Comment thread src/parser.rs Outdated
Comment thread src/parser.rs
Replace the committed parser's global work cap with a per-input ATN cycle guard so valid large loops remain unbounded while malformed non-consuming paths still terminate. Grow segmented stacks around committed child-rule descent to match generated dispatch behavior.

Track parameterized rule-call provenance internally for semantic candidates so prediction-visible callee predicates receive the same local arguments as committed descent. Reconcile adaptive diagnostics with the predicates that remain viable after semantic filtering.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8383a272ab

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/parser.rs Outdated
Comment thread src/bin/antlr4-rust-gen.rs
Probe the rule-depth cap before exiting the current left-recursive context. A rejected expansion now leaves parse-listener enter and exit events paired instead of emitting a second exit during outer rule cleanup.

Cover the depth-cap path with a listener-event snapshot regression.
@tinovyatkin

Copy link
Copy Markdown
Contributor Author

Addressed the outside-diff listener-balance finding in 3d6edf45.

The committed left-recursive walker now probes the rule-depth cap before emitting the current context's exit event, so a rejected expansion leaves the outer cleanup with exactly one matching exit. committed_left_recursive_depth_cap_keeps_listener_events_balanced snapshots the depth error and the enter:0, exit:0 sequence.

Validation: 367 runtime tests, 921 generator tests, 71 CLI tests, exact CI Clippy, and 357/357 upstream conformance cases.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3d6edf45d4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/bin/antlr4-rust-gen.rs Outdated
Comment thread src/parser.rs Outdated
Comment thread src/parser.rs
Offer rule-init events to semantic hooks at committed rule entry so indexed actions observe initialized state. Keep declined init events available for revision-1 generated source replay without treating them as dropped actions.

Allocate final typed-hook method names once per helper identity and add numeric disambiguation after predicate/action suffixing, so distinct helpers cannot collapse onto one trait method.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ba23d0091b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/bin/antlr4-rust-gen.rs Outdated

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/bin/antlr4-rust-gen.rs (1)

16454-16502: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Apply the same method-name collision fix to lexer typed hooks.

disambiguate_parser_typed_hook_names now tracks every assigned name in used and routes the final name through unique_typed_hook_method_name, so two distinct helpers that only collide after the _pred/_action suffix step (the exact scenario the new test typed_hook_action_method_names_remain_unique_after_suffixing covers) get disambiguated with a numeric suffix instead of producing two identical fn names.

lexer_typed_hook_mappings still uses the older approach: it only compares mapping.method_name against RESERVED_METHODS or against the pre-suffix predicate_names/action_names snapshot, with no final check against a running used set. Two distinct lexer helper names (for example one predicate/action pair whose name gets suffixed to foo_action, plus an unrelated helper whose Rust-sanitized name is already foo_action) can still collide and generate two identical method definitions in render_lexer_typed_hook_adapter's trait/adapter impl, which fails to compile.

Port the same allocated/used/unique_typed_hook_method_name pattern to the lexer path to close the same collision class there.

♻️ Suggested lexer-side fix
-    for mapping in &mut mappings {
-        if RESERVED_METHODS.contains(&mapping.method_name.as_str())
-            || (predicate_names.contains(&mapping.method_name)
-                && action_names.contains(&mapping.method_name))
-        {
-            mapping.method_name.push_str(match mapping.kind {
-                LexerTypedHookKind::Predicate => "_pred",
-                LexerTypedHookKind::Action => "_action",
-            });
-        }
-    }
+    let mut allocated = BTreeMap::<(LexerTypedHookKind, String), String>::new();
+    let mut used = BTreeSet::from(RESERVED_METHODS.map(str::to_owned));
+    for mapping in &mut mappings {
+        let helper = (mapping.kind, mapping.call.name.clone());
+        if let Some(method_name) = allocated.get(&helper) {
+            mapping.method_name.clone_from(method_name);
+            continue;
+        }
+        if RESERVED_METHODS.contains(&mapping.method_name.as_str())
+            || (predicate_names.contains(&mapping.method_name)
+                && action_names.contains(&mapping.method_name))
+        {
+            mapping.method_name.push_str(match mapping.kind {
+                LexerTypedHookKind::Predicate => "_pred",
+                LexerTypedHookKind::Action => "_action",
+            });
+        }
+        let method_name = unique_typed_hook_method_name(&mapping.method_name, &used);
+        used.insert(method_name.clone());
+        allocated.insert(helper, method_name.clone());
+        mapping.method_name = method_name;
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/bin/antlr4-rust-gen.rs` around lines 16454 - 16502, Update
lexer_typed_hook_mappings to track assigned method names in a running used set
and deduplicate each final name through unique_typed_hook_method_name, while
retaining allocated helper-name reuse and the existing predicate/action suffix
handling. Ensure distinct lexer helpers cannot receive the same post-suffix Rust
method name before render_lexer_typed_hook_adapter generates trait and adapter
methods.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/atn/parser.rs`:
- Around line 743-759: Keep track_prediction_rule_calls consistent for all
simulator instances sharing the same ATN cache and DFA entries. Update
new_shared and set_track_prediction_rule_calls so the tracking mode is
established in the shared store or included in the cache key, and cannot be
changed incompatibly by a later instance. Ensure shared entries either always
retain semantic_provenance or are isolated by tracking mode, preserving correct
semantic_context_matches behavior.

In `@src/parser.rs`:
- Around line 12898-12914: Gate the diagnostic.conflicting_alts loop in the
prediction handling block on self.parser.report_diagnostic_errors. Only evaluate
semantic_alternative_matches and populate semantic_results when diagnostic
reporting is enabled; preserve the existing alternative filtering and result
behavior within that condition.

In `@src/prediction.rs`:
- Around line 939-960: Prevent duplicate predicate provenance from being
appended by updating record_prediction_predicate in src/prediction.rs:939-960 to
skip entries matching the same rule_index, pred_index, and rule_calls, and
verify the corresponding key construction in src/atn/parser.rs:341-361 keeps
semantic_provenance out of termination-critical AtnConfigKey/ClosureConfigKey
values or relies on the deduplicated data; do not change the sibling site unless
required to enforce that key behavior.

---

Outside diff comments:
In `@src/bin/antlr4-rust-gen.rs`:
- Around line 16454-16502: Update lexer_typed_hook_mappings to track assigned
method names in a running used set and deduplicate each final name through
unique_typed_hook_method_name, while retaining allocated helper-name reuse and
the existing predicate/action suffix handling. Ensure distinct lexer helpers
cannot receive the same post-suffix Rust method name before
render_lexer_typed_hook_adapter generates trait and adapter methods.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1cf8fd9c-fc9c-47c1-9310-1dd54a686c4c

📥 Commits

Reviewing files that changed from the base of the PR and between da43783 and ba23d00.

⛔ Files ignored due to path filters (2)
  • src/bin/snapshots/antlr4_rust_gen__tests__typed_hook_action_method_names_remain_unique_after_suffixing.snap is excluded by !**/*.snap
  • src/snapshots/antlr4_runtime__parser__tests__committed_left_recursive_depth_cap_keeps_listener_events_balanced.snap is excluded by !**/*.snap
📒 Files selected for processing (4)
  • src/atn/parser.rs
  • src/bin/antlr4-rust-gen.rs
  • src/parser.rs
  • src/prediction.rs

Comment thread src/atn/parser.rs
Comment thread src/parser.rs Outdated
Comment thread src/prediction.rs Outdated
Honor action-index-specific assume overrides when deciding whether generated parser actions should dispatch hooks. Thread parameterized rule arguments through both generated and interpreted committed action contexts, and propagate descendant EOF consumption into parent rule boundaries.

Bump the generated-code API to revision 3 because newly generated parameterized-action calls require the new runtime hook, while retaining revisions 1 and 2. Regenerate checked-in recognizers, compatibility snapshots, and the self-hosted frontend hashes.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 307963d959

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/bin/antlr4-rust-gen.rs Outdated
Comment thread src/parser.rs
Comment thread src/parser.rs Outdated
Prevent adaptive ATN retries from replaying effectful generated actions by excluding action-owning rules and their transitive callers while keeping synthetic no-op actions eligible.

Keep shared DFA entries in a fixed untracked provenance mode, skip diagnostic-only predicates when reporting is disabled, and deduplicate predicate provenance so closure keys remain bounded.

@coderabbitai coderabbitai Bot 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/bin/antlr4-rust-gen.rs (1)

6444-6497: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Compute effectful_action_states once and pass it down.

render_generated_rule_routing (Lines 6444-6447) and render_generated_rule_dispatch_with_rule_names (Lines 6488-6491) each derive effectful_action_states from inline_action_statements with the identical filter, and the former calls the latter. Compute the set once in render_generated_rule_routing and pass it as a parameter to render_generated_rule_dispatch_with_rule_names instead of recomputing it.

This removes duplicate logic on a correctness-sensitive path (adaptive-retry exclusion for effectful actions). A future edit to one filter without the other would silently desynchronize the two computations.

♻️ Proposed refactor
 fn render_generated_rule_routing(
     rules: &[Option<GeneratedParserRule>],
     rule_names: &[String],
     inline_action_statements: &BTreeMap<usize, String>,
     track_alt_numbers: bool,
     track_context_alt_numbers: bool,
     embedded: Option<EmbeddedStepRender<'_>>,
     portable_locals: Option<PortableLocalStepRender<'_>>,
     decision_routing: DecisionRoutingRender<'_>,
 ) -> (String, usize) {
     let direct_generated_rule_calls = rules.iter().map(Option::is_some).collect::<Vec<_>>();
     let effectful_action_states = inline_action_statements
         .iter()
         .filter_map(|(state, statement)| (!statement.trim().is_empty()).then_some(*state))
         .collect::<BTreeSet<_>>();
     let preferred_rule_count = generated_adaptive_atn_preferred_rule_count(
         rules,
         embedded.is_some(),
         portable_locals.map(|portable| portable.required_generated_rules),
         &effectful_action_states,
     );
     let dispatch = render_generated_rule_dispatch_with_rule_names(
         rules,
         &direct_generated_rule_calls,
         rule_names,
         inline_action_statements,
+        &effectful_action_states,
         track_alt_numbers,
         track_context_alt_numbers,
         embedded,
         portable_locals,
         decision_routing,
     );
     (dispatch, preferred_rule_count)
 }

 fn render_generated_rule_dispatch_with_rule_names(
     rules: &[Option<GeneratedParserRule>],
     direct_generated_rule_calls: &[bool],
     rule_names: &[String],
     inline_action_statements: &BTreeMap<usize, String>,
+    effectful_action_states: &BTreeSet<usize>,
     track_alt_numbers: bool,
     track_context_alt_numbers: bool,
     embedded: Option<EmbeddedStepRender<'_>>,
     portable_locals: Option<PortableLocalStepRender<'_>>,
     decision_routing: DecisionRoutingRender<'_>,
 ) -> String {
     ...
-    let effectful_action_states = inline_action_statements
-        .iter()
-        .filter_map(|(state, statement)| (!statement.trim().is_empty()).then_some(*state))
-        .collect::<BTreeSet<_>>();
     let adaptive_atn_routing = generated_adaptive_atn_routing_excluding(
         rules,
         &force_generated_rules,
-        &effectful_action_states,
+        effectful_action_states,
     );

Note: other direct callers of render_generated_rule_dispatch_with_rule_names (e.g. test helpers) would need an added effectful_action_states argument (an empty &BTreeSet::new() where actions are irrelevant to the test).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/bin/antlr4-rust-gen.rs` around lines 6444 - 6497, Compute
effectful_action_states once in render_generated_rule_routing, then pass a
reference to that set into render_generated_rule_dispatch_with_rule_names.
Remove the duplicate filter and local set construction from the dispatch
function, and update all other callers, including test helpers, to provide the
appropriate set or an empty BTreeSet where actions are irrelevant.
src/atn/parser.rs (1)

1219-1232: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reuse record_prediction_semantic_candidates instead of re-deriving the same lookup.

Lines 1226-1232 duplicate the exact logic of record_prediction_semantic_candidates (defined a few lines above at 1339-1346 and already called at Line 1219 for the non-greedy-exit branch): look up self.store.decision_to_dfa.get(decision), map to semantic_prediction_candidates(dfa.configs(state_number)), and assign to self.prediction_semantic_candidates. Call the existing helper here too, to avoid two copies of this lookup diverging later.

♻️ Proposed refactor
         let Some(info) = self.dfa_prediction_info(decision, state_number) else {
             return Ok(None);
         };
         let prediction = info.prediction;
-        let semantic_candidates = self
-            .store
-            .decision_to_dfa
-            .get(decision)
-            .map(|dfa| semantic_prediction_candidates(dfa.configs(state_number)))
-            .unwrap_or_default();
-        self.prediction_semantic_candidates = semantic_candidates;
+        self.record_prediction_semantic_candidates(decision, state_number);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/atn/parser.rs` around lines 1219 - 1232, Replace the duplicated
semantic-candidate lookup after obtaining dfa_prediction_info with a call to
record_prediction_semantic_candidates(decision, state_number). Keep the existing
prediction extraction and return behavior unchanged, relying on the helper to
update self.prediction_semantic_candidates.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/atn/parser.rs`:
- Around line 1219-1232: Replace the duplicated semantic-candidate lookup after
obtaining dfa_prediction_info with a call to
record_prediction_semantic_candidates(decision, state_number). Keep the existing
prediction extraction and return behavior unchanged, relying on the helper to
update self.prediction_semantic_candidates.

In `@src/bin/antlr4-rust-gen.rs`:
- Around line 6444-6497: Compute effectful_action_states once in
render_generated_rule_routing, then pass a reference to that set into
render_generated_rule_dispatch_with_rule_names. Remove the duplicate filter and
local set construction from the dispatch function, and update all other callers,
including test helpers, to provide the appropriate set or an empty BTreeSet
where actions are irrelevant.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 599d0f37-321f-44a8-8a34-04975bc5687b

📥 Commits

Reviewing files that changed from the base of the PR and between ba23d00 and 3360973.

⛔ Files ignored due to path filters (11)
  • docs/migration.md is excluded by !**/docs/**
  • src/bin/snapshots/antlr4_rust_gen__tests__generated_module_file_header.snap is excluded by !**/*.snap
  • src/bin_support/grammar/generated/antlr_v4_lexer.rs is excluded by !**/generated/**
  • src/bin_support/grammar/generated/antlr_v4_parser.rs is excluded by !**/generated/**
  • src/bin_support/rust_syntax/generated/rust_lexer.rs is excluded by !**/generated/**
  • src/bin_support/rust_syntax/generated/rust_parser.rs is excluded by !**/generated/**
  • src/bin_support/rust_syntax/generated/semantics.json is excluded by !**/generated/**
  • src/xpath/generated/x_path_lexer.rs is excluded by !**/generated/**
  • tests/snapshots/antlr4_rust_gen_cli__generated_codegen_api_checks.snap is excluded by !**/*.snap
  • tests/snapshots/antlr4_rust_gen_cli__generated_codegen_api_mismatch_diagnostic.snap is excluded by !**/*.snap
  • tests/snapshots/antlr4_rust_gen_cli__named_parser_actions_semantics_manifest.snap is excluded by !**/*.snap
📒 Files selected for processing (10)
  • README.md
  • src/atn/parser.rs
  • src/bin/antlr4-rust-gen.rs
  • src/lib.rs
  • src/parser.rs
  • src/prediction.rs
  • tests/antlr4_rust_gen_cli.rs
  • tests/fixtures/antlr4-rust-gen/parser-action-hooks/ActionTiming.g4
  • tests/fixtures/antlr4-rust-gen/parser-action-hooks/patterns.toml
  • third_party/antlr-v4-grammar/self-hosted.sha256

Pass rule arguments through every committed fallback so action hooks retain parameterized-rule locals. Scope unresolved action hits around nested committed parses, and prioritize and drain sticky parser aborts before semantic misses in both runtime and generated entry paths.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 50e4fa2be1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/parser.rs
Comment thread src/parser.rs Outdated
Clear fail-loud semantic hits once a top-level committed entry returns their error so parser reuse starts clean. Notify error listeners for unrecovered committed bail failures only after parser-abort and semantic-error precedence has been resolved.
Intern rule-call and predicate provenance once per committed simulator and carry compact IDs through ATN configurations instead of Arc-backed paths. Pack precedence suppression into the same word and expand predicate calls only after prediction commits, keeping ordinary parser configs and closure keys small.

Preserve distinct provenance variants during config merging and reject tracking-mode changes after real DFA learning. Fresh precedence DFAs remain configurable because their synthetic start state is not learned prediction state.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3a58cd75c0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/bin/antlr4-rust-gen.rs

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/bin/antlr4-rust-gen.rs (1)

6432-6497: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Deduplicate the effectful_action_states computation.

render_generated_rule_routing (Line 6444) and render_generated_rule_dispatch_with_rule_names (Line 6488) each independently derive effectful_action_states from inline_action_statements with the identical filter expression. render_generated_rule_routing uses its copy to compute preferred_rule_count (which sizes the adaptive-retry slot arrays emitted on the parser struct), while render_generated_rule_dispatch_with_rule_names uses its own copy to assign the actual adaptive_atn_preferred_rule_slots indices used inside the dispatch body.

Today both copies are pure functions of the same inline_action_statements input, so they agree. But if a future change adjusts the filter in one place without updating the other, the emitted slot-array size and the slot indices used to index it could disagree, causing an out-of-bounds panic in generated code. Compute effectful_action_states once in render_generated_rule_routing and pass it into render_generated_rule_dispatch_with_rule_names instead of recomputing it.

♻️ Proposed refactor sketch
 fn render_generated_rule_routing(
     rules: &[Option<GeneratedParserRule>],
     rule_names: &[String],
     inline_action_statements: &BTreeMap<usize, String>,
     ...
 ) -> (String, usize) {
     let direct_generated_rule_calls = rules.iter().map(Option::is_some).collect::<Vec<_>>();
     let effectful_action_states = inline_action_statements
         .iter()
         .filter_map(|(state, statement)| (!statement.trim().is_empty()).then_some(*state))
         .collect::<BTreeSet<_>>();
     let preferred_rule_count = generated_adaptive_atn_preferred_rule_count(
         rules,
         embedded.is_some(),
         portable_locals.map(|portable| portable.required_generated_rules),
         &effectful_action_states,
     );
-    let dispatch = render_generated_rule_dispatch_with_rule_names(
-        rules,
-        &direct_generated_rule_calls,
-        rule_names,
-        inline_action_statements,
-        ...
-    );
+    let dispatch = render_generated_rule_dispatch_with_rule_names(
+        rules,
+        &direct_generated_rule_calls,
+        rule_names,
+        inline_action_statements,
+        &effectful_action_states,
+        ...
+    );
     (dispatch, preferred_rule_count)
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/bin/antlr4-rust-gen.rs` around lines 6432 - 6497, Compute
effectful_action_states once in render_generated_rule_routing using the existing
filter, then add a parameter to render_generated_rule_dispatch_with_rule_names
and pass that set through when invoking it. Remove the duplicate local
computation in render_generated_rule_dispatch_with_rule_names and use the passed
set for adaptive_atn_routing.
src/atn/parser.rs (1)

1261-1267: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Reuse record_prediction_semantic_candidates in prediction_or_full_context.

Lines 1261-1267 duplicate the body of record_prediction_semantic_candidates. Call the helper instead to keep one code path for recording DFA candidates.

♻️ Proposed refactor
         let prediction = info.prediction;
-        let semantic_candidates = self
-            .store
-            .decision_to_dfa
-            .get(decision)
-            .map(|dfa| semantic_prediction_candidates(dfa.configs(state_number)))
-            .unwrap_or_default();
-        self.prediction_semantic_candidates = semantic_candidates;
+        self.record_prediction_semantic_candidates(decision, state_number);

Also applies to: 1374-1381

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/atn/parser.rs` around lines 1261 - 1267, In prediction_or_full_context,
replace the duplicated decision_to_dfa lookup and assignment with a call to
record_prediction_semantic_candidates, passing the same decision and state
information required by the helper. Apply the same reuse at the corresponding
duplicate block around the other reported location, preserving the existing
candidate-recording behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/atn/parser.rs`:
- Around line 779-790: The set_track_prediction_rule_calls method should permit
no-op calls on shared simulators while still rejecting attempts to enable
tracking. Gate the shared_cache_key assertion on track_prediction_rule_calls !=
track, preserving the existing post-DFA mode-change assertion and assignment
behavior.

In `@src/prediction.rs`:
- Around line 880-884: Update PredictionSemanticProvenanceArena and its intern
method to avoid retaining each provenance twice: key interner by a hash of the
provenance with the record index as the value, or share the stored record
through Rc between records and interner. Preserve deduplication and returned
PredictionSemanticProvenanceId behavior.
- Around line 1134-1149: Update config_index and its add/remap_contexts usage to
key entries by the tuple (AtnConfigKey, PredictionSemanticProvenanceId),
allowing direct O(1) lookup for each provenance. In add, remove the fallback
linear scan and indexed-only insertion special case, and update entries for the
resolved config directly; in remap_contexts, replace the matching or_insert
behavior with tuple-keyed insertion. Remove the now-unused key.matches helper.

---

Outside diff comments:
In `@src/atn/parser.rs`:
- Around line 1261-1267: In prediction_or_full_context, replace the duplicated
decision_to_dfa lookup and assignment with a call to
record_prediction_semantic_candidates, passing the same decision and state
information required by the helper. Apply the same reuse at the corresponding
duplicate block around the other reported location, preserving the existing
candidate-recording behavior.

In `@src/bin/antlr4-rust-gen.rs`:
- Around line 6432-6497: Compute effectful_action_states once in
render_generated_rule_routing using the existing filter, then add a parameter to
render_generated_rule_dispatch_with_rule_names and pass that set through when
invoking it. Remove the duplicate local computation in
render_generated_rule_dispatch_with_rule_names and use the passed set for
adaptive_atn_routing.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 20768c3a-c30c-4414-a8d3-6f93322eed27

📥 Commits

Reviewing files that changed from the base of the PR and between 3360973 and 3a58cd7.

⛔ Files ignored due to path filters (3)
  • src/bin_support/grammar/generated/antlr_v4_parser.rs is excluded by !**/generated/**
  • src/bin_support/rust_syntax/generated/rust_parser.rs is excluded by !**/generated/**
  • src/snapshots/antlr4_runtime__parser__tests__committed_bail_error_notifies_error_listener.snap is excluded by !**/*.snap
📒 Files selected for processing (5)
  • src/atn/parser.rs
  • src/bin/antlr4-rust-gen.rs
  • src/parser.rs
  • src/prediction.rs
  • third_party/antlr-v4-grammar/self-hosted.sha256

Comment thread src/atn/parser.rs
Comment thread src/prediction.rs
Comment thread src/prediction.rs Outdated
Pass parser action indexes into portable boolean lowering so coordinate-specific assume and hook overrides suppress generated assignments before routing. Cover both assume policies and hook disposition with a focused regression test.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fc9efca7cc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/bin/antlr4-rust-gen.rs Outdated
Store semantic provenance once in hash-bucket collision chains instead of duplicating owned records in interner keys. Include the compact provenance ID in ATN config keys so tracked insertion stays O(1) while preserving distinct prediction paths.
Derive parameterized rules from grammar declarations so named action hook signatures stay local-aware even when call arguments are not literals. Forward a caller's declared argument by its grammar name and reject unsupported expressions instead of silently omitting them.

Cover generic forwarding through generated and interpreted parser paths and pin the fail-loud diagnostic.
@tinovyatkin
tinovyatkin merged commit dee1944 into main Aug 3, 2026
12 of 15 checks passed
@tinovyatkin
tinovyatkin deleted the issue-266-named-parser-actions branch August 3, 2026 07:16
@ophiarch ophiarch Bot mentioned this pull request Aug 3, 2026
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.

codegen: route named parser actions through typed hooks at committed positions

1 participant