diff --git a/Cargo.lock b/Cargo.lock index eb97cd5..2ceb4c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,6 +18,11 @@ dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bumpalo" version = "3.1.2" @@ -28,6 +33,14 @@ name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "discard" version = "1.0.4" @@ -38,6 +51,7 @@ name = "enterprise" version = "0.1.0" dependencies = [ "enterprise-compiler 0.1.0", + "parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "stdweb 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -78,6 +92,19 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "libc" +version = "0.2.66" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lock_api" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "log" version = "0.4.8" @@ -91,6 +118,28 @@ name = "maplit" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "parking_lot" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot_core" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "petgraph" version = "0.5.0" @@ -116,6 +165,11 @@ dependencies = [ "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rustc_version" version = "0.2.3" @@ -129,6 +183,11 @@ name = "ryu" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "scopeguard" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "semver" version = "0.9.0" @@ -172,6 +231,11 @@ name = "sha1" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "smallvec" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "spin" version = "0.5.2" @@ -288,30 +352,58 @@ name = "wasm-bindgen-shared" version = "0.2.58" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [metadata] "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" "checksum base-x 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b20b618342cf9891c292c4f5ac2cde7287cc5c87e87e9c769d617793607dec1" "checksum bimap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "783204f24fd7724ea274d327619cfa6a6018047bb0561a68aadff6f56787591b" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum bumpalo 3.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5fb8038c1ddc0a5f73787b130f4cc75151e96ed33e417fde765eb5a81e3532f4" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" "checksum fixedbitset 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" "checksum indexmap 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b54058f0a6ff80b6803da8faf8997cde53872b38f4023728f6830b06cd3c0dc" "checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" +"checksum lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" +"checksum parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc" +"checksum parking_lot_core 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1" "checksum petgraph 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29c127eea4a29ec6c85d153c59dc1213f33ec74cead30fe4730aecc88cc1fd92" "checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" +"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" "checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" "checksum serde_json 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "21b01d7f0288608a01dca632cf1df859df6fd6ffa885300fc275ce2ba6221953" "checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" +"checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" "checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" "checksum stdweb 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" "checksum stdweb-derive 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" @@ -324,3 +416,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wasm-bindgen-macro 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "574094772ce6921576fb6f2e3f7497b8a76273b6db092be18fc48a082de09dc3" "checksum wasm-bindgen-macro-support 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "e85031354f25eaebe78bb7db1c3d86140312a911a106b2e29f9cc440ce3e7668" "checksum wasm-bindgen-shared 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "f5e7e61fc929f4c0dddb748b102ebf9f632e2b8d739f2016542b4de2965a9601" +"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index cce246c..7dedd23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,4 @@ members = [ [dependencies] enterprise-compiler = { path = "enterprise-compiler" } stdweb = "0.4.20" +parking_lot = "0.10.0" diff --git a/enterprise-compiler/src/lib.rs b/enterprise-compiler/src/lib.rs index 369a31c..7de22c9 100644 --- a/enterprise-compiler/src/lib.rs +++ b/enterprise-compiler/src/lib.rs @@ -9,7 +9,7 @@ mod symbol; use std::collections::{HashMap, HashSet}; use bimap::BiHashMap; -use petgraph::{dot::Dot, graph::Graph, graphmap::DiGraphMap}; +use petgraph::{dot::Dot, graph::Graph, graphmap::DiGraphMap, visit::Dfs}; use proc_macro2::{Span, TokenStream, TokenTree}; use quote::ToTokens; use syn::{punctuated::Punctuated, Expr, ExprPath, Ident, Path, PathArguments, PathSegment}; @@ -57,8 +57,10 @@ impl TaggedRsx { #[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)] enum DepNode { // This is an attribute on an element - RsxAttr(Symbol), + // Not read-only + RsxAttr(Symbol, Symbol), // This is a text node (innertext) + // These are read-only RsxSpan(Symbol), // This is something in the model ModelValue(Symbol), @@ -85,6 +87,7 @@ struct Visitor { deps: DependencyGraph, model: HashMap, impl_code: TokenStream, + elem_attr_map: HashMap>, // symbol maps model_bimap: BiHashMap, @@ -113,6 +116,22 @@ impl Visitor { let new_node = match node { Rsx::Elem(Elem { tag, attrs, inner }) => { let tag_inner = self.make_graph(&inner); + for (lhs, rhs) in attrs { + if let TagLhs::Bind(attr) = lhs { + if let Some(id) = self.model_bimap.get_by_right(rhs) { + let from = DepNode::RsxAttr(node_id, Symbol::from(attr)); + let to = DepNode::ModelValue(*id); + self.deps.0.add_edge(from, to, ()); + if let Some(set) = self.elem_attr_map.get_mut(&node_id) { + set.insert(Symbol::from(attr)); + } else { + let mut set = HashSet::new(); + set.insert(Symbol::from(attr)); + self.elem_attr_map.insert(node_id, set); + } + } + } + } TaggedRsx::Elem( node_id, Elem { @@ -142,37 +161,89 @@ impl Visitor { fn gen_code(&mut self, nodes: &[TaggedRsx]) -> Vec { let mut names = Vec::new(); for node in nodes { - let node_id = node.get_id().as_str(); - let make_node_id = format_ident!("make_{}", node_id); + let node_str = node.get_id().as_str(); + let make_node_id = format_ident!("make_{}", node_str); match node { - TaggedRsx::Elem(_, Elem { tag, attrs, inner }) => { + TaggedRsx::Elem(node_id, Elem { tag, attrs, inner }) => { + let mut updates = TokenStream::new(); + if let Some(this_attrs) = self.elem_attr_map.get(node_id) { + for attr in this_attrs { + let starting = DepNode::RsxAttr(*node_id, *attr); + let mut dfs = Dfs::new(&self.deps.0, starting); + let mut update_func = TokenStream::new(); + while let Some(nx) = dfs.next(&self.deps.0) { + if nx != starting { + println!("NX: {:?}", nx); + match nx { + DepNode::ModelValue(sym) => { + let sym_name = format_ident!( + "{}", + self.model_bimap.get_by_left(&sym).unwrap() + ); + let inner_lock = format_ident!( + "inner_lock_{}", + Symbol::gensym().as_str() + ); + updates.extend(quote! { + let #inner_lock = self.#sym_name.clone(); + }); + update_func.extend(quote! { + { + let mut locked = #inner_lock.lock(); + *locked = new_value.clone(); + } + }); + } + DepNode::RsxSpan(id) => { + let id_str = id.as_str(); + update_func.extend(quote! { + { + if let Some(target) = document().get_element_by_id(#id_str) { + target.set_text_content(&new_value.clone()); + } + } + }); + } + _ => (), + } + } + } + let attr_name = attr.as_str(); + updates.extend(quote! { + let inner_el = el.clone(); + el.add_event_listener(move |evt: stdweb::web::event::InputEvent| { + let new_value = InputElement::try_from(inner_el.clone()).unwrap().raw_value(); + js! { console.log("bruh", @{inner_el.clone()}, @{&new_value}); } + #update_func + }); + }); + } + } self.impl_code.extend(quote! { fn #make_node_id(&self) -> impl stdweb::web::INode { let el = document().create_element(#tag).unwrap(); + el.set_attribute("id", #node_str); + #updates el } }); self.gen_code(&inner); } - TaggedRsx::Code(_, expr) => { + TaggedRsx::Code(node_id, expr) => { self.impl_code.extend(quote! { #[inline] fn #make_node_id(&self) -> impl stdweb::web::INode { let el = document().create_element("span").expect("shouldn't fail"); - el.set_attribute("id", #node_id); + el.set_attribute("id", #node_str); el } }); } - TaggedRsx::Text(_, literal) => { + TaggedRsx::Text(node_id, literal) => { self.impl_code.extend(quote! { #[inline] fn #make_node_id(&self) -> impl stdweb::web::INode { - use stdweb::unstable::TryFrom; - let string: Value = #literal.into(); - let reference = Reference::try_from(string).unwrap(); - let node = TextNode::try_from(reference).unwrap(); - node + document().create_text_node(#literal) } }); } @@ -225,12 +296,12 @@ fn process( let name = format_ident!("{}", name); // TODO: parse this into an actual expression tree for Vec let ty = format_ident!("{}", ty); - model.extend(quote! { #name : #ty , }); + model.extend(quote! { #name : Arc> , }); } for (name, value) in datainit { let name = format_ident!("{}", name); let value = syn::parse_str::(&value).unwrap(); - init.extend(quote! { #name : #value , }); + init.extend(quote! { #name : Arc::new(Mutex::new(#value)) , }); } let impl_code = &visitor.impl_code; diff --git a/src/main.rs b/src/main.rs index c335f76..ad29d98 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,17 @@ extern crate stdweb; mod backend; -use stdweb::{web::{document, Element, IElement, INode, TextNode, INonElementParentNode}, Reference, Value}; +use std::sync::Arc; + +use parking_lot::Mutex; +use stdweb::{ + unstable::TryFrom, + web::{ + document, html_element::InputElement, Element, IElement, IEventTarget, INode, + INonElementParentNode, TextNode, + }, + Reference, Value, +}; use crate::backend::{Backend, Web};