zyn_core/ast/at/
for_node.rs1use proc_macro2::Ident;
2use proc_macro2::Span;
3use proc_macro2::TokenStream;
4
5use quote::quote;
6
7use syn::ext::IdentExt;
8use syn::parse::Parse;
9use syn::parse::ParseStream;
10
11use crate::template::Template;
12
13use crate::Expand;
14
15pub struct ForNode {
27 pub span: Span,
29 pub binding: syn::Ident,
31 pub iter: TokenStream,
33 pub body: Box<Template>,
35}
36
37impl ForNode {
38 pub fn span(&self) -> Span {
39 self.span
40 }
41}
42
43impl Parse for ForNode {
44 fn parse(input: ParseStream) -> syn::Result<Self> {
45 let params;
46 syn::parenthesized!(params in input);
47
48 let fork = params.fork();
49 let is_classic = if fork.call(syn::Ident::parse_any).is_ok() {
50 let Ok(kw) = fork.call(syn::Ident::parse_any) else {
51 return Self::parse_classic(¶ms, input);
52 };
53 kw != "in"
54 } else {
55 true
56 };
57
58 if is_classic {
59 return Self::parse_classic(¶ms, input);
60 }
61
62 let binding: syn::Ident = params.call(syn::Ident::parse_any)?;
63 let _in_kw: syn::Ident = params.call(syn::Ident::parse_any)?;
64 let iter: TokenStream = params.parse()?;
65
66 let body_content;
67 syn::braced!(body_content in input);
68 let body = body_content.parse::<Template>()?;
69
70 Ok(Self {
71 span: Span::call_site(),
72 binding,
73 iter,
74 body: Box::new(body),
75 })
76 }
77}
78
79impl ForNode {
80 fn parse_classic(params: ParseStream, input: ParseStream) -> syn::Result<Self> {
81 let count: TokenStream = params.parse()?;
82 let binding = syn::Ident::new("_", Span::call_site());
83 let iter: TokenStream = quote! { 0..#count };
84
85 let body_content;
86 syn::braced!(body_content in input);
87 let body = body_content.parse::<Template>()?;
88
89 Ok(Self {
90 span: Span::call_site(),
91 binding,
92 iter,
93 body: Box::new(body),
94 })
95 }
96}
97
98impl Expand for ForNode {
99 fn expand(&self, output: &Ident, idents: &mut crate::ident::Iter) -> TokenStream {
100 let binding = &self.binding;
101 let iter = &self.iter;
102 let body_expanded = self.body.expand(output, idents);
103
104 quote! {
105 for #binding in #iter {
106 #body_expanded
107 }
108 }
109 }
110}