nom-derive-impl-0.10.0/.cargo_vcs_info.json0000644000000001120000000000100141100ustar { "git": { "sha1": "c21e8716f10e317adc0874db825de9908ebef69c" } } nom-derive-impl-0.10.0/Cargo.toml0000644000000022610000000000100121150ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "nom-derive-impl" version = "0.10.0" authors = ["Pierre Chifflier "] include = ["LICENSE-*", "README.md", ".gitignore", ".travis.yml", "Cargo.toml", "src/*.rs", "src/gen/*.rs", "src/meta/*.rs", "tests/*.rs"] description = "Custom derive nom parsers from struct" homepage = "https://github.com/rust-bakery/nom-derive" readme = "../README.md" keywords = ["parser", "nom"] categories = ["parsing"] license = "MIT/Apache-2.0" repository = "https://github.com/rust-bakery/nom-derive.git" [lib] proc-macro = true [dependencies.proc-macro2] version = "1.0" [dependencies.quote] version = "1.0" [dependencies.syn] version = ">=1.0.58" features = ["parsing", "extra-traits", "full"] nom-derive-impl-0.10.0/Cargo.toml.orig000064400000000000000000000013510072674642500156250ustar 00000000000000[package] name = "nom-derive-impl" description = "Custom derive nom parsers from struct" version = "0.10.0" license = "MIT/Apache-2.0" keywords = ["parser","nom"] categories = ["parsing"] authors = ["Pierre Chifflier "] homepage = "https://github.com/rust-bakery/nom-derive" repository = "https://github.com/rust-bakery/nom-derive.git" readme = "../README.md" edition = "2018" include = [ "LICENSE-*", "README.md", ".gitignore", ".travis.yml", "Cargo.toml", "src/*.rs", "src/gen/*.rs", "src/meta/*.rs", "tests/*.rs", ] [lib] proc-macro = true [dependencies] syn = { version=">=1.0.58", features=["parsing","extra-traits","full"] } quote = "1.0" proc-macro2 = "1.0" # [dev-dependencies] # nom = "6.0" nom-derive-impl-0.10.0/src/config.rs000064400000000000000000000075750072674642500153560ustar 00000000000000use crate::endian::ParserEndianness; use crate::meta::attr::{MetaAttr, MetaAttrType}; use proc_macro2::{Span, TokenStream}; use syn::{spanned::Spanned, Error}; #[derive(Debug)] pub struct Config { pub struct_name: String, /// Endianness for all parsers, if specified pub global_endianness: ParserEndianness, /// Endianness for this struct or enum, if specified pub object_endianness: ParserEndianness, /// Complete option for this struct (default: streaming) pub complete: bool, pub debug: bool, pub debug_derive: bool, pub generic_errors: bool, selector_type: Option, selector_name: Option, input_name: String, orig_input_name: String, lifetime_name: String, error_name: String, } impl Config { pub fn from_meta_list(name: String, l: &[MetaAttr]) -> Result { let mut req_big_endian = false; let mut req_little_endian = false; let mut complete = false; let mut debug = false; let mut debug_derive = false; let mut generic_errors = false; let mut span_endian = None; for meta in l { match meta.attr_type { MetaAttrType::BigEndian => { req_big_endian = true; span_endian = Some(meta.span()); } MetaAttrType::LittleEndian => req_little_endian = true, MetaAttrType::Complete => complete = true, MetaAttrType::Debug => debug = true, MetaAttrType::DebugDerive => debug_derive = true, MetaAttrType::GenericErrors => generic_errors = true, _ => (), } } if req_big_endian & req_little_endian { return Err(Error::new( span_endian.unwrap_or_else(Span::call_site), "Struct cannot be both big and little endian", )); } let object_endianness = if req_big_endian { ParserEndianness::BigEndian } else if req_little_endian { ParserEndianness::LittleEndian } else { ParserEndianness::Unspecified }; let input_name = l .iter() .find_map(|m| { if m.is_type(MetaAttrType::InputName) { Some(m.arg().unwrap().to_string()) } else { None } }) .unwrap_or_else(|| "i".to_string()); let selector_type = l.iter().find_map(|m| { if m.is_type(MetaAttrType::Selector) { Some(m.arg().unwrap().clone()) } else { None } }); let selector_name = if selector_type.is_some() { Some(String::from("selector")) } else { None }; Ok(Config { struct_name: name, global_endianness: ParserEndianness::Unspecified, object_endianness, complete, debug, debug_derive, generic_errors, selector_type, selector_name, orig_input_name: "orig_".to_string() + &input_name, lifetime_name: String::from("'nom"), error_name: String::from("NomErr"), input_name, }) } #[inline] pub fn selector_type(&self) -> Option<&TokenStream> { self.selector_type.as_ref() } #[inline] pub fn selector_name(&self) -> Option<&str> { self.selector_name.as_ref().map(|s| s.as_ref()) } #[inline] pub fn input_name(&self) -> &str { &self.input_name } #[inline] pub fn orig_input_name(&self) -> &str { &self.orig_input_name } #[inline] pub fn lifetime_name(&self) -> &str { &self.lifetime_name } #[inline] pub fn error_name(&self) -> &str { &self.error_name } } nom-derive-impl-0.10.0/src/endian.rs000064400000000000000000000107000072674642500153270ustar 00000000000000use crate::config::*; use crate::meta::attr::{MetaAttr, MetaAttrType}; use proc_macro2::Span; use syn::{spanned::Spanned, Error, Result}; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum ParserEndianness { Unspecified, LittleEndian, BigEndian, SetEndian, } pub fn get_object_endianness(config: &Config) -> ParserEndianness { // first, check struct endianness if config.object_endianness != ParserEndianness::Unspecified { return config.object_endianness; } // finally, return global endianness config.global_endianness } pub fn set_object_endianness( span: Span, endianness: ParserEndianness, meta_list: &[MetaAttr], config: &mut Config, ) -> Result<()> { config.object_endianness = endianness; // first, check local attribute let mut req_big_endian = false; let mut req_little_endian = false; let mut req_set_endian = false; let mut span_endian = None; for meta in meta_list { match meta.attr_type { MetaAttrType::BigEndian => req_big_endian = true, MetaAttrType::LittleEndian => req_little_endian = true, MetaAttrType::SetEndian => req_set_endian = true, _ => continue, } span_endian = Some(meta.span()); } // test if 2 or more flags are set if two_or_more(req_big_endian, req_little_endian, req_set_endian) { return Err(Error::new( span_endian.unwrap_or(span), "cannot be both big, little and/or set endian", )); } if req_big_endian { config.object_endianness = ParserEndianness::BigEndian; } else if req_little_endian { config.object_endianness = ParserEndianness::LittleEndian; } else if req_set_endian { config.object_endianness = ParserEndianness::SetEndian; }; Ok(()) } fn two_or_more(a: bool, b: bool, c: bool) -> bool { if a { b | c } else { b & c } } pub fn get_local_endianness( span: Span, meta_list: &[MetaAttr], config: &Config, ) -> Result { // first, check local attribute let mut req_big_endian = false; let mut req_little_endian = false; let mut req_set_endian = false; for meta in meta_list { match meta.attr_type { MetaAttrType::BigEndian => req_big_endian = true, MetaAttrType::LittleEndian => req_little_endian = true, MetaAttrType::SetEndian => req_set_endian = true, _ => (), } } // test if 2 or more flags are set if two_or_more(req_big_endian, req_little_endian, req_set_endian) { return Err(Error::new( span, "cannot be both big, little and/or set endian", )); } if req_big_endian { return Ok(ParserEndianness::BigEndian); } else if req_little_endian { return Ok(ParserEndianness::LittleEndian); } else if req_set_endian { return Ok(ParserEndianness::SetEndian); }; // otherwise, get object-level endianness Ok(get_object_endianness(config)) } pub fn validate_endianness( attr_endianness: ParserEndianness, object_endianness: ParserEndianness, global_endianness: ParserEndianness, ) -> Result<()> { let mut req_big_endian = false; let mut req_little_endian = false; let mut req_set_endian = false; match attr_endianness { ParserEndianness::Unspecified => (), ParserEndianness::BigEndian => req_big_endian = true, ParserEndianness::LittleEndian => req_little_endian = true, _ => unreachable!(), } match object_endianness { ParserEndianness::Unspecified => (), ParserEndianness::BigEndian => req_big_endian = true, ParserEndianness::LittleEndian => req_little_endian = true, ParserEndianness::SetEndian => req_set_endian = true, } match global_endianness { ParserEndianness::Unspecified => (), ParserEndianness::BigEndian => req_big_endian = true, ParserEndianness::LittleEndian => req_little_endian = true, _ => unreachable!(), } if req_big_endian & req_little_endian { return Err(Error::new( Span::call_site(), "Object cannot be both big and little endian", )); } if req_set_endian & (req_big_endian | req_little_endian) { return Err(Error::new( Span::call_site(), "Object cannot be both SetEndian, and specify big or little endian", )); } Ok(()) } nom-derive-impl-0.10.0/src/enums.rs000064400000000000000000000073000072674642500152220ustar 00000000000000use 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 { // 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 { 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 { 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, } } nom-derive-impl-0.10.0/src/gen/enums.rs000064400000000000000000000165530072674642500160050ustar 00000000000000use proc_macro2::Ident; use proc_macro2::Span; use proc_macro2::TokenStream; use syn::*; use crate::config::Config; use crate::endian::*; use crate::enums::*; use crate::gen::get_extra_args; use crate::meta; use crate::structs::get_pre_post_exec; use crate::Result; use super::Generator; pub struct GenEnum { pub name: Ident, pub config: Config, extra_args: Option, orig_generics: Generics, tl_pre: Option, tl_post: Option, variants_defs: Vec, } impl Generator for GenEnum { fn from_ast(ast: &DeriveInput, endianness: ParserEndianness) -> Result { match &ast.data { syn::Data::Enum(data_enum) => GenEnum::from_data_enum( &ast.ident, data_enum, &ast.attrs, &ast.generics, endianness, ), _ => panic!("Wrong type for GenEnum::from_ast"), } } #[inline] fn name(&self) -> &Ident { &self.name } fn set_debug(&mut self, debug_derive: bool) { self.config.debug_derive |= debug_derive; } #[inline] fn extra_args(&self) -> Option<&TokenStream> { self.extra_args.as_ref() } #[inline] fn orig_generics(&self) -> &Generics { &self.orig_generics } #[inline] fn config(&self) -> &Config { &self.config } fn gen_fn_body(&self, endianness: ParserEndianness) -> Result { let orig_input = Ident::new(self.config.orig_input_name(), Span::call_site()); let input = Ident::new(self.config.input_name(), Span::call_site()); let (tl_pre, tl_post) = (&self.tl_pre, &self.tl_post); // generate body let (default_case_handled, variants_code) = self.gen_variants(endianness)?; let default_case = if default_case_handled { quote! {} } else { quote! { _ => Err(nom::Err::Error(nom::error_position!(#input, nom::error::ErrorKind::Switch))) } }; let tokens = quote! { let #input = #orig_input; #tl_pre let (#input, enum_def) = match selector { #(#variants_code)* #default_case }?; #tl_post Ok((#input, enum_def)) }; Ok(tokens) } } impl GenEnum { pub fn from_data_enum( name: &Ident, data_enum: &DataEnum, attrs: &[Attribute], generics: &Generics, endianness: ParserEndianness, ) -> Result { let name = name.clone(); // parse top-level attributes and prepare tokens for each field parser let meta = meta::parse_nom_top_level_attribute(attrs)?; // eprintln!("top-level meta: {:?}", meta); let mut config = Config::from_meta_list(name.to_string(), &meta)?; // endianness must be set before parsing struct set_object_endianness(name.span(), endianness, &meta, &mut config)?; let extra_args = get_extra_args(&meta).map(Clone::clone); // test endianness validity (not 2 or more) validate_endianness( endianness, config.object_endianness, config.global_endianness, )?; // save global pre/post exec let (tl_pre, tl_post) = get_pre_post_exec(&meta, &config); // fieldless enums should not be handled by this generator assert!(config.selector_type().is_some()); // iter fields / variants and store info let variants_defs = data_enum .variants .iter() .map(|v| parse_variant(v, &mut config)) .collect::>>()?; Ok(Self { name, config, extra_args, orig_generics: generics.clone(), tl_pre, tl_post, variants_defs, }) } /// Generate parser code for every variant of the enum /// /// Returns a boolean indicating if default case was handled, and the list of tokens for each variant fn gen_variants(&self, endianness: ParserEndianness) -> Result<(bool, Vec)> { let name = &self.name; let input = syn::Ident::new(self.config.input_name(), Span::call_site()); let mut default_case_handled = false; let mut variants_code: Vec<_> = { self.variants_defs .iter() .map(|def| { if def.selector_type == "_" { default_case_handled = true; } let m: proc_macro2::TokenStream = def.selector_type.parse().expect("invalid selector value"); let variantname = &def.ident; let (idents, parser_tokens): (Vec<_>, Vec<_>) = def .struct_def .parsers .iter() .map(|sp| { let id = syn::Ident::new(&sp.name, Span::call_site()); // set current endianness for functions that do not specify it let item = sp.item.with_endianness(endianness); (id, item) }) .unzip(); let (pre, post): (Vec<_>, Vec<_>) = def .struct_def .parsers .iter() .map(|sp| (sp.pre_exec.as_ref(), sp.post_exec.as_ref())) .unzip(); let idents2 = idents.clone(); let struct_def = match (def.struct_def.empty, def.struct_def.unnamed) { (true, _) => quote! { ( #name::#variantname ) }, (_, true) => quote! { ( #name::#variantname ( #(#idents2),* ) ) }, (_, false) => quote! { ( #name::#variantname { #(#idents2),* } ) }, }; // // XXX this looks wrong: endianness does not appear in this function! // XXX parser_tokens should specify endianness // XXX // XXX this is caused by quote!{} calling to_string() quote! { #m => { #( #pre let (#input, #idents) = #parser_tokens (#input) ?; #post )* let struct_def = #struct_def; Ok((#input, struct_def)) // Err(nom::Err::Error(error_position!(#input_name, nom::ErrorKind::Switch))) }, } }) .collect() }; // if we have a default case, make sure it is the last entry if default_case_handled { let pos = self .variants_defs .iter() .position(|def| def.selector_type == "_") .expect("default case is handled but couldn't find index"); let last_index = self.variants_defs.len() - 1; if pos != last_index { // self.variants_defs.swap(pos, last_index); variants_code.swap(pos, last_index); } } Ok((default_case_handled, variants_code)) } } nom-derive-impl-0.10.0/src/gen/fieldless_enums.rs000064400000000000000000000126040072674642500200300ustar 00000000000000use proc_macro2::Ident; use proc_macro2::Span; use proc_macro2::TokenStream; use syn::*; use crate::config::Config; use crate::endian::*; use crate::enums::*; use crate::gen::get_extra_args; use crate::meta; use crate::parsertree::{ParserExpr, TypeItem}; use crate::structs::get_pre_post_exec; use crate::Result; use super::Generator; pub struct GenFieldlessEnum { pub name: Ident, pub config: Config, extra_args: Option, orig_generics: Generics, tl_pre: Option, tl_post: Option, repr_parser: ParserExpr, variants_code: Vec, } impl Generator for GenFieldlessEnum { fn from_ast(ast: &DeriveInput, endianness: ParserEndianness) -> Result { match &ast.data { syn::Data::Enum(data_enum) => GenFieldlessEnum::from_data_enum( &ast.ident, data_enum, &ast.attrs, &ast.generics, endianness, ), _ => panic!("Wrong type for GenFieldlessEnum::from_ast"), } } #[inline] fn name(&self) -> &Ident { &self.name } fn set_debug(&mut self, debug_derive: bool) { self.config.debug_derive |= debug_derive; } #[inline] fn extra_args(&self) -> Option<&TokenStream> { self.extra_args.as_ref() } #[inline] fn orig_generics(&self) -> &Generics { &self.orig_generics } #[inline] fn config(&self) -> &Config { &self.config } fn gen_fn_body(&self, endianness: ParserEndianness) -> Result { let orig_input = Ident::new(self.config.orig_input_name(), Span::call_site()); let input = Ident::new(self.config.input_name(), Span::call_site()); let (tl_pre, tl_post) = (&self.tl_pre, &self.tl_post); let variants_code = &self.variants_code; let parser = &self.repr_parser.with_endianness(endianness); // generate body let tokens = quote! { let #input = #orig_input; #tl_pre let (#input, selector) = #parser(#input)?; let enum_def = #(#variants_code else)* { return Err(nom::Err::Error(nom::error::make_error(#orig_input, nom::error::ErrorKind::Switch))); }; #tl_post Ok((#input, enum_def)) }; Ok(tokens) } } impl GenFieldlessEnum { pub fn from_data_enum( name: &Ident, data_enum: &DataEnum, attrs: &[Attribute], generics: &Generics, endianness: ParserEndianness, ) -> Result { let name = name.clone(); // parse top-level attributes and prepare tokens for each field parser let meta = meta::parse_nom_top_level_attribute(attrs)?; // eprintln!("top-level meta: {:?}", meta); let mut config = Config::from_meta_list(name.to_string(), &meta)?; // endianness must be set before parsing struct set_object_endianness(name.span(), endianness, &meta, &mut config)?; let extra_args = get_extra_args(&meta).map(Clone::clone); // test endianness validity (not 2 or more) validate_endianness( endianness, config.object_endianness, config.global_endianness, )?; // save global pre/post exec let (tl_pre, tl_post) = get_pre_post_exec(&meta, &config); if extra_args.is_some() { panic!("fieldless enums cannot have extra_args"); } let repr = get_repr(attrs).ok_or_else(|| { Error::new( name.span(), "Nom-derive: fieldless enums must have a 'repr' or 'selector' attribute", ) })?; let repr_string = repr.to_string(); let repr_type = syn::parse_str::(&repr_string).expect("could not parse repr type"); let repr_parser = match repr_string.as_ref() { "u8" | "u16" | "u24" | "u32" | "u64" | "u128" | "i8" | "i16" | "i24" | "i32" | "i64" | "i128" => { let endian = get_object_endianness(&config); match endian { ParserEndianness::BigEndian => { ParserExpr::CallParseBE(TypeItem(repr_type.clone())) } ParserEndianness::LittleEndian => { ParserExpr::CallParseLE(TypeItem(repr_type.clone())) } ParserEndianness::Unspecified => { ParserExpr::CallParse(TypeItem(repr_type.clone())) } ParserEndianness::SetEndian => unimplemented!("SetEndian for fieldless enums"), } } _ => { return Err(Error::new( repr.span(), "Nom-derive: cannot parse 'repr' content (must be a primitive type)", )) } }; let variants_code: Vec<_> = data_enum .variants .iter() .map(|variant| { let id = &variant.ident; quote! { if selector == #name::#id as #repr_type { #name::#id } } }) .collect(); Ok(Self { name, config, extra_args, orig_generics: generics.clone(), tl_pre, tl_post, repr_parser, variants_code, }) } } nom-derive-impl-0.10.0/src/gen/generator.rs000064400000000000000000000316320072674642500166370ustar 00000000000000use crate::config::Config; use crate::endian::*; use crate::meta::attr::{MetaAttr, MetaAttrType}; use proc_macro2::{Span, TokenStream}; use quote::ToTokens; use syn::parse::Parser; use syn::punctuated::Punctuated; use syn::token::Comma; use syn::*; pub(crate) trait Generator { fn from_ast(ast: &DeriveInput, endianness: ParserEndianness) -> Result where Self: Sized; fn name(&self) -> &Ident; fn set_debug(&mut self, debug_derive: bool); fn extra_args(&self) -> Option<&TokenStream>; fn orig_generics(&self) -> &Generics; fn impl_where_predicates(&self) -> Option<&Vec> { None } fn config(&self) -> &Config; fn gen_fn_body(&self, endianness: ParserEndianness) -> Result; fn gen_parse_be(&self) -> Result { let fn_decl = gen_fn_decl( ParserEndianness::BigEndian, self.extra_args(), self.config(), ); if self.has_impl_for_endianness(ParserEndianness::BigEndian) { let fn_body = self.gen_fn_body(ParserEndianness::BigEndian)?; let fn_tokens = quote! { #fn_decl { #fn_body } }; Ok(fn_tokens) } else { let call_args = self.get_call_args(); let ts = quote! { #fn_decl { Self::parse_le(#call_args) } }; Ok(ts) } } fn gen_parse_le(&self) -> Result { let fn_decl = gen_fn_decl( ParserEndianness::LittleEndian, self.extra_args(), self.config(), ); if self.has_impl_for_endianness(ParserEndianness::LittleEndian) { let fn_body = self.gen_fn_body(ParserEndianness::LittleEndian)?; let fn_tokens = quote! { #fn_decl { #fn_body } }; Ok(fn_tokens) } else { let call_args = self.get_call_args(); let ts = quote! { #fn_decl { Self::parse_be(#call_args) } }; Ok(ts) } } fn gen_parse(&self) -> Result { let ident_e = Ident::new(self.config().error_name(), Span::call_site()); let lft = Lifetime::new(self.config().lifetime_name(), Span::call_site()); // 'parse' function let maybe_err = if self.config().generic_errors { quote!( , #ident_e ) } else { quote!() }; let special_case = self.extra_args().is_some() || self.config().selector_type().is_some(); let scope = if special_case { quote! { pub } } else { quote! {} }; let tokens_parse = { let (fn_generics, where_clause) = if self.config().generic_errors && special_case { ( quote!(<#ident_e>), quote! {where #ident_e: nom_derive::nom::error::ParseError<&#lft [u8]>, #ident_e: std::fmt::Debug, }, ) } else { (quote!(), quote!()) }; let call_args = self.get_call_args(); let fn_args = get_fn_args(self.extra_args(), self.config()); quote! { #scope fn parse#fn_generics(#fn_args) -> nom::IResult<&'nom [u8], Self #maybe_err> #where_clause { Self::parse_be(#call_args) } } }; Ok(tokens_parse) } fn gen_impl(&self) -> Result { let name = self.name(); let lft = Lifetime::new(self.config().lifetime_name(), Span::call_site()); let ident_e = Ident::new(self.config().error_name(), Span::call_site()); let maybe_err = if self.config().generic_errors { quote!( , #ident_e ) } else { quote!() }; let tokens_parse = self.gen_parse()?; let tokens_parse_be = self.gen_parse_be()?; let tokens_parse_le = self.gen_parse_le()?; // extract impl parameters from struct let orig_generics = &self.orig_generics(); let (impl_generics, ty_generics, where_clause) = orig_generics.split_for_impl(); let mut gen_impl: Generics = parse_quote!(#impl_generics); gen_impl .params .push(GenericParam::Lifetime(LifetimeDef::new(lft.clone()))); let param_e = TypeParam::from(ident_e.clone()); let mut gen_wh: WhereClause = if where_clause.is_none() { parse_quote!(where) } else { parse_quote!(#where_clause) }; let lfts: Vec<_> = orig_generics.lifetimes().collect(); if !lfts.is_empty() { // input slice must outlive all lifetimes from Self let wh: WherePredicate = parse_quote! { #lft: #(#lfts)+* }; gen_wh.predicates.push(wh); }; // make sure generic parameters inplement Parse for param in orig_generics.type_params() { let param_ident = ¶m.ident; let dep: WherePredicate = parse_quote! { #param_ident: Parse< &#lft [u8] #maybe_err > }; gen_wh.predicates.push(dep); } if let Some(impl_where_predicates) = self.impl_where_predicates() { for wh in impl_where_predicates { gen_wh.predicates.push(wh.clone()); } } // Global impl let impl_tokens = if self.extra_args().is_some() || self.config().selector_type().is_some() { // There are extra arguments, so we can't generate the Parse impl // Generate an equivalent implementation if self.config().generic_errors { // XXX will fail: generic type should be added to function (npt struct), or // XXX compiler will complain that // XXX "the type parameter `NomErr` is not constrained by the impl trait, self type, or predicates" // this happens only when not implementing trait (the trait constrains NomErr) // let wh: WherePredicate = parse_quote!(#ident_e: nom::error::ParseError<& #lft [u8]>); // gen_wh.predicates.push(wh); // gen_impl.params.push(GenericParam::Type(param_e)); } quote! { impl #gen_impl #name #ty_generics #gen_wh { #tokens_parse_be #tokens_parse_le #tokens_parse } } } else { // Generate an impl block for the Parse trait let error; if self.config().generic_errors { let wh: WherePredicate = parse_quote!(#ident_e: nom::error::ParseError<& #lft [u8]>); gen_wh.predicates.push(wh); gen_impl.params.push(GenericParam::Type(param_e)); error = quote! { #ident_e }; } else { error = quote! { nom::error::Error<&#lft [u8]> }; } quote! { impl #gen_impl nom_derive::Parse<& #lft [u8], #error> for #name #ty_generics #gen_wh { #tokens_parse_be #tokens_parse_le #tokens_parse } } }; if self.config().debug_derive { eprintln!("tokens:\n{}", impl_tokens); } Ok(impl_tokens) } fn has_impl_for_endianness(&self, endianness: ParserEndianness) -> bool { assert!( endianness == ParserEndianness::BigEndian || endianness == ParserEndianness::LittleEndian ); // if self.config().object_endianness == endianness || self.config().global_endianness == endianness { return true; } if self.config().object_endianness == ParserEndianness::Unspecified || self.config().global_endianness == ParserEndianness::Unspecified { return true; } false } fn get_call_args(&self) -> TokenStream { let mut call_args: Punctuated<_, Token![,]> = Punctuated::new(); let orig_input = Ident::new(self.config().orig_input_name(), Span::call_site()); call_args.push(orig_input); // selector, if present if let Some(s) = self.config().selector_name() { let selector = Ident::new(s, Span::call_site()); call_args.push(selector); } // extra args, if any if let Some(ts) = self.extra_args() { let ts = ts.clone(); let parser = Punctuated::::parse_separated_nonempty; let extra_args = parser.parse2(ts).expect("parse extra_args"); for extra_arg in &extra_args { match extra_arg { syn::FnArg::Receiver(_) => panic!("self should not be used in extra_args"), syn::FnArg::Typed(t) => { if let syn::Pat::Ident(pat_ident) = t.pat.as_ref() { call_args.push(pat_ident.ident.clone()); } else { panic!("unexpected pattern in extra_args"); } } } } }; call_args.to_token_stream() } } pub(crate) fn gen_fn_decl( endianness: ParserEndianness, extra_args: Option<&TokenStream>, config: &Config, ) -> TokenStream { let parse = match endianness { ParserEndianness::BigEndian => "parse_be", ParserEndianness::LittleEndian => "parse_le", ParserEndianness::SetEndian => panic!("gen_fn_decl should never receive SetEndian"), ParserEndianness::Unspecified => "parse", }; let parse = Ident::new(parse, Span::call_site()); let fn_args = get_fn_args(extra_args, config); // get lifetimes let lft = Lifetime::new(config.lifetime_name(), Span::call_site()); let mut fn_where_clause = WhereClause { where_token: Token![where](Span::call_site()), predicates: punctuated::Punctuated::new(), }; // if we are generating a stub, we need to mark the function as `pub` let special_case = extra_args.is_some() || config.selector_type().is_some(); let scope = if special_case { quote! { pub } } else { quote! {} }; // function declaration line if config.generic_errors { let ident_e = Ident::new(config.error_name(), Span::call_site()); let mut fn_generics = None; if special_case { // special case: not implementing the Parse trait, // generic errors must be added to function, not struct // // extend where clause for generic parameters let dep: WherePredicate = parse_quote! { #ident_e: nom_derive::nom::error::ParseError<&#lft [u8]> }; fn_where_clause.predicates.push(dep); let dep: WherePredicate = parse_quote! { #ident_e: std::fmt::Debug }; fn_where_clause.predicates.push(dep); // add error type to function generics fn_generics = Some(quote!(<#ident_e>)); } quote! { #scope fn #parse#fn_generics(#fn_args) -> nom::IResult<&#lft [u8], Self, #ident_e> #fn_where_clause } } else { quote! { #scope fn #parse(#fn_args) -> nom::IResult<&#lft [u8], Self> #fn_where_clause } } } pub(crate) fn get_extra_args(meta_list: &[MetaAttr]) -> Option<&TokenStream> { meta_list .iter() .find(|m| m.attr_type == MetaAttrType::ExtraArgs) .and_then(MetaAttr::arg) } pub(crate) fn get_fn_args( extra_args: Option<&TokenStream>, config: &Config, ) -> Punctuated { let orig_input = Ident::new(config.orig_input_name(), Span::call_site()); // get lifetimes let lft = Lifetime::new(config.lifetime_name(), Span::call_site()); // function arguments: input first let mut fn_args: Punctuated<_, Token![,]> = Punctuated::new(); let arg_input: FnArg = parse_quote!(#orig_input: &#lft [u8]); fn_args.push(arg_input); // selector, if present if let Some(sel_type) = config.selector_type() { let s = config.selector_name().unwrap_or("selector"); let sel_name = Ident::new(s, Span::call_site()); let selector: FnArg = parse_quote!(#sel_name: #sel_type); fn_args.push(selector); } // extra args, if any if let Some(ts) = extra_args { let ts = ts.clone(); type Comma = syn::Token![,]; let parser = Punctuated::::parse_separated_nonempty; let extra_args = parser.parse2(ts).expect("parse extra_args"); for extra_arg in &extra_args { fn_args.push(extra_arg.clone()); } }; fn_args } nom-derive-impl-0.10.0/src/gen/structs.rs000064400000000000000000000131470072674642500163610ustar 00000000000000use proc_macro2::TokenStream; use syn::*; use crate::config::Config; use crate::endian::*; use crate::meta; use crate::structs::*; use super::*; pub struct GenStruct { pub name: Ident, pub config: Config, extra_args: Option, orig_generics: Generics, tl_pre: Option, tl_post: Option, parser_tree: StructParserTree, impl_where_predicates: Option>, } impl Generator for GenStruct { fn from_ast(ast: &DeriveInput, endianness: ParserEndianness) -> Result { match &ast.data { syn::Data::Struct(datastruct) => GenStruct::from_datastruct( &ast.ident, datastruct, &ast.attrs, &ast.generics, endianness, ), _ => panic!("Wrong type for GenEnum::from_ast"), } } #[inline] fn name(&self) -> &Ident { &self.name } fn set_debug(&mut self, debug_derive: bool) { self.config.debug_derive |= debug_derive; } #[inline] fn extra_args(&self) -> Option<&TokenStream> { self.extra_args.as_ref() } #[inline] fn orig_generics(&self) -> &Generics { &self.orig_generics } fn impl_where_predicates(&self) -> Option<&Vec> { self.impl_where_predicates.as_ref() } #[inline] fn config(&self) -> &Config { &self.config } fn gen_fn_body(&self, endianness: ParserEndianness) -> Result { let name = &self.name; let (tl_pre, tl_post) = (&self.tl_pre, &self.tl_post); let input = syn::Ident::new(self.config.input_name(), Span::call_site()); let orig_input = syn::Ident::new(self.config.orig_input_name(), Span::call_site()); // prepare tokens let (idents, parser_tokens): (Vec<_>, Vec<_>) = self .parser_tree .parsers .iter() .map(|sp| { let id = syn::Ident::new(&sp.name, Span::call_site()); // set current endianness for functions that do not specify it let item = sp.item.with_endianness(endianness); (id, item) }) .unzip(); let (pre, post): (Vec<_>, Vec<_>) = self .parser_tree .parsers .iter() .map(|sp| (sp.pre_exec.as_ref(), sp.post_exec.as_ref())) .unzip(); let idents2 = idents.clone(); // Code generation let struct_def = match (self.parser_tree.empty, self.parser_tree.unnamed) { (true, _) => quote! { #name }, (_, true) => quote! { #name ( #(#idents2),* ) }, (_, false) => quote! { #name { #(#idents2),* } }, }; let fn_body = quote! { let #input = #orig_input; #tl_pre #(#pre let (#input, #idents) = #parser_tokens (#input) ?; #post)* let struct_def = #struct_def; #tl_post Ok((#input, struct_def)) }; Ok(fn_body) } } impl GenStruct { pub fn from_datastruct( name: &Ident, datastruct: &DataStruct, attrs: &[Attribute], generics: &Generics, endianness: ParserEndianness, ) -> Result { let name = name.clone(); // parse top-level attributes and prepare tokens for each field parser let meta = meta::parse_nom_top_level_attribute(attrs)?; // eprintln!("top-level meta: {:?}", meta); let mut config = Config::from_meta_list(name.to_string(), &meta)?; // endianness must be set before parsing struct set_object_endianness(name.span(), endianness, &meta, &mut config)?; let extra_args = get_extra_args(&meta).map(Clone::clone); // test endianness validity (not 2 or more) validate_endianness( endianness, config.object_endianness, config.global_endianness, )?; // save global pre/post exec let (tl_pre, tl_post) = get_pre_post_exec(&meta, &config); let s = parse_struct(datastruct, &mut config)?; let impl_where_predicates = add_extra_where_predicates(&s, &config); Ok(GenStruct { name, config, extra_args, orig_generics: generics.clone(), tl_pre, tl_post, parser_tree: s, impl_where_predicates, }) } } /// Find additional where clauses to add (for ex. `String` requires `FromExternalError<&[u8], Utf8Error>`) #[allow(clippy::single_match)] fn add_extra_where_predicates( parser_tree: &StructParserTree, config: &Config, ) -> Option> { if config.generic_errors { let mut v = Vec::new(); let lft = Lifetime::new(config.lifetime_name(), Span::call_site()); let err = Ident::new(config.error_name(), Span::call_site()); // visit parser tree and look for types with requirement on Error type for p in &parser_tree.parsers { if let Some(ty) = p.item.expr.last_type() { if let Ok(s) = get_type_first_ident(&ty.0) { match s.as_ref() { "String" => { let wh: WherePredicate = parse_quote! {#err: nom::error::FromExternalError<&#lft [u8], core::str::Utf8Error>}; v.push(wh) } _ => (), } } } } if !v.is_empty() { Some(v) } else { None } } else { None } } nom-derive-impl-0.10.0/src/gen.rs000064400000000000000000000030500072674642500146420ustar 00000000000000use crate::{endian::ParserEndianness, enums::is_input_fieldless_enum, meta}; use proc_macro2::{Span, TokenStream}; use syn::*; mod enums; mod fieldless_enums; mod generator; mod structs; use enums::GenEnum; use fieldless_enums::GenFieldlessEnum; pub(crate) use generator::*; use structs::GenStruct; pub(crate) fn gen_impl( ast: &syn::DeriveInput, endianness: ParserEndianness, ) -> Result { // eprintln!("ast: {:#?}", ast); let generator: Box = match &ast.data { syn::Data::Enum(_) => { // look for a selector let meta = meta::parse_nom_top_level_attribute(&ast.attrs)?; if meta .iter() .any(|m| m.is_type(meta::attr::MetaAttrType::Selector)) { Box::new(GenEnum::from_ast(ast, endianness)?) } else { // no selector, try fieldless enum if is_input_fieldless_enum(ast) { Box::new(GenFieldlessEnum::from_ast(ast, endianness)?) } else { return Err(Error::new( ast.ident.span(), "Nom-derive: enums must have a 'selector' attribute", )); } } } syn::Data::Struct(_) => Box::new(GenStruct::from_ast(ast, endianness)?), syn::Data::Union(_) => panic!("Unions not supported"), }; let impl_tokens = generator.gen_impl()?; // eprintln!("\n***\nglobal_impl: {}\n---\n", impl_tokens); Ok(impl_tokens) } nom-derive-impl-0.10.0/src/lib.rs000064400000000000000000000052200072674642500146400ustar 00000000000000//! # nom-derive-impl //! //! ## Overview //! //! nom-derive is a custom derive attribute, to derive `nom` parsers automatically from the structure definition. //! //! This crate is not meant to be used directly. //! See [`nom-derive`](https://docs.rs/nom-derive) crate for documentation. extern crate proc_macro; extern crate proc_macro2; extern crate syn; #[macro_use] extern crate quote; use proc_macro::TokenStream; use syn::*; mod config; mod endian; mod enums; mod gen; mod meta; mod parsertree; mod structs; use crate::endian::*; use crate::gen::*; /// The `Nom` derive automatically generates a `parse` function for the structure /// using [nom] parsers. It will try to infer parsers for primitive of known /// types, but also allows you to specify parsers using custom attributes. /// /// Deriving parsers supports `struct` and `enum` types. /// /// The documentation of the `Nom` custom derive attribute and all possible options /// can be found in the [nom-derive documentation](https://docs.rs/nom-derive). /// /// Many examples are provided, and more can be found in the [project /// tests](https://github.com/rust-bakery/nom-derive/tree/master/tests). /// /// [nom]: https://github.com/Geal/nom #[proc_macro_derive(Nom, attributes(nom))] pub fn nom(input: TokenStream) -> TokenStream { // Parse the input tokens into a syntax tree let ast = parse_macro_input!(input as DeriveInput); // Build and return the generated impl match gen_impl(&ast, ParserEndianness::Unspecified) { Ok(ts) => ts.into(), Err(e) => e.to_compile_error().into(), } } /// The `NomBE` acts like the [`Nom`] attribute, but sets the endianness to big-endian for the /// current object. This can be overriden locally at the field-level. #[proc_macro_derive(NomBE, attributes(nom))] pub fn nom_be(input: TokenStream) -> TokenStream { // Parse the input tokens into a syntax tree let ast = parse_macro_input!(input as DeriveInput); // Build and return the generated impl match gen_impl(&ast, ParserEndianness::BigEndian) { Ok(ts) => ts.into(), Err(e) => e.to_compile_error().into(), } } /// The `NomLE` acts like the [`Nom`] attribute, but sets the endianness to little-endian for the /// current object. This can be overriden locally at the field-level. #[proc_macro_derive(NomLE, attributes(nom))] pub fn nom_le(input: TokenStream) -> TokenStream { // Parse the input tokens into a syntax tree let ast = parse_macro_input!(input as DeriveInput); // Build and return the generated impl match gen_impl(&ast, ParserEndianness::LittleEndian) { Ok(ts) => ts.into(), Err(e) => e.to_compile_error().into(), } } nom-derive-impl-0.10.0/src/meta/attr.rs000064400000000000000000000242210072674642500157740ustar 00000000000000use proc_macro2::{Span, TokenStream}; use quote::ToTokens; use std::fmt; use syn::parse::{Parse, ParseStream}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::{parenthesized, token, Ident, Token}; #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum MetaAttrType { AlignAfter, AlignBefore, BigEndian, Complete, Cond, Count, Debug, DebugDerive, ErrorIf, Exact, ExtraArgs, GenericErrors, Ignore, InputName, Into, LengthCount, LittleEndian, Map, Move, MoveAbs, Parse, PostExec, PreExec, Selector, SetEndian, SkipAfter, SkipBefore, Tag, Take, Value, Verify, } impl MetaAttrType { pub fn from_ident(ident: &syn::Ident) -> Option { match ident.to_string().as_ref() { "AlignAfter" => Some(MetaAttrType::AlignAfter), "AlignBefore" => Some(MetaAttrType::AlignBefore), "BigEndian" => Some(MetaAttrType::BigEndian), "Complete" => Some(MetaAttrType::Complete), "Count" => Some(MetaAttrType::Count), "Debug" => Some(MetaAttrType::Debug), "DebugDerive" => Some(MetaAttrType::DebugDerive), "ErrorIf" => Some(MetaAttrType::ErrorIf), "Exact" => Some(MetaAttrType::Exact), "ExtraArgs" => Some(MetaAttrType::ExtraArgs), "GenericErrors" => Some(MetaAttrType::GenericErrors), "If" | "Cond" => Some(MetaAttrType::Cond), "Ignore" | "Default" => Some(MetaAttrType::Ignore), "InputName" => Some(MetaAttrType::InputName), "Into" => Some(MetaAttrType::Into), "LengthCount" => Some(MetaAttrType::LengthCount), "LittleEndian" => Some(MetaAttrType::LittleEndian), "Map" => Some(MetaAttrType::Map), "Move" => Some(MetaAttrType::Move), "MoveAbs" => Some(MetaAttrType::MoveAbs), "Parse" => Some(MetaAttrType::Parse), "PostExec" => Some(MetaAttrType::PostExec), "PreExec" => Some(MetaAttrType::PreExec), "Selector" => Some(MetaAttrType::Selector), "SetEndian" => Some(MetaAttrType::SetEndian), "SkipAfter" => Some(MetaAttrType::SkipAfter), "SkipBefore" => Some(MetaAttrType::SkipBefore), "Tag" => Some(MetaAttrType::Tag), "Take" => Some(MetaAttrType::Take), "Value" => Some(MetaAttrType::Value), "Verify" => Some(MetaAttrType::Verify), _ => None, } } pub fn takes_argument(self) -> bool { matches!( self, MetaAttrType::AlignAfter | MetaAttrType::AlignBefore | MetaAttrType::Cond | MetaAttrType::Count | MetaAttrType::ErrorIf | MetaAttrType::ExtraArgs | MetaAttrType::InputName | MetaAttrType::LengthCount | MetaAttrType::Map | MetaAttrType::Move | MetaAttrType::MoveAbs | MetaAttrType::Parse | MetaAttrType::PostExec | MetaAttrType::PreExec | MetaAttrType::Selector | MetaAttrType::SetEndian | MetaAttrType::SkipAfter | MetaAttrType::SkipBefore | MetaAttrType::Tag | MetaAttrType::Take | MetaAttrType::Value | MetaAttrType::Verify ) } } impl fmt::Display for MetaAttrType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = match self { MetaAttrType::AlignAfter => "AlignAfter", MetaAttrType::AlignBefore => "AlignBefore", MetaAttrType::BigEndian => "BigEndian", MetaAttrType::Complete => "Complete", MetaAttrType::Cond => "Cond", MetaAttrType::Count => "Count", MetaAttrType::Debug => "Debug", MetaAttrType::DebugDerive => "DebugDerive", MetaAttrType::ErrorIf => "ErrorIf", MetaAttrType::Exact => "Exact", MetaAttrType::ExtraArgs => "ExtraArgs", MetaAttrType::GenericErrors => "GenericErrors", MetaAttrType::Ignore => "Ignore", MetaAttrType::InputName => "InputName", MetaAttrType::Into => "Into", MetaAttrType::LengthCount => "LengthCount", MetaAttrType::LittleEndian => "LittleEndian", MetaAttrType::Map => "Map", MetaAttrType::Move => "Move", MetaAttrType::MoveAbs => "MoveAbs", MetaAttrType::Parse => "Parse", MetaAttrType::PostExec => "PostExec", MetaAttrType::PreExec => "PreExec", MetaAttrType::Selector => "Selector", MetaAttrType::SetEndian => "SetEndian", MetaAttrType::SkipAfter => "SkipAfter", MetaAttrType::SkipBefore => "SkipBefore", MetaAttrType::Tag => "Tag", MetaAttrType::Take => "Take", MetaAttrType::Value => "Value", MetaAttrType::Verify => "Verify", }; f.write_str(s) } } #[derive(Debug)] pub struct MetaAttr { pub attr_type: MetaAttrType, arg0: Option, span: Span, } impl MetaAttr { pub fn new(attr_type: MetaAttrType, arg0: Option, span: Span) -> Self { MetaAttr { attr_type, arg0, span, } } /// Is attribute acceptable for top-level pub fn acceptable_tla(&self) -> bool { matches!( self.attr_type, MetaAttrType::DebugDerive | MetaAttrType::Complete | MetaAttrType::Debug | MetaAttrType::ExtraArgs | MetaAttrType::GenericErrors | MetaAttrType::InputName | MetaAttrType::LittleEndian | MetaAttrType::BigEndian | MetaAttrType::SetEndian | MetaAttrType::PreExec | MetaAttrType::PostExec | MetaAttrType::Exact | MetaAttrType::Selector ) } /// Is attribute acceptable for field-level pub fn acceptable_fla(&self) -> bool { !matches!( self.attr_type, MetaAttrType::DebugDerive | MetaAttrType::Exact | MetaAttrType::ExtraArgs | MetaAttrType::GenericErrors | MetaAttrType::InputName ) } #[inline] pub fn is_type(&self, attr_type: MetaAttrType) -> bool { self.attr_type == attr_type } #[inline] pub fn arg(&self) -> Option<&TokenStream> { self.arg0.as_ref() } } impl fmt::Display for MetaAttr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.attr_type)?; if let Some(arg) = &self.arg0 { write!(f, "({})", arg)?; } Ok(()) } } impl Spanned for MetaAttr { fn span(&self) -> Span { self.span } } impl Parse for MetaAttr { fn parse(input: ParseStream) -> syn::Result { let ident: Ident = input.parse()?; let attr_type = MetaAttrType::from_ident(&ident).unwrap_or_else(|| panic!("Wrong meta name {}", ident)); let arg0 = if attr_type.takes_argument() { // read (value), or ="value" let token_stream = match attr_type { MetaAttrType::ExtraArgs => { let content; let _paren_token = parenthesized!(content in input); type ExpectedType = Punctuated; let fields: ExpectedType = content.parse_terminated(syn::Field::parse_named)?; quote! { #fields } } MetaAttrType::PreExec | MetaAttrType::PostExec => { parse_content::(input)? } MetaAttrType::Selector => parse_content::(input)?, _ => parse_content::(input)?, }; Some(token_stream) } else { None }; Ok(MetaAttr::new(attr_type, arg0, ident.span())) } } fn parse_content

(input: ParseStream) -> syn::Result where P: Parse + ToTokens + fmt::Debug, { if input.peek(Token![=]) { // eprintln!("Exec Peek: ="); let _: Token![=] = input.parse()?; // next item is a string containing the real value let x = syn::Lit::parse(input)?; // eprintln!("content: {:?}", x); match x { syn::Lit::Str(s) => { let xx: P = s.parse()?; // eprintln!("xx: {:?}", xx); Ok(quote! { #xx }) } _ => Err(syn::Error::new( x.span(), "Unexpected type for nom attribute content (!LitStr)", )), } } else if input.peek(token::Paren) { // eprintln!("Exec Peek: ("); let content; let _paren_token = parenthesized!(content in input); let x = P::parse(&content)?; // let x: Punctuated = content.parse_terminated(Type::parse)?; // eprintln!("content: {:?}", x); Ok(quote! { #x }) } else { Err(syn::Error::new( input.span(), "Unexpected type for nom attribute content (!LitStr)", )) } } #[derive(Debug)] struct PatternAndGuard { pat: syn::Pat, guard: Option<(token::If, Box)>, } impl Parse for PatternAndGuard { fn parse(input: ParseStream) -> syn::Result { let pat = input.parse()?; let guard = if input.peek(Token![if]) { let tk_if: Token![if] = input.parse()?; let expr: syn::Expr = input.parse()?; Some((tk_if, Box::new(expr))) } else { None }; Ok(PatternAndGuard { pat, guard }) } } impl quote::ToTokens for PatternAndGuard { fn to_tokens(&self, tokens: &mut TokenStream) { self.pat.to_tokens(tokens); if let Some((tk_if, expr)) = &self.guard { tk_if.to_tokens(tokens); expr.to_tokens(tokens); } } } nom-derive-impl-0.10.0/src/meta/attr_list.rs000064400000000000000000000010370072674642500170270ustar 00000000000000use syn::parse::{Parse, ParseStream}; use syn::punctuated::Punctuated; use syn::{parenthesized, Token}; #[derive(Debug)] pub struct AttrList(pub Vec); impl Parse for AttrList { fn parse(input: ParseStream) -> syn::Result { // eprintln!("AttrList::parse: {:?}", input); let content; parenthesized!(content in input); Ok(AttrList( Punctuated::::parse_terminated(&content)? .into_iter() .collect(), )) } } nom-derive-impl-0.10.0/src/meta/error.rs000064400000000000000000000002470072674642500161550ustar 00000000000000use std::convert::From; #[derive(Debug)] pub struct MetaError; impl From for MetaError { fn from(_e: syn::Error) -> Self { MetaError } } nom-derive-impl-0.10.0/src/meta/mod.rs000064400000000000000000000033570072674642500156100ustar 00000000000000pub mod attr; pub mod attr_list; pub mod error; use syn::{spanned::Spanned, Error, Result}; pub fn parse_nom_top_level_attribute(attrs: &[syn::Attribute]) -> Result> { // eprintln!("attrs: {:?}", attrs); let x: Vec<_> = attrs .iter() .filter_map(|x| { if x.path.is_ident("nom") { Some(meta_from_attribute(x)) } else { None } }) .collect::, _>>()? .into_iter() .flat_map(|x| x.0.into_iter()) .collect(); // eprintln!("XXX: {:?}", x); if let Some(attr) = x.iter().find(|m| !m.acceptable_tla()) { return Err(Error::new( attr.span(), &format!("Attribute {} is not valid for top-level", attr), )); } Ok(x) } fn meta_from_attribute(attr: &syn::Attribute) -> Result> { // eprintln!("tlas_from_attribute: {:?}", attr); syn::parse2(attr.tokens.clone()) } pub fn parse_nom_attribute(attrs: &[syn::Attribute]) -> Result> { // eprintln!("attrs: {:?}", attrs); let x: Vec<_> = attrs .iter() .filter_map(|x| { if x.path.is_ident("nom") { Some(meta_from_attribute(x)) } else { None } }) .collect::, _>>()? .into_iter() .flat_map(|x| x.0.into_iter()) .collect(); // eprintln!("****\nXXX: {:?}\n", x); if let Some(attr) = x.iter().find(|m| !m.acceptable_fla()) { return Err(Error::new( attr.span(), &format!("Attribute {} is not valid for field-level", attr), )); } Ok(x) } nom-derive-impl-0.10.0/src/parsertree.rs000064400000000000000000000117420072674642500162540ustar 00000000000000use proc_macro2::TokenStream; use quote::ToTokens; use syn::Ident; use crate::endian::ParserEndianness; #[derive(Debug)] pub struct ParserTree { root: ParserExpr, } impl ToTokens for ParserTree { fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { self.root.to_tokens(tokens) } } #[derive(Debug)] pub struct ParserTreeItem { pub ident: Option, pub expr: ParserExpr, } impl ParserTreeItem { pub fn new(ident: Option, expr: ParserExpr) -> Self { ParserTreeItem { ident, expr } } pub fn with_endianness(&self, endianness: ParserEndianness) -> Self { ParserTreeItem { ident: self.ident.clone(), expr: self.expr.with_endianness(endianness), } } } impl ToTokens for ParserTreeItem { fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { self.expr.to_tokens(tokens) } } #[allow(clippy::upper_case_acronyms)] #[derive(Clone, Debug)] pub enum ParserExpr { CallParse(TypeItem), CallParseBE(TypeItem), CallParseLE(TypeItem), Complete(Box), Cond(Box, TokenStream), Count(Box, TokenStream), DbgDmp(Box, Ident), Into(Box), LengthCount(Box, TokenStream), Map(Box, TokenStream), Nop, PhantomData, Raw(TokenStream), Tag(TokenStream), Take(TokenStream), Value(TokenStream), Verify(Box, Ident, TokenStream), } impl ParserExpr { pub fn with_endianness(&self, endianness: ParserEndianness) -> Self { match self { ParserExpr::CallParse(item) => match endianness { ParserEndianness::BigEndian => ParserExpr::CallParseBE(item.clone()), ParserEndianness::LittleEndian => ParserExpr::CallParseLE(item.clone()), _ => unreachable!(), }, expr => expr.clone(), } } #[inline] pub fn complete(self) -> Self { ParserExpr::Complete(Box::new(self)) } pub fn last_type(&self) -> Option<&TypeItem> { match self { ParserExpr::CallParse(e) | ParserExpr::CallParseBE(e) | ParserExpr::CallParseLE(e) => { Some(e) } ParserExpr::Complete(expr) | ParserExpr::Cond(expr, _) | ParserExpr::Count(expr, _) | ParserExpr::DbgDmp(expr, _) | ParserExpr::Into(expr) | ParserExpr::LengthCount(expr, _) | ParserExpr::Map(expr, _) | ParserExpr::Verify(expr, _, _) => expr.last_type(), _ => None, } } } impl ToTokens for ParserExpr { fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { let ts = match self { ParserExpr::CallParse(s) => { quote! { <#s>::parse } } ParserExpr::CallParseBE(s) => { quote! { <#s>::parse_be } } ParserExpr::CallParseLE(s) => { quote! { <#s>::parse_le } } ParserExpr::Complete(expr) => { quote! { nom::combinator::complete(#expr) } } ParserExpr::Cond(expr, c) => { quote! { nom::combinator::cond(#c, #expr) } } ParserExpr::Count(expr, n) => { quote! { nom::multi::count(#expr, #n as usize) } } ParserExpr::DbgDmp(expr, i) => { let ident = format!("{}", i); quote! { nom::error::dbg_dmp(#expr, #ident) } } ParserExpr::Into(expr) => { quote! { nom::combinator::into(#expr) } } ParserExpr::LengthCount(expr, n) => { quote! { nom::multi::length_count(#n, #expr) } } ParserExpr::Map(expr, m) => { quote! { nom::combinator::map(#expr, #m) } } ParserExpr::Nop => { quote! { { |__i__| Ok((__i__, ())) } } } ParserExpr::PhantomData => { quote! { { |__i__| Ok((__i__, PhantomData)) } } } ParserExpr::Raw(s) => s.to_token_stream(), ParserExpr::Tag(s) => { quote! { nom::bytes::streaming::tag(#s) } } ParserExpr::Take(s) => { quote! { nom::bytes::streaming::take(#s as usize) } } ParserExpr::Value(ts) => { quote! { { |__i__| Ok((__i__, #ts)) } } } ParserExpr::Verify(expr, i, v) => { quote! { nom::combinator::verify(#expr, |#i| { #v }) } } }; tokens.extend(ts); } } #[derive(Clone, Debug)] pub struct TypeItem(pub syn::Type); impl ToTokens for TypeItem { fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { self.0.to_tokens(tokens) } } nom-derive-impl-0.10.0/src/structs.rs000064400000000000000000000426120072674642500156070ustar 00000000000000use crate::config::*; use crate::endian::*; use crate::meta; use crate::meta::attr::{MetaAttr, MetaAttrType}; use crate::parsertree::*; use proc_macro2::{Span, TokenStream, TokenTree}; use quote::ToTokens; use syn::spanned::Spanned; use syn::*; #[derive(Debug)] pub(crate) struct StructParser { pub name: String, pub item: ParserTreeItem, pub pre_exec: Option, pub post_exec: Option, } impl StructParser { pub fn new( name: String, item: ParserTreeItem, pre_exec: Option, post_exec: Option, ) -> Self { StructParser { name, item, pre_exec, post_exec, } } } #[derive(Debug)] pub(crate) struct StructParserTree { pub empty: bool, pub unnamed: bool, pub parsers: Vec, } fn get_type_parser(ty: &Type, meta_list: &[MetaAttr], config: &Config) -> Result { // special case: PhantomData let ident = get_type_first_ident(ty)?; if ident == "PhantomData" { return Ok(ParserExpr::PhantomData); } let endian = get_local_endianness(ty.span(), meta_list, config)?; match endian { ParserEndianness::BigEndian => Ok(ParserExpr::CallParseBE(TypeItem(ty.clone()))), ParserEndianness::LittleEndian => Ok(ParserExpr::CallParseLE(TypeItem(ty.clone()))), ParserEndianness::SetEndian => { let be = ParserExpr::CallParseBE(TypeItem(ty.clone())); let le = ParserExpr::CallParseLE(TypeItem(ty.clone())); let qq = quote! { if __endianness == nom::number::Endianness::Big { #be } else { #le } }; Ok(ParserExpr::Raw(qq)) } ParserEndianness::Unspecified => Ok(ParserExpr::CallParse(TypeItem(ty.clone()))), } } fn get_item_subtype_parser(ty: &Type, expected: &str, attr: &str) -> Result { if let Type::Path(ref typepath) = ty { let path = &typepath.path; if path.segments.len() != 1 { return Err(Error::new( ty.span(), "Nom-derive: multiple segments in type path are not supported", )); } let segment = path.segments.last().expect("empty segments list"); let ident_s = segment.ident.to_string(); if ident_s == expected { // segment.arguments should contain the values, wrapped in AngleBracketed if let PathArguments::AngleBracketed(args) = &segment.arguments { return Ok(args.args.to_token_stream()); } } } Err(Error::new( ty.span(), format!( "Nom-derive: unexpected type for {} attribute. Expected type: {}", attr, expected ), )) } pub(crate) fn get_type_first_ident(ty: &Type) -> Result { match ty { Type::Path(ref typepath) => { let path = &typepath.path; if path.segments.len() != 1 { return Err(Error::new( ty.span(), "Nom-derive: multiple segments in type path are not supported", )); } let segment = path.segments.last().expect("empty segments list"); let ident_s = segment.ident.to_string(); Ok(ident_s) } Type::Array(ref typearray) => get_type_first_ident(&typearray.elem), _ => Err(Error::new( ty.span(), "Nom-derive: could not get first path ident", )), } } fn get_type_default(ty: &Type) -> Result { let ident_s = get_type_first_ident(ty)?; let default = match ident_s.as_ref() { // "u8" | "u16" | "u32" | "u64" | "u128" | "i8" | "i16" | "i32" | "i64" | "i128" => { // "0".to_string() // } // "f32" | "f64" => "0.0".to_string(), "Option" => quote! { None }, "PhantomData" => quote! { PhantomData }, "Vec" => quote! { Vec::new() }, _ => quote! { <#ty>::default() }, }; // ParserTree::Raw(format!("{{ |i| Ok((i, {})) }}", default)) let ts = quote! { { |i| Ok((i, #default )) } }; Ok(ParserExpr::Raw(ts)) } fn get_parser( ident: Option<&Ident>, ty: &Type, // the list of remaining items to parse sub_meta_list: &[MetaAttr], // the list of all meta attributes for this type meta_list: &[MetaAttr], config: &Config, ) -> Result { // first check if we have attributes set // eprintln!("attrs: {:?}", field.attrs); // eprintln!("meta_list: {:?}", meta_list); let mut sub_meta_list = sub_meta_list; while let Some((meta, rem)) = sub_meta_list.split_first() { sub_meta_list = rem; // eprintln!(" meta {:?}", meta.attr_type); // eprintln!(" sub_meta_list: {:?}", sub_meta_list); match meta.attr_type { MetaAttrType::Tag => { let s = meta.arg().unwrap(); return Ok(ParserExpr::Tag(s.clone())); } MetaAttrType::Take => { // if meta.arg is string, parse content let ts = meta.arg().unwrap(); if let Some(TokenTree::Literal(_)) = ts.clone().into_iter().next() { let ts = syn::parse2::(ts.clone())?; return Ok(ParserExpr::Take(ts.to_token_stream())); } let s = meta.arg().unwrap(); return Ok(ParserExpr::Take(s.clone())); } MetaAttrType::Value => { let s = meta.arg().unwrap(); return Ok(ParserExpr::Value(s.clone())); } MetaAttrType::Parse => { let s = meta.arg().unwrap(); return Ok(ParserExpr::Raw(s.clone())); } MetaAttrType::Ignore => { return get_type_default(ty); } MetaAttrType::Complete => { let expr = get_parser(ident, ty, sub_meta_list, meta_list, config)?; return Ok(expr.complete()); } MetaAttrType::Debug => { let expr = get_parser(ident, ty, sub_meta_list, meta_list, config)?; let ident = match ident { Some(ident) => ident, None => { return Err(Error::new( meta.span(), "Nom-derive: can't use Verify with unnamed fields", )) } }; return Ok(ParserExpr::DbgDmp(Box::new(expr), ident.clone())); } MetaAttrType::Cond => { // try to infer subparser // check type is Option, and extract T let sub = get_item_subtype_parser(ty, "Option", "Cond")?; let sub_ty = syn::parse2::(sub)?; let expr = get_parser(ident, &sub_ty, sub_meta_list, meta_list, config)?; let ts = meta.arg().unwrap(); return Ok(ParserExpr::Cond(Box::new(expr), ts.clone())); } MetaAttrType::Count => { // try to infer subparser // check type is Vec, and extract T let sub = get_item_subtype_parser(ty, "Vec", "Count")?; let sub_ty = syn::parse2::(sub)?; let expr = get_parser(ident, &sub_ty, sub_meta_list, meta_list, config)?; let ts = meta.arg().unwrap(); return Ok(ParserExpr::Count(Box::new(expr), ts.clone())); } MetaAttrType::Into => { let expr = get_parser(ident, ty, sub_meta_list, meta_list, config)?; return Ok(ParserExpr::Into(Box::new(expr))); } MetaAttrType::LengthCount => { // try to infer subparser // check type is Vec, and extract T let sub = get_item_subtype_parser(ty, "Vec", "LengthCount")?; let sub_ty = syn::parse2::(sub)?; let expr = get_parser(ident, &sub_ty, sub_meta_list, meta_list, config)?; let ts = meta.arg().unwrap(); return Ok(ParserExpr::LengthCount(Box::new(expr), ts.clone())); } MetaAttrType::Map => { let expr = get_parser(ident, ty, sub_meta_list, meta_list, config)?; // if meta.arg is string, parse content let ts_arg = meta.arg().unwrap(); if let Some(TokenTree::Literal(_)) = ts_arg.clone().into_iter().next() { let ts_arg = syn::parse2::(ts_arg.clone())?; return Ok(ParserExpr::Map(Box::new(expr), ts_arg.to_token_stream())); } let ts_arg = meta.arg().unwrap(); return Ok(ParserExpr::Map(Box::new(expr), ts_arg.clone())); } MetaAttrType::Verify => { let expr = get_parser(ident, ty, sub_meta_list, meta_list, config)?; let ident = match ident { Some(ident) => ident, None => { return Err(Error::new( meta.span(), "Nom-derive: can't use Verify with unnamed fields", )) } }; // if meta.arg is string, parse content let ts_arg = meta.arg().unwrap(); if let Some(TokenTree::Literal(_)) = ts_arg.clone().into_iter().next() { let ts_arg = syn::parse2::(ts_arg.clone())?; return Ok(ParserExpr::Map(Box::new(expr), ts_arg.to_token_stream())); } let ts_arg = meta.arg().unwrap(); return Ok(ParserExpr::Verify( Box::new(expr), ident.clone(), ts_arg.clone(), )); } _ => (), } } // else try primitive types knowledge get_type_parser(ty, meta_list, config) } fn get_field_parser(field: &Field, meta_list: &[MetaAttr], config: &Config) -> Result { // eprintln!("field: {:?}", field); get_parser( field.ident.as_ref(), &field.ty, meta_list, meta_list, config, ) } fn quote_align(align: &TokenStream, config: &Config) -> TokenStream { let input = syn::Ident::new(config.input_name(), align.span()); let orig_input = syn::Ident::new(config.orig_input_name(), align.span()); quote! { let (#input, _) = { let offset = #input.as_ptr() as usize - #orig_input.as_ptr() as usize; let align = #align as usize; let align = ((align - (offset % align)) % align); nom::bytes::streaming::take(align)(#input) }?; } } // like quote_skip, but offset is an isize fn quote_move(offset: &TokenStream, config: &Config) -> TokenStream { let input = syn::Ident::new(config.input_name(), offset.span()); let orig_input = syn::Ident::new(config.orig_input_name(), offset.span()); quote! { let #input = { let start = #orig_input.as_ptr() as usize; let pos = #input.as_ptr() as usize - start; let offset = #offset as isize; let offset_u = offset.abs() as usize; let new_offset = if offset < 0 { if offset_u > pos { return Err(nom::Err::Error(nom::error::make_error(#input, nom::error::ErrorKind::TooLarge))); } pos - offset_u } else { if pos + offset_u > #orig_input.len() { return Err(nom::Err::Incomplete(nom::Needed::new(offset_u))); } pos + offset_u }; &#orig_input[new_offset..] }; } } // like quote_move, with absolute value as offset fn quote_move_abs(offset: &TokenStream, config: &Config) -> TokenStream { let input = syn::Ident::new(config.input_name(), offset.span()); let orig_input = syn::Ident::new(config.orig_input_name(), offset.span()); quote! { let #input = { let offset = #offset as usize; if offset > #orig_input.len() { return Err(nom::Err::Incomplete(nom::Needed::new(offset))); } &#orig_input[offset..] }; } } fn quote_skip(skip: &TokenStream, config: &Config) -> TokenStream { let input = syn::Ident::new(config.input_name(), skip.span()); quote! { let (#input, _) = { let skip = #skip as usize; nom::bytes::streaming::take(skip)(#input) }?; } } fn quote_error_if(cond: &TokenStream, config: &Config) -> TokenStream { let input = syn::Ident::new(config.input_name(), cond.span()); quote! { if #cond { return Err(nom::Err::Error(nom::error::make_error(#input, nom::error::ErrorKind::Verify))); } } } pub(crate) fn get_pre_post_exec( meta_list: &[MetaAttr], config: &Config, ) -> (Option, Option) { let mut tk_pre = proc_macro2::TokenStream::new(); let mut tk_post = proc_macro2::TokenStream::new(); for m in meta_list { match m.attr_type { MetaAttrType::PreExec => { tk_pre.extend(m.arg().unwrap().clone()); } MetaAttrType::PostExec => { tk_post.extend(m.arg().unwrap().clone()); } MetaAttrType::AlignAfter => { let align = m.arg().unwrap(); let qq = quote_align(align, config); tk_post.extend(qq); } MetaAttrType::AlignBefore => { let align = m.arg().unwrap(); let qq = quote_align(align, config); tk_pre.extend(qq); } MetaAttrType::SkipAfter => { let skip = m.arg().unwrap(); let qq = quote_skip(skip, config); tk_post.extend(qq); } MetaAttrType::SkipBefore => { let skip = m.arg().unwrap(); let qq = quote_skip(skip, config); tk_pre.extend(qq); } MetaAttrType::Move => { let offset = m.arg().unwrap(); let qq = quote_move(offset, config); tk_pre.extend(qq); } MetaAttrType::MoveAbs => { let offset = m.arg().unwrap(); let qq = quote_move_abs(offset, config); tk_pre.extend(qq); } MetaAttrType::ErrorIf => { let cond = m.arg().unwrap(); let qq = quote_error_if(cond, config); tk_pre.extend(qq); } MetaAttrType::Exact => { let input = syn::Ident::new(config.input_name(), m.span()); let cond = quote! { !#input.is_empty() }; let qq = quote_error_if(&cond, config); tk_post.extend(qq); } MetaAttrType::SetEndian => { let val = m.arg().unwrap(); let qq = quote! { let __endianness = #val; }; // config is updated in `get_parser` tk_pre.extend(qq); } _ => (), } } let pre = if tk_pre.is_empty() { None } else { Some(tk_pre) }; let post = if tk_post.is_empty() { None } else { Some(tk_post) }; (pre, post) } pub(crate) fn parse_fields(f: &Fields, config: &mut Config) -> Result { let mut parsers = vec![]; let mut empty = false; let mut unnamed = false; match f { Fields::Named(_) => (), Fields::Unnamed(_) => { unnamed = true; } Fields::Unit => { unnamed = false; empty = true; // the Parse attribute cannot be checked here (we only have 'Fields'), // so the caller must check and add attributes } } for (idx, field) in f.iter().enumerate() { let ident_str = if let Some(s) = field.ident.as_ref() { s.to_string() } else { format!("_{}", idx) }; let meta_list = meta::parse_nom_attribute(&field.attrs)?; // eprintln!("meta_list: {:?}", meta_list); let mut p = get_field_parser(field, &meta_list, config)?; if config.complete { p = p.complete(); } if config.debug { // debug is set for entire struct let ident = match &field.ident { Some(ident) => ident, None => { return Err(Error::new( Span::call_site(), "Nom-derive: can't use Debug with unnamed fields", )) } }; p = ParserExpr::DbgDmp(Box::new(p), ident.clone()); } // add pre and post code (also takes care of alignment) let (pre, post) = get_pre_post_exec(&meta_list, config); let item = ParserTreeItem::new(field.ident.clone(), p); let sp = StructParser::new(ident_str, item, pre, post); parsers.push(sp); } Ok(StructParserTree { empty, unnamed, parsers, }) } pub(crate) fn parse_struct(s: &DataStruct, config: &mut Config) -> Result { parse_fields(&s.fields, config) }