1use proc_macro2::{extra::DelimSpan, TokenStream};
2use quote::{ToTokens, TokenStreamExt};
3use syn::{
4 braced, bracketed, parenthesized,
5 parse::{Parse, ParseStream},
6 token::{self, Brace, Bracket, Group, Paren},
7 Token,
8};
9
10pub mod attrs;
11pub mod call;
12pub mod doctype;
13pub mod element;
14pub mod entity;
15pub mod for_stmt;
16pub mod if_stmt;
17pub mod let_stmt;
18pub mod match_stmt;
19pub mod name;
20pub mod raw_text;
21
22pub use {
23 attrs::Attr, call::Call, doctype::Doctype, element::Element, entity::Entity, for_stmt::For,
24 if_stmt::If, let_stmt::Let, match_stmt::Match, name::Name, raw_text::RawText,
25};
26
27mod kw {
28 syn::custom_keyword!(context);
29 syn::custom_keyword!(children);
30 syn::custom_keyword!(with);
31}
32
33fn parse_to_vec<T: Parse>(input: ParseStream) -> syn::Result<Vec<T>> {
35 let mut body = vec![];
36 while !input.is_empty() {
37 body.push(T::parse(input)?);
38 }
39 Ok(body)
40}
41
42#[derive(Debug, Clone)]
43pub struct Scope<T> {
44 pub pound: token::Pound,
45 pub brace: Brace,
46 pub body: Vec<T>,
47}
48
49impl<T: Parse> Parse for Scope<T> {
50 fn parse(input: ParseStream) -> syn::Result<Self> {
51 let content;
52 Ok(Self {
53 pound: input.parse()?,
54 brace: braced!(content in input),
55 body: parse_to_vec(&content)?,
56 })
57 }
58}
59
60impl<T: ToTokens> ToTokens for Scope<T> {
61 fn to_tokens(&self, tokens: &mut TokenStream) {
62 self.pound.to_tokens(tokens);
63 self.brace.surround(tokens, |tokens| {
64 tokens.append_all(&self.body);
65 });
66 }
67}
68
69#[derive(Debug, Clone)]
70pub enum Block {
71 Valid(syn::Block),
72 Invalid { brace: Brace, body: TokenStream },
73}
74
75impl Block {
76 pub fn brace_span(&self) -> DelimSpan {
77 match self {
78 Block::Valid(block) => block.brace_token.span,
79 Block::Invalid { brace, .. } => brace.span,
80 }
81 }
82}
83
84impl Parse for Block {
85 fn parse(input: ParseStream) -> syn::Result<Self> {
86 let content;
87 match input.parse() {
88 Ok(block) => Ok(Self::Valid(block)),
89 Err(_) => Ok(Self::Invalid {
90 brace: braced!(content in input),
91 body: content.parse()?,
92 }),
93 }
94 }
95}
96
97impl ToTokens for Block {
98 fn to_tokens(&self, tokens: &mut TokenStream) {
99 match self {
100 Self::Valid(block) => block.to_tokens(tokens),
101 Self::Invalid { brace, body } => {
102 brace.surround(tokens, |tokens| body.to_tokens(tokens))
103 }
104 }
105 }
106}
107
108#[derive(Debug, Clone)]
109pub struct With {
110 pub pound: Token![#],
111 pub with: kw::with,
112 pub context: kw::context,
113 pub ty: Option<(Token![:], Box<syn::Type>)>,
114 pub eq: Token![=],
115 pub expr: Box<syn::Expr>,
116 pub brace: Brace,
117 pub nodes: Vec<Node>,
118}
119
120impl Parse for With {
121 fn parse(input: ParseStream) -> syn::Result<Self> {
122 let content;
123 Ok(Self {
124 pound: input.parse()?,
125 with: input.parse()?,
126 context: input.parse()?,
127 ty: {
128 let lookahead1 = input.lookahead1();
129 if lookahead1.peek(Token![:]) {
130 Some((
131 input.parse()?,
132 Box::new(From::from(syn::TypeReference {
133 and_token: input.parse()?,
134 lifetime: None,
135 mutability: None,
136 elem: input.parse()?,
137 })),
138 ))
139 } else if lookahead1.peek(Token![=]) {
140 None
141 } else {
142 return Err(lookahead1.error());
143 }
144 },
145 eq: input.parse()?,
146 expr: Box::new(syn::Expr::parse_without_eager_brace(input)?),
147 brace: braced!(content in input),
148 nodes: parse_to_vec(&content)?,
149 })
150 }
151}
152
153impl ToTokens for With {
154 fn to_tokens(&self, tokens: &mut TokenStream) {
155 self.pound.to_tokens(tokens);
156 self.with.to_tokens(tokens);
157 self.context.to_tokens(tokens);
158 if let Some((colon, ty)) = &self.ty {
159 colon.to_tokens(tokens);
160 ty.to_tokens(tokens);
161 }
162 self.eq.to_tokens(tokens);
163 self.expr.to_tokens(tokens);
164 self.brace.surround(tokens, |tokens| {
165 tokens.append_all(&self.nodes);
166 });
167 }
168}
169
170#[derive(Debug, Clone)]
176pub enum Node {
177 Entity(Entity),
178 Doctype(Doctype),
179 Element(Element),
180 RawText(RawText),
181 Paren(Paren, Vec<Node>),
182 Bracket(Bracket, Vec<Node>),
183 Expr(Block),
184 If(If<Self>),
185 Match(Match<Self>),
186 For(For<Self>),
187 Scope(Scope<Self>),
188 Let(Let),
189 Call(Call),
190 With(With),
191}
192
193impl Parse for Node {
194 fn parse(input: ParseStream) -> syn::Result<Self> {
195 if input.peek(Token![&]) {
196 Ok(Self::Entity(input.parse()?))
197 } else if input.peek(Token![<]) {
198 if input.peek2(Token![!]) {
199 Ok(Self::Doctype(input.parse()?))
200 } else {
201 Ok(Self::Element(input.parse()?))
202 }
203 } else if input.peek(Brace) {
204 Ok(Self::Expr(input.parse()?))
205 } else if input.peek(Token![#]) {
206 if input.peek2(Token![if]) {
207 Ok(Self::If(input.parse()?))
208 } else if input.peek2(Token![match]) {
209 Ok(Self::Match(input.parse()?))
210 } else if input.peek2(Token![for]) {
211 Ok(Self::For(input.parse()?))
212 } else if input.peek2(Token![let]) {
213 Ok(Self::Let(input.parse()?))
214 } else if input.peek2(Brace) {
215 Ok(Self::Scope(input.parse()?))
216 } else if input.peek2(kw::with) {
217 Ok(Self::With(input.parse()?))
218 } else {
219 Ok(Self::Call(input.parse()?))
220 }
221 } else if input.peek(Paren) {
222 let content;
223 Ok(Self::Paren(
224 parenthesized!(content in input),
225 parse_to_vec(&content)?,
226 ))
227 } else if input.peek(Bracket) {
228 let content;
229 Ok(Self::Bracket(
230 bracketed!(content in input),
231 parse_to_vec(&content)?,
232 ))
233 } else if input.peek(Group) {
234 Err(input.error("unexpected none deliminated group"))
235 } else if input.is_empty() {
236 Err(input.error("expected a templr node"))
237 } else {
238 Ok(Self::RawText(input.parse()?))
239 }
240 }
241}
242
243impl ToTokens for Node {
244 fn to_tokens(&self, tokens: &mut TokenStream) {
245 match self {
246 Self::Entity(slf) => slf.to_tokens(tokens),
247 Self::Doctype(slf) => slf.to_tokens(tokens),
248 Self::Element(slf) => slf.to_tokens(tokens),
249 Self::RawText(slf) => slf.to_tokens(tokens),
250 Self::Paren(paren, nodes) => paren.surround(tokens, |tokens| {
251 tokens.append_all(nodes);
252 }),
253 Self::Bracket(bracket, nodes) => bracket.surround(tokens, |tokens| {
254 tokens.append_all(nodes);
255 }),
256 Self::Expr(slf) => slf.to_tokens(tokens),
257 Self::If(slf) => slf.to_tokens(tokens),
258 Self::Match(slf) => slf.to_tokens(tokens),
259 Self::For(slf) => slf.to_tokens(tokens),
260 Self::Scope(slf) => slf.to_tokens(tokens),
261 Self::Let(slf) => slf.to_tokens(tokens),
262 Self::Call(slf) => slf.to_tokens(tokens),
263 Self::With(slf) => slf.to_tokens(tokens),
264 }
265 }
266}
267
268#[derive(Debug, Clone)]
269pub struct UseContext {
270 pub pound: Token![#],
271 pub use_token: Token![use],
272 pub context: kw::context,
273 pub as_pat: Option<(Token![as], Box<syn::Pat>)>,
274 pub colon_ty: Option<(Token![:], Box<syn::Type>)>,
275 pub semi: Token![;],
276}
277
278impl Parse for UseContext {
279 fn parse(input: ParseStream) -> syn::Result<Self> {
280 Ok(Self {
281 pound: input.parse()?,
282 use_token: input.parse()?,
283 context: input.parse()?,
284 as_pat: {
285 let lookahead1 = input.lookahead1();
286 match lookahead1.peek(Token![as]) {
287 true => Some((input.parse()?, Box::new(syn::Pat::parse_single(input)?))),
288 false if lookahead1.peek(Token![:]) || lookahead1.peek(Token![;]) => None,
289 false => return Err(lookahead1.error()),
290 }
291 },
292 colon_ty: {
293 let lookahead1 = input.lookahead1();
294 match lookahead1.peek(Token![:]) {
295 true => Some((
296 input.parse()?,
297 Box::new(From::from(syn::TypeReference {
298 and_token: input.parse()?,
299 lifetime: None,
300 mutability: None,
301 elem: input.parse()?,
302 })),
303 )),
304 false if lookahead1.peek(Token![;]) => None,
305 false => return Err(lookahead1.error()),
306 }
307 },
308 semi: input.parse()?,
309 })
310 }
311}
312
313impl ToTokens for UseContext {
314 fn to_tokens(&self, tokens: &mut TokenStream) {
315 self.pound.to_tokens(tokens);
316 self.use_token.to_tokens(tokens);
317 self.context.to_tokens(tokens);
318 if let Some((as_token, pat)) = &self.as_pat {
319 as_token.to_tokens(tokens);
320 pat.to_tokens(tokens);
321 }
322 if let Some((colon, ty)) = &self.colon_ty {
323 colon.to_tokens(tokens);
324 ty.to_tokens(tokens);
325 }
326 self.semi.to_tokens(tokens);
327 }
328}
329
330#[derive(Debug, Clone)]
331pub struct UseChildren {
332 pub pound: Token![#],
333 pub use_token: Token![use],
334 pub children: kw::children,
335 pub as_pat: Option<(Token![as], Box<syn::Pat>)>,
336 pub semi: Token![;],
337}
338
339impl Parse for UseChildren {
340 fn parse(input: ParseStream) -> syn::Result<Self> {
341 Ok(Self {
342 pound: input.parse()?,
343 use_token: input.parse()?,
344 children: input.parse()?,
345 as_pat: {
346 let lookahead1 = input.lookahead1();
347 match lookahead1.peek(Token![as]) {
348 true => Some((input.parse()?, Box::new(syn::Pat::parse_single(input)?))),
349 false if lookahead1.peek(Token![;]) => None,
350 false => return Err(lookahead1.error()),
351 }
352 },
353 semi: input.parse()?,
354 })
355 }
356}
357
358impl ToTokens for UseChildren {
359 fn to_tokens(&self, tokens: &mut TokenStream) {
360 self.pound.to_tokens(tokens);
361 self.use_token.to_tokens(tokens);
362 self.children.to_tokens(tokens);
363 if let Some((as_token, pat)) = &self.as_pat {
364 as_token.to_tokens(tokens);
365 pat.to_tokens(tokens);
366 }
367 self.semi.to_tokens(tokens);
368 }
369}
370
371#[derive(Debug, Clone)]
372pub enum Use {
373 Context(UseContext),
374 Children(UseChildren),
375}
376
377impl Parse for Use {
378 fn parse(input: ParseStream) -> syn::Result<Self> {
379 let fork = input.fork();
380 let _: Token![#] = fork.parse()?;
381 let _: Token![use] = fork.parse()?;
382 let lookahead1 = fork.lookahead1();
383 if lookahead1.peek(kw::children) {
384 Ok(Use::Children(input.parse()?))
385 } else if lookahead1.peek(kw::context) {
386 Ok(Use::Context(input.parse()?))
387 } else {
388 Err(lookahead1.error())
389 }
390 }
391}
392
393impl ToTokens for Use {
394 fn to_tokens(&self, tokens: &mut TokenStream) {
395 match self {
396 Self::Context(slf) => slf.to_tokens(tokens),
397 Self::Children(slf) => slf.to_tokens(tokens),
398 }
399 }
400}
401
402#[derive(Debug, Clone)]
403pub struct TemplBody {
404 pub uses: Vec<Use>,
405 pub nodes: Vec<Node>,
406}
407
408impl TemplBody {
409 pub fn use_children(&self) -> Option<&UseChildren> {
410 self.uses.iter().find_map(|u| match u {
411 Use::Children(u) => Some(u),
412 _ => None,
413 })
414 }
415 pub fn use_context(&self) -> Option<&UseContext> {
416 self.uses.iter().find_map(|u| match u {
417 Use::Context(u) => Some(u),
418 _ => None,
419 })
420 }
421}
422
423impl Parse for TemplBody {
424 fn parse(input: ParseStream) -> syn::Result<Self> {
425 let mut uses = vec![];
426
427 while input.peek(Token![#]) && input.peek2(Token![use]) {
428 uses.push(Use::parse(input)?);
429 }
430 if let Some(u) = uses
431 .iter()
432 .filter_map(|u| match u {
433 Use::Children(u) => Some(u),
434 _ => None,
435 })
436 .nth(1)
437 {
438 return Err(syn::Error::new(
439 u.pound.span,
440 "Cannot redefine `#use children ...`",
441 ));
442 } else if let Some(u) = uses
443 .iter()
444 .filter_map(|u| match u {
445 Use::Context(u) => Some(u),
446 _ => None,
447 })
448 .nth(1)
449 {
450 return Err(syn::Error::new(
451 u.pound.span,
452 "Cannot redefine `#use context ...`",
453 ));
454 }
455
456 Ok(Self {
457 uses,
458 nodes: parse_to_vec(input)?,
459 })
460 }
461}
462
463impl ToTokens for TemplBody {
464 fn to_tokens(&self, tokens: &mut TokenStream) {
465 tokens.append_all(&self.uses);
466 tokens.append_all(&self.nodes);
467 }
468}