• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use proc_macro2::TokenStream;
2 use syn::{
3     punctuated::Punctuated, token, Abi, Attribute, Generics, Ident, Lifetime, ReturnType, Token,
4     Variadic, Visibility,
5 };
6 
7 use super::PatType;
8 
9 ast_struct! {
10     /// A free-standing function: `fn process(n: usize) -> Result<()> { ...
11     /// }`.
12     pub struct ItemFn {
13         pub attrs: Vec<Attribute>,
14         pub vis: Visibility,
15         pub sig: Signature,
16         pub block: Box<Block>,
17     }
18 }
19 
20 ast_struct! {
21     /// A braced block containing Rust statements.
22     pub struct Block {
23         pub brace_token: token::Brace,
24         /// Statements in a block
25         pub stmts: TokenStream,
26     }
27 }
28 
29 ast_struct! {
30     /// A function signature in a trait or implementation: `unsafe fn
31     /// initialize(&self)`.
32     pub struct Signature {
33         pub constness: Option<Token![const]>,
34         pub asyncness: Option<Token![async]>,
35         pub unsafety: Option<Token![unsafe]>,
36         pub abi: Option<Abi>,
37         pub fn_token: Token![fn],
38         pub ident: Ident,
39         pub generics: Generics,
40         pub paren_token: token::Paren,
41         pub inputs: Punctuated<FnArg, Token![,]>,
42         pub variadic: Option<Variadic>,
43         pub output: ReturnType,
44     }
45 }
46 
47 ast_enum_of_structs! {
48     /// An argument in a function signature: the `n: usize` in `fn f(n: usize)`.
49     pub enum FnArg {
50         /// The `self` argument of an associated method, whether taken by value
51         /// or by reference.
52         Receiver(Receiver),
53 
54         /// A function argument accepted by pattern and type.
55         Typed(PatType),
56     }
57 }
58 
59 ast_struct! {
60     /// The `self` argument of an associated method, whether taken by value
61     /// or by reference.
62     pub struct Receiver {
63         pub attrs: Vec<Attribute>,
64         pub reference: Option<(Token![&], Option<Lifetime>)>,
65         pub mutability: Option<Token![mut]>,
66         pub self_token: Token![self],
67     }
68 }
69 
70 mod parsing {
71     use syn::{
72         braced, parenthesized,
73         parse::{discouraged::Speculative, Parse, ParseStream, Result},
74         parse2, Abi, Attribute, Generics, Ident, ReturnType, Token, Type, Variadic, Visibility,
75     };
76 
77     use super::{Block, FnArg, ItemFn, PatType, Receiver, Signature};
78 
79     impl Parse for Block {
parse(input: ParseStream<'_>) -> Result<Self>80         fn parse(input: ParseStream<'_>) -> Result<Self> {
81             let content;
82             Ok(Self { brace_token: braced!(content in input), stmts: content.parse()? })
83         }
84     }
85 
86     impl Parse for Signature {
parse(input: ParseStream<'_>) -> Result<Self>87         fn parse(input: ParseStream<'_>) -> Result<Self> {
88             fn get_variadic(input: &&FnArg) -> Option<Variadic> {
89                 if let FnArg::Typed(PatType { ty, .. }) = input {
90                     if let Type::Verbatim(tokens) = &**ty {
91                         if let Ok(dots) = parse2(tokens.clone()) {
92                             return Some(Variadic { attrs: Vec::new(), dots });
93                         }
94                     }
95                 }
96                 None
97             }
98 
99             let constness: Option<Token![const]> = input.parse()?;
100             let asyncness: Option<Token![async]> = input.parse()?;
101             let unsafety: Option<Token![unsafe]> = input.parse()?;
102             let abi: Option<Abi> = input.parse()?;
103             let fn_token: Token![fn] = input.parse()?;
104             let ident: Ident = input.parse()?;
105             let mut generics: Generics = input.parse()?;
106 
107             let content;
108             let paren_token = parenthesized!(content in input);
109             let inputs = content.parse_terminated(FnArg::parse)?;
110             let variadic = inputs.last().as_ref().and_then(get_variadic);
111 
112             let output: ReturnType = input.parse()?;
113             generics.where_clause = input.parse()?;
114 
115             Ok(Self {
116                 constness,
117                 asyncness,
118                 unsafety,
119                 abi,
120                 fn_token,
121                 ident,
122                 paren_token,
123                 inputs,
124                 output,
125                 variadic,
126                 generics,
127             })
128         }
129     }
130 
131     impl Parse for ItemFn {
parse(input: ParseStream<'_>) -> Result<Self>132         fn parse(input: ParseStream<'_>) -> Result<Self> {
133             let attrs = input.call(Attribute::parse_outer)?;
134             let vis: Visibility = input.parse()?;
135             let sig = input.parse()?;
136             let block = input.parse()?;
137             Ok(Self { attrs, vis, sig, block: Box::new(block) })
138         }
139     }
140 
141     impl Parse for FnArg {
parse(input: ParseStream<'_>) -> Result<Self>142         fn parse(input: ParseStream<'_>) -> Result<Self> {
143             let attrs = input.call(Attribute::parse_outer)?;
144 
145             let ahead = input.fork();
146             if let Ok(mut receiver) = ahead.parse::<Receiver>() {
147                 if !ahead.peek(Token![:]) {
148                     input.advance_to(&ahead);
149                     receiver.attrs = attrs;
150                     return Ok(FnArg::Receiver(receiver));
151                 }
152             }
153 
154             let mut typed = input.call(fn_arg_typed)?;
155             typed.attrs = attrs;
156             Ok(FnArg::Typed(typed))
157         }
158     }
159 
160     impl Parse for Receiver {
parse(input: ParseStream<'_>) -> Result<Self>161         fn parse(input: ParseStream<'_>) -> Result<Self> {
162             Ok(Self {
163                 attrs: Vec::new(),
164                 reference: {
165                     if input.peek(Token![&]) {
166                         Some((input.parse()?, input.parse()?))
167                     } else {
168                         None
169                     }
170                 },
171                 mutability: input.parse()?,
172                 self_token: input.parse()?,
173             })
174         }
175     }
176 
fn_arg_typed(input: ParseStream<'_>) -> Result<PatType>177     fn fn_arg_typed(input: ParseStream<'_>) -> Result<PatType> {
178         Ok(PatType {
179             attrs: Vec::new(),
180             pat: input.parse()?,
181             colon_token: input.parse()?,
182             ty: Box::new(input.parse()?),
183         })
184     }
185 }
186 
187 mod printing {
188     use proc_macro2::TokenStream;
189     use quote::{ToTokens, TokenStreamExt};
190     use syn::{punctuated::Punctuated, Token, Type};
191 
192     use super::{Block, FnArg, ItemFn, Receiver, Signature};
193 
194     impl ToTokens for Block {
to_tokens(&self, tokens: &mut TokenStream)195         fn to_tokens(&self, tokens: &mut TokenStream) {
196             self.brace_token.surround(tokens, |tokens| {
197                 tokens.append_all(self.stmts.clone());
198             });
199         }
200     }
201 
has_variadic(inputs: &Punctuated<FnArg, Token![,]>) -> bool202     fn has_variadic(inputs: &Punctuated<FnArg, Token![,]>) -> bool {
203         let last = match inputs.last() {
204             Some(last) => last,
205             None => return false,
206         };
207 
208         let pat = match last {
209             FnArg::Typed(pat) => pat,
210             FnArg::Receiver(_) => return false,
211         };
212 
213         let tokens = match pat.ty.as_ref() {
214             Type::Verbatim(tokens) => tokens,
215             _ => return false,
216         };
217 
218         tokens.to_string() == "..."
219     }
220 
221     impl ToTokens for Signature {
to_tokens(&self, tokens: &mut TokenStream)222         fn to_tokens(&self, tokens: &mut TokenStream) {
223             self.constness.to_tokens(tokens);
224             self.asyncness.to_tokens(tokens);
225             self.unsafety.to_tokens(tokens);
226             self.abi.to_tokens(tokens);
227             self.fn_token.to_tokens(tokens);
228             self.ident.to_tokens(tokens);
229             self.generics.to_tokens(tokens);
230             self.paren_token.surround(tokens, |tokens| {
231                 self.inputs.to_tokens(tokens);
232                 if self.variadic.is_some() && !has_variadic(&self.inputs) {
233                     if !self.inputs.empty_or_trailing() {
234                         <Token![,]>::default().to_tokens(tokens);
235                     }
236                     self.variadic.to_tokens(tokens);
237                 }
238             });
239             self.output.to_tokens(tokens);
240             self.generics.where_clause.to_tokens(tokens);
241         }
242     }
243 
244     impl ToTokens for ItemFn {
to_tokens(&self, tokens: &mut TokenStream)245         fn to_tokens(&self, tokens: &mut TokenStream) {
246             tokens.append_all(&self.attrs);
247             self.vis.to_tokens(tokens);
248             self.sig.to_tokens(tokens);
249             self.block.brace_token.surround(tokens, |tokens| {
250                 tokens.append_all(self.block.stmts.clone());
251             });
252         }
253     }
254 
255     impl ToTokens for Receiver {
to_tokens(&self, tokens: &mut TokenStream)256         fn to_tokens(&self, tokens: &mut TokenStream) {
257             tokens.append_all(&self.attrs);
258             if let Some((ampersand, lifetime)) = &self.reference {
259                 ampersand.to_tokens(tokens);
260                 lifetime.to_tokens(tokens);
261             }
262             self.mutability.to_tokens(tokens);
263             self.self_token.to_tokens(tokens);
264         }
265     }
266 }
267