1mod codegen;
2pub(crate) mod grammar;
3mod macro_inputs;
4use crate::codegen::string_rendering::class_name_to_struct_identifier;
5use crate::codegen::{render_classes, render_generate_dwind_class};
6use crate::grammar::{parse_class_string, parse_selector};
7use crate::macro_inputs::DwindInputSignal;
8use dwind_base::media_queries::Breakpoint;
9use macro_inputs::{DwGenerateInput, DwGenerateMapInput, DwindInput};
10use proc_macro::TokenStream;
11use quote::quote;
12use std::future::Future;
13use std::pin::Pin;
14use std::rc::Rc;
15use std::task::{Context, Poll};
16
17#[proc_macro]
32pub fn dwclass(input: TokenStream) -> TokenStream {
33 let DwindInput {
34 self_ident,
35 classes,
36 } = syn::parse::<DwindInput>(input).unwrap();
37
38 let classes = parse_class_string(classes.value().as_str()).unwrap();
39 let classes = render_classes(classes);
40
41 let (generator_classes, normal_classes): (Vec<_>, Vec<_>) = classes
42 .into_iter()
43 .map(|class| match class {
44 (tokens, breakpoint, false) => (None, Some((tokens, breakpoint))),
45 (tokens, breakpoint, true) => (Some((tokens, breakpoint)), None),
46 })
47 .unzip();
48
49 let v = Rc::new(Some(""));
50
51 v.as_ref().as_ref().map(|v| {});
52
53 let classes = normal_classes.into_iter().filter_map(|v| v).map(|(class, breakpoint)| {
54 if let Some(breakpoint) = breakpoint {
55 let bp = breakpoint.breakpoint;
56
57 if breakpoint.is_media_query {
58 let Breakpoint::MediaQuery(mq) = bp else { unreachable!() };
59
60 quote! {
61 .class_signal(#class, dominator::media_query(#mq))
62 }
63 } else {
64 let bp_value = match bp {
65 Breakpoint::VerySmall => quote! { dwind::prelude::media_queries::Breakpoint::VerySmall },
66 Breakpoint::Small => quote! { dwind::prelude::media_queries::Breakpoint::Small },
67 Breakpoint::Medium => quote! { dwind::prelude::media_queries::Breakpoint::Medium },
68 Breakpoint::Large => quote! { dwind::prelude::media_queries::Breakpoint::Large },
69 Breakpoint::VeryLarge => quote! { dwind::prelude::media_queries::Breakpoint::VeryLarge },
70 _ => { panic!("media query breakpoint not supported here")}
71 };
72
73 if let Some(_modifier) = breakpoint.modifier {
74 quote! {
75 .class_signal(#class, dwind::prelude::media_queries::breakpoint_less_than_signal(#bp_value))
76 }
77 } else {
78 quote! {
79 .class_signal(#class, dwind::prelude::media_queries::breakpoint_active_signal(#bp_value))
80 }
81 }
82 }
83 } else {
84 quote! {
85 .class(#class)
86 }
87 }
88 });
89
90 let gen_classes = generator_classes.into_iter().filter_map(|v| v).map(|(class_tokens, breakpoint)| {
91 if let Some(breakpoint) = breakpoint {
92 let bp = breakpoint.breakpoint;
93
94 let apply = if breakpoint.is_media_query {
95 let Breakpoint::MediaQuery(mq) = bp else { unreachable!() };
96
97 quote! {
98 .class_signal(&*foobar, dominator::media_query(#mq))
99 }
100 } else {
101 let bp_value = match bp {
102 Breakpoint::VerySmall => quote! { dwind::prelude::media_queries::Breakpoint::VerySmall },
103 Breakpoint::Small => quote! { dwind::prelude::media_queries::Breakpoint::Small },
104 Breakpoint::Medium => quote! { dwind::prelude::media_queries::Breakpoint::Medium },
105 Breakpoint::Large => quote! { dwind::prelude::media_queries::Breakpoint::Large },
106 Breakpoint::VeryLarge => quote! { dwind::prelude::media_queries::Breakpoint::VeryLarge },
107 _ => { panic!("media query breakpoint not supported here")}
108 };
109
110 if let Some(_modifier) = breakpoint.modifier {
111 quote! {
112 .class_signal(&*foobar, dwind::prelude::media_queries::breakpoint_less_than_signal(#bp_value))
113 }
114 } else {
115 quote! {
116 .class_signal(&*foobar, dwind::prelude::media_queries::breakpoint_active_signal(#bp_value))
117 }
118 }
119 };
120
121 quote! {
122 let #self_ident = {
123 #[doc(hidden)]
124 pub static foobar: once_cell::sync::Lazy<String> = once_cell::sync::Lazy::new(|| {
125 #class_tokens
126 });
127
128 #self_ident . #apply
129 };
130 }
131 } else {
132 quote! {
133 let #self_ident = {
134 #[doc(hidden)]
135 pub static foobar: once_cell::sync::Lazy<String> = once_cell::sync::Lazy::new(|| {
136 #class_tokens
137 });
138
139 #self_ident . class(&*foobar)
140 };
141 }
142 }
143 });
144
145 quote! {
146 {
147 #(#gen_classes)*
148 #self_ident #(#classes)*
149 }
150 }
151 .into()
152}
153
154#[proc_macro]
169pub fn dwclass_signal(input: TokenStream) -> TokenStream {
170 let DwindInputSignal {
171 input: DwindInput {
172 self_ident,
173 classes,
174 },
175 signal,
176 } = syn::parse::<DwindInputSignal>(input).unwrap();
177
178 let classes = parse_class_string(classes.value().as_str()).unwrap();
179 let classes = render_classes(classes);
180
181 let (generator_classes, normal_classes): (Vec<_>, Vec<_>) = classes
182 .into_iter()
183 .map(|class| match class {
184 (tokens, breakpoint, false) => (None, Some((tokens, breakpoint))),
185 (tokens, breakpoint, true) => (Some((tokens, breakpoint)), None),
186 })
187 .unzip();
188
189 let classes = normal_classes
190 .into_iter()
191 .filter_map(|v| v)
192 .map(|(class, _breakpoint)| {
193 quote! {
194 .class_signal(#class, #signal)
195 }
196 });
197
198 let gen_classes = generator_classes.into_iter().filter_map(|v| v).map(|(class_tokens, _breakpoint)| {
199 quote! {
200 let #self_ident = {
201 #[doc(hidden)]
202 pub static foobar: once_cell::sync::Lazy<String> = once_cell::sync::Lazy::new(|| {
203 #class_tokens
204 });
205
206 #self_ident . class_signal(&*foobar, #signal)
207 };
208 }
209 });
210
211 quote! {
212 {
213 #(#gen_classes)*
214 #self_ident #(#classes)*
215 }
216 }
217 .into()
218}
219
220#[proc_macro]
252pub fn dwgenerate(input: TokenStream) -> TokenStream {
253 let DwGenerateInput {
254 class_definition,
255 class_name,
256 } = syn::parse(input).unwrap();
257
258 let class_definition = parse_selector(class_definition.value().as_str())
259 .map(|v| v.1)
260 .unwrap();
261
262 let class_name = class_name_to_struct_identifier(&class_name.value());
263
264 let rendered = render_generate_dwind_class(class_name, class_definition);
265
266 rendered.into()
267}
268
269#[proc_macro]
296pub fn dwgenerate_map(input: TokenStream) -> TokenStream {
297 let input: DwGenerateMapInput = syn::parse(input).unwrap();
298
299 let DwGenerateMapInput {
300 base_output_ident,
301 dwind_class_lit,
302 args,
303 } = input;
304
305 let output = args.tuples.into_iter().map(|input_tuple| {
306 let ident_name = class_name_to_struct_identifier(&format!(
308 "{}-{}",
309 base_output_ident.value(),
310 input_tuple.first.value()
311 ));
312
313 let class_literal = format!(
315 "{}[{}]",
316 dwind_class_lit.value(),
317 input_tuple.second.value()
318 );
319
320 let class = parse_selector(class_literal.as_str()).unwrap().1;
322
323 render_generate_dwind_class(ident_name, class)
324 });
325
326 quote! {
327 #(#output)*
328 }
329 .into()
330}