1 use super::*;
2 use crate::token::{Brace, Bracket, Paren};
3 use proc_macro2::TokenStream;
4 #[cfg(feature = "parsing")]
5 use proc_macro2::{Delimiter, Group, Span, TokenTree};
6
7 #[cfg(feature = "parsing")]
8 use crate::parse::{Parse, ParseStream, Parser, Result};
9 #[cfg(feature = "extra-traits")]
10 use crate::tt::TokenStreamHelper;
11 #[cfg(feature = "extra-traits")]
12 use std::hash::{Hash, Hasher};
13
14 ast_struct! {
15 /// A macro invocation: `println!("{}", mac)`.
16 ///
17 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
18 /// feature.*
19 pub struct Macro #manual_extra_traits {
20 pub path: Path,
21 pub bang_token: Token![!],
22 pub delimiter: MacroDelimiter,
23 pub tokens: TokenStream,
24 }
25 }
26
27 ast_enum! {
28 /// A grouping token that surrounds a macro body: `m!(...)` or `m!{...}` or `m![...]`.
29 ///
30 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
31 /// feature.*
32 pub enum MacroDelimiter {
33 Paren(Paren),
34 Brace(Brace),
35 Bracket(Bracket),
36 }
37 }
38
39 #[cfg(feature = "extra-traits")]
40 impl Eq for Macro {}
41
42 #[cfg(feature = "extra-traits")]
43 impl PartialEq for Macro {
eq(&self, other: &Self) -> bool44 fn eq(&self, other: &Self) -> bool {
45 self.path == other.path
46 && self.bang_token == other.bang_token
47 && self.delimiter == other.delimiter
48 && TokenStreamHelper(&self.tokens) == TokenStreamHelper(&other.tokens)
49 }
50 }
51
52 #[cfg(feature = "extra-traits")]
53 impl Hash for Macro {
hash<H>(&self, state: &mut H) where H: Hasher,54 fn hash<H>(&self, state: &mut H)
55 where
56 H: Hasher,
57 {
58 self.path.hash(state);
59 self.bang_token.hash(state);
60 self.delimiter.hash(state);
61 TokenStreamHelper(&self.tokens).hash(state);
62 }
63 }
64
65 #[cfg(feature = "parsing")]
delimiter_span_close(macro_delimiter: &MacroDelimiter) -> Span66 fn delimiter_span_close(macro_delimiter: &MacroDelimiter) -> Span {
67 let delimiter = match macro_delimiter {
68 MacroDelimiter::Paren(_) => Delimiter::Parenthesis,
69 MacroDelimiter::Brace(_) => Delimiter::Brace,
70 MacroDelimiter::Bracket(_) => Delimiter::Bracket,
71 };
72 let mut group = Group::new(delimiter, TokenStream::new());
73 group.set_span(match macro_delimiter {
74 MacroDelimiter::Paren(token) => token.span,
75 MacroDelimiter::Brace(token) => token.span,
76 MacroDelimiter::Bracket(token) => token.span,
77 });
78 group.span_close()
79 }
80
81 impl Macro {
82 /// Parse the tokens within the macro invocation's delimiters into a syntax
83 /// tree.
84 ///
85 /// This is equivalent to `syn::parse2::<T>(mac.tokens)` except that it
86 /// produces a more useful span when `tokens` is empty.
87 ///
88 /// # Example
89 ///
90 /// ```
91 /// use syn::{parse_quote, Expr, ExprLit, Ident, Lit, LitStr, Macro, Token};
92 /// use syn::ext::IdentExt;
93 /// use syn::parse::{Error, Parse, ParseStream, Result};
94 /// use syn::punctuated::Punctuated;
95 ///
96 /// // The arguments expected by libcore's format_args macro, and as a
97 /// // result most other formatting and printing macros like println.
98 /// //
99 /// // println!("{} is {number:.prec$}", "x", prec=5, number=0.01)
100 /// struct FormatArgs {
101 /// format_string: Expr,
102 /// positional_args: Vec<Expr>,
103 /// named_args: Vec<(Ident, Expr)>,
104 /// }
105 ///
106 /// impl Parse for FormatArgs {
107 /// fn parse(input: ParseStream) -> Result<Self> {
108 /// let format_string: Expr;
109 /// let mut positional_args = Vec::new();
110 /// let mut named_args = Vec::new();
111 ///
112 /// format_string = input.parse()?;
113 /// while !input.is_empty() {
114 /// input.parse::<Token![,]>()?;
115 /// if input.is_empty() {
116 /// break;
117 /// }
118 /// if input.peek(Ident::peek_any) && input.peek2(Token![=]) {
119 /// while !input.is_empty() {
120 /// let name: Ident = input.call(Ident::parse_any)?;
121 /// input.parse::<Token![=]>()?;
122 /// let value: Expr = input.parse()?;
123 /// named_args.push((name, value));
124 /// if input.is_empty() {
125 /// break;
126 /// }
127 /// input.parse::<Token![,]>()?;
128 /// }
129 /// break;
130 /// }
131 /// positional_args.push(input.parse()?);
132 /// }
133 ///
134 /// Ok(FormatArgs {
135 /// format_string,
136 /// positional_args,
137 /// named_args,
138 /// })
139 /// }
140 /// }
141 ///
142 /// // Extract the first argument, the format string literal, from an
143 /// // invocation of a formatting or printing macro.
144 /// fn get_format_string(m: &Macro) -> Result<LitStr> {
145 /// let args: FormatArgs = m.parse_body()?;
146 /// match args.format_string {
147 /// Expr::Lit(ExprLit { lit: Lit::Str(lit), .. }) => Ok(lit),
148 /// other => {
149 /// // First argument was not a string literal expression.
150 /// // Maybe something like: println!(concat!(...), ...)
151 /// Err(Error::new_spanned(other, "format string must be a string literal"))
152 /// }
153 /// }
154 /// }
155 ///
156 /// fn main() {
157 /// let invocation = parse_quote! {
158 /// println!("{:?}", Instant::now())
159 /// };
160 /// let lit = get_format_string(&invocation).unwrap();
161 /// assert_eq!(lit.value(), "{:?}");
162 /// }
163 /// ```
164 #[cfg(feature = "parsing")]
parse_body<T: Parse>(&self) -> Result<T>165 pub fn parse_body<T: Parse>(&self) -> Result<T> {
166 self.parse_body_with(T::parse)
167 }
168
169 /// Parse the tokens within the macro invocation's delimiters using the
170 /// given parser.
171 #[cfg(feature = "parsing")]
parse_body_with<F: Parser>(&self, parser: F) -> Result<F::Output>172 pub fn parse_body_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
173 let scope = delimiter_span_close(&self.delimiter);
174 crate::parse::parse_scoped(parser, scope, self.tokens.clone())
175 }
176 }
177
178 #[cfg(feature = "parsing")]
parse_delimiter(input: ParseStream) -> Result<(MacroDelimiter, TokenStream)>179 pub fn parse_delimiter(input: ParseStream) -> Result<(MacroDelimiter, TokenStream)> {
180 input.step(|cursor| {
181 if let Some((TokenTree::Group(g), rest)) = cursor.token_tree() {
182 let span = g.span();
183 let delimiter = match g.delimiter() {
184 Delimiter::Parenthesis => MacroDelimiter::Paren(Paren(span)),
185 Delimiter::Brace => MacroDelimiter::Brace(Brace(span)),
186 Delimiter::Bracket => MacroDelimiter::Bracket(Bracket(span)),
187 Delimiter::None => {
188 return Err(cursor.error("expected delimiter"));
189 }
190 };
191 Ok(((delimiter, g.stream()), rest))
192 } else {
193 Err(cursor.error("expected delimiter"))
194 }
195 })
196 }
197
198 #[cfg(feature = "parsing")]
199 pub mod parsing {
200 use super::*;
201
202 use crate::parse::{Parse, ParseStream, Result};
203
204 impl Parse for Macro {
parse(input: ParseStream) -> Result<Self>205 fn parse(input: ParseStream) -> Result<Self> {
206 let tokens;
207 Ok(Macro {
208 path: input.call(Path::parse_mod_style)?,
209 bang_token: input.parse()?,
210 delimiter: {
211 let (delimiter, content) = parse_delimiter(input)?;
212 tokens = content;
213 delimiter
214 },
215 tokens,
216 })
217 }
218 }
219 }
220
221 #[cfg(feature = "printing")]
222 mod printing {
223 use super::*;
224 use proc_macro2::TokenStream;
225 use quote::ToTokens;
226
227 impl ToTokens for Macro {
to_tokens(&self, tokens: &mut TokenStream)228 fn to_tokens(&self, tokens: &mut TokenStream) {
229 self.path.to_tokens(tokens);
230 self.bang_token.to_tokens(tokens);
231 match &self.delimiter {
232 MacroDelimiter::Paren(paren) => {
233 paren.surround(tokens, |tokens| self.tokens.to_tokens(tokens));
234 }
235 MacroDelimiter::Brace(brace) => {
236 brace.surround(tokens, |tokens| self.tokens.to_tokens(tokens));
237 }
238 MacroDelimiter::Bracket(bracket) => {
239 bracket.surround(tokens, |tokens| self.tokens.to_tokens(tokens));
240 }
241 }
242 }
243 }
244 }
245