diff options
Diffstat (limited to 'components/config_plugins/parse.rs')
-rw-r--r-- | components/config_plugins/parse.rs | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/components/config_plugins/parse.rs b/components/config_plugins/parse.rs new file mode 100644 index 00000000000..715b60f50e9 --- /dev/null +++ b/components/config_plugins/parse.rs @@ -0,0 +1,149 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use proc_macro2::Span; +use syn::parse::{Parse, ParseStream, Result}; +use syn::{braced, punctuated::Punctuated, token, Attribute, Ident, Path, Token, Type}; + +#[allow(non_camel_case_types)] +mod kw { + syn::custom_keyword!(accessor_type); + syn::custom_keyword!(gen_accessors); + syn::custom_keyword!(gen_types); +} + +pub struct MacroInput { + pub type_def: RootTypeDef, + pub gen_accessors: Ident, + pub accessor_type: Path, +} + +enum MacroArg { + GenAccessors(ArgInner<kw::gen_accessors, Ident>), + AccessorType(ArgInner<kw::accessor_type, Path>), + Types(ArgInner<kw::gen_types, RootTypeDef>), +} + +struct ArgInner<K, V> { + _field_kw: K, + _equals: Token![=], + value: V, +} + +pub struct Field { + pub attributes: Vec<Attribute>, + pub name: Ident, + _colon: Token![:], + pub field_type: FieldType, +} + +pub enum FieldType { + Existing(Type), + NewTypeDef(NewTypeDef), +} + +pub struct NewTypeDef { + _braces: token::Brace, + pub fields: Punctuated<Field, Token![, ]>, +} + +pub struct RootTypeDef { + pub type_name: Ident, + pub type_def: NewTypeDef, +} + +impl Parse for MacroInput { + fn parse(input: ParseStream) -> Result<Self> { + let fields: Punctuated<MacroArg, Token![, ]> = input.parse_terminated(MacroArg::parse)?; + let mut gen_accessors = None; + let mut type_def = None; + let mut accessor_type = None; + for arg in fields.into_iter() { + match arg { + MacroArg::GenAccessors(ArgInner { value, .. }) => gen_accessors = Some(value), + MacroArg::AccessorType(ArgInner { value, .. }) => accessor_type = Some(value), + MacroArg::Types(ArgInner { value, .. }) => type_def = Some(value), + } + } + + fn missing_attr(att_name: &str) -> syn::Error { + syn::Error::new( + Span::call_site(), + format!("Expected `{}` attribute", att_name), + ) + } + + Ok(MacroInput { + type_def: type_def.ok_or_else(|| missing_attr("gen_types"))?, + gen_accessors: gen_accessors.ok_or_else(|| missing_attr("gen_accessors"))?, + accessor_type: accessor_type.ok_or_else(|| missing_attr("accessor_type"))?, + }) + } +} + +impl Parse for MacroArg { + fn parse(input: ParseStream) -> Result<Self> { + let lookahead = input.lookahead1(); + if lookahead.peek(kw::gen_types) { + Ok(MacroArg::Types(input.parse()?)) + } else if lookahead.peek(kw::gen_accessors) { + Ok(MacroArg::GenAccessors(input.parse()?)) + } else if lookahead.peek(kw::accessor_type) { + Ok(MacroArg::AccessorType(input.parse()?)) + } else { + Err(lookahead.error()) + } + } +} + +impl<K: Parse, V: Parse> Parse for ArgInner<K, V> { + fn parse(input: ParseStream) -> Result<Self> { + Ok(ArgInner { + _field_kw: input.parse()?, + _equals: input.parse()?, + value: input.parse()?, + }) + } +} + +impl Parse for Field { + fn parse(input: ParseStream) -> Result<Self> { + Ok(Field { + attributes: input.call(Attribute::parse_outer)?, + name: input.parse()?, + _colon: input.parse()?, + field_type: input.parse()?, + }) + } +} + +impl Parse for RootTypeDef { + fn parse(input: ParseStream) -> Result<Self> { + Ok(RootTypeDef { + type_name: input.parse()?, + type_def: input.parse()?, + }) + } +} + +impl Parse for NewTypeDef { + fn parse(input: ParseStream) -> Result<Self> { + let content; + #[allow(clippy::eval_order_dependence)] + Ok(NewTypeDef { + _braces: braced!(content in input), + fields: content.parse_terminated(Field::parse)?, + }) + } +} + +impl Parse for FieldType { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(token::Brace) { + Ok(FieldType::NewTypeDef(input.parse()?)) + } else { + Ok(FieldType::Existing(input.parse()?)) + } + } +} |