gmt_dos_clients_scope_macros/
lib.rs1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{
4 bracketed, parenthesized, parse::Parse, parse_macro_input, Expr, Ident, LitInt, LitStr, Token,
5};
6
7#[proc_macro]
24pub fn scope(input: TokenStream) -> TokenStream {
25 let input = parse_macro_input!(input as Scope);
26 let scope = input.scope();
27 let variables = input.variables();
28 let signals = input.signals();
29 let expanded = quote! {
30 #(#variables)*
31 #scope
32 #(#signals)*
33 .show();
34 };
35 TokenStream::from(expanded)
36}
37
38#[proc_macro]
54pub fn shot(input: TokenStream) -> TokenStream {
55 let input = parse_macro_input!(input as Scope);
56 let scope = input.shot();
57 let variables = input.images();
58 let signals = input.signals();
59 let expanded = quote! {
60 #(#variables)*
61 #scope
62 #(#signals)*
63 .show();
64 };
65 TokenStream::from(expanded)
66}
67
68#[proc_macro]
84pub fn gmt_shot(input: TokenStream) -> TokenStream {
85 let input = parse_macro_input!(input as Scope);
86 let scope = input.gmt_shot();
87 let variables = input.gmt_images();
88 let signals = input.signals();
89 let expanded = quote! {
90 #(#variables)*
91 #scope
92 #(#signals)*
93 .show();
94 };
95 TokenStream::from(expanded)
96}
97
98enum Port {
99 LitInt(LitInt),
100 Expr(Expr),
101}
102impl From<LitInt> for Port {
103 fn from(value: LitInt) -> Self {
104 Self::LitInt(value)
105 }
106}
107impl From<Expr> for Port {
108 fn from(value: Expr) -> Self {
109 Self::Expr(value)
110 }
111}
112impl Port {
113 pub fn port(&self) -> proc_macro2::TokenStream {
114 match self {
115 Port::LitInt(value) => quote!(#value),
116 Port::Expr(value) => quote!(#value),
117 }
118 }
119}
120
121struct Signal {
122 ident: Ident,
123 port: Port,
124}
125impl Signal {
126 fn variable(&self) -> proc_macro2::TokenStream {
127 let Signal { ident, .. } = self;
128 quote!(
129 #[derive(::gmt_dos_clients::interface::UID)]
130 #[uid(data = f64)]
131 pub enum #ident {}
132 )
133 }
134 fn image(&self) -> proc_macro2::TokenStream {
135 let Signal { ident, .. } = self;
136 quote!(
137 #[derive(::gmt_dos_clients::interface::UID)]
138 pub enum #ident {}
139 )
140 }
141 fn gmt_image(&self) -> proc_macro2::TokenStream {
142 let Signal { ident, .. } = self;
143 quote!(
144 #[derive(::gmt_dos_clients::interface::UID)]
145 #[uid(data = (Vec<f64>,Vec<bool>))]
146 pub enum #ident {}
147 )
148 }
149 fn signal(&self) -> proc_macro2::TokenStream {
150 let Signal { ident, port } = self;
151 let port = port.port();
152 quote! {
153 .signal::<#ident>(#port)?
154 }
155 }
156}
157
158impl Parse for Signal {
159 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
160 let ident: Ident = input.parse()?;
161 input.parse::<Token![,]>()?;
162 let port: Port = if let Ok(port) = input.parse::<LitInt>() {
163 Ok(port.into())
164 } else {
165 input.parse::<Expr>().map(|port| Port::from(port))
166 }?;
167 Ok(Self { ident, port })
168 }
169}
170
171struct ParenthesizedSignal(Signal);
172
173impl Parse for ParenthesizedSignal {
174 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
175 let content;
176 let _ = parenthesized!(content in input);
177 let signal: Signal = content.parse()?;
178 Ok(Self(signal))
179 }
180}
181
182struct Scope {
184 server_address: LitStr,
185 client_address: LitStr,
186 signals: Vec<Signal>,
187}
188
189impl Scope {
190 pub fn scope(&self) -> proc_macro2::TokenStream {
191 let Self {
192 server_address,
193 client_address,
194 ..
195 } = self;
196 quote! {
197 ::gmt_dos_clients_scope::client::Scope::new(#server_address, #client_address)
198 }
199 }
200 pub fn shot(&self) -> proc_macro2::TokenStream {
201 let Self {
202 server_address,
203 client_address,
204 ..
205 } = self;
206 quote! {
207 ::gmt_dos_clients_scope::client::Shot::new(#server_address, #client_address)
208 }
209 }
210 pub fn gmt_shot(&self) -> proc_macro2::TokenStream {
211 let Self {
212 server_address,
213 client_address,
214 ..
215 } = self;
216 quote! {
217 ::gmt_dos_clients_scope::client::GmtShot::new(#server_address, #client_address)
218 }
219 }
220 pub fn signals(&self) -> Vec<proc_macro2::TokenStream> {
221 self.signals.iter().map(|signal| signal.signal()).collect()
222 }
223 pub fn variables(&self) -> Vec<proc_macro2::TokenStream> {
224 self.signals
225 .iter()
226 .map(|signal| signal.variable())
227 .collect()
228 }
229 pub fn images(&self) -> Vec<proc_macro2::TokenStream> {
230 self.signals.iter().map(|signal| signal.image()).collect()
231 }
232 pub fn gmt_images(&self) -> Vec<proc_macro2::TokenStream> {
233 self.signals
234 .iter()
235 .map(|signal| signal.gmt_image())
236 .collect()
237 }
238}
239
240impl Parse for Scope {
241 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
242 let server_address: LitStr = input.parse()?;
243 input.parse::<Token![,]>()?;
244 let client_address: LitStr = input.parse()?;
245 input.parse::<Token![,]>()?;
246
247 let content;
248 let _ = bracketed!(content in input);
249 let signals: Vec<_> = content
250 .parse_terminated(ParenthesizedSignal::parse, Token![,])?
251 .into_iter()
252 .map(|x| x.0)
253 .collect();
254
255 Ok(Self {
256 server_address,
257 client_address,
258 signals,
259 })
260 }
261}