Skip to main content

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    /// Parse with an expression.
38    pub(crate) fn parse_with_meta_path(
39        parser: &mut Parser,
40        attributes: Vec<ast::Attribute>,
41        path: ast::Path,
42    ) -> Result<Self> {
43        let bang = parser.parse()?;
44
45        let mut level = 1;
46        let open = parser.next()?;
47
48        let delim = match open.kind {
49            ast::Kind::Open(delim) => delim,
50            _ => {
51                return Err(compile::Error::expected(open, Expectation::OpenDelimiter));
52            }
53        };
54
55        let close;
56
57        let mut stream = Vec::new();
58
59        loop {
60            let token = parser.next()?;
61
62            match token.kind {
63                ast::Kind::Open(..) => level += 1,
64                ast::Kind::Close(actual) => {
65                    level -= 1;
66
67                    if level == 0 {
68                        if actual != delim {
69                            return Err(compile::Error::new(
70                                open,
71                                ErrorKind::ExpectedMacroCloseDelimiter {
72                                    actual: token.kind,
73                                    expected: ast::Kind::Close(delim),
74                                },
75                            ));
76                        }
77
78                        close = token;
79                        break;
80                    }
81                }
82                _ => (),
83            }
84
85            stream.try_push(token)?;
86        }
87
88        Ok(Self {
89            id: Default::default(),
90            attributes,
91            bang,
92            path,
93            open,
94            input: TokenStream::from(stream),
95            close,
96        })
97    }
98}
99
100impl Parse for MacroCall {
101    fn parse(parser: &mut Parser<'_>) -> Result<Self> {
102        let attributes = parser.parse()?;
103        let path = parser.parse()?;
104        Self::parse_with_meta_path(parser, attributes, path)
105    }
106}