rune/ast/
macro_call.rs

1use crate::ast::prelude::*;
2
3#[test]
4#[cfg(not(miri))]
5fn ast_parse() {
6    rt::<ast::MacroCall>("foo!()");
7    rt::<ast::MacroCall>("::bar::foo!(question to life)");
8}
9
10/// A macro call.
11///
12/// * `<expr>!(<args>)`.
13#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
14#[non_exhaustive]
15pub struct MacroCall {
16    /// Opaque identifier for macro call. Use to store reference to internally
17    /// expanded macros.
18    #[rune(skip)]
19    pub(crate) id: Option<NonZeroId>,
20    /// Attributes associated with macro call.
21    #[rune(iter)]
22    pub attributes: Vec<ast::Attribute>,
23    /// The expression being called over.
24    pub path: ast::Path,
25    /// Bang operator `!`.
26    pub bang: T![!],
27    /// Opening token.
28    pub open: ast::Token,
29    /// The tokens provided to the macro.
30    #[rune(iter)]
31    pub input: TokenStream,
32    /// Closing token.
33    pub close: ast::Token,
34}
35
36impl MacroCall {
37    /// Test if macro needs semi or not.
38    pub(crate) fn needs_semi(&self) -> bool {
39        !matches!(self.close.kind, K!['}'])
40    }
41
42    /// The span of the input token stream.
43    pub(crate) fn input_span(&self) -> Span {
44        if let Some(span) = self.input.option_span() {
45            span
46        } else {
47            self.open.span.tail()
48        }
49    }
50
51    /// Parse with an expression.
52    pub(crate) fn parse_with_meta_path(
53        parser: &mut Parser,
54        attributes: Vec<ast::Attribute>,
55        path: ast::Path,
56    ) -> Result<Self> {
57        let bang = parser.parse()?;
58
59        let mut level = 1;
60        let open = parser.next()?;
61
62        let delim = match open.kind {
63            ast::Kind::Open(delim) => delim,
64            _ => {
65                return Err(compile::Error::expected(open, Expectation::OpenDelimiter));
66            }
67        };
68
69        let close;
70
71        let mut stream = Vec::new();
72
73        loop {
74            let token = parser.next()?;
75
76            match token.kind {
77                ast::Kind::Open(..) => level += 1,
78                ast::Kind::Close(actual) => {
79                    level -= 1;
80
81                    if level == 0 {
82                        if actual != delim {
83                            return Err(compile::Error::new(
84                                open,
85                                ErrorKind::ExpectedMacroCloseDelimiter {
86                                    actual: token.kind,
87                                    expected: ast::Kind::Close(delim),
88                                },
89                            ));
90                        }
91
92                        close = token;
93                        break;
94                    }
95                }
96                _ => (),
97            }
98
99            stream.try_push(token)?;
100        }
101
102        Ok(Self {
103            id: Default::default(),
104            attributes,
105            bang,
106            path,
107            open,
108            input: TokenStream::from(stream),
109            close,
110        })
111    }
112}
113
114impl Parse for MacroCall {
115    fn parse(parser: &mut Parser<'_>) -> Result<Self> {
116        let attributes = parser.parse()?;
117        let path = parser.parse()?;
118        Self::parse_with_meta_path(parser, attributes, path)
119    }
120}