Skip to content

feat(codegen)!: centralize recognizer facades - #300

Merged
tinovyatkin merged 2 commits into
mainfrom
issue-278-recognizer-facades
Aug 4, 2026
Merged

feat(codegen)!: centralize recognizer facades#300
tinovyatkin merged 2 commits into
mainfrom
issue-278-recognizer-facades

Conversation

@tinovyatkin

@tinovyatkin tinovyatkin commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Closes #278.

Summary

  • Move stable generated lexer/parser facade methods and trait delegation into
    doc-hidden runtime macros while keeping grammar-specific metadata, semantic
    dispatch, typed hooks, and optional parser state in generated modules.
  • Preserve the existing concrete recognizer APIs and behavior without wildcard
    imports or blanket implementations; qualify macro-owned paths so invocation
    site names cannot shadow support code.
  • Increment the generated-code API from revision 4 to 5, retain revisions 1
    through 4, and update checked-in recognizers, compatibility tests, snapshots,
    hashes, and migration documentation.

Measured Impact

Representative output Baseline Current Change
Lexer-only lines 231 128 -44.59%
Lexer-only bytes 12,544 9,168 -26.91%
Parser-only lines 13,723 13,509 -1.56%
Parser-only bytes 758,811 750,574 -1.09%
Combined-grammar lines 53,224 52,907 -0.60%
Combined-grammar bytes 3,742,214 3,730,610 -0.31%
Release generator bytes 11,617,920 11,601,408 -0.142%

Warm cargo check --locked --quiet -p antlr-rust-g4-parser samples were
0.11/0.21/0.17/0.15s before and 0.10/0.08/0.07/0.08s after. These short
samples are reported separately as requested; this PR does not claim a
compile-time improvement from source compaction.

Validation

  • cargo test --locked --workspace --all-features
  • cargo clippy --locked --workspace --all-targets --all-features -- -D warnings
  • cargo fmt --all -- --check
  • ANTLRv4 Stage 1/Stage 2 fixed point plus frontend corpus checks
  • Rust syntax checked-in recognizer regeneration
  • Kotlin parity: 9/9 fixtures
  • JavaScript parity: 6/6 fixtures
  • TypeScript parity: 5/5 fixtures
  • Upstream ANTLR runtime testsuite: 357 passed, 0 failed, 0 skipped
  • git diff --check

Summary by CodeRabbit

  • New Features

    • Added runtime-supported lexer and parser facades for generated Rust code.
    • Generated recognizers now receive standardized lifecycle, metadata, token, listener, and parser APIs.
  • Compatibility

    • Updated the code-generation API to revision 5.
    • Runtime compatibility now supports generated revisions 1–5.
  • Documentation

    • Updated compatibility guidance for generated sources and runtime support.
  • Tests

    • Expanded validation and snapshots for facade-based generated lexers and parsers.

Move grammar-independent generated lexer and parser facade methods and trait
delegation behind doc-hidden runtime macros. Generated modules now declare
their concrete recognizer types, storage fields, metadata/ATN providers,
semantic token dispatch, and optional reset state while the runtime owns the
stable forwarding implementation.

Keep generated imports explicit, qualify macro-owned paths through $crate or
the standard-library roots, and emit concrete implementations rather than
blanket trait impls. Preserve constructors, typed hooks, listener management,
stream/tree accessors, DFA controls, semantic dispatch, and parser
configuration behavior.

Bump the generated-code API to revision 5 because newly generated recognizers
require the facade macros. Keep revisions 1 through 4 accepted while their
runtime surfaces remain available, and regenerate checked-in recognizers,
compatibility snapshots, and documentation.

Representative generated source drops by 3,376 bytes for a lexer-only
grammar, 8,237 bytes for a parser-only grammar, and 11,604 bytes for the
combined Rust grammar. The release generator binary is 16,512 bytes smaller;
warm package-check samples are reported separately without claiming a
compile-time improvement from source compaction.
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@tinovyatkin, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 49 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8a9f945d-c814-4aff-b15b-e9b52f7da8a1

📥 Commits

Reviewing files that changed from the base of the PR and between 2652a5d and 4daafbd.

📒 Files selected for processing (1)
  • crates/antlr-rust-runtime/src/generated.rs
📝 Walkthrough

Walkthrough

The runtime now owns shared lexer and parser facade implementations. Generated recognizers invoke runtime macros for trait delegation and lifecycle APIs. The generated-code API revision advances to 5, with updated compatibility checks, snapshots, documentation, and checked-in grammar hashes.

Changes

Recognizer facade migration

Layer / File(s) Summary
Runtime facade contracts
crates/antlr-rust-runtime/src/generated.rs, crates/antlr-rust-runtime/src/lib.rs
Added exported lexer and parser facade macros for shared metadata, lifecycle, accessor, and trait delegation behavior. Updated the compatibility revision to 5 and added macro hygiene coverage.
Generated lexer integration
crates/antlr-rust-codegen/src/lexer/render.rs
Replaced manual lexer implementations with __antlr4_rust_lexer_facade!. Generated tokenization now uses the facade’s lexer.base binding.
Generated parser integration
crates/antlr-rust-codegen/src/parser/render/..., crates/antlr-rust-codegen/src/parser/routing.rs
Removed generated listener and parse-pattern helpers. Parser rendering now invokes __antlr4_rust_parser_facade!, with reset logic targeting the facade parser binding.
Compatibility and generated-output validation
README.md, crates/antlr-rust-codegen/src/generator/tests.rs, crates/antlr-rust-codegen/tests/antlr4_rust_gen_cli/*, third_party/antlr-v4-grammar/self-hosted.sha256
Updated facade snapshots, API extraction, compatibility diagnostics, typed-tree checks, documentation, and generated-source checksums.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Codegen
  participant GeneratedLexerParser
  participant RuntimeFacades
  participant RuntimeTraits
  Codegen->>GeneratedLexerParser: render lexer and parser facade invocations
  GeneratedLexerParser->>RuntimeFacades: invoke lexer/parser facade macros
  RuntimeFacades->>RuntimeTraits: provide delegated recognizer behavior
  RuntimeTraits-->>GeneratedLexerParser: expose lifecycle, accessors, and parsing/tokenization APIs
Loading

Possibly related issues

  • None. The retrieved issue targets per-rule lifecycle and recovery scaffolding, not recognizer facade delegation.

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check ❓ Inconclusive Core changes centralize lexer/parser facades and update compatibility tests, but excluded snapshots, generated recognizers, and migration docs prevent full verification. Review files excluded by !/*.snap, !/generated/, and !/docs/** to verify snapshot coverage, regenerated recognizers, and migration documentation.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the primary change: centralizing generated recognizer facades.
Out of Scope Changes check ✅ Passed The changes support facade deduplication, compatibility updates, testing, documentation, and regeneration requirements from issue #278.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-278-recognizer-facades

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

❤️ Share

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

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

Copy/Paste Detection

Found 9 duplication(s) across 10 changed non-generated Rust file(s) (threshold: 100 tokens).

Show duplications

Found a 26 line (142 tokens) duplication in the following files:

  • Starting at line 4049 of crates/antlr-rust-codegen/src/generator/tests.rs
  • Starting at line 4272 of crates/antlr-rust-codegen/src/generator/tests.rs
    atn.set_end_state(1, 4).expect("block end state");
    atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
        .expect("transition");
    atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
        .expect("transition");
    atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 3 })
        .expect("transition");
    atn.add_transition(
        2,
        ParserTransitionSpec::Atom {
            target: 4,
            label: 1,
        },
    )
    .expect("transition");
    atn.add_transition(
        3,
        ParserTransitionSpec::Atom {
            target: 4,
            label: 2,
        },
    )
    .expect("transition");
    atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
        .expect("transition");
    atn.add_decision_state(1).expect("decision state");
```rust

---

Found a 26 line (125 tokens) duplication in the following files:
* Starting at line 340 of crates/antlr-rust-runtime/src/generated.rs
* Starting at line 511 of crates/antlr-rust-runtime/src/generated.rs

```rust
            $input: $crate::char_stream::CharStream,
            $hooks: $crate::parser::SemanticHooks,
        {
            pub fn metadata() -> &'static $crate::generated::GrammarMetadata {
                $metadata()
            }

            /// Adds a listener for lexer diagnostics.
            pub fn add_error_listener<T>(&mut self, listener: T)
            where
                T: for<'a> $crate::errors::ErrorListener<dyn $crate::recognizer::Recognizer + 'a>
                    + ::core::marker::Send
                    + 'static,
            {
                $crate::recognizer::Recognizer::add_error_listener(&mut self.$base, listener);
            }

            /// Removes every lexer error listener, including the default console listener.
            pub fn remove_error_listeners(&mut self) {
                $crate::recognizer::Recognizer::remove_error_listeners(&mut self.$base);
            }

            /// Routes every token through ATN interpretation instead of the compiled
            /// lexer DFA, so the learned-DFA trace (`lexer_dfa_string`) observes each
            /// match.
            pub fn set_force_interpreted(&mut self, force_interpreted: bool) {

Found a 25 line (115 tokens) duplication in the following files:

  • Starting at line 4020 of crates/antlr-rust-codegen/src/generator/tests.rs
  • Starting at line 4230 of crates/antlr-rust-codegen/src/generator/tests.rs
        atn.add_state(AtnStateKind::BlockStart, Some(0))
            .expect("state")
            .index(),
        1
    );
    assert_eq!(
        atn.add_state(AtnStateKind::Basic, Some(0))
            .expect("state")
            .index(),
        2
    );
    assert_eq!(
        atn.add_state(AtnStateKind::Basic, Some(0))
            .expect("state")
            .index(),
        3
    );
    assert_eq!(
        atn.add_state(AtnStateKind::BlockEnd, Some(0))
            .expect("state")
            .index(),
        4
    );
    assert_eq!(
        atn.add_state(AtnStateKind::RuleStop, Some(0))
```rust

---

Found a 22 line (112 tokens) duplication in the following files:
* Starting at line 4147 of crates/antlr-rust-codegen/src/generator/tests.rs
* Starting at line 4221 of crates/antlr-rust-codegen/src/generator/tests.rs

```rust
fn plus_loop_atn() -> ParserAtn {
    let mut atn = ParserAtnBuilder::new(2);
    assert_eq!(
        atn.add_state(AtnStateKind::RuleStart, Some(0))
            .expect("state")
            .index(),
        0
    );
    assert_eq!(
        atn.add_state(AtnStateKind::PlusBlockStart, Some(0))
            .expect("state")
            .index(),
        1
    );
    assert_eq!(
        atn.add_state(AtnStateKind::Basic, Some(0))
            .expect("state")
            .index(),
        2
    );
    assert_eq!(
        atn.add_state(AtnStateKind::BlockEnd, Some(0))

Found a 27 line (110 tokens) duplication in the following files:

  • Starting at line 3374 of crates/antlr-rust-codegen/src/generator/tests.rs
  • Starting at line 3486 of crates/antlr-rust-codegen/src/generator/tests.rs
            decision: 0,
            alts: (1, 2),
            track_alt_number: false,
            allow_semantic_context: true,
            force_context: false,
            plus_loop: false,
            fast_path: None,
            body: &body,
        },
        0,
        GeneratedStepRenderContext {
            current_rule_index: 0,
            embedded: None,
            portable_locals: None,
            decision_routing: DecisionRoutingRender::default(),
            inline_action_statements: &BTreeMap::new(),
            track_alt_numbers: false,
            track_context_alt_numbers: false,
            direct_generated_rule_calls: &[],
            atn_preferred_rule_calls: &[],
            adaptive_atn_preferred_rule_slots: &[],
            adaptive_atn_probe_rule_slots: &[],
        },
    );

    // The whole rendered star-loop captures the leading-predicate-to-exit-alt filtering.
    insta::assert_snapshot!(
```rust

---

Found a 17 line (105 tokens) duplication in the following files:
* Starting at line 168 of crates/antlr-rust-runtime/src/generated.rs
* Starting at line 265 of crates/antlr-rust-runtime/src/generated.rs

```rust
            fn __from_node_with_invocation_states(
                node: $crate::RuleNodeView<'a>,
                invocation_states: Option<Vec<isize>>,
            ) -> Self {
                $(
                    let __default = <$attrs>::default();
                    let __attrs = node.generated_attrs::<$attrs>().unwrap_or(&__default);
                )?
                Self {
                    __node: __GeneratedRuleContext::Stored(node),
                    __invocation_states: invocation_states,
                    __state: std::marker::PhantomData,
                    $(
                        $($field: __attrs.$field.clone(),)+
                    )?
                }
            }

Found a 25 line (104 tokens) duplication in the following files:

  • Starting at line 3114 of crates/antlr-rust-codegen/src/generator/tests.rs
  • Starting at line 3281 of crates/antlr-rust-codegen/src/generator/tests.rs
            state: 1,
            decision: 0,
            track_alt_number: false,
            allow_semantic_context: false,
            force_context: false,
            fast_path: None,
            alts: &alts,
        },
        0,
        GeneratedStepRenderContext {
            current_rule_index: 0,
            embedded: None,
            portable_locals: None,
            decision_routing: DecisionRoutingRender::default(),
            inline_action_statements: &BTreeMap::new(),
            track_alt_numbers: false,
            track_context_alt_numbers: false,
            direct_generated_rule_calls: &[],
            atn_preferred_rule_calls: &[],
            adaptive_atn_preferred_rule_slots: &[],
            adaptive_atn_probe_rule_slots: &[],
        },
    );

    assert!(rendered.contains("ll1_decision_prediction(atn(), 1)"));
```rust

---

Found a 28 line (102 tokens) duplication in the following files:
* Starting at line 3167 of crates/antlr-rust-codegen/src/generator/tests.rs
* Starting at line 3327 of crates/antlr-rust-codegen/src/generator/tests.rs

```rust
            state: 1,
            decision: 0,
            track_alt_number: false,
            allow_semantic_context: true,
            force_context: false,
            fast_path: None,
            alts: &alts,
        },
        0,
        GeneratedStepRenderContext {
            current_rule_index: 0,
            embedded: None,
            portable_locals: None,
            decision_routing: DecisionRoutingRender::default(),
            inline_action_statements: &BTreeMap::new(),
            track_alt_numbers: false,
            track_context_alt_numbers: false,
            direct_generated_rule_calls: &[],
            atn_preferred_rule_calls: &[],
            adaptive_atn_preferred_rule_slots: &[],
            adaptive_atn_probe_rule_slots: &[],
        },
    );

    // One decision renders into a fresh String; snapshot the whole emitted control flow (the
    // semantic-context gate, both predicate probes, the alt rewrite, the no-viable fallback)
    // instead of six positive probes plus one negative guard.
    insta::assert_snapshot!(

Found a 16 line (101 tokens) duplication in the following files:

  • Starting at line 4120 of crates/antlr-rust-codegen/src/generator/tests.rs
  • Starting at line 4272 of crates/antlr-rust-codegen/src/generator/tests.rs
    atn.set_loop_back_state(3, 4).expect("loop back state");
    atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
        .expect("transition");
    atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
        .expect("transition");
    atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 3 })
        .expect("transition");
    atn.add_transition(
        2,
        ParserTransitionSpec::Atom {
            target: 4,
            label: 1,
        },
    )
    .expect("transition");
    atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 1 })
```rust

@claude

claude Bot commented Aug 4, 2026

Copy link
Copy Markdown

Claude Code is working…

I'll analyze this and get back to you.

View job run

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 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 `@crates/antlr-rust-runtime/src/generated.rs`:
- Around line 908-967: Update the facade_hygiene fixture to shadow Rc alongside
the other prelude names, covering the lexer facade’s TokenSource::source_text
expansion. Add a comment explaining that successful compilation of both facade
macro invocations is the hygiene assertion; retain the test only if needed to
exercise the fixture, without implying its size assertion is the purpose of the
module.
🪄 Autofix

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: 6c25d7a6-0f7f-436e-a887-4da592fd978b

📥 Commits

Reviewing files that changed from the base of the PR and between 920bb67 and 2652a5d.

⛔ Files ignored due to path filters (13)
  • crates/antlr-rust-codegen/src/generator/snapshots/antlr_rust_codegen__generator__tests__generated_lexer_lifecycle_facade.snap is excluded by !**/*.snap
  • crates/antlr-rust-codegen/src/generator/snapshots/antlr_rust_codegen__generator__tests__generated_module_file_header.snap is excluded by !**/*.snap
  • crates/antlr-rust-codegen/src/generator/snapshots/antlr_rust_codegen__generator__tests__generated_parser_optional_state_facade.snap is excluded by !**/*.snap
  • crates/antlr-rust-codegen/src/generator/snapshots/antlr_rust_codegen__generator__tests__generated_plain_recognizer_facades.snap is excluded by !**/*.snap
  • crates/antlr-rust-codegen/src/generator/snapshots/antlr_rust_codegen__generator__tests__generated_recognizers_reuse_cached_static_metadata.snap is excluded by !**/*.snap
  • crates/antlr-rust-codegen/tests/antlr4_rust_gen_cli/snapshots/antlr4_rust_gen_cli__cli__generated_codegen_api_checks.snap is excluded by !**/*.snap
  • crates/antlr-rust-codegen/tests/antlr4_rust_gen_cli/snapshots/antlr4_rust_gen_cli__cli__generated_codegen_api_mismatch_diagnostic.snap is excluded by !**/*.snap
  • crates/antlr-rust-g4-parser/src/generated/antlr_v4_lexer.rs is excluded by !**/generated/**
  • crates/antlr-rust-g4-parser/src/generated/antlr_v4_parser.rs is excluded by !**/generated/**
  • crates/antlr-rust-rs-parser/src/generated/rust_lexer.rs is excluded by !**/generated/**
  • crates/antlr-rust-rs-parser/src/generated/rust_parser.rs is excluded by !**/generated/**
  • crates/antlr-rust-runtime/src/xpath/generated/x_path_lexer.rs is excluded by !**/generated/**
  • docs/migration.md is excluded by !**/docs/**
📒 Files selected for processing (12)
  • README.md
  • crates/antlr-rust-codegen/src/generator/tests.rs
  • crates/antlr-rust-codegen/src/lexer/render.rs
  • crates/antlr-rust-codegen/src/parser/render/mod.rs
  • crates/antlr-rust-codegen/src/parser/render_model.rs
  • crates/antlr-rust-codegen/src/parser/routing.rs
  • crates/antlr-rust-codegen/tests/antlr4_rust_gen_cli/cli.rs
  • crates/antlr-rust-codegen/tests/antlr4_rust_gen_cli/support.rs
  • crates/antlr-rust-codegen/tests/antlr4_rust_gen_cli/typed_tree.rs
  • crates/antlr-rust-runtime/src/generated.rs
  • crates/antlr-rust-runtime/src/lib.rs
  • third_party/antlr-v4-grammar/self-hosted.sha256
💤 Files with no reviewable changes (1)
  • crates/antlr-rust-codegen/src/parser/render_model.rs

Comment thread crates/antlr-rust-runtime/src/generated.rs
@codecov

codecov Bot commented Aug 4, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 21.05263% with 210 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
crates/antlr-rust-runtime/src/generated.rs 17.64% 210 Missing ⚠️

📢 Thoughts on this report? Let us know!

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

📊 Source Code Metrics (this PR vs main)

File Cyclomatic Cognitive Functions LLOC MI
crates/antlr-rust-codegen/src/generator/tests.rs 284 (main: 280) 🔴 48 ⚪ 199 (main: 197) 🔴 1344 (main: 1362) 🟢 0 ⚪
crates/antlr-rust-codegen/src/parser/render_model.rs 90 (main: 92) 🟢 61 ⚪ 20 (main: 22) 🟢 130 (main: 132) 🟢 0 ⚪
crates/antlr-rust-runtime/src/generated.rs 20 (main: 18) 🔴 0 ⚪ 14 (main: 12) 🔴 21 (main: 19) 🔴 5.44 (main: 13.31) 🔴
crates/antlr-rust-codegen/src/parser/render/mod.rs 43 ⚪ 41 ⚪ 3 ⚪ 91 (main: 93) 🟢 7.02 (main: 4.56) 🟢
crates/antlr-rust-runtime/src/lib.rs 4 ⚪ 3 ⚪ 1 ⚪ 7 ⚪ 29.85 (main: 29.93) 🔴

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

@tinovyatkin

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 👍

Reviewed commit: 4daafbdc7a

ℹ️ 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".

@tinovyatkin
tinovyatkin merged commit a50acb6 into main Aug 4, 2026
16 of 17 checks passed
@tinovyatkin
tinovyatkin deleted the issue-278-recognizer-facades branch August 4, 2026 20:18
@ophiarch ophiarch Bot mentioned this pull request Aug 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

codegen: deduplicate generated lexer/parser facades and trait delegation

1 participant