1pub(crate) use rowan::{GreenNode, GreenToken, NodeOrToken, SyntaxKind as RSyntaxKind};
4
5macro_rules! quote_impl_ {
6 ( @append $children:ident ) => {}; ( @append $children:ident
9 $node:ident {
10 $($tree:tt)*
11 }
12 $($rest:tt)*
13 ) => {
14 {
15 #[allow(unused_mut)]
16 let mut inner_children = ::std::vec::Vec::<$crate::ast::make::quote::NodeOrToken<
17 $crate::ast::make::quote::GreenNode,
18 $crate::ast::make::quote::GreenToken,
19 >>::new();
20 $crate::ast::make::quote::quote_impl!( @append inner_children
21 $($tree)*
22 );
23 let kind = <$crate::ast::$node as $crate::ast::AstNode>::kind();
24 let node = $crate::ast::make::quote::GreenNode::new($crate::ast::make::quote::RSyntaxKind(kind as u16), inner_children);
25 $children.push($crate::ast::make::quote::NodeOrToken::Node(node));
26 }
27 $crate::ast::make::quote::quote_impl!( @append $children $($rest)* );
28 };
29
30 ( @append $children:ident
31 [ $token_kind:ident $token_text:expr ]
32 $($rest:tt)*
33 ) => {
34 $children.push($crate::ast::make::quote::NodeOrToken::Token(
35 $crate::ast::make::quote::GreenToken::new(
36 $crate::ast::make::quote::RSyntaxKind($crate::SyntaxKind::$token_kind as u16),
37 &$token_text,
38 ),
39 ));
40 $crate::ast::make::quote::quote_impl!( @append $children $($rest)* );
41 };
42
43 ( @append $children:ident
44 [$($token:tt)+]
45 $($rest:tt)*
46 ) => {
47 $children.push($crate::ast::make::quote::NodeOrToken::Token(
48 $crate::ast::make::quote::GreenToken::new(
49 $crate::ast::make::quote::RSyntaxKind($crate::T![ $($token)+ ] as u16),
50 const { $crate::T![ $($token)+ ].text() },
51 ),
52 ));
53 $crate::ast::make::quote::quote_impl!( @append $children $($rest)* );
54 };
55
56 ( @append $children:ident
57 $whitespace:literal
58 $($rest:tt)*
59 ) => {
60 const { $crate::ast::make::quote::verify_only_whitespaces($whitespace) };
61 $children.push($crate::ast::make::quote::NodeOrToken::Token(
62 $crate::ast::make::quote::GreenToken::new(
63 $crate::ast::make::quote::RSyntaxKind($crate::SyntaxKind::WHITESPACE as u16),
64 $whitespace,
65 ),
66 ));
67 $crate::ast::make::quote::quote_impl!( @append $children $($rest)* );
68 };
69
70 ( @append $children:ident
71 # $var:ident
72 $($rest:tt)*
73 ) => {
74 $crate::ast::make::quote::ToNodeChild::append_node_child($var, &mut $children);
75 $crate::ast::make::quote::quote_impl!( @append $children $($rest)* );
76 };
77
78 ( @append $children:ident
79 #( $($repetition:tt)+ )*
80 $($rest:tt)*
81 ) => {
82 $crate::ast::make::quote::quote_impl!( @extract_pounded_in_repetition $children
83 [] [] $($repetition)*
84 );
85 $crate::ast::make::quote::quote_impl!( @append $children $($rest)* );
86 };
87
88 ( @extract_pounded_in_repetition $children:ident
90 [ $($repetition:tt)* ] [ ]
91 ) => {
92 ::std::compile_error!("repetition in `ast::make::quote!()` without variable");
93 };
94
95 ( @extract_pounded_in_repetition $children:ident
97 [ $($repetition:tt)* ] [ $repetition_var:ident ]
98 ) => {
99 ::std::iter::IntoIterator::into_iter($repetition_var).for_each(|$repetition_var| {
100 $crate::ast::make::quote::quote_impl!( @append $children $($repetition)* );
101 });
102 };
103
104 ( @extract_pounded_in_repetition $children:ident
105 [ $($repetition:tt)* ] [ $repetition_var1:ident ] # $repetition_var2:ident $($rest:tt)*
106 ) => {
107 ::std::compile_error!("repetition in `ast::make::quote!()` with more than one variable");
108 };
109
110 ( @extract_pounded_in_repetition $children:ident
111 [ $($repetition:tt)* ] [ ] # $repetition_var:ident $($rest:tt)*
112 ) => {
113 $crate::ast::make::quote::quote_impl!( @extract_pounded_in_repetition $children
114 [ $($repetition)* # $repetition_var ] [ $repetition_var ] $($rest)*
115 );
116 };
117
118 ( @extract_pounded_in_repetition $children:ident
119 [ $($repetition:tt)* ] [ $($repetition_var:tt)* ] $non_repetition_var:tt $($rest:tt)*
120 ) => {
121 $crate::ast::make::quote::quote_impl!( @extract_pounded_in_repetition $children
122 [ $($repetition)* $non_repetition_var ] [ $($repetition_var)* ] $($rest)*
123 );
124 };
125}
126pub(crate) use quote_impl_ as quote_impl;
127
128macro_rules! quote_ {
143 ( $root:ident { $($tree:tt)* } ) => {{
144 #[allow(unused_mut)]
145 let mut root = ::std::vec::Vec::<$crate::ast::make::quote::NodeOrToken<
146 $crate::ast::make::quote::GreenNode,
147 $crate::ast::make::quote::GreenToken,
148 >>::with_capacity(1);
149 $crate::ast::make::quote::quote_impl!( @append root $root { $($tree)* } );
150 let root = root.into_iter().next().unwrap();
151 let root = $crate::SyntaxNode::new_root(root.into_node().unwrap());
152 <$crate::ast::$root as $crate::ast::AstNode>::cast(root).unwrap()
153 }};
154}
155pub(crate) use quote_ as quote;
156
157use crate::AstNode;
158
159pub(crate) trait ToNodeChild {
160 fn append_node_child(self, children: &mut Vec<NodeOrToken<GreenNode, GreenToken>>);
161}
162
163impl<N: AstNode> ToNodeChild for N {
164 fn append_node_child(self, children: &mut Vec<NodeOrToken<GreenNode, GreenToken>>) {
165 children.push((*self.syntax().clone_subtree().green()).to_owned().into());
166 }
167}
168
169impl<C: ToNodeChild> ToNodeChild for Option<C> {
170 fn append_node_child(self, children: &mut Vec<NodeOrToken<GreenNode, GreenToken>>) {
171 if let Some(child) = self {
172 child.append_node_child(children);
173 }
174 }
175}
176
177impl ToNodeChild for () {
179 fn append_node_child(self, _children: &mut Vec<NodeOrToken<GreenNode, GreenToken>>) {}
180}
181
182pub(crate) const fn verify_only_whitespaces(text: &str) {
183 let text = text.as_bytes();
184 let mut i = 0;
185 while i < text.len() {
186 if !text[i].is_ascii_whitespace() {
187 panic!("non-whitespace found in whitespace token");
188 }
189 i += 1;
190 }
191}