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