feat(codegen): run named parser actions at committed positions - #287
Conversation
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.
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe 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. ChangesParser action pipeline
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
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
|
I'll analyze this and get back to you. |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
📊 Source Code Metrics (this PR vs
|
| 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.
There was a problem hiding this comment.
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
⛔ Files ignored due to path filters (12)
docs/migration.mdis excluded by!**/docs/**src/bin/snapshots/antlr4_rust_gen__tests__generated_decision_does_not_hoist_portable_predicate_past_local_action.snapis excluded by!**/*.snapsrc/bin/snapshots/antlr4_rust_gen__tests__generated_module_file_header.snapis excluded by!**/*.snapsrc/bin_support/grammar/generated/antlr_v4_lexer.rsis excluded by!**/generated/**src/bin_support/grammar/generated/antlr_v4_parser.rsis excluded by!**/generated/**src/bin_support/rust_syntax/generated/rust_lexer.rsis excluded by!**/generated/**src/bin_support/rust_syntax/generated/rust_parser.rsis excluded by!**/generated/**src/xpath/generated/x_path_lexer.rsis excluded by!**/generated/**tests/snapshots/antlr4_rust_gen_cli__antlr4rust_compat_semantics_manifest.snapis excluded by!**/*.snaptests/snapshots/antlr4_rust_gen_cli__generated_codegen_api_checks.snapis excluded by!**/*.snaptests/snapshots/antlr4_rust_gen_cli__generated_codegen_api_mismatch_diagnostic.snapis excluded by!**/*.snaptests/snapshots/antlr4_rust_gen_cli__named_parser_actions_semantics_manifest.snapis excluded by!**/*.snap
📒 Files selected for processing (7)
README.mdsrc/bin/antlr4-rust-gen.rssrc/lib.rssrc/parser.rstests/antlr4_rust_gen_cli.rstests/fixtures/antlr4-rust-gen/parser-action-hooks/ActionTiming.g4tests/fixtures/antlr4-rust-gen/parser-action-hooks/patterns.toml
There was a problem hiding this comment.
💡 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".
Copy/Paste DetectionFound 3169 duplication(s) across 11 changed Rust file(s) (threshold: 100 tokens). Show duplicationsFound a 364 line (1962 tokens) duplication in the following files:
&[None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, 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:
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:
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:
&["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:
&[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.
|
@codex review |
There was a problem hiding this comment.
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 winFire the expansion exit event only after the depth probe succeeds.
The expansion path calls
parse_listener_exit_ruleat Line 12660, then probes the depth cap at Line 12661. If the probe returns an error,walk_rulereturnsErr, andparse_rulefiresparse_listener_exit_ruleagain at Line 12585. A listener then receives two exit events for one enter event. The same imbalance occurs whenparse_listener_enter_ruleat 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
⛔ Files ignored due to path filters (3)
src/snapshots/antlr4_runtime__parser__tests__committed_predicate_star_loop_uses_single_token_deletion.snapis excluded by!**/*.snapsrc/snapshots/antlr4_runtime__parser__tests__committed_walker_dispatches_recovery_diagnostics.snapis excluded by!**/*.snaptests/snapshots/antlr4_rust_gen_cli__parser_action_hook_signature_conflict_diagnostic.snapis excluded by!**/*.snap
📒 Files selected for processing (3)
src/atn/parser.rssrc/parser.rstests/antlr4_rust_gen_cli.rs
There was a problem hiding this comment.
💡 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".
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.
There was a problem hiding this comment.
💡 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".
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.
|
Addressed the outside-diff listener-balance finding in 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. Validation: 367 runtime tests, 921 generator tests, 71 CLI tests, exact CI Clippy, and 357/357 upstream conformance cases. |
There was a problem hiding this comment.
💡 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".
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.
There was a problem hiding this comment.
💡 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".
There was a problem hiding this comment.
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 winApply the same method-name collision fix to lexer typed hooks.
disambiguate_parser_typed_hook_namesnow tracks every assigned name inusedand routes the final name throughunique_typed_hook_method_name, so two distinct helpers that only collide after the_pred/_actionsuffix step (the exact scenario the new testtyped_hook_action_method_names_remain_unique_after_suffixingcovers) get disambiguated with a numeric suffix instead of producing two identicalfnnames.
lexer_typed_hook_mappingsstill uses the older approach: it only comparesmapping.method_nameagainstRESERVED_METHODSor against the pre-suffixpredicate_names/action_namessnapshot, with no final check against a runningusedset. Two distinct lexer helper names (for example one predicate/action pair whose name gets suffixed tofoo_action, plus an unrelated helper whose Rust-sanitized name is alreadyfoo_action) can still collide and generate two identical method definitions inrender_lexer_typed_hook_adapter's trait/adapter impl, which fails to compile.Port the same
allocated/used/unique_typed_hook_method_namepattern 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
⛔ Files ignored due to path filters (2)
src/bin/snapshots/antlr4_rust_gen__tests__typed_hook_action_method_names_remain_unique_after_suffixing.snapis excluded by!**/*.snapsrc/snapshots/antlr4_runtime__parser__tests__committed_left_recursive_depth_cap_keeps_listener_events_balanced.snapis excluded by!**/*.snap
📒 Files selected for processing (4)
src/atn/parser.rssrc/bin/antlr4-rust-gen.rssrc/parser.rssrc/prediction.rs
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.
There was a problem hiding this comment.
💡 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".
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.
There was a problem hiding this comment.
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 winCompute
effectful_action_statesonce and pass it down.
render_generated_rule_routing(Lines 6444-6447) andrender_generated_rule_dispatch_with_rule_names(Lines 6488-6491) each deriveeffectful_action_statesfrominline_action_statementswith the identical filter, and the former calls the latter. Compute the set once inrender_generated_rule_routingand pass it as a parameter torender_generated_rule_dispatch_with_rule_namesinstead 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 addedeffectful_action_statesargument (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 winReuse
record_prediction_semantic_candidatesinstead 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 upself.store.decision_to_dfa.get(decision), map tosemantic_prediction_candidates(dfa.configs(state_number)), and assign toself.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
⛔ Files ignored due to path filters (11)
docs/migration.mdis excluded by!**/docs/**src/bin/snapshots/antlr4_rust_gen__tests__generated_module_file_header.snapis excluded by!**/*.snapsrc/bin_support/grammar/generated/antlr_v4_lexer.rsis excluded by!**/generated/**src/bin_support/grammar/generated/antlr_v4_parser.rsis excluded by!**/generated/**src/bin_support/rust_syntax/generated/rust_lexer.rsis excluded by!**/generated/**src/bin_support/rust_syntax/generated/rust_parser.rsis excluded by!**/generated/**src/bin_support/rust_syntax/generated/semantics.jsonis excluded by!**/generated/**src/xpath/generated/x_path_lexer.rsis excluded by!**/generated/**tests/snapshots/antlr4_rust_gen_cli__generated_codegen_api_checks.snapis excluded by!**/*.snaptests/snapshots/antlr4_rust_gen_cli__generated_codegen_api_mismatch_diagnostic.snapis excluded by!**/*.snaptests/snapshots/antlr4_rust_gen_cli__named_parser_actions_semantics_manifest.snapis excluded by!**/*.snap
📒 Files selected for processing (10)
README.mdsrc/atn/parser.rssrc/bin/antlr4-rust-gen.rssrc/lib.rssrc/parser.rssrc/prediction.rstests/antlr4_rust_gen_cli.rstests/fixtures/antlr4-rust-gen/parser-action-hooks/ActionTiming.g4tests/fixtures/antlr4-rust-gen/parser-action-hooks/patterns.tomlthird_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.
There was a problem hiding this comment.
💡 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".
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.
There was a problem hiding this comment.
💡 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".
There was a problem hiding this comment.
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 winDeduplicate the
effectful_action_statescomputation.
render_generated_rule_routing(Line 6444) andrender_generated_rule_dispatch_with_rule_names(Line 6488) each independently deriveeffectful_action_statesfrominline_action_statementswith the identical filter expression.render_generated_rule_routinguses its copy to computepreferred_rule_count(which sizes the adaptive-retry slot arrays emitted on the parser struct), whilerender_generated_rule_dispatch_with_rule_namesuses its own copy to assign the actualadaptive_atn_preferred_rule_slotsindices used inside the dispatch body.Today both copies are pure functions of the same
inline_action_statementsinput, 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. Computeeffectful_action_statesonce inrender_generated_rule_routingand pass it intorender_generated_rule_dispatch_with_rule_namesinstead 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 valueReuse
record_prediction_semantic_candidatesinprediction_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
⛔ Files ignored due to path filters (3)
src/bin_support/grammar/generated/antlr_v4_parser.rsis excluded by!**/generated/**src/bin_support/rust_syntax/generated/rust_parser.rsis excluded by!**/generated/**src/snapshots/antlr4_runtime__parser__tests__committed_bail_error_notifies_error_listener.snapis excluded by!**/*.snap
📒 Files selected for processing (5)
src/atn/parser.rssrc/bin/antlr4-rust-gen.rssrc/parser.rssrc/prediction.rsthird_party/antlr-v4-grammar/self-hosted.sha256
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.
There was a problem hiding this comment.
💡 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".
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.

Summary
[[helper]] kind = "parser-action"calls to stable named typed-hook methods keyed by grammar action coordinatesassume-*andhookaction overrides before portable boolean lowering and propagate descendant EOF boundaries into parent contextsCompatibility
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:All five comparisons pass the CI
1.15xregression 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 warningscargo fmt --all -- --check--features codegen1.15xthresholdFixes #266