awesome: arbitrary expressions excepted without braces

This commit is contained in:
Jonathan Kelley committed 2021-12-30 03:14:47 -05:00
1 parent 14961023f9
commit 4c85bcfdc8
40 files changed
+825 -767

No files matched your search

+116 -63
View File
@@ -4,7 +4,7 @@ use proc_macro2::TokenStream as TokenStream2;
use quote::{quote, ToTokens, TokenStreamExt};
use syn::{
parse::{Parse, ParseBuffer, ParseStream},
token, Expr, ExprClosure, Ident, LitStr, Result, Token,
Expr, Ident, LitStr, Result, Token,
};
// =======================================
@@ -33,45 +33,69 @@ impl Parse for Element {
let mut key = None;
let mut _el_ref = None;
// todo: more descriptive error handling
while !content.is_empty() {
// parse fields with commas
// break when we don't get this pattern anymore
// start parsing bodynodes
// "def": 456,
// abc: 123,
loop {
// Parse the raw literal fields
if content.peek(LitStr) && content.peek2(Token![:]) && !content.peek3(Token![:]) {
let name = content.parse::<LitStr>()?;
let ident = name.clone();
content.parse::<Token![:]>()?;
if content.peek(LitStr) {
let value = content.parse::<LitStr>()?;
attributes.push(ElementAttrNamed {
el_name: el_name.clone(),
attr: ElementAttr::CustomAttrText { name, value },
});
} else {
let value = content.parse::<Expr>()?;
attributes.push(ElementAttrNamed {
el_name: el_name.clone(),
attr: ElementAttr::CustomAttrExpression { name, value },
});
}
if content.is_empty() {
break;
}
// todo: add a message saying you need to include commas between fields
if content.parse::<Token![,]>().is_err() {
proc_macro_error::emit_error!(
ident,
"This attribute is misisng a trailing comma"
)
}
continue;
}
if content.peek(Ident) && content.peek2(Token![:]) && !content.peek3(Token![:]) {
let name = content.parse::<Ident>()?;
let ident = name.clone();
let name_str = name.to_string();
content.parse::<Token![:]>()?;
if name_str.starts_with("on") {
if content.peek(token::Brace) {
let mycontent;
syn::braced!(mycontent in content);
listeners.push(ElementAttrNamed {
el_name: el_name.clone(),
attr: ElementAttr::EventTokens {
name,
tokens: mycontent.parse()?,
},
});
} else {
listeners.push(ElementAttrNamed {
el_name: el_name.clone(),
attr: ElementAttr::EventClosure {
name,
closure: content.parse()?,
},
});
};
listeners.push(ElementAttrNamed {
el_name: el_name.clone(),
attr: ElementAttr::EventTokens {
name,
tokens: content.parse()?,
},
});
} else {
match name_str.as_str() {
"key" => {
key = Some(content.parse()?);
}
"classes" => {
todo!("custom class list not supported")
}
"namespace" => {
todo!("custom namespace not supported")
}
"classes" => todo!("custom class list not supported yet"),
// "namespace" => todo!("custom namespace not supported yet"),
"node_ref" => {
_el_ref = Some(content.parse::<Expr>()?);
}
@@ -96,27 +120,56 @@ impl Parse for Element {
}
}
}
} else if content.peek(LitStr) && content.peek2(Token![:]) {
let name = content.parse::<LitStr>()?;
content.parse::<Token![:]>()?;
if content.peek(LitStr) {
let value = content.parse::<LitStr>()?;
attributes.push(ElementAttrNamed {
el_name: el_name.clone(),
attr: ElementAttr::CustomAttrText { name, value },
});
} else {
let value = content.parse::<Expr>()?;
attributes.push(ElementAttrNamed {
el_name: el_name.clone(),
attr: ElementAttr::CustomAttrExpression { name, value },
});
if content.is_empty() {
break;
}
} else {
children.push(content.parse::<BodyNode>()?);
// todo: add a message saying you need to include commas between fields
if content.parse::<Token![,]>().is_err() {
proc_macro_error::emit_error!(
ident,
"This attribute is misisng a trailing comma"
)
}
continue;
}
break;
}
while !content.is_empty() {
if (content.peek(LitStr) && content.peek2(Token![:])) && !content.peek3(Token![:]) {
let ident = content.parse::<LitStr>().unwrap();
let name = ident.value();
proc_macro_error::emit_error!(
ident, "This attribute `{}` is in the wrong place.", name;
help =
"All attribute fields must be placed above children elements.
div {
attr: \"...\", <---- attribute is above children
div { } <---- children are below attributes
}";
)
}
if (content.peek(Ident) && content.peek2(Token![:])) && !content.peek3(Token![:]) {
let ident = content.parse::<Ident>().unwrap();
let name = ident.to_string();
proc_macro_error::emit_error!(
ident, "This attribute `{}` is in the wrong place.", name;
help =
"All attribute fields must be placed above children elements.
div {
attr: \"...\", <---- attribute is above children
div { } <---- children are below attributes
}";
)
}
children.push(content.parse::<BodyNode>()?);
// consume comma if it exists
// we don't actually care if there *are* commas after elements/text
if content.peek(Token![,]) {
@@ -138,7 +191,7 @@ impl Parse for Element {
impl ToTokens for Element {
fn to_tokens(&self, tokens: &mut TokenStream2) {
let name = &self.name;
let childs = &self.children;
let children = &self.children;
let listeners = &self.listeners;
let attr = &self.attributes;
@@ -153,7 +206,7 @@ impl ToTokens for Element {
dioxus_elements::#name,
[ #(#listeners),* ],
[ #(#attr),* ],
[ #(#childs),* ],
[ #(#children),* ],
#key,
)
});
@@ -173,8 +226,8 @@ enum ElementAttr {
// "attribute": true,
CustomAttrExpression { name: LitStr, value: Expr },
// onclick: move |_| {}
EventClosure { name: Ident, closure: ExprClosure },
// // onclick: move |_| {}
// EventClosure { name: Ident, closure: ExprClosure },
// onclick: {}
EventTokens { name: Ident, tokens: Expr },
@@ -189,7 +242,7 @@ impl ToTokens for ElementAttrNamed {
fn to_tokens(&self, tokens: &mut TokenStream2) {
let ElementAttrNamed { el_name, attr } = self;
let toks = match attr {
tokens.append_all(match attr {
ElementAttr::AttrText { name, value } => {
quote! {
dioxus_elements::#el_name.#name(__cx, format_args_f!(#value))
@@ -200,26 +253,26 @@ impl ToTokens for ElementAttrNamed {
dioxus_elements::#el_name.#name(__cx, #value)
}
}
ElementAttr::CustomAttrText { name, value } => {
quote! { __cx.attr( #name, format_args_f!(#value), None, false ) }
}
ElementAttr::CustomAttrExpression { name, value } => {
quote! { __cx.attr( #name, format_args_f!(#value), None, false ) }
}
ElementAttr::EventClosure { name, closure } => {
quote! {
dioxus_elements::on::#name(__cx, #closure)
__cx.attr( #name, format_args_f!(#value), None, false )
}
}
ElementAttr::CustomAttrExpression { name, value } => {
quote! {
__cx.attr( #name, format_args_f!(#value), None, false )
}
}
// ElementAttr::EventClosure { name, closure } => {
// quote! {
// dioxus_elements::on::#name(__cx, #closure)
// }
// }
ElementAttr::EventTokens { name, tokens } => {
quote! {
dioxus_elements::on::#name(__cx, #tokens)
}
}
};
tokens.append_all(toks);
});
}
}