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{}\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}} }}",
79 field_initializers
80 );
81 let component_get_rt = ts!("fn get_rt(&self) -> Weak<Runtime<'a, ()>> {{ self._rt.clone() }}");
82
83 let component_field_getters_and_setters = property_field_getters_and_setters
84 .iter()
85 .map(|i| i.to_string())
86 .collect::<String>();
87 let component_impl = ts!(
88 "{}\nimpl<'a> Component<'a> for {} <'a> {{\n{}\n{}\n}}\n{}\nimpl<'a> {} <'a> {{\n{}\n}}",
89 attrs,
90 component_name_camel,
91 component_new,
92 component_get_rt,
93 attrs,
94 component_name_camel,
95 component_field_getters_and_setters
96 );
97 ts!(
98 "{}\n{}\n{}\n{} async fn {}({}) {}",
99 component_struct,
100 component_impl,
101 attrs,
102 vis,
103 component_name,
104 component_arguments,
105 component_block
106 )
107}