1pub mod at;
17mod group_node;
18mod interp_node;
19mod pipe_node;
20mod tokens_node;
21
22pub use at::*;
23pub use group_node::GroupNode;
24pub use interp_node::InterpNode;
25pub use pipe_node::PipeNode;
26pub use tokens_node::TokensNode;
27
28use proc_macro2::Ident;
29use proc_macro2::Span;
30use proc_macro2::TokenStream;
31use proc_macro2::TokenTree;
32
33use quote::ToTokens;
34
35use syn::Token;
36use syn::parse::ParseStream;
37
38use crate::Expand;
39use crate::ident;
40
41pub enum Node {
45 Tokens(TokensNode),
47 Interp(InterpNode),
49 At(AtNode),
51 Group(GroupNode),
53}
54
55impl Node {
56 pub fn is_tokens(&self) -> bool {
58 matches!(self, Self::Tokens(_))
59 }
60
61 pub fn is_interp(&self) -> bool {
63 matches!(self, Self::Interp(_))
64 }
65
66 pub fn is_at(&self) -> bool {
68 matches!(self, Self::At(_))
69 }
70
71 pub fn is_group(&self) -> bool {
73 matches!(self, Self::Group(_))
74 }
75}
76
77impl Node {
78 pub fn as_tokens(&self) -> &TokensNode {
80 match self {
81 Self::Tokens(v) => v,
82 _ => panic!("called as_tokens on non-Tokens node"),
83 }
84 }
85
86 pub fn as_interp(&self) -> &InterpNode {
88 match self {
89 Self::Interp(v) => v,
90 _ => panic!("called as_interp on non-Interp node"),
91 }
92 }
93
94 pub fn as_at(&self) -> &AtNode {
96 match self {
97 Self::At(v) => v,
98 _ => panic!("called as_at on non-At node"),
99 }
100 }
101
102 pub fn as_group(&self) -> &GroupNode {
104 match self {
105 Self::Group(v) => v,
106 _ => panic!("called as_group on non-Group node"),
107 }
108 }
109}
110
111impl Node {
112 pub fn span(&self) -> Span {
114 match self {
115 Self::Tokens(v) => v.span(),
116 Self::Interp(v) => v.span(),
117 Self::At(v) => v.span(),
118 Self::Group(v) => v.span(),
119 }
120 }
121
122 pub fn to_display_stream(&self, injections: &[(String, TokenStream)]) -> TokenStream {
123 match self {
124 Self::Tokens(v) => v.to_display_stream(injections),
125 Self::Interp(v) => v.to_display_stream(injections),
126 Self::At(v) => v.to_display_stream(injections),
127 Self::Group(v) => v.to_display_stream(injections),
128 }
129 }
130}
131
132impl From<TokensNode> for Node {
133 fn from(v: TokensNode) -> Self {
134 Self::Tokens(v)
135 }
136}
137
138impl From<InterpNode> for Node {
139 fn from(v: InterpNode) -> Self {
140 Self::Interp(v)
141 }
142}
143
144impl From<AtNode> for Node {
145 fn from(v: AtNode) -> Self {
146 Self::At(v)
147 }
148}
149
150impl From<GroupNode> for Node {
151 fn from(v: GroupNode) -> Self {
152 Self::Group(v)
153 }
154}
155
156impl Node {
157 pub fn parse_brace(input: ParseStream) -> syn::Result<Self> {
158 let content;
159 let brace = syn::braced!(content in input);
160 let span = brace.span.join();
161
162 let fork = content.fork();
163 let is_interp = if fork.peek(syn::token::Brace) {
164 let inner;
165 syn::braced!(inner in fork);
166 fork.is_empty()
167 } else {
168 false
169 };
170
171 if is_interp {
172 let inner;
173 syn::braced!(inner in content);
174
175 let mut expr = TokenStream::new();
176 let mut pipes = Vec::new();
177
178 while !inner.is_empty() {
179 if inner.peek(Token![|]) {
180 inner.parse::<Token![|]>()?;
181 pipes.push(inner.parse::<PipeNode>()?);
182 } else if pipes.is_empty() {
183 let tt: TokenTree = inner.parse()?;
184 tt.to_tokens(&mut expr);
185 } else {
186 break;
187 }
188 }
189
190 if expr.is_empty() {
191 return Err(syn::Error::new(span, "empty interpolation"));
192 }
193
194 Ok(InterpNode { span, expr, pipes }.into())
195 } else {
196 let body = content.parse::<crate::template::Template>()?;
197 Ok(GroupNode {
198 span,
199 delimiter: proc_macro2::Delimiter::Brace,
200 body: Box::new(body),
201 }
202 .into())
203 }
204 }
205}
206
207impl Expand for Node {
208 fn expand(&self, output: &Ident, idents: &mut ident::Iter) -> TokenStream {
209 match self {
210 Self::Tokens(v) => v.expand(output, idents),
211 Self::Interp(v) => v.expand(output, idents),
212 Self::At(v) => v.expand(output, idents),
213 Self::Group(v) => v.expand(output, idents),
214 }
215 }
216}