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