Merge branch 'master' into jk/autofmt-fixues
This commit is contained in:
commit
09b38574db
336 files changed
+19973
-16881
No files matched your search
+147
-15
@@ -5,9 +5,10 @@ use super::*;
|
||||
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||
use quote::{quote, ToTokens, TokenStreamExt};
|
||||
use syn::{
|
||||
braced,
|
||||
parse::{Parse, ParseStream},
|
||||
spanned::Spanned,
|
||||
token, LitStr, Result,
|
||||
token, Expr, ExprIf, LitStr, Pat, Result,
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -18,12 +19,14 @@ Parse
|
||||
-> "text {with_args}"
|
||||
-> (0..10).map(|f| rsx!("asd")), // <--- notice the comma - must be a complete expr
|
||||
*/
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
||||
pub enum BodyNode {
|
||||
Element(Element),
|
||||
Component(Component),
|
||||
Text(TextNode),
|
||||
RawExpr(RawExprNode),
|
||||
ForLoop(ForLoop),
|
||||
IfChain(ExprIf),
|
||||
Text(IfmtInput),
|
||||
RawExpr(Expr),
|
||||
}
|
||||
|
||||
impl BodyNode {
|
||||
@@ -35,8 +38,10 @@ impl BodyNode {
|
||||
match self {
|
||||
BodyNode::Element(el) => el.name.span(),
|
||||
BodyNode::Component(component) => component.name.span(),
|
||||
BodyNode::Text(text) => text.span(),
|
||||
BodyNode::Text(text) => text.source.span(),
|
||||
BodyNode::RawExpr(exp) => exp.span(),
|
||||
BodyNode::ForLoop(fl) => fl.for_token.span(),
|
||||
BodyNode::IfChain(f) => f.if_token.span(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,17 +58,18 @@ impl Parse for BodyNode {
|
||||
// - one ident
|
||||
// - followed by `{`
|
||||
// - 1st char is lowercase
|
||||
// - no underscores (reserved for components)
|
||||
//
|
||||
// example:
|
||||
// div {}
|
||||
if let Some(ident) = path.get_ident() {
|
||||
let el_name = ident.to_string();
|
||||
|
||||
let first_char = el_name.chars().next().unwrap();
|
||||
|
||||
if body_stream.peek(token::Brace)
|
||||
&& ident
|
||||
.to_string()
|
||||
.chars()
|
||||
.next()
|
||||
.unwrap()
|
||||
.is_ascii_lowercase()
|
||||
&& first_char.is_ascii_lowercase()
|
||||
&& !el_name.contains('_')
|
||||
{
|
||||
return Ok(BodyNode::Element(stream.parse::<Element>()?));
|
||||
}
|
||||
@@ -89,7 +95,35 @@ impl Parse for BodyNode {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(BodyNode::RawExpr(stream.parse()?))
|
||||
// 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;
|
||||
braced!(body in stream);
|
||||
let mut children = vec![];
|
||||
while !body.is_empty() {
|
||||
children.push(body.parse()?);
|
||||
}
|
||||
|
||||
return Ok(BodyNode::ForLoop(ForLoop {
|
||||
for_token: _f,
|
||||
pat,
|
||||
in_token: _i,
|
||||
expr,
|
||||
body: children,
|
||||
}));
|
||||
}
|
||||
|
||||
// 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>()?))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,12 +132,110 @@ impl ToTokens for BodyNode {
|
||||
match &self {
|
||||
BodyNode::Element(el) => el.to_tokens(tokens),
|
||||
BodyNode::Component(comp) => comp.to_tokens(tokens),
|
||||
BodyNode::Text(text) => tokens.append_all(quote! {
|
||||
__cx.text(format_args_f!(#text))
|
||||
BodyNode::Text(txt) => tokens.append_all(quote! {
|
||||
__cx.text_node(#txt)
|
||||
}),
|
||||
BodyNode::RawExpr(exp) => tokens.append_all(quote! {
|
||||
__cx.fragment_from_iter(#exp)
|
||||
__cx.make_node(#exp)
|
||||
}),
|
||||
BodyNode::ForLoop(exp) => {
|
||||
let ForLoop {
|
||||
pat, expr, body, ..
|
||||
} = exp;
|
||||
|
||||
let renderer = TemplateRenderer { roots: body };
|
||||
|
||||
tokens.append_all(quote! {
|
||||
__cx.make_node(
|
||||
(#expr).into_iter().map(|#pat| { #renderer })
|
||||
)
|
||||
})
|
||||
}
|
||||
BodyNode::IfChain(chain) => {
|
||||
if is_if_chain_terminated(chain) {
|
||||
tokens.append_all(quote! {
|
||||
__cx.make_node(#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.make_node(#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: Vec<BodyNode>,
|
||||
}
|
||||
|
||||
fn is_if_chain_terminated(chain: &ExprIf) -> bool {
|
||||
let mut current = chain;
|
||||
loop {
|
||||
if let Some((_, else_block)) = ¤t.else_branch {
|
||||
if let Expr::If(else_if) = else_block.as_ref() {
|
||||
current = else_if;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user