fix(codegen): union token sets for a group label shared across alternatives - #211
Conversation
…atives
A token-group label used in multiple alternatives of the same rule
(CEL's calc: 'calc op=('*'|'/'|'%') calc | calc op=('+'|'-') calc')
was silently dropped because context_label_accessor required every
declaration to carry an identical token set. ANTLR declares a single
Token op field for this shape, so union the per-alternative sets and
emit one accessor matching the union; per-alternative selector checks
still reject layouts where a single occurrence lookup cannot serve
every alternative, and an optional labeled occurrence that a later
union member could shadow now opts out instead of misresolving.
Fixes #205
Copy/Paste DetectionFound 1 duplication(s) across 2 changed Rust file(s) (threshold: 100 tokens). Show duplicationsFound a 22 line (132 tokens) duplication in the following files:
"parser grammar Delegate;\ndelegated: {isTypeName()}? ID;\n",
)
.expect("delegate grammar should be writable");
fs::write(&tokens, "lexer grammar Tokens;\nID: [a-z]+;\n")
.expect("token grammar should be writable");
let output = run_antlr4_rust_gen(&[
root.as_os_str(),
tokens.as_os_str(),
OsStr::new("-I"),
temp.path().as_os_str(),
OsStr::new("--out-dir"),
out.as_os_str(),
]);
assert!(
output.status.success(),
"stdout: {}\nstderr: {}",
utf8(&output.stdout),
utf8(&output.stderr)
);
let parser = fs::read_to_string(out.join("root.rs")).expect("parser should be emitted");
assert!(parser.contains("pub trait RootHooks"), "{parser}");
```rust
</details> |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThe generator now unions compatible token-backed labels across alternatives and suppresses shadowed accessors for absent optional labels. New grammar, unit, and CLI integration tests validate shared operator accessors and token selection. ChangesToken-group accessor generation
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant Grammar
participant Generator
participant GeneratedParser
participant IntegrationTest
Grammar->>Generator: generate lexer and parser
Generator->>GeneratedParser: emit unioned op() accessors
IntegrationTest->>GeneratedParser: parse expression input
GeneratedParser->>IntegrationTest: return operator labels
Possibly related issues
🚥 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 |
|
Claude encountered an error after 7m 31s —— View job Code review — PR #211
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@tests/antlr4_rust_gen_cli.rs`:
- Around line 461-530: Extend the fixture grammar used by
token_group_label_shared_across_alternatives_unions_the_sets with a rule such as
shadowed: x=IDENT? IDENT; and update the generated-output assertion to cover it.
Verify the generated parser omits the unsafe x() accessor for the optional
labeled occurrence, exercising the shadowed_when_absent guard while preserving
the existing alternative-label assertions.
🪄 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: bd07fbef-e6db-4293-b41a-96376271803a
📒 Files selected for processing (3)
src/bin/antlr4-rust-gen.rstests/antlr4_rust_gen_cli.rstests/fixtures/antlr4-rust-gen/multi-alternative-label/T.g4
📊 Source Code Metrics (this PR vs
|
| File | Cyclomatic | Cognitive | Functions | LLOC | MI |
|---|---|---|---|---|---|
| src/bin/antlr4-rust-gen.rs | 2257 (main: 2250) 🔴 | 1418 (main: 1415) 🔴 | 500 (main: 499) 🔴 | 3953 (main: 3944) 🔴 | 0 ⚪ |
Generated by mehen v1.7.0 — the code quality watcher.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c46ce694d3
ℹ️ 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".
…review - Snapshot CalcContext (union accessor over both operator groups) and ShadowedContext (lead=PLUS? PLUS drops lead()) via the in-crate render_parser pattern, covering the shadowed_when_absent branch that also removes previously-emitted unsafe accessors for x=A? A shapes: with x absent, .nth(0) returned the unlabeled following token instead of None, so those accessors misresolved on every parse. - Reword the union comment generically per AGENTS.md codegen boundary (no language-specific rule shapes in antlr4-rust-gen.rs). - Drop the unreachable non-shared-target arm: target is only rendered for rule-backed labels, where the guard already forces one target.
|
Review round addressed in d079735 + follow-up issues: Fixed in d079735
Follow-up issues filed
No action
Local validation after the changes: |

Summary
Fixes #205 — a token-group label used in multiple alternatives of the same rule got no accessor. In the CEL grammar (cel-go's CEL.g4):
RelationContext(label in one alternative) gotop(), butCalcContextsilently lost it:context_label_accessorrequired every declaration of a label to carry an identical token set (same_context_ref_target), and the two operator groups differ. Java ANTLR declares a singleToken opfield for this shape regardless of per-alternative grouping — parity target is accessor presence.Fix
ElementRefand thread it through the existing per-alternative selector checks (occurrence position, cardinality, no-following-match). Those checks still reject layouts where a single occurrence lookup cannot serve every alternative. Rule-reference labels keep requiring one shared target (the feat(codegen): emit typed accessors for labeled token groups and same-rule label mixes #201 same-rule label-mix shapes are out of scope here).shadowed_when_absentguard incontext_label_selector: an optional labeled token that a later union-matching element could slide into when absent now drops the accessor instead of misresolving — closes the correctness hole the wider union would otherwise open.Generated result for the CEL shape:
Option(notResult) because the label is absent on the non-operator alternative.Validation
token_group_label_shared_across_alternatives_unions_the_setswith a CEL-shapedrelation/calcfixture:op()exists on both contexts; parsinga * b + c < dreads<,+,*through.op()at each tree level,Noneon the primary alternative.op()now emitted on Expr/Relation/Calc contexts; scratch crate parsinga * 2 + 1 < bpasses. cel-rust's hand-rolledbinary_operator_token()workaround becomes unnecessary.cargo test --locked --features codegen: 1076 tests pass.cargo clippy --locked --all-targets --all-features -- -D warnings: clean.Summary by CodeRabbit
Bug Fixes
Tests