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