Răsfoiți Sursa

handle expressions in attributes

Evan Almloff 3 ani în urmă
părinte
comite
5b0a60c294

+ 4 - 1
examples/hot_reload.rs

@@ -19,6 +19,9 @@ fn app(cx: Scope) -> Element {
     });
 
     cx.render(rsx! {
-        h1 { "High-Five counter: {count}" }
+        h1 {
+            x: count,
+            "High-Five counter: {count}"
+        }
     })
 }

+ 3 - 2
packages/core-macro/src/lib.rs

@@ -194,6 +194,8 @@ pub fn rsx(s: TokenStream) -> TokenStream {
                     {
                         let line_num = get_line_num();
                         let rsx_text_index: RsxTextIndex = cx.consume_context().unwrap();
+                        // only the insert the rsx text once
+                        // todo: rsx could be conditionally rendered which would brake this
                         use_state(&cx, || {
                             rsx_text_index.insert(
                                 line_num.clone(),
@@ -210,8 +212,7 @@ pub fn rsx(s: TokenStream) -> TokenStream {
                                 )
                             }
                             else{
-                                println!("rsx: line number {:?} not found", line_num);
-                                factory.static_text("")
+                                panic!("rsx: line number {:?} not found", line_num);
                             }
                         })
                     }

+ 21 - 15
packages/rsx_interperter/src/captuered_context.rs

@@ -1,7 +1,7 @@
 use dioxus_core::VNode;
 use dioxus_rsx::{BodyNode, CallBody, Component, ElementAttr, IfmtInput};
 use quote::{quote, ToTokens, TokenStreamExt};
-use std::collections::HashMap;
+use std::{any::Any, collections::HashMap};
 use syn::Expr;
 
 #[derive(Default)]
@@ -10,6 +10,7 @@ pub struct CapturedContextBuilder {
     pub text: Vec<IfmtInput>,
     pub components: Vec<Component>,
     pub iterators: Vec<Expr>,
+    pub captured_expressions: Vec<Expr>,
 }
 
 impl CapturedContextBuilder {
@@ -18,6 +19,7 @@ impl CapturedContextBuilder {
         self.text.extend(other.text);
         self.components.extend(other.components);
         self.iterators.extend(other.iterators);
+        self.captured_expressions.extend(other.captured_expressions);
     }
 
     pub fn from_call_body(body: CallBody) -> Self {
@@ -33,23 +35,25 @@ impl CapturedContextBuilder {
         match node {
             BodyNode::Element(el) => {
                 for attr in el.attributes {
-                    let (name, value_tokens) = match attr.attr {
+                    match attr.attr {
                         ElementAttr::AttrText { name, value } => {
-                            (name.to_string(), value.to_token_stream())
+                            let (name, value_tokens) = (name.to_string(), value.to_token_stream());
+                            let formated: IfmtInput = syn::parse2(value_tokens).unwrap();
+                            captured.attributes.insert(name, formated);
                         }
                         ElementAttr::AttrExpression { name, value } => {
-                            todo!()
+                            captured.captured_expressions.push(value);
                         }
                         ElementAttr::CustomAttrText { name, value } => {
-                            (name.value(), value.to_token_stream())
+                            let (name, value_tokens) = (name.value(), value.to_token_stream());
+                            let formated: IfmtInput = syn::parse2(value_tokens).unwrap();
+                            captured.attributes.insert(name, formated);
                         }
                         ElementAttr::CustomAttrExpression { name, value } => {
-                            todo!()
+                            captured.captured_expressions.push(value);
                         }
-                        _ => continue,
-                    };
-                    let formated: IfmtInput = syn::parse2(value_tokens).unwrap();
-                    captured.attributes.insert(name, formated);
+                        _ => (),
+                    }
                 }
                 for child in el.children {
                     captured.extend(Self::find_captured(child));
@@ -77,6 +81,7 @@ impl ToTokens for CapturedContextBuilder {
             text,
             components,
             iterators,
+            captured_expressions,
         } = self;
         let captured: Vec<_> = attributes
             .iter()
@@ -86,6 +91,9 @@ impl ToTokens for CapturedContextBuilder {
             .collect();
         let captured_names = captured.iter().map(|(n, _)| n.to_string());
         let captured_expr = captured.iter().map(|(_, e)| e);
+        let captured_attr_expressions_text = captured_expressions
+            .iter()
+            .map(|e| format!("{}", e.to_token_stream()));
         tokens.append_all(quote! {
             CapturedContext {
                 captured: IfmtArgs{
@@ -93,16 +101,12 @@ impl ToTokens for CapturedContextBuilder {
                 },
                 components: vec![#(#components),*],
                 iterators: vec![#(#iterators),*],
+                expressions: vec![#((#captured_attr_expressions_text, #captured_expressions.to_string())),*],
             }
         })
     }
 }
 
-struct CapturedComponentBuilder {
-    name: syn::Path,
-    function: String,
-}
-
 pub struct CapturedContext<'a> {
     // map of the variable name to the formated value
     pub captured: IfmtArgs,
@@ -112,6 +116,8 @@ pub struct CapturedContext<'a> {
     pub components: Vec<VNode<'a>>,
     // we can't reasonably interpert iterators, so they are staticly inserted
     pub iterators: Vec<VNode<'a>>,
+    // map expression to the value resulting from the expression
+    pub expressions: Vec<(&'static str, String)>,
 }
 
 pub struct IfmtArgs {

+ 55 - 31
packages/rsx_interperter/src/interperter.rs

@@ -1,8 +1,7 @@
 use dioxus_core::{Attribute, NodeFactory, VNode};
-use dioxus_rsx::{BodyNode, CallBody, ElementAttr, IfmtInput};
+use dioxus_rsx::{BodyNode, CallBody, ElementAttr};
 use quote::ToTokens;
 use std::str::FromStr;
-use syn::parse2;
 
 use crate::attributes::attrbute_to_static_str;
 use crate::captuered_context::{CapturedContext, IfmtArgs};
@@ -108,41 +107,66 @@ fn build_node<'a>(
         BodyNode::Element(el) => {
             let attributes: &mut Vec<Attribute> = bump.alloc(Vec::new());
             for attr in el.attributes {
-                let result: Option<(String, InterperedIfmt)> = match attr.attr {
-                    ElementAttr::AttrText { name, value } => {
-                        Some((name.to_string(), value.value().parse().unwrap()))
-                    }
+                match attr.attr {
+                    ElementAttr::AttrText { .. } | ElementAttr::CustomAttrText { .. } => {
+                        let (name, value): (String, InterperedIfmt) = match attr.attr {
+                            ElementAttr::AttrText { name, value } => {
+                                (name.to_string(), value.value().parse().unwrap())
+                            }
+                            ElementAttr::CustomAttrText { name, value } => {
+                                (name.value(), value.value().parse().unwrap())
+                            }
+                            _ => unreachable!(),
+                        };
 
-                    ElementAttr::AttrExpression { name, value } => {
-                        todo!()
+                        if let Some((name, namespace)) = attrbute_to_static_str(&name) {
+                            let value = bump.alloc(value.resolve(&ctx.captured));
+                            attributes.push(Attribute {
+                                name,
+                                value,
+                                is_static: true,
+                                is_volatile: false,
+                                namespace,
+                            });
+                        } else {
+                            return None;
+                        }
                     }
 
-                    ElementAttr::CustomAttrText { name, value } => {
-                        Some((name.value(), value.value().parse().unwrap()))
-                    }
+                    ElementAttr::AttrExpression { .. }
+                    | ElementAttr::CustomAttrExpression { .. } => {
+                        let (name, value) = match attr.attr {
+                            ElementAttr::AttrExpression { name, value } => {
+                                (name.to_string(), value)
+                            }
+                            ElementAttr::CustomAttrExpression { name, value } => {
+                                (name.value(), value)
+                            }
 
-                    ElementAttr::CustomAttrExpression { name, value } => {
-                        todo!()
+                            _ => unreachable!(),
+                        };
+                        let formatted_expr = format!("{}", value.to_token_stream());
+                        if let Some((_, resulting_value)) =
+                            ctx.expressions.iter().find(|(n, _)| *n == formatted_expr)
+                        {
+                            if let Some((name, namespace)) = attrbute_to_static_str(&name) {
+                                let value = bump.alloc(resulting_value.clone());
+                                attributes.push(Attribute {
+                                    name,
+                                    value,
+                                    is_static: true,
+                                    is_volatile: false,
+                                    namespace,
+                                });
+                            }
+                        } else {
+                            panic!("could not resolve expression {}", formatted_expr);
+                        }
                     }
-
-                    ElementAttr::EventTokens { .. } => None,
-
-                    ElementAttr::Meta(_) => None,
+                    // Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident { ident: \"count\", span: #0 bytes(497..502) }, arguments: None }] } })
+                    // Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(count), arguments: None }] } })
+                    _ => (),
                 };
-                if let Some((name, value)) = result {
-                    if let Some((name, namespace)) = attrbute_to_static_str(&name) {
-                        let value = bump.alloc(value.resolve(&ctx.captured));
-                        attributes.push(Attribute {
-                            name,
-                            value,
-                            is_static: true,
-                            is_volatile: false,
-                            namespace,
-                        })
-                    } else {
-                        return None;
-                    }
-                }
             }
             let children = bump.alloc(Vec::new());
             for (i, child) in el.children.into_iter().enumerate() {