component generator
This commit is contained in:
+2
-2
@@ -51,14 +51,14 @@ fn emit_node_scope(node: &RsxNode) -> TokenStream {
|
||||
RsxNode::Text(_) => {
|
||||
let emit = emit_node(node);
|
||||
quote! {
|
||||
r.static_scope(|scope| {#emit});
|
||||
r.static_scope(move |scope| {#emit});
|
||||
}
|
||||
}
|
||||
|
||||
RsxNode::Component(_) => {
|
||||
let emit = emit_node(node);
|
||||
quote! {
|
||||
r.static_scope(|scope| {#emit});
|
||||
r.static_scope(move |scope| {#emit});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+102
-1
@@ -1,10 +1,111 @@
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{FnArg, ItemFn, Pat, ReturnType, Type, parse_macro_input};
|
||||
|
||||
mod emit;
|
||||
mod parse;
|
||||
|
||||
#[proc_macro]
|
||||
pub fn rsx(input: TokenStream) -> TokenStream {
|
||||
let ast = syn::parse_macro_input!(input as parse::RsxRoot);
|
||||
let ast = parse_macro_input!(input as parse::RsxRoot);
|
||||
emit::emit_rsx(ast).into()
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn component(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(item as ItemFn);
|
||||
|
||||
let name = &input.sig.ident;
|
||||
let vis = &input.vis;
|
||||
let body = &input.block;
|
||||
|
||||
let return_ty = match &input.sig.output {
|
||||
ReturnType::Type(_, ty) => ty,
|
||||
_ => {
|
||||
return syn::Error::new_spanned(&input.sig, "component must return View")
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
};
|
||||
|
||||
let mut inputs = input.sig.inputs.iter();
|
||||
|
||||
// ---- First param must be cx ----
|
||||
let cx = match inputs.next() {
|
||||
Some(FnArg::Typed(pat)) => pat,
|
||||
_ => {
|
||||
return syn::Error::new_spanned(&input.sig, "first argument must be cx: &Arc<Context>")
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
};
|
||||
|
||||
let cx_ident = match &*cx.pat {
|
||||
Pat::Ident(id) => &id.ident,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let cx_ty = &cx.ty;
|
||||
|
||||
// ---- Remaining params are props ----
|
||||
let mut struct_fields = Vec::new();
|
||||
let mut render_params = Vec::new();
|
||||
let mut call_args = Vec::new();
|
||||
|
||||
for arg in inputs {
|
||||
let FnArg::Typed(pat) = arg else { continue };
|
||||
|
||||
let ident = match &*pat.pat {
|
||||
Pat::Ident(id) => &id.ident,
|
||||
_ => {
|
||||
return syn::Error::new_spanned(pat, "unsupported prop pattern")
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
};
|
||||
|
||||
// Strip leading &
|
||||
let owned_ty = match &*pat.ty {
|
||||
Type::Reference(r) => &r.elem,
|
||||
ty => ty,
|
||||
};
|
||||
|
||||
struct_fields.push(quote! {
|
||||
pub #ident: #owned_ty
|
||||
});
|
||||
|
||||
render_params.push(quote! {
|
||||
#ident: &#owned_ty
|
||||
});
|
||||
|
||||
call_args.push(quote! {
|
||||
&self.#ident
|
||||
});
|
||||
}
|
||||
|
||||
let expanded = quote! {
|
||||
#vis struct #name {
|
||||
#(#struct_fields,)*
|
||||
}
|
||||
|
||||
impl #name {
|
||||
pub fn component(
|
||||
#cx_ident: #cx_ty,
|
||||
#(#render_params,)*
|
||||
) -> #return_ty {
|
||||
#body
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentImpl for #name {
|
||||
fn call(&self, cx: &std::sync::Arc<Context>) -> #return_ty {
|
||||
Self::component(
|
||||
cx,
|
||||
#(#call_args,)*
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
expanded.into()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user