|
@@ -6,7 +6,8 @@ use syn::{
|
|
|
braced,
|
|
|
parse::{Parse, ParseStream},
|
|
|
spanned::Spanned,
|
|
|
- token, Expr, ExprIf, LitStr, Pat, Result,
|
|
|
+ token::{self, Brace},
|
|
|
+ Expr, ExprIf, LitStr, Pat, Result,
|
|
|
};
|
|
|
|
|
|
/*
|
|
@@ -15,14 +16,14 @@ Parse
|
|
|
-> Component {}
|
|
|
-> component()
|
|
|
-> "text {with_args}"
|
|
|
--> (0..10).map(|f| rsx!("asd")), // <--- notice the comma - must be a complete expr
|
|
|
+-> {(0..10).map(|f| rsx!("asd"))} // <--- notice the curly braces
|
|
|
*/
|
|
|
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
|
|
pub enum BodyNode {
|
|
|
Element(Element),
|
|
|
Component(Component),
|
|
|
ForLoop(ForLoop),
|
|
|
- IfChain(ExprIf),
|
|
|
+ IfChain(IfChain),
|
|
|
Text(IfmtInput),
|
|
|
RawExpr(Expr),
|
|
|
}
|
|
@@ -112,7 +113,27 @@ impl Parse for BodyNode {
|
|
|
return Ok(BodyNode::IfChain(stream.parse()?));
|
|
|
}
|
|
|
|
|
|
- Ok(BodyNode::RawExpr(stream.parse::<Expr>()?))
|
|
|
+ // Match statements are special but have no special arm syntax
|
|
|
+ // we could allow arm syntax if we wanted
|
|
|
+ //
|
|
|
+ // ```
|
|
|
+ // match {
|
|
|
+ // val => div {}
|
|
|
+ // other_val => div {}
|
|
|
+ // }
|
|
|
+ // ```
|
|
|
+ if stream.peek(Token![match]) {
|
|
|
+ return Ok(BodyNode::RawExpr(stream.parse::<Expr>()?));
|
|
|
+ }
|
|
|
+
|
|
|
+ if stream.peek(token::Brace) {
|
|
|
+ return Ok(BodyNode::RawExpr(stream.parse::<Expr>()?));
|
|
|
+ }
|
|
|
+
|
|
|
+ Err(syn::Error::new(
|
|
|
+ stream.span(),
|
|
|
+ "Expected a valid body node.\nExpressions must be wrapped in curly braces.",
|
|
|
+ ))
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -151,71 +172,52 @@ impl ToTokens for BodyNode {
|
|
|
})
|
|
|
}
|
|
|
BodyNode::IfChain(chain) => {
|
|
|
- if is_if_chain_terminated(chain) {
|
|
|
- tokens.append_all(quote! {
|
|
|
- {
|
|
|
- let ___nodes = (#chain).into_dyn_node(__cx);
|
|
|
- ___nodes
|
|
|
- }
|
|
|
- });
|
|
|
- } else {
|
|
|
- let ExprIf {
|
|
|
+ let mut body = TokenStream2::new();
|
|
|
+ let mut terminated = false;
|
|
|
+
|
|
|
+ let mut elif = Some(chain);
|
|
|
+
|
|
|
+ while let Some(chain) = elif {
|
|
|
+ let IfChain {
|
|
|
+ if_token,
|
|
|
cond,
|
|
|
then_branch,
|
|
|
+ else_if_branch,
|
|
|
else_branch,
|
|
|
- ..
|
|
|
} = chain;
|
|
|
|
|
|
- let mut body = TokenStream2::new();
|
|
|
-
|
|
|
- body.append_all(quote! {
|
|
|
- if #cond {
|
|
|
- Some(#then_branch)
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- let mut elif = else_branch;
|
|
|
-
|
|
|
- while let Some((_, ref branch)) = elif {
|
|
|
- match branch.as_ref() {
|
|
|
- Expr::If(ref eelif) => {
|
|
|
- let ExprIf {
|
|
|
- cond,
|
|
|
- then_branch,
|
|
|
- else_branch,
|
|
|
- ..
|
|
|
- } = eelif;
|
|
|
-
|
|
|
- body.append_all(quote! {
|
|
|
- else if #cond {
|
|
|
- Some(#then_branch)
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- elif = else_branch;
|
|
|
- }
|
|
|
- _ => {
|
|
|
- body.append_all(quote! {
|
|
|
- else {
|
|
|
- #branch
|
|
|
- }
|
|
|
- });
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
+ let mut renderer: TemplateRenderer = TemplateRenderer {
|
|
|
+ roots: then_branch,
|
|
|
+ location: None,
|
|
|
+ };
|
|
|
+
|
|
|
+ body.append_all(quote! { #if_token #cond { Some({#renderer}) } });
|
|
|
+
|
|
|
+ if let Some(next) = else_if_branch {
|
|
|
+ body.append_all(quote! { else });
|
|
|
+ elif = Some(next);
|
|
|
+ } else if let Some(else_branch) = else_branch {
|
|
|
+ renderer.roots = else_branch;
|
|
|
+ body.append_all(quote! { else { Some({#renderer}) } });
|
|
|
+ terminated = true;
|
|
|
+ break;
|
|
|
+ } else {
|
|
|
+ elif = None;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
+ if !terminated {
|
|
|
body.append_all(quote! {
|
|
|
else { None }
|
|
|
});
|
|
|
-
|
|
|
- tokens.append_all(quote! {
|
|
|
- {
|
|
|
- let ___nodes = (#body).into_dyn_node(__cx);
|
|
|
- ___nodes
|
|
|
- }
|
|
|
- });
|
|
|
}
|
|
|
+
|
|
|
+ tokens.append_all(quote! {
|
|
|
+ {
|
|
|
+ let ___nodes = (#body).into_dyn_node(__cx);
|
|
|
+ ___nodes
|
|
|
+ }
|
|
|
+ });
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -240,26 +242,73 @@ impl Parse for ForLoop {
|
|
|
let in_token: Token![in] = input.parse()?;
|
|
|
let expr: Expr = input.call(Expr::parse_without_eager_brace)?;
|
|
|
|
|
|
- let content;
|
|
|
- let brace_token = braced!(content in input);
|
|
|
-
|
|
|
- let mut children = vec![];
|
|
|
-
|
|
|
- while !content.is_empty() {
|
|
|
- children.push(content.parse()?);
|
|
|
- }
|
|
|
+ let (brace_token, body) = parse_buffer_as_braced_children(input)?;
|
|
|
|
|
|
Ok(Self {
|
|
|
for_token,
|
|
|
pat,
|
|
|
in_token,
|
|
|
- body: children,
|
|
|
- expr: Box::new(expr),
|
|
|
+ body,
|
|
|
brace_token,
|
|
|
+ expr: Box::new(expr),
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
|
|
+pub struct IfChain {
|
|
|
+ pub if_token: Token![if],
|
|
|
+ pub cond: Box<Expr>,
|
|
|
+ pub then_branch: Vec<BodyNode>,
|
|
|
+ pub else_if_branch: Option<Box<IfChain>>,
|
|
|
+ pub else_branch: Option<Vec<BodyNode>>,
|
|
|
+}
|
|
|
+
|
|
|
+impl Parse for IfChain {
|
|
|
+ fn parse(input: ParseStream) -> Result<Self> {
|
|
|
+ let if_token: Token![if] = input.parse()?;
|
|
|
+
|
|
|
+ // stolen from ExprIf
|
|
|
+ let cond = Box::new(input.call(Expr::parse_without_eager_brace)?);
|
|
|
+
|
|
|
+ let (_, then_branch) = parse_buffer_as_braced_children(input)?;
|
|
|
+
|
|
|
+ let mut else_branch = None;
|
|
|
+ let mut else_if_branch = None;
|
|
|
+
|
|
|
+ // if the next token is `else`, set the else branch as the next if chain
|
|
|
+ if input.peek(Token![else]) {
|
|
|
+ input.parse::<Token![else]>()?;
|
|
|
+ if input.peek(Token![if]) {
|
|
|
+ else_if_branch = Some(Box::new(input.parse::<IfChain>()?));
|
|
|
+ } else {
|
|
|
+ let (_, else_branch_nodes) = parse_buffer_as_braced_children(input)?;
|
|
|
+ else_branch = Some(else_branch_nodes);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Ok(Self {
|
|
|
+ cond,
|
|
|
+ if_token,
|
|
|
+ then_branch,
|
|
|
+ else_if_branch,
|
|
|
+ else_branch,
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+fn parse_buffer_as_braced_children(
|
|
|
+ input: &syn::parse::ParseBuffer<'_>,
|
|
|
+) -> Result<(Brace, Vec<BodyNode>)> {
|
|
|
+ let content;
|
|
|
+ let brace_token = braced!(content in input);
|
|
|
+ let mut then_branch = vec![];
|
|
|
+ while !content.is_empty() {
|
|
|
+ then_branch.push(content.parse()?);
|
|
|
+ }
|
|
|
+ Ok((brace_token, then_branch))
|
|
|
+}
|
|
|
+
|
|
|
pub(crate) fn is_if_chain_terminated(chain: &ExprIf) -> bool {
|
|
|
let mut current = chain;
|
|
|
loop {
|