1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use syn::parse_macro_input;
5
6use xrune_nexus::ds_node::DsRoot;
7use xrune_nexus::ds_rune::DsRune;
8use xrune_nexus::ds_rune::decipher::decipher;
9
10struct DefaultRune {
12 tokens: proc_macro2::TokenStream,
13 parent_name: String,
14}
15
16impl DefaultRune {
17 fn new() -> Self {
18 Self {
19 tokens: proc_macro2::TokenStream::new(),
20 parent_name: String::new(),
21 }
22 }
23}
24
25impl DsRune for DefaultRune {
26 fn inscribe_root(&mut self, parent_expr: &syn::Expr) {
27 use quote::quote;
28 self.tokens.extend(quote! {
29 println!("let parent = {:?}", #parent_expr);
30 });
31 self.parent_name = "parent".to_string();
32 }
33
34 fn inscribe_widget(
35 &mut self,
36 name: &syn::Ident,
37 attrs: &[xrune_nexus::ds_node::ds_attr::DsAttr],
38 _enchants: &[syn::Expr],
39 on_handlers: &[xrune_nexus::ds_node::ds_on::DsOn],
40 children: &[xrune_nexus::ds_node::DsTreeRef],
41 ) {
42 use quote::quote;
43 let name_string = name.to_string();
44 let parent_name = &self.parent_name;
45
46 self.tokens.extend(quote! {
47 println!("let {} = obj::new({})", #name_string, #parent_name);
48 });
49
50 for attr in attrs {
51 let attr_name = match &attr.name {
52 Some(n) => n.to_string(),
53 None => "<positional>".to_string(),
54 };
55 let attr_value = &attr.value;
56 self.tokens.extend(quote! {
57 println!("{}.set_{}({:?})", #name_string, #attr_name, #attr_value);
58 });
59 }
60
61 for on in on_handlers {
62 let event_name = on.get_name().to_string();
63 let arg_count = on.get_args().len();
64 self.tokens.extend(quote! {
65 println!("{}.on_{}({} args)", #name_string, #event_name, #arg_count);
66 });
67 }
68
69 let prev_parent = self.parent_name.clone();
70 self.parent_name = name_string;
71 for child in children {
72 decipher(child, self);
73 }
74 self.parent_name = prev_parent;
75 }
76
77 fn inscribe_if(
78 &mut self,
79 condition: &syn::Expr,
80 _reactive: bool,
81 children: &[xrune_nexus::ds_node::DsTreeRef],
82 else_branch: Option<&xrune_nexus::ds_node::DsTreeRef>,
83 ) {
84 use quote::quote;
85 let con = quote!(#condition).to_string();
86 self.tokens.extend(quote! {
87 println!("if {} {{", #con);
88 });
89 for child in children {
90 decipher(child, self);
91 }
92 self.tokens.extend(quote! {
93 println!("}}");
94 });
95 if let Some(branch) = else_branch {
96 decipher(branch, self);
97 }
98 }
99
100 fn inscribe_iter(
101 &mut self,
102 iterable: &syn::Expr,
103 variable: &syn::Ident,
104 _reactive: bool,
105 _key: Option<&syn::Expr>,
106 children: &[xrune_nexus::ds_node::DsTreeRef],
107 ) {
108 use quote::quote;
109 let iterable_str = quote!(#iterable).to_string();
110 let variable_str = variable.to_string();
111 self.tokens.extend(quote! {
112 println!("for {} in {} {{", #variable_str, #iterable_str);
113 });
114 for child in children {
115 decipher(child, self);
116 }
117 self.tokens.extend(quote! {
118 println!("}}");
119 });
120 }
121
122 fn inscribe_niche(&mut self, name: &syn::Ident, children: &[xrune_nexus::ds_node::DsTreeRef]) {
123 use quote::quote;
124 let name_str = name.to_string();
125 self.tokens.extend(quote! {
126 println!("@{} {{", #name_str);
127 });
128 for child in children {
129 decipher(child, self);
130 }
131 self.tokens.extend(quote! {
132 println!("}}");
133 });
134 }
135
136 fn inscribe_match(
137 &mut self,
138 scrutinee: &syn::Expr,
139 _reactive: bool,
140 arms: &[xrune_nexus::ds_node::ds_match::DsMatchArm],
141 ) {
142 use quote::quote;
143 let scrutinee_str = quote!(#scrutinee).to_string();
144 self.tokens.extend(quote! {
145 println!("match {} {{", #scrutinee_str);
146 });
147 for arm in arms {
148 let pat = arm.get_pat();
149 let pat_str = quote!(#pat).to_string();
150 self.tokens.extend(quote! {
151 println!(" {} => {{", #pat_str);
152 });
153 for child in arm.get_children() {
154 decipher(child, self);
155 }
156 self.tokens.extend(quote! {
157 println!(" }}");
158 });
159 }
160 self.tokens.extend(quote! {
161 println!("}}");
162 });
163 }
164
165 fn seal(self) -> proc_macro2::TokenStream {
166 self.tokens
167 }
168}
169
170#[proc_macro]
171pub fn ui(input: TokenStream) -> TokenStream {
172 let root = parse_macro_input!(input as DsRoot);
173
174 let mut rune = DefaultRune::new();
175
176 rune.inscribe_root(&root.get_parent());
178
179 let content = root.get_content();
181 decipher(&content, &mut rune);
182
183 TokenStream::from(rune.seal())
184}