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#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
14#[non_exhaustive]
15pub struct MacroCall {
16 #[rune(skip)]
19 pub(crate) id: Option<NonZeroId>,
20 #[rune(iter)]
22 pub attributes: Vec<ast::Attribute>,
23 pub path: ast::Path,
25 pub bang: T![!],
27 pub open: ast::Token,
29 #[rune(iter)]
31 pub input: TokenStream,
32 pub close: ast::Token,
34}
35
36impl MacroCall {
37 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}