Bug 1899949 - Add the ability to have a custom parse function to derived variants. r=jwatt

Differential Revision: https://phabricator.services.mozilla.com/D212448
This commit is contained in:
Emilio Cobos Álvarez 2024-06-03 16:40:08 +00:00
parent 6045fc076c
commit a572c0d70b
2 changed files with 17 additions and 3 deletions

View File

@ -178,6 +178,9 @@ impl<'a> ParserContext<'a> {
/// * `#[parse(condition = "function")]` can be used to make the parsing of the /// * `#[parse(condition = "function")]` can be used to make the parsing of the
/// value conditional on `function`, which needs to fulfill /// value conditional on `function`, which needs to fulfill
/// `fn(&ParserContext) -> bool`. /// `fn(&ParserContext) -> bool`.
///
/// * `#[parse(parse_fn = "function")]` can be used to specify a function other than Parser::parse
/// for a particular variant.
pub trait Parse: Sized { pub trait Parse: Sized {
/// Parse a value of this type. /// Parse a value of this type.
/// ///

View File

@ -14,6 +14,7 @@ use synstructure::{Structure, VariantInfo};
pub struct ParseVariantAttrs { pub struct ParseVariantAttrs {
pub aliases: Option<String>, pub aliases: Option<String>,
pub condition: Option<Path>, pub condition: Option<Path>,
pub parse_fn: Option<Path>,
} }
#[derive(Default, FromField)] #[derive(Default, FromField)]
@ -109,6 +110,7 @@ fn parse_non_keyword_variant(
if let Some(ref bitflags) = variant_attrs.bitflags { if let Some(ref bitflags) = variant_attrs.bitflags {
assert!(skip_try, "Should be the only variant"); assert!(skip_try, "Should be the only variant");
assert!(parse_attrs.parse_fn.is_none(), "should not be needed");
assert!( assert!(
parse_attrs.condition.is_none(), parse_attrs.condition.is_none(),
"Should be the only variant" "Should be the only variant"
@ -118,18 +120,25 @@ fn parse_non_keyword_variant(
} }
let field_attrs = cg::parse_field_attrs::<ParseFieldAttrs>(binding_ast); let field_attrs = cg::parse_field_attrs::<ParseFieldAttrs>(binding_ast);
if field_attrs.field_bound { if field_attrs.field_bound {
cg::add_predicate(where_clause, parse_quote!(#ty: crate::parser::Parse)); cg::add_predicate(where_clause, parse_quote!(#ty: crate::parser::Parse));
} }
let mut parse = if skip_try { let mut parse = if let Some(ref parse_fn) = parse_attrs.parse_fn {
quote! { #parse_fn(context, input) }
} else {
quote! { <#ty as crate::parser::Parse>::parse(context, input) }
};
parse = if skip_try {
quote! { quote! {
let v = <#ty as crate::parser::Parse>::parse(context, input)?; let v = #parse?;
return Ok(#name::#variant_name(v)); return Ok(#name::#variant_name(v));
} }
} else { } else {
quote! { quote! {
if let Ok(v) = input.try(|i| <#ty as crate::parser::Parse>::parse(context, i)) { if let Ok(v) = input.try(|input| #parse) {
return Ok(#name::#variant_name(v)); return Ok(#name::#variant_name(v));
} }
} }
@ -188,6 +197,8 @@ pub fn derive(mut input: DeriveInput) -> TokenStream {
continue; continue;
} }
assert!(parse_attrs.parse_fn.is_none());
let identifier = cg::to_css_identifier( let identifier = cg::to_css_identifier(
&css_variant_attrs &css_variant_attrs
.keyword .keyword