Skip to content

feat(loomgen): add line-mode lexer fallback#703

Merged
dowdiness merged 5 commits into
mainfrom
feat/700-fallback-lex
Jul 12, 2026
Merged

feat(loomgen): add line-mode lexer fallback#703
dowdiness merged 5 commits into
mainfrom
feat/700-fallback-lex

Conversation

@dowdiness

@dowdiness dowdiness commented Jul 11, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add #loom.fallback_lex("fn") for #loom.line_mode term variants.
  • Delegate line-mode no-match input to the named mode-compatible fallback lexer.
  • Preserve Invalid behavior when no fallback is declared.
  • Validate token/term placement, function names, required mode annotations, and conflicting same-mode fallbacks.
  • Simplify same-mode fallback validation to a single-pass Map.

Verification

  • moon fmt --check
  • moon check loomgen --target native
  • moon test loomgen --target native — 169/169
  • moon test --target native — 3323/3323
  • Fixture regeneration is deterministic.

The existing test runner diagnostic for the intentional AToken collision remains present, but all tests pass.

Codex pre-PR review was attempted twice but was unavailable in this environment (unsupported requested model and default retry timeout); the focused diff was self-reviewed and all verification commands passed.

End-to-end compilation and runtime tokenization of generated line lexers is tracked separately in #701. Skeleton integration is tracked in #699. Ambiguous #loom.pattern plus #loom.line_pattern validation is tracked in #702.

Closes #700

Summary by CodeRabbit

  • New Features

    • Added #loom.fallback_lex("function_name") support for line-mode lexers.
    • Line-mode lexers can now delegate unmatched input to a specified fallback lexer.
    • Existing Invalid behavior remains unchanged when no fallback is configured.
  • Documentation

    • Added usage guidance, design details, validation rules, and implementation records for line-mode fallback lexing.
  • Tests

    • Added coverage for successful fallback delegation and invalid or conflicting annotation configurations.

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

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

Next review available in: 40 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 03c99b04-20d0-4dd6-9749-5bd6b4dae1ab

📥 Commits

Reviewing files that changed from the base of the PR and between f63677d and 21c1cb9.

📒 Files selected for processing (2)
  • docs/README.md
  • loomgen/emit_lexer_wbtest.mbt
📝 Walkthrough

Walkthrough

Adds #loom.fallback_lex parsing and validation, generates line-mode fallback delegation, preserves Invalid behavior without a fallback, updates fixtures and tests, and documents the accepted design and implementation.

Changes

Line-mode fallback lexer

Layer / File(s) Summary
Fallback annotation contract
loomgen/parse_annotations.mbt
Adds fallback_lex metadata and validates argument shape, lexer-mode prerequisites, token restrictions, and same-mode conflicts.
Line-mode fallback emission
loomgen/emit_line_lexer.mbt, loomgen/fixtures/line_pattern_fixture.mbt, loomgen/fixtures/line_pattern_fixture.g.mbt
Passes per-mode fallback functions into generated lexers, delegates unmatched input when configured, and retains Invalid recovery otherwise.
Fixtures, tests, and documentation
loomgen/emit_lexer_wbtest.mbt, loomgen/README.md, docs/README.md, docs/decisions/..., docs/superpowers/specs/..., docs/archive/completed-phases/...
Adds generation and validation coverage and documents the annotation, design, implementation plan, and accepted decision.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AnnotationParser
  participant emit_line_lexer
  participant GeneratedModeLexer
  participant FallbackLexer
  AnnotationParser->>emit_line_lexer: provide validated fallback_lex metadata
  emit_line_lexer->>GeneratedModeLexer: generate mode-specific no-match handling
  GeneratedModeLexer->>FallbackLexer: call fallback function for unmatched input
Loading

Possibly related issues

  • Issue 561 — The PR extends the line-mode lexer behavior introduced by this issue by replacing selected no-match Invalid results with fallback delegation.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding line-mode lexer fallback support.
Description check ✅ Passed The description covers the required summary and verification details, and it addresses the docs/ADR checklist items in prose.
Linked Issues check ✅ Passed The changes satisfy #700 by delegating line-mode fallthrough to a named fallback lexer and preserving Invalid when no fallback is set.
Out of Scope Changes check ✅ Passed The changes are focused on the fallback feature, related validation, tests, and required docs/ADR updates, with no clear unrelated additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/700-fallback-lex

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.

@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

🧹 Nitpick comments (3)
loomgen/emit_lexer_wbtest.mbt (3)

1074-1078: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert the no-fallback behavior per mode.

generated.contains(...) only proves that at least one generated function contains the Invalid path. Slice lex_line_start and lex_block_quote_line_start separately and assert both retain the no-fallback behavior.

🤖 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 `@loomgen/emit_lexer_wbtest.mbt` around lines 1074 - 1078, Update the
no-fallback assertions in the relevant lexer workbench test to inspect generated
code separately for lex_line_start and lex_block_quote_line_start, and assert
that each mode retains the “Not a block-level token (line_pattern)” Invalid path
instead of relying on one aggregate generated.contains check.

888-921: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add a multi-mode fallback isolation test.

This test has only one line mode, so it cannot detect accidentally applying lex_inline to every generated mode. Add a second mode without a fallback and assert that only the declared mode delegates while the other retains Invalid.

🤖 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 `@loomgen/emit_lexer_wbtest.mbt` around lines 888 - 921, Extend the test around
emit_line_lexer to declare a second line lex mode without fallback_lex, then
assert generated code delegates to lex_inline only for the mode that declares
it. Also assert the fallback-free mode retains Invalid handling, using the
existing generated output and mode-specific symbols to distinguish both paths.

924-985: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Cover invalid fallback function names.

The new negative tests cover placement and conflicting declarations, but not the promised function-reference validation. Add invalid-name cases such as bad name) or a..b, plus a qualified @pkg.fn positive case.

🤖 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 `@loomgen/emit_lexer_wbtest.mbt` around lines 924 - 985, The annotation parser
tests need coverage for fallback_lex function-reference validation. Add negative
cases using malformed names such as “bad name)” and “a..b”, asserting the
appropriate parse errors, and add a positive case confirming a qualified
reference like “@pkg.fn” is accepted; place these alongside the existing
fallback_lex tests and preserve their current placement/conflict coverage.
🤖 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 `@docs/README.md`:
- Line 73: Reorder the ADR index entry for
decisions/2026-07-12-line-mode-fallback-lexer.md so it appears before all July
10, 2026 entries, preserving the section’s descending-date order and leaving the
entry text unchanged.

---

Nitpick comments:
In `@loomgen/emit_lexer_wbtest.mbt`:
- Around line 1074-1078: Update the no-fallback assertions in the relevant lexer
workbench test to inspect generated code separately for lex_line_start and
lex_block_quote_line_start, and assert that each mode retains the “Not a
block-level token (line_pattern)” Invalid path instead of relying on one
aggregate generated.contains check.
- Around line 888-921: Extend the test around emit_line_lexer to declare a
second line lex mode without fallback_lex, then assert generated code delegates
to lex_inline only for the mode that declares it. Also assert the fallback-free
mode retains Invalid handling, using the existing generated output and
mode-specific symbols to distinguish both paths.
- Around line 924-985: The annotation parser tests need coverage for
fallback_lex function-reference validation. Add negative cases using malformed
names such as “bad name)” and “a..b”, asserting the appropriate parse errors,
and add a positive case confirming a qualified reference like “@pkg.fn” is
accepted; place these alongside the existing fallback_lex tests and preserve
their current placement/conflict coverage.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 36f85698-0cc3-46e6-8444-5577738ca92c

📥 Commits

Reviewing files that changed from the base of the PR and between b3eedd5 and f63677d.

📒 Files selected for processing (10)
  • docs/README.md
  • docs/archive/completed-phases/2026-07-fallback-lex.md
  • docs/decisions/2026-07-12-line-mode-fallback-lexer.md
  • docs/superpowers/specs/2026-07-12-fallback-lex-design.md
  • loomgen/README.md
  • loomgen/emit_lexer_wbtest.mbt
  • loomgen/emit_line_lexer.mbt
  • loomgen/fixtures/line_pattern_fixture.g.mbt
  • loomgen/fixtures/line_pattern_fixture.mbt
  • loomgen/parse_annotations.mbt

Comment thread docs/README.md
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.

loomgen: line-mode lexer fallthrough should delegate to inline mode, not emit Invalid (#561 follow-up)

1 participant