1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use syn::bracketed;
use syn::parse::Parse;
use syn::punctuated::Punctuated;
use syn::Attribute;
use syn::Token;
use crate::Params;
use crate::Proxy;
impl Parse for Proxy {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
if input.peek(Token![trait]) {
let kwd: Token![trait] = input.parse()?;
Ok(Self::Trait(kwd, input.parse()?))
} else {
Err(syn::Error::new(
input.span(),
"Expected `struct`, `trait` or `impl`",
))
}
}
}
impl Parse for Params {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let mut enum_attr = Attribute::parse_outer(input)?;
let visibility: syn::Visibility = input
.fork()
.parse::<syn::Visibility>()
.ok()
.and_then(|_| input.parse().ok())
.unwrap_or(syn::Visibility::Inherited);
let _: Token![enum] = input.parse()?;
let enum_name: syn::Ident = input.parse()?;
let mut returnval = None;
let mut proxies = Vec::new();
let mut context = None;
while input.peek(Token![,]) {
let _comma: Token![,] = input.parse()?;
if input.is_empty() {
break;
}
if input.peek(Token![trait]) {
proxies.extend(input.parse());
continue;
}
let arg: syn::Ident = input.parse()?;
match arg.to_string().as_str() {
"enum_attr" => {
let content;
enum_attr.push(Attribute {
pound_token: Token),
style: syn::AttrStyle::Outer,
bracket_token: bracketed!(content in input),
path: content.call(syn::Path::parse_mod_style)?,
tokens: content.parse()?,
})
}
"returnval" => {
if returnval.is_some() {
return Err(syn::Error::new_spanned(
arg,
"Argument `returnval` specified twice",
));
}
let _eq: Token![=] = input.parse()?;
returnval = Some(input.parse()?)
}
"proxy" => {
let contents;
if input.peek(syn::token::Paren) {
let _paren = syn::parenthesized!(contents in input);
} else {
let _paren = syn::braced!(contents in input);
}
let punct: Punctuated<Proxy, Token![;]> =
Punctuated::parse_terminated(&contents)?;
proxies.extend(punct)
}
"context" => {
if context.is_some() {
return Err(syn::Error::new_spanned(
arg,
"Argument `context` specified twice",
));
}
let contents;
let _paren = syn::parenthesized!(contents in input);
let ident = contents.parse()?;
let _colon: Token![:] = contents.parse()?;
let ty = contents.parse()?;
context = Some((ident, ty))
}
_ => {
return Err(syn::Error::new(
arg.span(),
format!("Unknown argument `{arg}` to ctrlgen"),
))
}
};
}
Ok(Self {
visibility,
enum_name,
returnval,
proxies,
enum_attr,
context,
})
}
}