1#[cfg(feature = "parsing")]
2use crate::error::Result;
3#[cfg(feature = "parsing")]
4use crate::parse::{Parse, ParseStream, Parser};
5use crate::path::Path;
6use crate::token::{Brace, Bracket, Paren};
7use proc_macro2::extra::DelimSpan;
8#[cfg(feature = "parsing")]
9use proc_macro2::Delimiter;
10use proc_macro2::TokenStream;
11#[cfg(feature = "parsing")]
12use proc_macro2::TokenTree;
13
14#[doc = r#" A macro invocation: `println!("{}", mac)`."#]
#[doc(cfg(any(feature = "full", feature = "derive")))]
pub struct Macro {
pub path: Path,
pub bang_token: crate::token::Not,
pub delimiter: MacroDelimiter,
pub tokens: TokenStream,
}ast_struct! {
15 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
17 pub struct Macro {
18 pub path: Path,
19 pub bang_token: Token![!],
20 pub delimiter: MacroDelimiter,
21 pub tokens: TokenStream,
22 }
23}
24
25#[doc =
r" A grouping token that surrounds a macro body: `m!(...)` or `m!{...}` or `m![...]`."]
#[doc(cfg(any(feature = "full", feature = "derive")))]
pub enum MacroDelimiter { Paren(Paren), Brace(Brace), Bracket(Bracket), }ast_enum! {
26 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
28 pub enum MacroDelimiter {
29 Paren(Paren),
30 Brace(Brace),
31 Bracket(Bracket),
32 }
33}
34
35impl MacroDelimiter {
36 pub fn span(&self) -> &DelimSpan {
37 match self {
38 MacroDelimiter::Paren(token) => &token.span,
39 MacroDelimiter::Brace(token) => &token.span,
40 MacroDelimiter::Bracket(token) => &token.span,
41 }
42 }
43
44 #[cfg(all(feature = "full", any(feature = "parsing", feature = "printing")))]
45 pub(crate) fn is_brace(&self) -> bool {
46 match self {
47 MacroDelimiter::Brace(_) => true,
48 MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => false,
49 }
50 }
51}
52
53impl Macro {
54 #[cfg(feature = "parsing")]
137 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
138 pub fn parse_body<T: Parse>(&self) -> Result<T> {
139 self.parse_body_with(T::parse)
140 }
141
142 #[cfg(feature = "parsing")]
145 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
146 pub fn parse_body_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
147 let scope = self.delimiter.span().close();
148 crate::parse::parse_scoped(parser, scope, self.tokens.clone())
149 }
150}
151
152#[cfg(feature = "parsing")]
153pub(crate) fn parse_delimiter(input: ParseStream) -> Result<(MacroDelimiter, TokenStream)> {
154 input.step(|cursor| {
155 if let Some((TokenTree::Group(g), rest)) = cursor.token_tree() {
156 let span = g.delim_span();
157 let delimiter = match g.delimiter() {
158 Delimiter::Parenthesis => MacroDelimiter::Paren(Paren(span)),
159 Delimiter::Brace => MacroDelimiter::Brace(Brace(span)),
160 Delimiter::Bracket => MacroDelimiter::Bracket(Bracket(span)),
161 Delimiter::None => {
162 return Err(cursor.error("expected delimiter"));
163 }
164 };
165 Ok(((delimiter, g.stream()), rest))
166 } else {
167 Err(cursor.error("expected delimiter"))
168 }
169 })
170}
171
172#[cfg(feature = "parsing")]
173pub(crate) mod parsing {
174 use crate::error::Result;
175 use crate::mac::{parse_delimiter, Macro};
176 use crate::parse::{Parse, ParseStream};
177 use crate::path::Path;
178
179 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
180 impl Parse for Macro {
181 fn parse(input: ParseStream) -> Result<Self> {
182 let tokens;
183 Ok(Macro {
184 path: input.call(Path::parse_mod_style)?,
185 bang_token: input.parse()?,
186 delimiter: {
187 let (delimiter, content) = parse_delimiter(input)?;
188 tokens = content;
189 delimiter
190 },
191 tokens,
192 })
193 }
194 }
195}
196
197#[cfg(feature = "printing")]
198mod printing {
199 use crate::mac::{Macro, MacroDelimiter};
200 use crate::path;
201 use crate::path::printing::PathStyle;
202 use crate::token;
203 use proc_macro2::{Delimiter, TokenStream};
204 use quote::ToTokens;
205
206 impl MacroDelimiter {
207 pub(crate) fn surround(&self, tokens: &mut TokenStream, inner: TokenStream) {
208 let (delim, span) = match self {
209 MacroDelimiter::Paren(paren) => (Delimiter::Parenthesis, paren.span),
210 MacroDelimiter::Brace(brace) => (Delimiter::Brace, brace.span),
211 MacroDelimiter::Bracket(bracket) => (Delimiter::Bracket, bracket.span),
212 };
213 token::printing::delim(delim, span.join(), tokens, inner);
214 }
215 }
216
217 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
218 impl ToTokens for Macro {
219 fn to_tokens(&self, tokens: &mut TokenStream) {
220 path::printing::print_path(tokens, &self.path, PathStyle::Mod);
221 self.bang_token.to_tokens(tokens);
222 self.delimiter.surround(tokens, self.tokens.clone());
223 }
224 }
225}