mac.rs 7.9 KB

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