Add configurable rules_mod attribute for generated module name#26
Add configurable rules_mod attribute for generated module name#26
Conversation
|
Important Review skippedBot user detected. To trigger a single review, invoke the You can disable this status message by setting the Note Other AI code review bot(s) detectedCodeRabbit 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. Comment |
Co-authored-by: tomtau <2410580+tomtau@users.noreply.github.com>
|
@copilot |
Co-authored-by: tomtau <2410580+tomtau@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces a configurable rules module name feature, allowing users to customize the generated module name instead of using the hardcoded "rules" default. The implementation adds a rules_mod attribute that can be set via #[rules_mod = "custom_name"].
- Added
rules_mod: Option<String>field to theConfigstruct - Implemented attribute parsing for
#[rules_mod = "..."] - Modified code generation to use the configurable module name
- Refactored
Configto be passed by reference throughout the codebase
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| generator/src/typed/config.rs | Added rules_mod field to Config struct; removed Copy trait due to String field |
| generator/src/typed/attr.rs | Added parsing logic for the rules_mod attribute |
| generator/src/typed/output.rs | Made types_mod() function accept optional module name parameter; threaded rules_mod through Output struct |
| generator/src/typed/getter.rs | Removed unused types_mod import after refactoring |
| generator/src/typed/generator.rs | Changed all Config parameters from pass-by-value to pass-by-reference to accommodate non-Copy Config |
| derive/src/lib.rs | Added rules_mod to the list of derive macro attributes |
| derive/tests/custom_rules_mod.rs | Added tests for custom module name and default behavior |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
generator/src/typed/attr.rs
Outdated
| } else if path.is_ident("box_all_rules") { | ||
| config.box_rules_only_if_needed = get_bool(attr, "box_all_rules"); | ||
| } else if path.is_ident("rules_mod") { | ||
| config.rules_mod = Some(get_string(attr, "rules_mod")); |
There was a problem hiding this comment.
The rules_mod attribute value is not validated before being used with format_ident!. If a user provides an invalid Rust identifier (e.g., containing spaces, starting with a digit, or using keywords like "self" or "super"), it will cause a panic at compile time with an unhelpful error. Consider validating the input is a valid Rust identifier before storing it in the config, or providing a more helpful error message.
| config.rules_mod = Some(get_string(attr, "rules_mod")); | |
| let value = get_string(attr, "rules_mod"); | |
| if syn::parse_str::<syn::Ident>(&value).is_err() { | |
| panic!( | |
| "Invalid #[rules_mod = \"{}\"]: value must be a valid Rust identifier", | |
| value | |
| ); | |
| } | |
| config.rules_mod = Some(value); |
| no_warnings, | ||
| box_rules_only_if_needed, | ||
| no_getter, | ||
| rules_mod, |
There was a problem hiding this comment.
The new rules_mod attribute is not documented in the module-level documentation, while other attributes like grammar, grammar_inline, and configuration options are demonstrated in examples. Consider adding documentation or an example showing how to use the rules_mod attribute to customize the generated module name.
| #![allow(unused_variables)] | ||
| use anyhow::Result; | ||
| use pest3_core::typed::TypedNode as _; | ||
| use pest3_derive::Parser; | ||
|
|
||
| /// Test that the `rules_mod` attribute allows customizing the generated module name. | ||
| mod custom_mod_test { | ||
| use super::*; | ||
|
|
||
| #[derive(Parser)] | ||
| #[grammar_inline = r#" | ||
| main = "hello" | ||
| "#] | ||
| #[rules_mod = "custom"] | ||
| struct ParserWithCustomMod; | ||
|
|
||
| #[test] | ||
| fn custom_module_name() -> Result<()> { | ||
| // Access through the custom module name | ||
| custom::main::try_parse("hello")?; | ||
| Ok(()) | ||
| } | ||
| } | ||
|
|
||
| /// Test default behavior (rules module name should be "rules") | ||
| mod default_mod_test { | ||
| use super::*; | ||
|
|
||
| #[derive(Parser)] | ||
| #[grammar_inline = r#" | ||
| greeting = "world" | ||
| "#] | ||
| struct ParserWithDefaultMod; | ||
|
|
||
| #[test] | ||
| fn default_module_name() -> Result<()> { | ||
| // Access through the default "rules" module name | ||
| rules::greeting::try_parse("world")?; | ||
| Ok(()) | ||
| } | ||
| } |
There was a problem hiding this comment.
Consider adding test coverage for edge cases such as identifiers with underscores (e.g., my_rules), raw identifiers (e.g., r#type), or names that conflict with common Rust keywords. This would help ensure the feature handles various valid Rust identifier patterns correctly.
generator/src/typed/attr.rs
Outdated
| } else if path.is_ident("box_all_rules") { | ||
| config.box_rules_only_if_needed = get_bool(attr, "box_all_rules"); | ||
| } else if path.is_ident("rules_mod") { | ||
| config.rules_mod = Some(get_string(attr, "rules_mod")); |
There was a problem hiding this comment.
If an empty string is provided for rules_mod (e.g., #[rules_mod = ""]), it will be stored as Some("") and later passed to format_ident!("{}", "") in the types_mod function, which will cause a panic. Consider validating that the string is not empty and is a valid Rust identifier when parsing the attribute, providing a clear error message to the user.
| config.rules_mod = Some(get_string(attr, "rules_mod")); | |
| let rules_mod_value = get_string(attr, "rules_mod"); | |
| if rules_mod_value.is_empty() { | |
| panic!( | |
| "Attribute #[rules_mod = \"...\"] must not be empty; provide a valid Rust identifier." | |
| ); | |
| } | |
| if syn::parse_str::<proc_macro2::Ident>(&rules_mod_value).is_err() { | |
| panic!( | |
| "Invalid #[rules_mod = \"{}\"] attribute: expected a valid Rust identifier.", | |
| rules_mod_value | |
| ); | |
| } | |
| config.rules_mod = Some(rules_mod_value); |
|
@copilot Can you bump the toolchain on CI to 1.83, so that |
Co-authored-by: tomtau <2410580+tomtau@users.noreply.github.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #26 +/- ##
==========================================
- Coverage 87.04% 86.97% -0.08%
==========================================
Files 26 26
Lines 6208 6227 +19
==========================================
+ Hits 5404 5416 +12
- Misses 804 811 +7
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
rules_modfield toConfigstruct ingenerator/src/typed/config.rsattr.rsto parse#[rules_mod = "..."]attributeoutput.rsto use configurable module name from configtypes_mod()calls (inoutput.rsandgetter.rs)rules_modtoproc_macro_deriveattributes inderive/src/lib.rsOriginal prompt
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.