1mod arguments;
2mod block;
3#[macro_use]
4mod macros;
5mod utils;
6
7use {
8 arguments::handle_arguments,
9 block::handle_block,
10 proc_macro::{TokenStream, TokenTree},
11 utils::to_camel,
12};
13
14#[proc_macro_attribute]
15pub fn component(attrs: TokenStream, item: TokenStream) -> TokenStream {
16 let mut iter = item.into_iter();
17 let mut ident = iter.next();
18 let vis = if let Some(TokenTree::Ident(i)) = &ident
19 && i.to_string() == "pub"
20 {
21 ident = iter.next();
22 "pub"
23 } else {
24 ""
25 };
26 match &ident {
27 Some(TokenTree::Ident(i)) if i.to_string() != "async" => {
28 return error!(raw, i.span(), "Expected keyword `async`, got `{}`", i);
29 }
30 None => return error!(raw, "Expected keyword `async`, got eof"),
31 _ => (),
32 }
33 if let Some(TokenTree::Ident(i)) = iter.next()
34 && i.to_string() != "fn"
35 {
36 return error!(raw, i.span(), "Expected keyword `fn`, got `{}`", i);
37 }
38 let component_name = if let Some(TokenTree::Ident(i)) = iter.next() {
39 i.to_string()
40 } else {
41 return error!(raw, "Expected ident (component name), got eof");
42 };
43 let Some(TokenTree::Group(g)) = iter.next() else {
44 return error!(raw, "Expected function arguments (component properties)");
45 };
46 let (
47 component_arguments,
48 mut component_var_bindings,
49 property_field_defines,
50 property_field_initializers,
51 property_field_getters_and_setters,
52 ) = handle_arguments(g.stream(), &component_name);
53 let Some(TokenTree::Group(g)) = iter.next() else {
54 return error!(raw, "Expected function block");
55 };
56 let (component_block, mut field_defines, mut field_initializers) =
57 handle_block(g.stream(), &mut component_var_bindings, &component_name);
58 let component_name_camel = to_camel(&component_name);
59 field_defines.extend_from_slice(&property_field_defines);
60 let field_defines = field_defines
61 .iter()
62 .map(|i| i.to_string())
63 .collect::<String>();
64 let component_struct = ts!(
65 "{}\n{} struct {} <'a> {{\n_rt: Weak<Runtime<'a, ()>>,\n_cancellable: RefCell<Cancellable>,\n{}\n}}",
66 attrs,
67 vis,
68 component_name_camel,
69 field_defines
70 );
71 field_initializers.extend_from_slice(&property_field_initializers);
72 let field_initializers = field_initializers
73 .iter()
74 .map(|i| i.to_string())
75 .collect::<String>();
76
77 let component_new = ts!(
78 "fn new(rt: Weak<Runtime<'a, ()>>) -> Self {{ Self {{\n{}\n_rt: rt,\n_cancellable: Default::default(),\n}} }}",
79 field_initializers
80 );
81 let component_get_rt = ts!("fn get_rt(&self) -> Weak<Runtime<'a, ()>> {{ self._rt.clone() }}");
82 let component_update = ts!(
83 "fn update(self: &Rc<Self>) {{\nlet mut cancellable = self._cancellable.borrow_mut();\ncancellable.cancel();\n*cancellable = self.spawn({}(Rc::downgrade(self)));\n}}",
84 component_name
85 );
86
87 let component_field_getters_and_setters = property_field_getters_and_setters
88 .iter()
89 .map(|i| i.to_string())
90 .collect::<String>();
91 let component_impl = ts!(
92 "{}\nimpl<'a> Component<'a> for {} <'a> {{\n{}\n{}\n{}\n}}\n{}\nimpl<'a> {} <'a> {{\n{}\n}}",
93 attrs,
94 component_name_camel,
95 component_new,
96 component_get_rt,
97 component_update,
98 attrs,
99 component_name_camel,
100 component_field_getters_and_setters
101 );
102 ts!(
103 "{}\n{}\n{}\n{} async fn {}({}) {}",
104 component_struct,
105 component_impl,
106 attrs,
107 vis,
108 component_name,
109 component_arguments,
110 component_block
111 )
112}