feat: conditionals and iterators in rsx

This commit is contained in:
Jonathan Kelley committed 2022-11-16 22:10:13 -08:00
1 parent cd93e469e2
commit 6b473cbdc5
3 files changed
+132 -4

No files matched your search

+2 -2
View File
@@ -172,7 +172,7 @@ export class Interpreter {
node.style = {}; node.style = {};
} }
node.style[name] = value; node.style[name] = value;
} else if (ns != null || ns != undefined) { } else if (ns != null && ns != undefined) {
node.setAttributeNS(ns, name, value); node.setAttributeNS(ns, name, value);
} else { } else {
switch (name) { switch (name) {
@@ -266,7 +266,7 @@ export class Interpreter {
this.AssignId(edit.path, edit.id); this.AssignId(edit.path, edit.id);
break; break;
case "CreateElement": case "CreateElement":
if (edit.namespace !== null || edit.namespace !== undefined) { if (edit.namespace !== null && edit.namespace !== undefined) {
this.CreateElementNs(edit.name, edit.id, edit.namespace); this.CreateElementNs(edit.name, edit.id, edit.namespace);
} else { } else {
this.CreateElement(edit.name, edit.id); this.CreateElement(edit.name, edit.id);
+5 -1
View File
@@ -245,7 +245,11 @@ impl<'a> DynamicContext<'a> {
quote! { ::dioxus::core::TemplateNode::Text(#text) } quote! { ::dioxus::core::TemplateNode::Text(#text) }
} }
BodyNode::Text(_) | BodyNode::RawExpr(_) | BodyNode::Component(_) => { BodyNode::RawExpr(_)
| BodyNode::Text(_)
| BodyNode::ForLoop(_)
| BodyNode::IfChain(_)
| BodyNode::Component(_) => {
let ct = self.dynamic_nodes.len(); let ct = self.dynamic_nodes.len();
self.dynamic_nodes.push(root); self.dynamic_nodes.push(root);
self.node_paths.push(self.current_path.clone()); self.node_paths.push(self.current_path.clone());
+125 -1
View File
@@ -5,7 +5,7 @@ use quote::{quote, ToTokens, TokenStreamExt};
use syn::{ use syn::{
parse::{Parse, ParseStream}, parse::{Parse, ParseStream},
spanned::Spanned, spanned::Spanned,
token, Expr, LitStr, Result, token, Block, Expr, ExprIf, LitStr, Pat, Result,
}; };
/* /*
@@ -20,6 +20,8 @@ Parse
pub enum BodyNode { pub enum BodyNode {
Element(Element), Element(Element),
Component(Component), Component(Component),
ForLoop(ForLoop),
IfChain(ExprIf),
Text(IfmtInput), Text(IfmtInput),
RawExpr(Expr), RawExpr(Expr),
} }
@@ -35,6 +37,8 @@ impl BodyNode {
BodyNode::Component(component) => component.name.span(), BodyNode::Component(component) => component.name.span(),
BodyNode::Text(text) => text.source.span(), BodyNode::Text(text) => text.source.span(),
BodyNode::RawExpr(exp) => exp.span(), BodyNode::RawExpr(exp) => exp.span(),
BodyNode::ForLoop(fl) => fl.for_token.span(),
BodyNode::IfChain(f) => f.if_token.span(),
} }
} }
} }
@@ -89,6 +93,28 @@ impl Parse for BodyNode {
} }
} }
// Transform for loops into into_iter calls
if stream.peek(Token![for]) {
let _f = stream.parse::<Token![for]>()?;
let pat = stream.parse::<Pat>()?;
let _i = stream.parse::<Token![in]>()?;
let expr = stream.parse::<Box<Expr>>()?;
let body = stream.parse::<Block>()?;
return Ok(BodyNode::ForLoop(ForLoop {
for_token: _f,
pat,
in_token: _i,
expr,
body,
}));
}
// Transform unterminated if statements into terminated optional if statements
if stream.peek(Token![if]) {
return Ok(BodyNode::IfChain(stream.parse()?));
}
Ok(BodyNode::RawExpr(stream.parse::<Expr>()?)) Ok(BodyNode::RawExpr(stream.parse::<Expr>()?))
} }
} }
@@ -104,6 +130,104 @@ impl ToTokens for BodyNode {
BodyNode::RawExpr(exp) => tokens.append_all(quote! { BodyNode::RawExpr(exp) => tokens.append_all(quote! {
__cx.fragment_from_iter(#exp) __cx.fragment_from_iter(#exp)
}), }),
BodyNode::ForLoop(exp) => {
let ForLoop {
pat, expr, body, ..
} = exp;
tokens.append_all(quote! {
__cx.fragment_from_iter(
(#expr).into_iter().map(|#pat| {
#body
})
)
})
}
BodyNode::IfChain(chain) => {
if is_if_chain_terminated(chain) {
tokens.append_all(quote! {
__cx.fragment_from_iter(#chain)
});
} else {
let ExprIf {
cond,
then_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;
}
}
}
body.append_all(quote! {
else { None }
});
tokens.append_all(quote! {
__cx.fragment_from_iter(#body)
});
}
}
}
}
}
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
pub struct ForLoop {
pub for_token: Token![for],
pub pat: Pat,
pub in_token: Token![in],
pub expr: Box<Expr>,
pub body: Block,
}
fn is_if_chain_terminated(chain: &ExprIf) -> bool {
let mut current = chain;
loop {
if let Some((_, else_block)) = &current.else_branch {
if let Expr::If(else_if) = else_block.as_ref() {
current = else_if;
} else {
return true;
}
} else {
return false;
} }
} }
} }