-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enable outer and inner attributes on enum with all unit variants. #35
Conversation
…umed in unit variants of enum
WalkthroughThe changes introduce a more sophisticated attribute handling system for the Changes
Sequence DiagramsequenceDiagram
participant Macro as FromPest Derive Macro
participant Attributes as Attribute Handlers
participant FieldConverter as Field Converter
Macro->>Attributes: Parse Field Attributes
Attributes-->>Macro: Attribute Structures
Macro->>FieldConverter: Convert Fields
alt Struct Fields
FieldConverter->>Macro: struct_convert
else Enum Variants
FieldConverter->>Macro: enum_convert
end
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🔭 Outside diff range comments (2)
derive/src/from_pest/field.rs (1)
Line range hint
141-170
: Reduce code duplication betweenenum_convert
andstruct_convert
Both
enum_convert
andstruct_convert
functions share similar logic when handlingFields::Named
andFields::Unnamed
. Duplicated code can lead to maintenance issues.Consider extracting the common logic into a helper function that can be utilized by both conversion functions. This will improve code reuse and maintainability.
derive/src/from_pest/mod.rs (1)
Line range hint
180-193
: Ensure correct variant name usage inderive_for_enum
The
variant_name
variable is introduced to represent&variant.ident
. However, in thequote!
macro,stringify!(#variant_name)
may not correctly interpolate the variant name as intended.Adjust the usage to ensure that the variant name is correctly expanded:
let variant_name = &variant.ident; let construct_variant = field::enum_convert(&parse_quote!(#name::#variant_name), &variant)?; let extraneous = crate::trace(quote! { - "when converting {}, found extraneous {:?}", stringify!(#name), stringify!(#variant_name) + concat!("when converting ", stringify!(#name), "::", stringify!(#variant_name), ", found extraneous") });
🧹 Nitpick comments (3)
derive/src/from_pest/field.rs (2)
Line range hint
35-49
: Simplify theConversionStrategy::from_attrs
matching logicThe current implementation of
ConversionStrategy::from_attrs
uses a match statement that could be simplified for better readability and maintainability. Specifically, handling the case where multiple attributes are provided can be made clearer.Apply this diff to refactor the matching logic:
fn from_attrs(attrs: Vec<FieldAttribute>) -> Result<Self> { let mut attrs = attrs.into_iter(); - Ok(match (attrs.next(), attrs.next()) { - (Some(_), Some(attr)) => Err(Error::new( - attr.span(), - "only a single field attribute allowed", - ))?, - (None, None) => ConversionStrategy::FromPest, - (Some(FieldAttribute::Outer(attr)), None) => ConversionStrategy::Outer( - attr.span(), - attr.with.into_iter().map(|attr| attr.path).collect(), - ), - (Some(FieldAttribute::Inner(attr)), None) => ConversionStrategy::Inner( - attr.span(), - attr.with.into_iter().map(|attr| attr.path).collect(), - attr.rule.map(|attr| { - let path = attr.path; - let variant = attr.variant; - parse_quote!(#path::#variant) - }), - ), - _ => unreachable!(), - }) + match (attrs.next(), attrs.next()) { + (Some(attr), Some(_)) => Err(Error::new( + attr.span(), + "only a single field attribute allowed", + )), + (None, None) => Ok(ConversionStrategy::FromPest), + (Some(FieldAttribute::Outer(attr)), None) => Ok(ConversionStrategy::Outer( + attr.span(), + attr.with.into_iter().map(|attr| attr.path).collect(), + )), + (Some(FieldAttribute::Inner(attr)), None) => Ok(ConversionStrategy::Inner( + attr.span(), + attr.with.into_iter().map(|attr| attr.path).collect(), + attr.rule.map(|attr| { + let path = attr.path; + let variant = attr.variant; + parse_quote!(#path::#variant) + }), + )), + _ => unreachable!(), + } }
133-137
: Handle unit variants without using a placeholder memberIn the
Fields::Unit
case withinenum_convert
, the code applies the conversion strategy to aMember::Unnamed(Index::from(0))
, which doesn't conceptually represent anything for unit variants. This could be misleading.Consider adjusting the implementation to apply the conversion strategy without using a placeholder member:
Fields::Unit => { let attrs = FieldAttribute::from_attributes(variant.attrs.clone())?; - let real_name = - ConversionStrategy::from_attrs(attrs)?.apply(Member::Unnamed(Index::from(0))); - quote!(#real_name) + let strategy = ConversionStrategy::from_attrs(attrs)?; + match strategy { + ConversionStrategy::FromPest => quote!(#name), + _ => strategy.apply(Member::Named(variant.ident.clone())), + } }derive/src/attributes.rs (1)
Line range hint
35-49
: Add documentation for the newFieldAttribute
enum variantsThe
FieldAttribute
enum has been introduced withOuter
andInner
variants, but lacks comprehensive documentation explaining their usage and significance.Consider adding Rust doc comments to describe the purpose and usage of
FieldAttribute
,OuterAttribute
, andInnerAttribute
./// `#[pest_ast(..)]` for fields in `#[derive(FromPest)]` #[derive(Debug)] +/// Represents field-level attributes for the `FromPest` derive macro. +/// +/// Variants: +/// - `Outer`: Denotes that the field should be parsed from an outer rule. +/// - `Inner`: Indicates that the field should be parsed from an inner rule, potentially with a specific rule and additional attributes. pub(crate) enum FieldAttribute { /// `outer(with(path::to),*)` Outer(OuterAttribute), /// `inner(rule(path::to), with(path::to),*)` Inner(InnerAttribute), }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
derive/src/attributes.rs
(3 hunks)derive/src/from_pest/field.rs
(3 hunks)derive/src/from_pest/mod.rs
(2 hunks)
🔇 Additional comments (3)
derive/src/from_pest/mod.rs (1)
Line range hint
136-154
: Verify the handling of generated lifetimesIn the
derive
function, when synthesizing a new lifetime'unique_lifetime_name
, it is essential to ensure that this does not conflict with existing lifetimes or cause unintended behavior.Please confirm that introducing the
'unique_lifetime_name
lifetime does not introduce any conflicts in the generated code, especially when dealing with complex generics or existing lifetimes.derive/src/attributes.rs (2)
51-58
: Ensure proper parsing ofOuterAttribute
andInnerAttribute
The parsing implementations for
OuterAttribute
andInnerAttribute
should handle edge cases, such as empty lists or unexpected tokens.Please review the
parse
implementations for these structs to ensure they correctly handle all possible inputs and provide meaningful error messages.
67-69
: ImplementParse
andToTokens
forWithAttribute
While
WithAttribute
is defined, ensure that itsParse
andToTokens
traits are properly implemented to integrate seamlessly with the syn and quote crates.The implementations for
Parse
andToTokens
forWithAttribute
are correctly provided, enabling it to be used in attribute parsing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@TonyWu20 thanks for your contribution. pest-ast is passively maintained and not that widely used (at least among OSS projects), so it's a bit hard to tell whether this change breaks any existing behaviour off the top of my head, but it looks it should hopefully be all right.
One way to improve it is perhaps to abstract the duplicate common code between convert_struct and convert_enum, but ok to merge it as it is
This is a quick and dirty hack. I was attempting to get the pest-at derive works on my enums with all variants are unit type. The enum is like this:
And the formatted output and input to be parsed are in the same format like:
MyEnum : A
, and it is case-insensitive.So I wrote my
.pest
grammar as follows:To achieve the conversion from
&str
toMyEnum
, I use my own proc-macro derive crate to generate code like this:and then I added attributes to each variants first.
The original
pest-ast
codebase does not apply the conversion on unit variant, as I found inderive/src/from_pest/field.rs
. The reason is theconvert
function accepts(name: &Path, fields: Fields)
andFields
is not available for unit variant in enum, provided by the dependencysyn
crate. However, one can still access to the attributes macros on unit variants byvariant.attrs
.Therefore, I edited the
convert
function infield.rs
to accept parametervariant: &Variant
for enum case, and leave the original version to be used for struct case. This makes me pass all the existing tests inast
bycargo test
.Still, I don't have the time and knowledge to fully test this with more potential error-prone cases. In my current usage, it seems my mod only need and only can recognise one
#[pest_ast]
outer or inner attribute. For my intended purpose this is workable enough, since all variants share the same rule and same method to convert to the enum. However, it could be not powerful enough to handle cases with more customisation needed. Finally, as I have zero experience with the development ofpest
andpest-ast
, I believe this kind of mod is of low quality. I was also surprised to see why it seems nobody cares about usingpest-ast
, this incredible crate, on enum with unit variants. Hopefully, experienced developers ofpest
can see my efforts and discuss if we can make a better version for this demand. Thank you.Summary by CodeRabbit
Refactor
New Features