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 {
28 pub span: Span,
30 pub name: TokenStream,
32 pub props: Vec<(syn::Ident, TokenStream)>,
34 pub children: Option<Box<Template>>,
36}
37
38impl ElementNode {
39 pub fn span(&self) -> Span {
40 self.span
41 }
42
43 pub fn parse_with_ident(input: ParseStream, first_ident: syn::Ident) -> syn::Result<Self> {
44 let span = first_ident.span();
45
46 let mut name = TokenStream::new();
47 first_ident.to_tokens(&mut name);
48
49 while input.peek(Token![::]) {
50 let colons: Token![::] = input.parse()?;
51 colons.to_tokens(&mut name);
52 let segment: syn::Ident = input.parse()?;
53 segment.to_tokens(&mut name);
54 }
55
56 parse_props_and_children(input, span, name)
57 }
58}
59
60impl Expand for ElementNode {
61 fn expand(&self, output: &Ident, idents: &mut crate::ident::Iter) -> TokenStream {
62 let name = pascal!(self.name => token_stream);
63 let prop_names: Vec<&syn::Ident> = self.props.iter().map(|(n, _)| n).collect();
64 let prop_values: Vec<&TokenStream> = self.props.iter().map(|(_, v)| v).collect();
65
66 if let Some(children) = &self.children {
67 let inner = idents.next().unwrap();
68 let children_expanded = children.expand(&inner, idents);
69
70 quote! {
71 {
72 let mut #inner = ::zyn::proc_macro2::TokenStream::new();
73 #children_expanded
74 let __zyn_rendered = ::zyn::Render::render(&#name {
75 #(#prop_names: #prop_values,)*
76 children: #inner,
77 }, &::zyn::Input::from(input.clone()));
78 let (__zyn_tokens, __zyn_diag) = __zyn_rendered.into_parts();
79 #output.extend(__zyn_tokens);
80 __zyn_diagnostic = __zyn_diagnostic.add(__zyn_diag);
81 }
82 }
83 } else {
84 quote! {
85 {
86 let __zyn_rendered = ::zyn::Render::render(&#name {
87 #(#prop_names: #prop_values,)*
88 }, &::zyn::Input::from(input.clone()));
89 let (__zyn_tokens, __zyn_diag) = __zyn_rendered.into_parts();
90 #output.extend(__zyn_tokens);
91 __zyn_diagnostic = __zyn_diagnostic.add(__zyn_diag);
92 }
93 }
94 }
95 }
96}
97
98impl Parse for ElementNode {
99 fn parse(input: ParseStream) -> syn::Result<Self> {
100 let first_ident: syn::Ident = input.parse()?;
101 let span = first_ident.span();
102
103 let mut name = TokenStream::new();
104 first_ident.to_tokens(&mut name);
105
106 while input.peek(Token![::]) {
107 let colons: Token![::] = input.parse()?;
108 colons.to_tokens(&mut name);
109 let segment: syn::Ident = input.parse()?;
110 segment.to_tokens(&mut name);
111 }
112
113 parse_props_and_children(input, span, name)
114 }
115}
116
117fn parse_props_and_children(
118 input: ParseStream,
119 span: Span,
120 name: TokenStream,
121) -> syn::Result<ElementNode> {
122 let mut props = Vec::new();
123
124 if input.peek(syn::token::Paren) {
125 let props_content;
126 syn::parenthesized!(props_content in input);
127
128 while !props_content.is_empty() {
129 let prop_name: syn::Ident = props_content.parse()?;
130 props_content.parse::<Token![=]>()?;
131
132 let mut value = TokenStream::new();
133
134 while !props_content.is_empty() && !props_content.peek(Token![,]) {
135 let tt: TokenTree = props_content.parse()?;
136 tt.to_tokens(&mut value);
137 }
138
139 props.push((prop_name, value));
140
141 if props_content.peek(Token![,]) {
142 props_content.parse::<Token![,]>()?;
143 }
144 }
145 }
146
147 let children = if input.peek(syn::token::Brace) {
148 let children_content;
149 syn::braced!(children_content in input);
150 Some(Box::new(children_content.parse::<Template>()?))
151 } else {
152 None
153 };
154
155 Ok(ElementNode {
156 span,
157 name,
158 props,
159 children,
160 })
161}