Skip to content

Conversation

@tomtau
Copy link
Contributor

@tomtau tomtau commented Aug 25, 2025

Summary by CodeRabbit

  • New Features

    • Grammar: rule bodies may omit braces for cleaner syntax.
    • Parser: new public replace(...) method for in-place AST replacement.
    • Generator: silent rules with arguments are now inlined across modules.
  • Refactor

    • Unified, clearer error and display messages across parsing and diagnostics.
  • Tests

    • Added tests for silent-rule inlining and inline-grammar parsing.
  • Chores

    • CI: Rust toolchain updated to 1.81.
    • Package and workspace dependency version bumps.

@tomtau tomtau requested a review from Copilot August 25, 2025 12:53
@coderabbitai
Copy link

coderabbitai bot commented Aug 25, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Bumps CI Rust toolchain to 1.81; widespread formatting macro style changes to named placeholders; generator inlines silent rules with arguments and renames generated state identifiers; meta parser adds ParseExpr::replace and makes rule-body braces optional; assorted test, bench, and dependency version updates.

Changes

Cohort / File(s) Summary
CI toolchain bump
\.github/workflows/ci.yml
Updated Rust toolchain from 1.741.81 in check and coverage jobs; components unchanged.
Formatting style updates
core/src/formatter.rs, core/src/token/mod.rs, core/src/typed/tracker.rs, generator/src/config.rs, generator/src/typed/getter.rs, generator/src/typed/output.rs, generator/tests/generator.rs, meta/src/error.rs, pest/tests/predefined_node.rs, derive/benches/json.rs, derive/tests/json.rs, pest/src/bin/unicode.rs, derive/tests/meta_rules_silent.rs
Replaced positional format/writeln placeholders with named/inline placeholders across diagnostics, displays, docs, tests and benches; behavior preserved except one writeln! change may alter emitted literal if unintended.
Core typed simplifications
core/src/typed/template/mod.rs, core/src/typed/traits.rs
Simplified Option handling (use of Option::map / if let Some) replacing explicit match; semantics unchanged.
Core formatter adjustments
core/src/formatter.rs
Updated format macro invocations and dynamic width spec usage for padding and line-number alignment in snippet display helpers; intended visual alignment preserved.
Generator: silent-rule inlining & state naming
generator/src/typed/generator.rs, generator/src/state_builder.rs
Added helpers to collect and inline silent rules with args across modules; generate_typed now inlines before codegen; renamed generated state identifiers to inline-capture formatting; tests updated.
Generator minor doc/panic tweaks
generator/src/config.rs, generator/src/typed/getter.rs, generator/src/typed/output.rs, generator/tests/generator.rs
Converted panic/doc strings to named formatting and removed some unused-let bindings; no behavior changes.
Meta parser features & printing
meta/src/parser.rs, meta/src/error.rs
Added pub fn replace(&mut self, arg_name: &str, new_expr: &ParseExpr) -> bool; made rule-body braces optional in parse_rule; many Display/error messages switched to named formatting.
Derive tests — inline parser & updates
derive/tests/meta_rules_silent.rs, derive/tests/json.rs, derive/benches/json.rs
Added inline test module with derived ParserInline and CSV-like tests; converted matches to let-else in tests and updated bench/test formatting.
Pest miscellany & deps
pest/benches/position.rs, pest/src/bin/unicode.rs, pest/src/lib.rs, Cargo.toml, derive/Cargo.toml, generator/Cargo.toml, pest/Cargo.toml
Changed bench constant type to &str; adjusted writeln! formatting; removed extern crate alloc from lib.rs; bumped workspace crate versions and several dependencies.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Dev
  participant Gen as generator::typed::generator
  participant Inl as inline_silent_rules_with_args
  participant Mod as GrammarModule
  participant Code as Codegen

  Dev->>Gen: generate_typed(module)
  Gen->>Inl: inline_silent_rules_with_args(module)
  Inl->>Mod: collect_silent_rules_with_args(module & imports)
  Inl->>Inl: traverse parse exprs, substitute args into call sites
  Inl-->>Gen: inlined_module
  Gen->>Code: generate typed parser from inlined_module
  Code-->>Dev: typed parser artifacts
Loading
sequenceDiagram
  autonumber
  actor Dev
  participant P as meta::parser::parse_rule
  participant T as TokenStream

  Dev->>P: parse_rule(tokens)
  P->>T: peek for opening_brace
  alt braces present
    P->>T: skip opening_brace
    P->>T: parse body
    P->>T: skip closing_brace
  else no braces
    P->>T: parse body directly
  end
  P-->>Dev: Rule { body }
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

I nibble lines and swap the place,
Named placeholders snug in space.
I inline rules where args would stray,
Braces optional — hop away! 🥕

Pre-merge checks and finishing touches

✅ 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 accurately and concisely highlights the primary change—adding inlining for silent meta‐rules—which directly corresponds to the core updates in the parser and generator modules.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch inline-silent

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7900178 and ef44ea0.

📒 Files selected for processing (4)
  • Cargo.toml (1 hunks)
  • derive/Cargo.toml (1 hunks)
  • generator/Cargo.toml (1 hunks)
  • pest/Cargo.toml (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • generator/Cargo.toml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Continuous Benchmarking with Bencher
🔇 Additional comments (3)
Cargo.toml (1)

7-17: Workspace version bumps look consistent.

Root package version and shared dependencies are updated coherently; nothing else to flag here.

pest/Cargo.toml (1)

14-15: Dependency alignment confirmed.

pest3_core and pest3_derive now match the workspace’s 0.0.2 release, so the crate graph remains consistent.

derive/Cargo.toml (1)

13-18: Derive crate deps in sync.

Both the direct and dev dependencies now target the 0.0.2 workspace release, and the dev build enabling meta continues to align with generator changes.


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 and usage tips.

@codecov-commenter
Copy link

codecov-commenter commented Aug 25, 2025

Codecov Report

❌ Patch coverage is 87.62376% with 25 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.04%. Comparing base (5d8482a) to head (ef44ea0).

Files with missing lines Patch % Lines
meta/src/parser.rs 81.81% 10 Missing ⚠️
generator/src/typed/generator.rs 94.11% 7 Missing ⚠️
core/src/typed/tracker.rs 57.14% 3 Missing ⚠️
core/src/token/mod.rs 0.00% 2 Missing ⚠️
generator/src/config.rs 0.00% 1 Missing ⚠️
meta/src/error.rs 0.00% 1 Missing ⚠️
pest/src/bin/unicode.rs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master      #25      +/-   ##
==========================================
- Coverage   87.27%   87.04%   -0.23%     
==========================================
  Files          29       26       -3     
  Lines        6216     6208       -8     
==========================================
- Hits         5425     5404      -21     
- Misses        791      804      +13     
Flag Coverage Δ
unittests 87.04% <87.62%> (-0.23%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@tomtau tomtau linked an issue Aug 25, 2025 that may be closed by this pull request
@tomtau tomtau requested a review from dragostis August 25, 2025 12:55
@tomtau
Copy link
Contributor Author

tomtau commented Aug 25, 2025

FYI @TheVeryDarkness

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

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

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

114-121: Critical: generated code uses obsolete ... range patterns; breaks on Rust 2021/1.81. Replace with ..=.

Inside the quoted code, patterns like Some(#start...#end) and #start...#end are 2021-edition obsolete and will fail on current toolchains. Use inclusive ..= patterns instead.

Rationale: The Rust Reference specifies inclusive range patterns as ..= and notes the obsolete range pattern syntax is removed in the 2021 edition. The Book also demonstrates ..= for inclusive matches. (rust.googlesource.com, doc.rust-lang.org)

Apply this targeted diff:

@@
-                        match self.input.get(self.index) {
-                            Some(#start...#end) => {
+                        match self.input.get(self.index) {
+                            Some(#start..=#end) => {
                                 self.index += 1;
                                 return self.#accept();
                             }
                             _ => return self.#reject()
                         }
@@
-                            match u32::from_le_bytes(bytes) {
-                                #start...#end => {
+                            match u32::from_le_bytes(bytes) {
+                                #start..=#end => {
                                     self.index += #len;
                                     return self.#accept();
                                 }
                                 _ => ()
                             }

Follow-up: consider a quick grep for ... in codegen paths to catch any other occurrences that surface in emitted code.

Also applies to: 128-144

🧹 Nitpick comments (7)
pest/benches/position.rs (1)

28-28: Prefer explicit 'static lifetime on FRAG for clarity and const-compatibility

The literal is 'static, but annotating FRAG as &'static str encodes intent and avoids subtle lifetime inference surprises when used in other const contexts (e.g., wrapper::String::CONTENT expects &'static str).

-const FRAG: &str = "0123456789abcdef";
+const FRAG: &'static str = "0123456789abcdef";
generator/src/config.rs (1)

74-77: Include the full path in the panic to aid debugging.

Printing only file_name can be ambiguous when multiple files share the same name. Use {path:?} (or path.display()) to include the full resolved path.

Apply this focused diff:

-                    Err(error) => panic!("error opening {file_name:?}: {error}"),
+                    Err(error) => panic!("error opening {path:?}: {error}"),
generator/src/state_builder.rs (1)

76-79: Nit: unify state name formatting style within this file.

A few places still use format!("state{}", …). For consistency with the new style, switch to captured identifiers.

Suggested diff:

-        let enter = Ident::new(&format!("state{}", enter_state.id), Span::call_site());
+        let enter = Ident::new(&format!("state{enter_id}"), Span::call_site());
+        let enter_id = enter_state.id;
-                let name = Ident::new(&format!("state{}", self.id), Span::call_site());
+                let name = Ident::new(&format!("state{sid}"), Span::call_site());
+                let sid = self.id;

Alternatively, keep the original variable ordering and just swap the format strings:

-        let enter = Ident::new(&format!("state{}", enter_state.id), Span::call_site());
+        let enter = Ident::new(&format!("state{eid}"), Span::call_site());
+        let eid = enter_state.id;

Pick whichever reads better with your local style.

Also applies to: 230-236

derive/tests/meta_rules_silent.rs (1)

28-31: Avoid repeating field() calls to reduce temporary churn

Minor: you call records[0].field() twice, constructing two temporaries. Bind once to improve clarity.

Apply this diff:

-        assert_eq!(records[0].field().0.span.as_str(), "123");
-        assert_eq!(records[0].field().1[0].span.as_str(), "456");
+        let (first, rest) = records[0].field();
+        assert_eq!(first.span.as_str(), "123");
+        assert_eq!(rest[0].span.as_str(), "456");
core/src/formatter.rs (1)

248-249: Consistency: use the same dynamic-width style throughout

You’ve updated one site to {line:index_digit$}. For consistency, consider updating the remaining occurrences that still use format!("{:w$}", line, w = index_digit) in this file (e.g., Lines 175, 211, 286, 310) to the same style.

Example patches:

-        let number = format!("{:w$}", line.line + 1, w = index_digit);
+        let number = format!("{:index_digit$}", line.line + 1);
-        let number = format!("{:w$}", start.line + 1, w = index_digit);
+        let number = format!("{:index_digit$}", start.line + 1);
-        let number = format!("{:w$}", end.line + 1, w = index_digit);
+        let number = format!("{:index_digit$}", end.line + 1);
generator/src/typed/generator.rs (2)

849-870: Consider adding documentation for the silent rule collection logic.

The collect_silent_rules_with_args function would benefit from a doc comment explaining:

  • Its purpose in the inlining process
  • The structure of the returned nested map (module path -> rule name -> rule)
  • Why silent rules with arguments need special handling
+/// Collects all silent rules with arguments from a module and its imports.
+/// 
+/// Returns a nested map where:
+/// - The outer key is the optional module path (None for the root module)
+/// - The inner map contains rule name to rule mappings for silent rules with arguments
+/// 
+/// This is used to identify which rules need to be inlined during code generation.
 fn collect_silent_rules_with_args<'a>(
     path: Option<&'a str>,
     module: &'a GrammarModule,
 ) -> BTreeMap<Option<&'a str>, BTreeMap<&'a str, &'a ParseRule>> {

889-900: Consider extracting the module path lookup logic.

The nested find_map with multiple conditionals could be clearer if extracted into a helper function.

+fn find_silent_rule<'a>(
+    rule_name: &str,
+    silent_rules: &BTreeMap<Option<&'a str>, BTreeMap<&'a str, &'a ParseRule>>,
+) -> Option<&'a ParseRule> {
+    silent_rules
+        .values()
+        .find_map(|rules| rules.get(rule_name))
+}

 // In the main loop:
-if let Some(silent_rule) = silent_rules
-    .iter()
-    .find_map(|(mod_path, rules)| rules.get(rule_name.as_str()))
+if let Some(silent_rule) = find_silent_rule(rule_name.as_str(), &silent_rules)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 5d8482a and 7997290.

📒 Files selected for processing (21)
  • .github/workflows/ci.yml (2 hunks)
  • core/src/formatter.rs (8 hunks)
  • core/src/token/mod.rs (1 hunks)
  • core/src/typed/template/mod.rs (1 hunks)
  • core/src/typed/tracker.rs (5 hunks)
  • core/src/typed/traits.rs (1 hunks)
  • derive/benches/json.rs (4 hunks)
  • derive/tests/json.rs (2 hunks)
  • derive/tests/meta_rules_silent.rs (1 hunks)
  • generator/src/config.rs (1 hunks)
  • generator/src/state_builder.rs (2 hunks)
  • generator/src/typed/generator.rs (9 hunks)
  • generator/src/typed/getter.rs (1 hunks)
  • generator/src/typed/output.rs (1 hunks)
  • generator/tests/generator.rs (1 hunks)
  • meta/src/error.rs (1 hunks)
  • meta/src/parser.rs (8 hunks)
  • pest/benches/position.rs (1 hunks)
  • pest/src/bin/unicode.rs (1 hunks)
  • pest/src/lib.rs (0 hunks)
  • pest/tests/predefined_node.rs (1 hunks)
💤 Files with no reviewable changes (1)
  • pest/src/lib.rs
🧰 Additional context used
🧬 Code graph analysis (3)
derive/tests/json.rs (1)
core/src/span.rs (1)
  • as_str (218-221)
derive/tests/meta_rules_silent.rs (2)
core/src/typed/traits.rs (2)
  • try_parse (48-53)
  • try_parse (283-285)
core/src/span.rs (1)
  • as_str (218-221)
derive/benches/json.rs (1)
core/src/typed/traits.rs (1)
  • check (91-99)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Continuous Benchmarking with Bencher
🔇 Additional comments (20)
core/src/typed/traits.rs (1)

190-192: Option::for_each_child_pair simplification is correct and clearer

Switching from a match to if let Some(...) preserves semantics and improves readability with no allocation or control-flow changes.

meta/src/error.rs (1)

29-29: Named-arg debug formatting is a no-op behaviorally and aligns with repo style

format!("{other_rule:?}") is equivalent to the prior positional form and keeps formatting consistent with other files.

pest/tests/predefined_node.rs (1)

73-74: Tests: switch to named-arg formatting is clean and idiomatic

format!("{s:?}") / format!("{trivia:?}") read better and match the repository-wide formatting updates. No impact on assertions.

Also applies to: 81-82

core/src/typed/template/mod.rs (1)

469-476: Nice micro-simplification with Option::map; behavior preserved.

input.next_char() advances input in place; returning (input, Self { content: c }) keeps the mutated position. All good.

core/src/token/mod.rs (1)

47-52: LGTM: switch to captured identifiers in fmt strings.

Using {first} / {item} is clear and requires Rust ≥ 1.58; compatible with the toolchain bump.

generator/src/state_builder.rs (2)

21-26: LGTM: format!("state{id}") modernizes formatting without changing semantics.


98-101: LGTM: consistent captured formatting for accept/reject state idents.

pest/src/bin/unicode.rs (1)

13-15: LGTM: captured identifier formatting in writeln!.

writeln!(out, "crate::unicode!({unicode});") correctly captures unicode and emits the intended macro invocation.

derive/benches/json.rs (2)

35-36: LGTM: remove unused binding in benches

Switching from let _ = rules::json::check(&s).unwrap(); to calling rules::json::check(&s).unwrap(); directly is tidy and avoids the unnecessary temporary. No behavior change in the benchmarked operation.

Also applies to: 71-72


26-26: Review comment no longer applies: format! macro is used correctly

Both occurrences in derive/benches/json.rs already use the format! macro (with the !), and a project-wide grep found no plain format( calls:

  • derive/benches/json.rs: lines 26 and 62 both use format!("{…}")
  • No other instances of format("…") detected in the repo

No changes are needed here.

Likely an incorrect or invalid review comment.

core/src/typed/tracker.rs (1)

36-38: Named-arg formatting migration looks correct

The shift to named placeholders improves readability and avoids argument-ordering mistakes. Message content and tests remain consistent with prior behavior. No logical or control-flow changes observed.

Also applies to: 221-221, 235-235, 244-245, 259-259, 267-267

derive/tests/meta_rules_silent.rs (1)

6-12: Confirm intent of ^ usage and sequencing around line breaks

The inline grammar defines a rule named ^ as CRLF/LF and then uses it in file = pest::soi - (record ^ "")* - pest::eoi. Please confirm:

  • That ^ is indeed allowed as a rule identifier in this grammar dialect.
  • That omitting - around ^ (i.e., record ^ "" instead of record - ^ - "") is intentional and parsed as desired, rather than a sequencing oversight.

If sequencing is intended, consider making the separators explicit for clarity.

If helpful, I can draft an additional test that exercises inputs with: trailing newline, missing trailing newline, and multiple consecutive newlines to pin down the intended semantics.

meta/src/parser.rs (3)

217-246: LGTM! Well-implemented AST replacement functionality.

The replace method provides a clean implementation for substituting rule arguments with actual expressions during inlining. The recursive traversal correctly handles all AST node types, and the boolean return value effectively tracks whether replacements occurred.


494-520: LGTM! Proper handling of optional braces in rule definitions.

The implementation correctly:

  1. Checks for the presence of braces before parsing the rule body
  2. Skips opening/closing braces only when they exist
  3. Maintains backward compatibility with existing rule formats

106-110: LGTM! Consistent adoption of named format arguments throughout.

The migration to named format arguments improves code readability and maintainability. This change aligns well with Rust's modern formatting practices and makes the code more self-documenting.

Also applies to: 152-153, 165-169, 252-271, 375-376, 771-771

generator/tests/generator.rs (1)

13-17: LGTM! Consistent formatting style update.

The change to named format arguments in panic messages is consistent with the broader formatting improvements across the codebase.

generator/src/typed/getter.rs (1)

268-268: LGTM! Improved documentation formatting.

The change to use a named placeholder in the generated doc string improves consistency with the rest of the codebase's formatting updates.

generator/src/typed/output.rs (1)

69-69: LGTM! Consistent formatting update.

The change to use a named placeholder in the doc string generation aligns with the codebase-wide formatting improvements.

generator/src/typed/generator.rs (2)

872-943: Well-implemented inlining logic with proper argument substitution.

The inline_silent_rules_with_args function correctly:

  1. Removes silent rules with arguments from the output
  2. Recursively traverses and replaces rule calls with their inlined bodies
  3. Validates argument counts with a clear assertion message
  4. Properly substitutes arguments using the new replace method

The implementation handles all edge cases and provides good error messages.


1079-1105: Excellent test coverage for the inlining feature.

The test properly validates:

  1. Silent rules with arguments are removed after inlining
  2. The inlined expression structure matches expectations
  3. The transformation preserves the semantic meaning of the rules

This comment was marked as outdated.

@tomtau tomtau requested a review from Copilot August 25, 2025 23:53
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Updates string formatting throughout the codebase to use modern Rust interpolation syntax, adds support for silent meta-rules with arguments that are automatically inlined across modules, and includes minor improvements like removing unnecessary extern crate declarations and updating CI toolchain.

  • Modern string formatting using {var} instead of {:?} with variables
  • Silent rule inlining functionality for improved code generation and performance
  • Updated Rust toolchain to version 1.81

Reviewed Changes

Copilot reviewed 20 out of 21 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
pest/tests/predefined_node.rs Updated string formatting in test assertions
pest/src/lib.rs Removed unnecessary extern crate declaration
pest/benches/position.rs Updated string literal lifetime annotation
meta/src/parser.rs Added silent rule replacement logic and updated string formatting
meta/src/error.rs Updated string formatting in error handling
generator/tests/generator.rs Updated error message formatting
generator/src/typed/output.rs Updated documentation string formatting
generator/src/typed/getter.rs Updated documentation string formatting
generator/src/typed/generator.rs Added silent rule inlining implementation with supporting functions
generator/src/state_builder.rs Updated string formatting in code generation
generator/src/config.rs Updated error message formatting
derive/tests/meta_rules_silent.rs New test file for silent rule inlining functionality
derive/tests/json.rs Simplified match expressions to if-let patterns
derive/benches/json.rs Updated string formatting and removed unused assignments
core/src/typed/traits.rs Simplified match expression to if-let pattern
core/src/typed/tracker.rs Updated string formatting in error messages
core/src/typed/template/mod.rs Simplified match expression using map
core/src/token/mod.rs Updated string formatting in Display implementation
core/src/formatter.rs Updated string formatting throughout formatter
.github/workflows/ci.yml Updated Rust toolchain from 1.74 to 1.81

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Copy link

@coderabbitai coderabbitai bot left a comment

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 (1)
meta/src/parser.rs (1)

494-519: parse_rule: optional braces and silent modifier — verify edge cases; avoid unwraps

Logic for optional braces and silent modifier ordering looks correct. Two follow-ups:

  • Add tests for: "a = _ b" and "a = _ { b }" to cover both forms with the silent modifier.
  • Consider avoiding .peek().unwrap() here to prevent panics on malformed input and surface a structured parse error instead.

Suggested refactor (keeps behavior, removes unwraps on peeks):

-// Then check for silent modifier
-let silent = matches!(pairs.peek().unwrap().as_rule(), Rule::silent_modifier);
+// Then check for silent modifier
+let silent = matches!(pairs.peek().map(|p| p.as_rule()), Some(Rule::silent_modifier));

 if silent {
     pairs.next().unwrap(); // modifier
 }
-// Check if we have braces or direct expression
-let has_braces = matches!(pairs.peek().unwrap().as_rule(), Rule::opening_brace);
+// Check if we have braces or direct expression
+let has_braces = matches!(pairs.peek().map(|p| p.as_rule()), Some(Rule::opening_brace));

Please extend tests to cover the two silent forms above.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0bd3c2f and 7900178.

📒 Files selected for processing (1)
  • meta/src/parser.rs (8 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
meta/src/parser.rs (2)
core/src/token/mod.rs (1)
  • fmt (44-55)
generator/src/typed/generator.rs (4)
  • fmt (80-89)
  • fmt (141-147)
  • fmt (290-292)
  • path (136-136)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Test Coverage
  • GitHub Check: Continuous Benchmarking with Bencher
🔇 Additional comments (7)
meta/src/parser.rs (7)

103-114: Display: switch to named args is correct

Formatting for Range using {start} and {end} looks good.


144-155: Display: PathArgs::Slice -> "[{range}]"

Bracketed slice rendering is consistent with parser-side syntax. Good change.


157-172: fmt_sep: cleaner named-arg formatting

Refactor is fine and keeps behavior unchanged.


249-273: Display(ParseExpr): named placeholders and composite renders LGTM

All variant printers look correct and align with new PathArgs/Range displays.


275-281: skip(): improved panic message

"expected {rule:?}" is clearer. Looks good.


366-386: Import I/O error message improved

The new message with {path:?} and {err} is clearer; good change.


762-775: Bounded repeat error message: updated wording

New "{start} > {end}" message matches updated test expectations.

Comment on lines +217 to +247
impl ParseExpr {
pub fn replace(&mut self, arg_name: &str, new_expr: &ParseExpr) -> bool {
match self {
Self::Path(p, None) if p.len() == 1 && p[0] == arg_name => {
*self = new_expr.clone();
true
}
Self::PosPred(inner)
| Self::NegPred(inner)
| Self::Opt(inner)
| Self::Rep(inner)
| Self::RepOnce(inner)
| Self::RepRange(inner, _)
| Self::Separated(inner, _) => inner.expr.replace(arg_name, new_expr),
Self::Seq(lhs, rhs, _) => {
let replaced_lhs = lhs.expr.replace(arg_name, new_expr);
let replaced_rhs = rhs.expr.replace(arg_name, new_expr);
replaced_lhs || replaced_rhs
}
Self::Choice(lhs, rhs) => {
let replaced_lhs = lhs.expr.replace(arg_name, new_expr);
let replaced_rhs = rhs.expr.replace(arg_name, new_expr);
replaced_lhs || replaced_rhs
}
Self::Path(_, Some(PathArgs::Call(args))) => args
.iter_mut()
.any(|arg| arg.expr.replace(arg_name, new_expr)),
_ => false,
}
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

ParseExpr::replace: solid tree rewrite; add coverage

The traversal covers all relevant variants (incl. call-arg recursion) and returns a useful boolean. Please add unit tests for:

  • Simple identifier replacement
  • Nested in Seq/Choice
  • In call arguments
  • No-op when the path has multiple segments or a slice

Optionally, add a doc comment clarifying it only replaces single-segment identifiers (Path len == 1, no args).

To confirm usage and identify where to add tests, run:


🏁 Script executed:

#!/bin/bash
# Find replace() definition and call sites
rg -n -C3 -g '!**/target/**' -P '\bimpl\s+ParseExpr\b|\breplace\s*\('

# Grep for tests referencing silent rules or inlining to guide new test placement
rg -n -C2 -g '!**/target/**' -P 'silent_modifier|inline|inlin(e|ing)\s+silent'

Length of output: 297


🏁 Script executed:

#!/bin/bash
# Locate ParseExpr::replace definition and its call sites
rg -n --no-ignore -C3 -P '\bimpl\s+ParseExpr\b|\breplace\s*\(' .

# Find existing Rust test modules to determine placement for new tests
rg -n --no-ignore 'mod\s+tests' -g '*.rs' .

Length of output: 2983


Add unit tests for ParseExpr::replace
Cover the following cases in the meta/src/parser.rs tests module (around line 956):

  • simple single-segment identifier replacement
  • nested replacement in Seq/Choice
  • replacement within call-argument lists
  • no-op when Path has multiple segments or non-None args

Optionally, add a doc comment noting it only replaces bare, single-segment identifiers.

🤖 Prompt for AI Agents
In meta/src/parser.rs around lines 217 to 247, the ParseExpr::replace method
lacks unit test coverage; add tests in the tests module near line 956 that (1)
assert a simple single-segment identifier Path is replaced with the new
expression, (2) assert nested replacements occur in Seq and Choice nodes (both
sides), (3) assert replacement happens for arguments inside PathArgs::Call
argument lists, and (4) assert no replacement occurs when Path has multiple
segments or non-None args; also optionally add a short doc comment above replace
stating it only replaces bare, single-segment identifiers.

@tomtau tomtau merged commit 2d4260a into master Sep 25, 2025
3 checks passed
@tomtau tomtau deleted the inline-silent branch September 25, 2025 09:27
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.

Add support for "Meta-rules"

3 participants