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 ::zyn::quote::ToTokens::to_tokens(&__zyn_rendered, &mut #output);
79 }
80 }
81 } else {
82 quote! {
83 {
84 let __zyn_rendered = ::zyn::Render::render(&#name {
85 #(#prop_names: #prop_values,)*
86 }, &::zyn::Input::from(input.clone()));
87 ::zyn::quote::ToTokens::to_tokens(&__zyn_rendered, &mut #output);
88 }
89 }
90 }
91 }
92}
93
94impl Parse for ElementNode {
95 fn parse(input: ParseStream) -> syn::Result<Self> {
96 let first_ident: syn::Ident = input.parse()?;
97 let span = first_ident.span();
98
99 let mut name = TokenStream::new();
100 first_ident.to_tokens(&mut name);
101
102 while input.peek(Token![::]) {
103 let colons: Token![::] = input.parse()?;
104 colons.to_tokens(&mut name);
105 let segment: syn::Ident = input.parse()?;
106 segment.to_tokens(&mut name);
107 }
108
109 parse_props_and_children(input, span, name)
110 }
111}
112
113fn parse_props_and_children(
114 input: ParseStream,
115 span: Span,
116 name: TokenStream,
117) -> syn::Result<ElementNode> {
118 let mut props = Vec::new();
119
120 if input.peek(syn::token::Paren) {
121 let props_content;
122 syn::parenthesized!(props_content in input);
123
124 while !props_content.is_empty() {
125 let prop_name: syn::Ident = props_content.parse()?;
126 props_content.parse::<Token![=]>()?;
127
128 let mut value = TokenStream::new();
129
130 while !props_content.is_empty() && !props_content.peek(Token![,]) {
131 let tt: TokenTree = props_content.parse()?;
132 tt.to_tokens(&mut value);
133 }
134
135 props.push((prop_name, value));
136
137 if props_content.peek(Token![,]) {
138 props_content.parse::<Token![,]>()?;
139 }
140 }
141 }
142
143 let children = if input.peek(syn::token::Brace) {
144 let children_content;
145 syn::braced!(children_content in input);
146 Some(Box::new(children_content.parse::<Template>()?))
147 } else {
148 None
149 };
150
151 Ok(ElementNode {
152 span,
153 name,
154 props,
155 children,
156 })
157}