| 1 | |
| 2 |
|
| 3 | #[cfg(feature = "parsing")]
|
| 4 | use crate::error::Result;
|
| 5 | #[cfg(feature = "parsing")]
|
| 6 | use crate::parse::{Parse, ParseStream, Parser};
|
| 7 | use crate::path::Path;
|
| 8 | use crate::token::{Brace, Bracket, Paren};
|
| 9 | use proc_macro2::extra::DelimSpan;
|
| 10 | #[cfg(feature = "parsing")]
|
| 11 | use proc_macro2::Delimiter;
|
| 12 | use proc_macro2::TokenStream;
|
| 13 | #[cfg(feature = "parsing")]
|
| 14 | use proc_macro2::TokenTree;
|
| 15 |
|
| 16 | ast_struct! {
|
| 17 | |
| 18 | #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
| 19 | pub struct Macro {
|
| 20 | pub path: Path,
|
| 21 | pub bang_token: Token![!],
|
| 22 | pub delimiter: MacroDelimiter,
|
| 23 | pub tokens: TokenStream,
|
| 24 | }
|
| 25 | }
|
| 26 |
|
| 27 | ast_enum! {
|
| 28 | |
| 29 | #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
| 30 | pub enum MacroDelimiter {
|
| 31 | Paren(Paren),
|
| 32 | Brace(Brace),
|
| 33 | Bracket(Bracket),
|
| 34 | }
|
| 35 | }
|
| 36 |
|
| 37 | impl MacroDelimiter {
|
| 38 | pub fn span(&self) -> &DelimSpan {
|
| 39 | match self {
|
| 40 | MacroDelimiter::Paren(token) => &token.span,
|
| 41 | MacroDelimiter::Brace(token) => &token.span,
|
| 42 | MacroDelimiter::Bracket(token) => &token.span,
|
| 43 | }
|
| 44 | }
|
| 45 |
|
| 46 | #[cfg(all(feature = "full", any(feature = "parsing", feature = "printing")))]
|
| 47 | pub(crate) fn is_brace(&self) -> bool {
|
| 48 | match self {
|
| 49 | MacroDelimiter::Brace(_) => true,
|
| 50 | MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => false,
|
| 51 | }
|
| 52 | }
|
| 53 | }
|
| 54 |
|
| 55 | impl Macro {
|
| 56 | |
| 57 | |
| 58 | |
| 59 | |
| 60 | |
| 61 | |
| 62 | |
| 63 | |
| 64 | |
| 65 | |
| 66 | |
| 67 | |
| 68 | |
| 69 | |
| 70 | |
| 71 | |
| 72 | |
| 73 | |
| 74 | |
| 75 | |
| 76 | |
| 77 | |
| 78 | |
| 79 | |
| 80 | |
| 81 | |
| 82 | |
| 83 | |
| 84 | |
| 85 | |
| 86 | |
| 87 | |
| 88 | |
| 89 | |
| 90 | |
| 91 | |
| 92 | |
| 93 | |
| 94 | |
| 95 | |
| 96 | |
| 97 | |
| 98 | |
| 99 | |
| 100 | |
| 101 | |
| 102 | |
| 103 | |
| 104 | |
| 105 | |
| 106 | |
| 107 | |
| 108 | |
| 109 | |
| 110 | |
| 111 | |
| 112 | |
| 113 | |
| 114 | |
| 115 | |
| 116 | |
| 117 | |
| 118 | |
| 119 | |
| 120 | |
| 121 | |
| 122 | |
| 123 | |
| 124 | |
| 125 | |
| 126 | |
| 127 | |
| 128 | |
| 129 | |
| 130 | |
| 131 | |
| 132 | |
| 133 | |
| 134 | |
| 135 | |
| 136 | |
| 137 | |
| 138 | #[cfg(feature = "parsing")]
|
| 139 | #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
| 140 | pub fn parse_body<T: Parse>(&self) -> Result<T> {
|
| 141 | self.parse_body_with(T::parse)
|
| 142 | }
|
| 143 |
|
| 144 | |
| 145 | |
| 146 | #[cfg(feature = "parsing")]
|
| 147 | #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
| 148 | pub fn parse_body_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
|
| 149 | let scope = self.delimiter.span().close();
|
| 150 | crate::parse::parse_scoped(parser, scope, self.tokens.clone())
|
| 151 | }
|
| 152 | }
|
| 153 |
|
| 154 | #[cfg(feature = "parsing")]
|
| 155 | pub(crate) fn parse_delimiter(input: ParseStream) -> Result<(MacroDelimiter, TokenStream)> {
|
| 156 | input.step(|cursor| {
|
| 157 | if let Some((TokenTree::Group(g), rest)) = cursor.token_tree() {
|
| 158 | let span = g.delim_span();
|
| 159 | let delimiter = match g.delimiter() {
|
| 160 | Delimiter::Parenthesis => MacroDelimiter::Paren(Paren(span)),
|
| 161 | Delimiter::Brace => MacroDelimiter::Brace(Brace(span)),
|
| 162 | Delimiter::Bracket => MacroDelimiter::Bracket(Bracket(span)),
|
| 163 | Delimiter::None => {
|
| 164 | return Err(cursor.error("expected delimiter"));
|
| 165 | }
|
| 166 | };
|
| 167 | Ok(((delimiter, g.stream()), rest))
|
| 168 | } else {
|
| 169 | Err(cursor.error("expected delimiter"))
|
| 170 | }
|
| 171 | })
|
| 172 | }
|
| 173 |
|
| 174 | #[cfg(feature = "parsing")]
|
| 175 | pub(crate) mod parsing {
|
| 176 | use crate::error::Result;
|
| 177 | use crate::mac::{parse_delimiter, Macro};
|
| 178 | use crate::parse::{Parse, ParseStream};
|
| 179 | use crate::path::Path;
|
| 180 |
|
| 181 | #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
| 182 | impl Parse for Macro {
|
| 183 | fn parse(input: ParseStream) -> Result<Self> {
|
| 184 | let tokens;
|
| 185 | Ok(Macro {
|
| 186 | path: input.call(Path::parse_mod_style)?,
|
| 187 | bang_token: input.parse()?,
|
| 188 | delimiter: {
|
| 189 | let (delimiter, content) = parse_delimiter(input)?;
|
| 190 | tokens = content;
|
| 191 | delimiter
|
| 192 | },
|
| 193 | tokens,
|
| 194 | })
|
| 195 | }
|
| 196 | }
|
| 197 | }
|
| 198 |
|
| 199 | #[cfg(feature = "printing")]
|
| 200 | mod printing {
|
| 201 | use crate::mac::{Macro, MacroDelimiter};
|
| 202 | use crate::path;
|
| 203 | use crate::path::printing::PathStyle;
|
| 204 | use crate::token;
|
| 205 | use proc_macro2::{Delimiter, TokenStream};
|
| 206 | use quote::ToTokens;
|
| 207 |
|
| 208 | impl MacroDelimiter {
|
| 209 | pub(crate) fn surround(&self, tokens: &mut TokenStream, inner: TokenStream) {
|
| 210 | let (delim, span) = match self {
|
| 211 | MacroDelimiter::Paren(paren) => (Delimiter::Parenthesis, paren.span),
|
| 212 | MacroDelimiter::Brace(brace) => (Delimiter::Brace, brace.span),
|
| 213 | MacroDelimiter::Bracket(bracket) => (Delimiter::Bracket, bracket.span),
|
| 214 | };
|
| 215 | token::printing::delim(delim, span.join(), tokens, inner);
|
| 216 | }
|
| 217 | }
|
| 218 |
|
| 219 | #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
| 220 | impl ToTokens for Macro {
|
| 221 | fn to_tokens(&self, tokens: &mut TokenStream) {
|
| 222 | path::printing::print_path(tokens, &self.path, PathStyle::Mod);
|
| 223 | self.bang_token.to_tokens(tokens);
|
| 224 | self.delimiter.surround(tokens, self.tokens.clone());
|
| 225 | }
|
| 226 | }
|
| 227 | }
|