zyn_core/ast/at/
element_node.rs1use proc_macro2::Ident;
2use proc_macro2::Span;
3use proc_macro2::TokenStream;
4use proc_macro2::TokenTree;
5
6use quote::ToTokens;
7use quote::quote;
8
9use syn::Token;
10use syn::parse::Parse;
11use syn::parse::ParseStream;
12
13use crate::template::Template;
14
15use crate::Expand;
16use crate::pascal;
17
18pub struct ElementNode {
19 pub span: Span,
20 pub name: TokenStream,
21 pub props: Vec<(syn::Ident, TokenStream)>,
22 pub children: Option<Box<Template>>,
23}
24
25impl ElementNode {
26 pub fn span(&self) -> Span {
27 self.span
28 }
29
30 pub fn parse_with_ident(input: ParseStream, first_ident: syn::Ident) -> syn::Result<Self> {
31 let span = first_ident.span();
32
33 let mut name = TokenStream::new();
34 first_ident.to_tokens(&mut name);
35
36 while input.peek(Token![::]) {
37 let colons: Token![::] = input.parse()?;
38 colons.to_tokens(&mut name);
39 let segment: syn::Ident = input.parse()?;
40 segment.to_tokens(&mut name);
41 }
42
43 parse_props_and_children(input, span, name)
44 }
45}
46
47impl Expand for ElementNode {
48 fn expand(&self, output: &Ident, idents: &mut crate::ident::Iter) -> TokenStream {
49 let name = pascal!(self.name => token_stream);
50 let prop_names: Vec<&syn::Ident> = self.props.iter().map(|(n, _)| n).collect();
51 let prop_values: Vec<&TokenStream> = self.props.iter().map(|(_, v)| v).collect();
52
53 if let Some(children) = &self.children {
54 let inner = idents.next().unwrap();
55 let children_expanded = children.expand(&inner, idents);
56
57 quote! {
58 {
59 let mut #inner = ::zyn::proc_macro2::TokenStream::new();
60 #children_expanded
61 let __zyn_rendered = ::zyn::Render::render(&#name {
62 #(#prop_names: #prop_values,)*
63 children: #inner,
64 }, &::zyn::Input::from(input.clone()));
65 ::zyn::quote::ToTokens::to_tokens(&__zyn_rendered, &mut #output);
66 }
67 }
68 } else {
69 quote! {
70 {
71 let __zyn_rendered = ::zyn::Render::render(&#name {
72 #(#prop_names: #prop_values,)*
73 }, &::zyn::Input::from(input.clone()));
74 ::zyn::quote::ToTokens::to_tokens(&__zyn_rendered, &mut #output);
75 }
76 }
77 }
78 }
79}
80
81impl Parse for ElementNode {
82 fn parse(input: ParseStream) -> syn::Result<Self> {
83 let first_ident: syn::Ident = input.parse()?;
84 let span = first_ident.span();
85
86 let mut name = TokenStream::new();
87 first_ident.to_tokens(&mut name);
88
89 while input.peek(Token![::]) {
90 let colons: Token![::] = input.parse()?;
91 colons.to_tokens(&mut name);
92 let segment: syn::Ident = input.parse()?;
93 segment.to_tokens(&mut name);
94 }
95
96 parse_props_and_children(input, span, name)
97 }
98}
99
100fn parse_props_and_children(
101 input: ParseStream,
102 span: Span,
103 name: TokenStream,
104) -> syn::Result<ElementNode> {
105 let mut props = Vec::new();
106
107 if input.peek(syn::token::Paren) {
108 let props_content;
109 syn::parenthesized!(props_content in input);
110
111 while !props_content.is_empty() {
112 let prop_name: syn::Ident = props_content.parse()?;
113 props_content.parse::<Token![=]>()?;
114
115 let mut value = TokenStream::new();
116
117 while !props_content.is_empty() && !props_content.peek(Token![,]) {
118 let tt: TokenTree = props_content.parse()?;
119 tt.to_tokens(&mut value);
120 }
121
122 props.push((prop_name, value));
123
124 if props_content.peek(Token![,]) {
125 props_content.parse::<Token![,]>()?;
126 }
127 }
128 }
129
130 let children = if input.peek(syn::token::Brace) {
131 let children_content;
132 syn::braced!(children_content in input);
133 Some(Box::new(children_content.parse::<Template>()?))
134 } else {
135 None
136 };
137
138 Ok(ElementNode {
139 span,
140 name,
141 props,
142 children,
143 })
144}