|
@@ -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 ) }
|
|
|
+ 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::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);
|
|
|
+ });
|
|
|
}
|
|
|
}
|