From ab9548920c4deabfad6d600ba3c1bde1e3589776 Mon Sep 17 00:00:00 2001 From: Leo dev Date: Sat, 31 Jan 2026 00:09:14 +0100 Subject: [PATCH] Improved rsx parsing --- macros/src/emit.rs | 11 ++----- macros/src/parse.rs | 71 ++++++++++++++++++++++----------------------- 2 files changed, 37 insertions(+), 45 deletions(-) diff --git a/macros/src/emit.rs b/macros/src/emit.rs index 6595c93..60884ca 100644 --- a/macros/src/emit.rs +++ b/macros/src/emit.rs @@ -33,15 +33,8 @@ fn emit_deps_vec(deps: &[Dep]) -> TokenStream { let deps = deps.iter().map(|d| { let ident = &d.ident; - if let Some(pat) = &d.pat { - quote! {{ - let #pat = #ident.clone(); - Box::new(#pat) as Box - }} - } else { - quote! { - Box::new(#ident.clone()) as Box - } + quote! { + std::sync::Arc::new(#ident) as std::sync::Arc } }); diff --git a/macros/src/parse.rs b/macros/src/parse.rs index 29a8d9a..7252ec3 100644 --- a/macros/src/parse.rs +++ b/macros/src/parse.rs @@ -1,4 +1,5 @@ use syn::braced; +use syn::parse::discouraged::Speculative; use syn::{ Expr, Ident, LitStr, Pat, Path, Result, Token, parse::{Parse, ParseStream}, @@ -82,7 +83,7 @@ fn parse_deps(input: ParseStream) -> Result> { impl Parse for RsxNode { fn parse(input: ParseStream) -> Result { - // --- @{ expr } --- + // @{ $expr } if input.peek(Token![@]) { input.parse::()?; @@ -93,7 +94,7 @@ impl Parse for RsxNode { return Ok(RsxNode::Expr(expr)); } - // --- existing code --- + // !$ident if input.peek(Token![!]) { input.parse::()?; let mount: Ident = input.parse()?; @@ -102,6 +103,7 @@ impl Parse for RsxNode { let deps = parse_deps(input)?; + // %$dep if $expr { $rsx } if input.peek(Token![if]) { input.parse::()?; let cond: Expr = input.parse()?; @@ -115,6 +117,7 @@ impl Parse for RsxNode { }); } + // %$dep for $pat in $expr { $rsx } if input.peek(Token![for]) { input.parse::()?; let pat: Pat = Pat::parse_multi(input)?; @@ -131,6 +134,7 @@ impl Parse for RsxNode { }); } + // "%$dep for $pat in $expr { $rsx }" if input.peek(LitStr) { return Ok(RsxNode::Text(input.parse()?)); } @@ -163,49 +167,44 @@ fn parse_component_invocation(input: ParseStream) -> Result { }) } -/// Parses comma-separated "ident: expr" (props) and RsxNode (children) inside braces. fn parse_props_and_children(input: ParseStream) -> Result<(Vec, Vec)> { + Ok((parse_props(input)?, RsxRoot::parse(input)?.nodes)) +} + +fn parse_props(input: ParseStream) -> Result> { let mut props = Vec::new(); - let mut children = Vec::new(); while !input.is_empty() { - if input.peek(LitStr) { - children.push(input.parse()?); - } else { - let path: Path = input.parse()?; + let fork = input.fork(); - if input.peek(Token![:]) { - let name = path - .get_ident() - .cloned() - .ok_or_else(|| input.error("prop name must be a single identifier"))?; - input.parse::()?; - let value: Expr = input.parse()?; - props.push(RsxProp { name, value }); - } else if input.peek(Brace) { - let nested_content; - braced!(nested_content in input); - let (nested_props, nested_children) = parse_props_and_children(&nested_content)?; - children.push(RsxNode::Component { - path, - props: nested_props, - children: nested_children, - }); - } else { - children.push(RsxNode::Component { - path, - props: Vec::new(), - children: Vec::new(), - }); + let path: Path = match fork.parse() { + Ok(p) => p, + Err(_) => break, + }; + + if fork.peek(Token![:]) { + let name = path + .get_ident() + .cloned() + .ok_or_else(|| fork.error("prop name must be a single identifier"))?; + + fork.parse::()?; + let value: Expr = fork.parse()?; + + input.advance_to(&fork); + + props.push(RsxProp { name, value }); + + if input.peek(Token![,]) { + input.parse::()?; } - } - - if !input.is_empty() { - input.parse::()?; + } else { + // ❌ do not commit → nothing consumed + break; } } - Ok((props, children)) + Ok(props) } fn parse_children(input: ParseStream) -> Result> {