diff options
Diffstat (limited to 'rust/vendor/nom-derive-impl/src/enums.rs')
-rw-r--r-- | rust/vendor/nom-derive-impl/src/enums.rs | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/rust/vendor/nom-derive-impl/src/enums.rs b/rust/vendor/nom-derive-impl/src/enums.rs new file mode 100644 index 0000000..3bb99cd --- /dev/null +++ b/rust/vendor/nom-derive-impl/src/enums.rs @@ -0,0 +1,105 @@ +use crate::config::*; +use crate::meta; +use crate::meta::attr::{MetaAttr, MetaAttrType}; +use crate::parsertree::{ParserExpr, ParserTreeItem}; +use crate::structs::{get_pre_post_exec, parse_fields, StructParser, StructParserTree}; +use syn::{spanned::Spanned, *}; + +#[derive(Debug)] +pub(crate) struct VariantParserTree { + pub ident: syn::Ident, + pub selector_type: String, + pub struct_def: StructParserTree, +} + +pub(crate) fn parse_variant( + variant: &syn::Variant, + config: &mut Config, +) -> Result<VariantParserTree> { + // eprintln!("variant: {:?}", variant); + let meta_list = + meta::parse_nom_attribute(&variant.attrs).expect("Parsing the 'nom' meta attribute failed"); + let selector = get_selector(&meta_list).ok_or_else(|| { + Error::new( + variant.span(), + "Nom-derive: the 'Selector' attribute must be used to give the value of selector item", + ) + })?; + let mut struct_def = parse_fields(&variant.fields, config)?; + if variant.fields == syn::Fields::Unit { + let mut p = None; + for meta in &meta_list { + if meta.attr_type == MetaAttrType::Parse { + let s = meta.arg().unwrap(); + p = Some(ParserExpr::Raw(s.clone())); + } + } + let (pre, post) = get_pre_post_exec(&meta_list, config); + let p = p.unwrap_or(ParserExpr::Nop); + let item = ParserTreeItem::new(Some(variant.ident.clone()), p); + let sp = StructParser::new("_".to_string(), item, pre, post); + struct_def.parsers.push(sp); + } + // discriminant ? + Ok(VariantParserTree { + ident: variant.ident.clone(), + selector_type: selector, + struct_def, + }) +} + +fn get_selector(meta_list: &[MetaAttr]) -> Option<String> { + for meta in meta_list { + if MetaAttrType::Selector == meta.attr_type { + return Some(meta.arg().unwrap().to_string()); + } + } + None +} + +pub(crate) fn get_repr(attrs: &[syn::Attribute]) -> Option<Ident> { + for attr in attrs { + if let Ok(ref meta) = attr.parse_meta() { + match meta { + syn::Meta::NameValue(_) | syn::Meta::Path(_) => (), + syn::Meta::List(ref metalist) => { + if let Some(ident) = metalist.path.get_ident() { + if ident == "repr" { + for n in metalist.nested.iter() { + match n { + syn::NestedMeta::Meta(meta) => match meta { + syn::Meta::Path(path) => { + if let Some(word) = path.get_ident() { + return Some(word.clone()); + } else { + panic!("unsupported nested type for 'repr'") + } + } + _ => panic!("unsupported nested type for 'repr'"), + }, + _ => panic!("unsupported meta type for 'repr'"), + } + } + } + } + } + } + } + } + None +} + +pub(crate) fn is_input_fieldless_enum(ast: &syn::DeriveInput) -> bool { + match ast.data { + syn::Data::Enum(ref data_enum) => { + // eprintln!("{:?}", data_enum); + for v in data_enum.variants.iter() { + if syn::Fields::Unit != v.fields { + return false; + } + } + true + } + _ => false, + } +} |