From 5b0a60c294fe9e8ec90ec22a10a16df06272a270 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 26 May 2022 19:16:51 -0500 Subject: [PATCH] handle expressions in attributes --- examples/hot_reload.rs | 5 +- packages/core-macro/src/lib.rs | 5 +- .../rsx_interperter/src/captuered_context.rs | 36 ++++---- packages/rsx_interperter/src/interperter.rs | 90 ++++++++++++------- 4 files changed, 85 insertions(+), 51 deletions(-) diff --git a/examples/hot_reload.rs b/examples/hot_reload.rs index 1fda9a977..be7d9e533 100644 --- a/examples/hot_reload.rs +++ b/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}" + } }) } diff --git a/packages/core-macro/src/lib.rs b/packages/core-macro/src/lib.rs index ea187ce7d..23822dbad 100644 --- a/packages/core-macro/src/lib.rs +++ b/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); } }) } diff --git a/packages/rsx_interperter/src/captuered_context.rs b/packages/rsx_interperter/src/captuered_context.rs index 9564186d1..639752ffc 100644 --- a/packages/rsx_interperter/src/captuered_context.rs +++ b/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, pub components: Vec, pub iterators: Vec, + pub captured_expressions: Vec, } 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>, // we can't reasonably interpert iterators, so they are staticly inserted pub iterators: Vec>, + // map expression to the value resulting from the expression + pub expressions: Vec<(&'static str, String)>, } pub struct IfmtArgs { diff --git a/packages/rsx_interperter/src/interperter.rs b/packages/rsx_interperter/src/interperter.rs index 28abffef9..159f060a9 100644 --- a/packages/rsx_interperter/src/interperter.rs +++ b/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 = 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!(), + }; + + 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::AttrExpression { name, value } => { - todo!() + 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) + } + + _ => 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::CustomAttrText { name, value } => { - Some((name.value(), value.value().parse().unwrap())) - } - - ElementAttr::CustomAttrExpression { name, value } => { - todo!() - } - - 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() {