1 use proc_macro2::{Span, TokenStream}; 2 use syn::{ 3 braced, 4 parse::{Parse, ParseStream}, 5 punctuated::Punctuated, 6 Error, Result, Token, 7 }; 8 use wiggle_generate::config as w; 9 10 mod kw { 11 syn::custom_keyword!(witx); 12 syn::custom_keyword!(witx_literal); 13 syn::custom_keyword!(ctx); 14 syn::custom_keyword!(errors); 15 syn::custom_keyword!(constructor); 16 syn::custom_keyword!(pre_hook); 17 syn::custom_keyword!(post_hook); 18 } 19 20 #[derive(Debug, Clone)] 21 pub struct Config { 22 pub wiggle: w::Config, 23 pub constructor: TokenStream, 24 pub pre_hook: Option<TokenStream>, 25 pub post_hook: Option<TokenStream>, 26 } 27 28 #[derive(Debug, Clone)] 29 pub enum ConfigField { 30 Wiggle(w::ConfigField), 31 Constructor(TokenStream), 32 PreHook(TokenStream), 33 PostHook(TokenStream), 34 } 35 36 impl Parse for ConfigField { parse(input: ParseStream) -> Result<Self>37 fn parse(input: ParseStream) -> Result<Self> { 38 let lookahead = input.lookahead1(); 39 if lookahead.peek(kw::constructor) { 40 input.parse::<kw::constructor>()?; 41 input.parse::<Token![:]>()?; 42 let contents; 43 let _lbrace = braced!(contents in input); 44 Ok(ConfigField::Constructor(contents.parse()?)) 45 } else if lookahead.peek(kw::pre_hook) { 46 input.parse::<kw::pre_hook>()?; 47 input.parse::<Token![:]>()?; 48 let contents; 49 let _lbrace = braced!(contents in input); 50 Ok(ConfigField::PreHook(contents.parse()?)) 51 } else if lookahead.peek(kw::post_hook) { 52 input.parse::<kw::post_hook>()?; 53 input.parse::<Token![:]>()?; 54 let contents; 55 let _lbrace = braced!(contents in input); 56 Ok(ConfigField::PostHook(contents.parse()?)) 57 } else if lookahead.peek(kw::witx) { 58 input.parse::<kw::witx>()?; 59 input.parse::<Token![:]>()?; 60 Ok(ConfigField::Wiggle(w::ConfigField::Witx( 61 w::WitxConf::Paths(input.parse()?), 62 ))) 63 } else if lookahead.peek(kw::witx_literal) { 64 input.parse::<kw::witx_literal>()?; 65 input.parse::<Token![:]>()?; 66 Ok(ConfigField::Wiggle(w::ConfigField::Witx( 67 w::WitxConf::Literal(input.parse()?), 68 ))) 69 } else if lookahead.peek(kw::ctx) { 70 input.parse::<kw::ctx>()?; 71 input.parse::<Token![:]>()?; 72 Ok(ConfigField::Wiggle(w::ConfigField::Ctx(input.parse()?))) 73 } else if lookahead.peek(kw::errors) { 74 input.parse::<kw::errors>()?; 75 input.parse::<Token![:]>()?; 76 Ok(ConfigField::Wiggle(w::ConfigField::Error(input.parse()?))) 77 } else { 78 Err(lookahead.error()) 79 } 80 } 81 } 82 83 impl Config { build(fields: impl Iterator<Item = ConfigField> + Clone, err_loc: Span) -> Result<Self>84 pub fn build(fields: impl Iterator<Item = ConfigField> + Clone, err_loc: Span) -> Result<Self> { 85 let wiggle = w::Config::build( 86 fields.clone().filter_map(|f| match f { 87 ConfigField::Wiggle(w) => Some(w), 88 _ => None, 89 }), 90 err_loc, 91 )?; 92 let mut constructor = None; 93 let mut pre_hook = None; 94 let mut post_hook = None; 95 for f in fields { 96 match f { 97 ConfigField::Constructor(c) => { 98 constructor = Some(c); 99 } 100 ConfigField::PreHook(c) => { 101 pre_hook = Some(c); 102 } 103 ConfigField::PostHook(c) => { 104 post_hook = Some(c); 105 } 106 ConfigField::Wiggle { .. } => {} // Ignore 107 } 108 } 109 Ok(Config { 110 wiggle, 111 constructor: constructor 112 .take() 113 .ok_or_else(|| Error::new(err_loc, "`constructor` field required"))?, 114 pre_hook, 115 post_hook, 116 }) 117 } 118 } 119 120 impl Parse for Config { parse(input: ParseStream) -> Result<Self>121 fn parse(input: ParseStream) -> Result<Self> { 122 let contents; 123 let _lbrace = braced!(contents in input); 124 let fields: Punctuated<ConfigField, Token![,]> = 125 contents.parse_terminated(ConfigField::parse)?; 126 Ok(Config::build(fields.into_iter(), input.span())?) 127 } 128 } 129