use super::*; use proc_macro2::TokenStream as TokenStream2; use quote::{quote, ToTokens, TokenStreamExt}; use syn::{ parse::{Parse, ParseStream}, token, Expr, LitStr, Result, Token, }; /* Parse -> div {} -> Component {} -> component() -> "text {with_args}" -> (0..10).map(|f| rsx!("asd")), // <--- notice the comma - must be a complete expr */ pub enum BodyNode { Element(Element), Component(Component), Text(LitStr), RawExpr(Expr), } impl Parse for BodyNode { fn parse(stream: ParseStream) -> Result { if stream.peek(LitStr) { return Ok(BodyNode::Text(stream.parse()?)); } // div {} -> el // Div {} -> comp if stream.peek(syn::Ident) && stream.peek2(token::Brace) { if stream .fork() .parse::()? .to_string() .chars() .next() .unwrap() .is_ascii_uppercase() { return Ok(BodyNode::Component(stream.parse()?)); } else { return Ok(BodyNode::Element(stream.parse::()?)); } } // component() -> comp // ::component {} -> comp // ::component () -> comp if (stream.peek(syn::Ident) && stream.peek2(token::Paren)) || (stream.peek(Token![::])) || (stream.peek(Token![:]) && stream.peek2(Token![:])) { return Ok(BodyNode::Component(stream.parse::()?)); } // crate::component{} -> comp // crate::component() -> comp if let Ok(pat) = stream.fork().parse::() { if pat.segments.len() > 1 { return Ok(BodyNode::Component(stream.parse::()?)); } } Ok(BodyNode::RawExpr(stream.parse::()?)) } } impl ToTokens for BodyNode { fn to_tokens(&self, tokens: &mut TokenStream2) { match &self { BodyNode::Element(el) => el.to_tokens(tokens), BodyNode::Component(comp) => comp.to_tokens(tokens), BodyNode::Text(txt) => tokens.append_all(quote! { __cx.text(format_args_f!(#txt)) }), BodyNode::RawExpr(exp) => tokens.append_all(quote! { __cx.fragment_from_iter(#exp) }), } } }