symbol graph
This commit is contained in:
parent
c427485d6e
commit
028f8805b2
6 changed files with 261 additions and 106 deletions
18
Cargo.lock
generated
18
Cargo.lock
generated
|
@ -10,6 +10,14 @@ name = "base-x"
|
||||||
version = "0.2.6"
|
version = "0.2.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bimap"
|
||||||
|
version = "0.4.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)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.1.2"
|
version = "3.1.2"
|
||||||
|
@ -37,10 +45,13 @@ dependencies = [
|
||||||
name = "enterprise-compiler"
|
name = "enterprise-compiler"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bimap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"petgraph 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"petgraph 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -161,6 +172,11 @@ name = "sha1"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stdweb"
|
name = "stdweb"
|
||||||
version = "0.4.20"
|
version = "0.4.20"
|
||||||
|
@ -275,6 +291,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
[metadata]
|
[metadata]
|
||||||
"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
"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 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 bumpalo 3.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5fb8038c1ddc0a5f73787b130f4cc75151e96ed33e417fde765eb5a81e3532f4"
|
"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 cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||||
"checksum discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
|
"checksum discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
|
||||||
|
@ -295,6 +312,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
|
"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 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 sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
|
||||||
|
"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 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"
|
"checksum stdweb-derive 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef"
|
||||||
"checksum stdweb-internal-macros 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11"
|
"checksum stdweb-internal-macros 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11"
|
||||||
|
|
|
@ -5,7 +5,9 @@ authors = ["Michael Zhang <iptq@protonmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["enterprise-compiler"]
|
members = [
|
||||||
|
"enterprise-compiler",
|
||||||
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
enterprise-compiler = { path = "enterprise-compiler" }
|
enterprise-compiler = { path = "enterprise-compiler" }
|
||||||
|
|
|
@ -8,9 +8,12 @@ edition = "2018"
|
||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
bimap = "0.4.0"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
maplit = "1.0.2"
|
maplit = "1.0.2"
|
||||||
quote = "1.0.2"
|
|
||||||
petgraph = "0.5.0"
|
petgraph = "0.5.0"
|
||||||
syn = { version = "1.0.14", features = ["extra-traits", "full"] }
|
|
||||||
proc-macro2 = "1.0.8"
|
proc-macro2 = "1.0.8"
|
||||||
|
quote = "1.0.2"
|
||||||
|
spin = "0.5.2"
|
||||||
|
syn = { version = "1.0.14", features = ["extra-traits", "full"] }
|
||||||
|
|
||||||
|
|
|
@ -4,14 +4,19 @@ extern crate quote;
|
||||||
extern crate maplit;
|
extern crate maplit;
|
||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
|
|
||||||
|
mod symbol;
|
||||||
|
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
|
use bimap::BiHashMap;
|
||||||
use petgraph::{dot::Dot, graph::Graph, graphmap::DiGraphMap};
|
use petgraph::{dot::Dot, graph::Graph, graphmap::DiGraphMap};
|
||||||
use proc_macro2::{Span, TokenStream, TokenTree};
|
use proc_macro2::{Span, TokenStream, TokenTree};
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
use syn::{punctuated::Punctuated, Expr, ExprPath, Ident, Path, PathArguments, PathSegment};
|
use syn::{punctuated::Punctuated, Expr, ExprPath, Ident, Path, PathArguments, PathSegment};
|
||||||
|
|
||||||
type Id = String;
|
use crate::symbol::Symbol;
|
||||||
|
|
||||||
|
type Id = Symbol;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
enum TagLhs {
|
enum TagLhs {
|
||||||
|
@ -42,18 +47,21 @@ enum TaggedRsx {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TaggedRsx {
|
impl TaggedRsx {
|
||||||
pub fn get_id(&self) -> &str {
|
pub fn get_id(&self) -> Id {
|
||||||
match self {
|
match self {
|
||||||
TaggedRsx::Elem(id, _) | TaggedRsx::Code(id, _) | TaggedRsx::Text(id, _) => id.as_ref(),
|
TaggedRsx::Elem(id, _) | TaggedRsx::Code(id, _) | TaggedRsx::Text(id, _) => *id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
|
||||||
enum DepNode {
|
enum DepNode {
|
||||||
RsxAttr,
|
// This is an attribute on an element
|
||||||
RsxSpan,
|
RsxAttr(Symbol),
|
||||||
ModelValue,
|
// This is a text node (innertext)
|
||||||
|
RsxSpan(Symbol),
|
||||||
|
// This is something in the model
|
||||||
|
ModelValue(Symbol),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -62,7 +70,7 @@ enum DepActions {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
struct DependencyGraph(DiGraphMap<u32, ()>);
|
struct DependencyGraph(DiGraphMap<DepNode, ()>);
|
||||||
|
|
||||||
impl DependencyGraph {
|
impl DependencyGraph {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
|
@ -75,9 +83,11 @@ impl DependencyGraph {
|
||||||
struct Visitor {
|
struct Visitor {
|
||||||
idx: u32,
|
idx: u32,
|
||||||
deps: DependencyGraph,
|
deps: DependencyGraph,
|
||||||
wtf: HashMap<u32, DepNode>,
|
model: HashMap<Id, String>,
|
||||||
model: HashMap<String, String>,
|
|
||||||
impl_code: TokenStream,
|
impl_code: TokenStream,
|
||||||
|
|
||||||
|
// symbol maps
|
||||||
|
model_bimap: BiHashMap<Id, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Visitor {
|
impl Visitor {
|
||||||
|
@ -88,30 +98,19 @@ impl Visitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_model(&mut self, model: &HashMap<String, String>) {
|
fn load_model(&mut self, model: &HashMap<String, String>) {
|
||||||
self.model.extend(model.clone());
|
for (key, value) in model {
|
||||||
|
let id = Symbol::gensym();
|
||||||
|
self.model_bimap.insert(id, key.clone());
|
||||||
|
self.model.insert(id, value.clone());
|
||||||
}
|
}
|
||||||
|
// self.model.extend(model.clone());
|
||||||
fn unique_name(&mut self, base: impl AsRef<str>) -> String {
|
|
||||||
// TODO: normalize the name somehow so it fits in an ident (ex. strip punct)
|
|
||||||
let base = base.as_ref();
|
|
||||||
let next = self.idx;
|
|
||||||
self.idx += 1;
|
|
||||||
format!("{}_{}", base, next)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unique_idx(&mut self, node: DepNode) -> u32 {
|
|
||||||
let next = self.idx;
|
|
||||||
self.idx += 1;
|
|
||||||
self.wtf.insert(next, node);
|
|
||||||
next
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_graph(&mut self, nodes: &[Rsx]) -> Vec<TaggedRsx> {
|
fn make_graph(&mut self, nodes: &[Rsx]) -> Vec<TaggedRsx> {
|
||||||
nodes
|
let mut new_nodes = Vec::new();
|
||||||
.iter()
|
for node in nodes {
|
||||||
.map(|node| {
|
let node_id = Symbol::gensym();
|
||||||
let node_id = self.unique_name("node");
|
let new_node = match node {
|
||||||
match node {
|
|
||||||
Rsx::Elem(Elem { tag, attrs, inner }) => {
|
Rsx::Elem(Elem { tag, attrs, inner }) => {
|
||||||
let tag_inner = self.make_graph(&inner);
|
let tag_inner = self.make_graph(&inner);
|
||||||
TaggedRsx::Elem(
|
TaggedRsx::Elem(
|
||||||
|
@ -124,30 +123,29 @@ impl Visitor {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Rsx::Code(expr) => {
|
Rsx::Code(expr) => {
|
||||||
let deps = extract_model_dependencies(expr);
|
let deps = self.extract_model_dependencies(expr);
|
||||||
for dep in deps {
|
for dep in deps {
|
||||||
if self.model.contains_key(&dep) {
|
let from = DepNode::ModelValue(dep);
|
||||||
let from = self.unique_idx(DepNode::ModelValue);
|
let to = DepNode::RsxSpan(node_id);
|
||||||
let to = self.unique_idx(DepNode::RsxSpan);
|
|
||||||
self.deps.0.add_edge(from, to, ());
|
self.deps.0.add_edge(from, to, ());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
TaggedRsx::Code(node_id, expr.clone())
|
TaggedRsx::Code(node_id, expr.clone())
|
||||||
}
|
}
|
||||||
Rsx::Text(literal) => TaggedRsx::Text(node_id, literal.clone()),
|
Rsx::Text(literal) => TaggedRsx::Text(node_id, literal.clone()),
|
||||||
|
};
|
||||||
|
new_nodes.push(new_node);
|
||||||
}
|
}
|
||||||
})
|
new_nodes
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_code(&mut self, nodes: &[TaggedRsx]) -> Vec<String> {
|
fn gen_code(&mut self, nodes: &[TaggedRsx]) -> Vec<String> {
|
||||||
let mut names = Vec::new();
|
let mut names = Vec::new();
|
||||||
for node in nodes {
|
for node in nodes {
|
||||||
let node_id = node.get_id();
|
let node_id = node.get_id().as_str();
|
||||||
let make_node_id = format_ident!("make_{}", node_id);
|
let make_node_id = format_ident!("make_{}", node_id);
|
||||||
match node {
|
match node {
|
||||||
TaggedRsx::Elem(node_id, Elem { tag, attrs, inner }) => {
|
TaggedRsx::Elem(_, Elem { tag, attrs, inner }) => {
|
||||||
self.impl_code.extend(quote! {
|
self.impl_code.extend(quote! {
|
||||||
fn #make_node_id(&self) -> impl stdweb::web::IElement {
|
fn #make_node_id(&self) -> impl stdweb::web::IElement {
|
||||||
let el = document().create_element(#tag).unwrap();
|
let el = document().create_element(#tag).unwrap();
|
||||||
|
@ -156,7 +154,7 @@ impl Visitor {
|
||||||
});
|
});
|
||||||
self.gen_code(&inner);
|
self.gen_code(&inner);
|
||||||
}
|
}
|
||||||
TaggedRsx::Code(node_id, expr) => {
|
TaggedRsx::Code(_, expr) => {
|
||||||
self.impl_code.extend(quote! {
|
self.impl_code.extend(quote! {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn #make_node_id(&self) -> impl stdweb::web::IElement {
|
fn #make_node_id(&self) -> impl stdweb::web::IElement {
|
||||||
|
@ -166,7 +164,7 @@ impl Visitor {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
TaggedRsx::Text(node_id, literal) => {
|
TaggedRsx::Text(_, literal) => {
|
||||||
self.impl_code.extend(quote! {
|
self.impl_code.extend(quote! {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn #make_node_id(&self) -> impl stdweb::web::IElement {
|
fn #make_node_id(&self) -> impl stdweb::web::IElement {
|
||||||
|
@ -182,50 +180,35 @@ impl Visitor {
|
||||||
}
|
}
|
||||||
names
|
names
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// This is using a really dumb heuristic
|
/// This is using a really dumb heuristic
|
||||||
fn extract_model_dependencies(expr: &Expr) -> HashSet<String> {
|
fn extract_model_dependencies(&self, expr: &Expr) -> HashSet<Symbol> {
|
||||||
let tokens = expr.to_token_stream();
|
let tokens = expr.to_token_stream();
|
||||||
let mut result = HashSet::new();
|
let mut result = HashSet::new();
|
||||||
|
|
||||||
for token in tokens.into_iter() {
|
for token in tokens.into_iter() {
|
||||||
if let TokenTree::Ident(ident) = token {
|
if let TokenTree::Ident(ident) = token {
|
||||||
result.insert(format!("{}", ident));
|
if let Some(id) = self.model_bimap.get_by_right(&ident.to_string()) {
|
||||||
|
result.insert(*id);
|
||||||
|
}
|
||||||
|
// result.insert(format!("{}", ident));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro]
|
fn process(
|
||||||
pub fn example(input_tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
name: impl AsRef<str>,
|
||||||
let helloworld_name = "HelloWorld".to_string();
|
datamodel: &HashMap<String, String>,
|
||||||
|
datainit: &HashMap<String, String>,
|
||||||
let helloworld_datamodel: HashMap<String, String> = hashmap! {
|
dom: &[Rsx],
|
||||||
"name".into() => "String".into(),
|
) -> TokenStream {
|
||||||
};
|
let name = name.as_ref();
|
||||||
|
|
||||||
let helloworld_datainit: HashMap<String, String> = hashmap! {
|
|
||||||
"name".into() => "\"world\".into()".into(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let helloworld_dom = vec![
|
|
||||||
Rsx::Elem(Elem {
|
|
||||||
tag: "input".into(),
|
|
||||||
attrs: hashmap! {
|
|
||||||
TagLhs::Bind("value".into()) => "name".into(),
|
|
||||||
},
|
|
||||||
inner: vec![],
|
|
||||||
}),
|
|
||||||
Rsx::Text("Hello, ".into()),
|
|
||||||
Rsx::Code(syn::parse_str::<Expr>("name").unwrap()),
|
|
||||||
Rsx::Text("!".into()),
|
|
||||||
];
|
|
||||||
|
|
||||||
let mut visitor = Visitor::new();
|
let mut visitor = Visitor::new();
|
||||||
visitor.load_model(&helloworld_datamodel);
|
visitor.load_model(&datamodel);
|
||||||
let new_dom = visitor.make_graph(&helloworld_dom);
|
let new_dom = visitor.make_graph(&dom);
|
||||||
let toplevel_names = visitor.gen_code(&new_dom);
|
let toplevel_names = visitor.gen_code(&new_dom);
|
||||||
|
|
||||||
// println!("{:?}", visitor);
|
// println!("{:?}", visitor);
|
||||||
|
@ -233,16 +216,16 @@ pub fn example(input_tokens: proc_macro::TokenStream) -> proc_macro::TokenStream
|
||||||
let graph: Graph<_, _, _> = visitor.deps.0.clone().into_graph();
|
let graph: Graph<_, _, _> = visitor.deps.0.clone().into_graph();
|
||||||
println!("{:?}", Dot::new(&graph));
|
println!("{:?}", Dot::new(&graph));
|
||||||
|
|
||||||
let name = format_ident!("{}", helloworld_name);
|
let name = format_ident!("{}", name);
|
||||||
let mut model = TokenStream::new();
|
let mut model = TokenStream::new();
|
||||||
let mut init = TokenStream::new();
|
let mut init = TokenStream::new();
|
||||||
for (name, ty) in visitor.model {
|
for (name, ty) in datamodel {
|
||||||
let name = format_ident!("{}", name);
|
let name = format_ident!("{}", name);
|
||||||
// TODO: parse this into an actual expression tree for Vec<T>
|
// TODO: parse this into an actual expression tree for Vec<T>
|
||||||
let ty = format_ident!("{}", ty);
|
let ty = format_ident!("{}", ty);
|
||||||
model.extend(quote! { #name : #ty , });
|
model.extend(quote! { #name : #ty , });
|
||||||
}
|
}
|
||||||
for (name, value) in helloworld_datainit {
|
for (name, value) in datainit {
|
||||||
let name = format_ident!("{}", name);
|
let name = format_ident!("{}", name);
|
||||||
let value = syn::parse_str::<Expr>(&value).unwrap();
|
let value = syn::parse_str::<Expr>(&value).unwrap();
|
||||||
init.extend(quote! { #name : #value , });
|
init.extend(quote! { #name : #value , });
|
||||||
|
@ -258,7 +241,7 @@ pub fn example(input_tokens: proc_macro::TokenStream) -> proc_macro::TokenStream
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = quote! {
|
quote! {
|
||||||
struct #name<B> {
|
struct #name<B> {
|
||||||
_b: std::marker::PhantomData<B>,
|
_b: std::marker::PhantomData<B>,
|
||||||
#model
|
#model
|
||||||
|
@ -280,7 +263,37 @@ pub fn example(input_tokens: proc_macro::TokenStream) -> proc_macro::TokenStream
|
||||||
#init_el_code
|
#init_el_code
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn example(input_tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
|
let helloworld_datamodel: HashMap<String, String> = hashmap! {
|
||||||
|
"name".into() => "String".into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
result.into()
|
let helloworld_datainit: HashMap<String, String> = hashmap! {
|
||||||
|
"name".into() => "\"world\".into()".into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let helloworld_dom = vec![
|
||||||
|
Rsx::Elem(Elem {
|
||||||
|
tag: "input".into(),
|
||||||
|
attrs: hashmap! {
|
||||||
|
TagLhs::Bind("value".into()) => "name".into(),
|
||||||
|
},
|
||||||
|
inner: vec![],
|
||||||
|
}),
|
||||||
|
Rsx::Text("Hello, ".into()),
|
||||||
|
Rsx::Code(syn::parse_str::<Expr>("name").unwrap()),
|
||||||
|
Rsx::Text("!".into()),
|
||||||
|
];
|
||||||
|
|
||||||
|
process(
|
||||||
|
"HelloWorld",
|
||||||
|
&helloworld_datamodel,
|
||||||
|
&helloworld_datainit,
|
||||||
|
&helloworld_dom,
|
||||||
|
)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
|
|
119
enterprise-compiler/src/symbol.rs
Normal file
119
enterprise-compiler/src/symbol.rs
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
// https://github.com/remexre/symbol-rs
|
||||||
|
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::collections::BTreeSet;
|
||||||
|
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
|
||||||
|
use std::mem::{forget, transmute};
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
|
||||||
|
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use spin::Mutex;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref SYMBOL_HEAP: Mutex<BTreeSet<&'static str>> = Mutex::new(BTreeSet::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An interned string with O(1) equality.
|
||||||
|
#[derive(Clone, Copy, Eq, Hash, PartialOrd)]
|
||||||
|
pub struct Symbol {
|
||||||
|
s: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Symbol {
|
||||||
|
/// Retrieves the address of the backing string.
|
||||||
|
pub fn addr(self) -> usize {
|
||||||
|
self.s.as_ptr() as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves the string from the Symbol.
|
||||||
|
pub fn as_str(self) -> &'static str {
|
||||||
|
self.s
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates a new symbol with a name of the form `G#n`, where `n` is some positive integer.
|
||||||
|
pub fn gensym() -> Symbol {
|
||||||
|
lazy_static! {
|
||||||
|
static ref N: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut heap = SYMBOL_HEAP.lock();
|
||||||
|
let n = loop {
|
||||||
|
let n = leak_string(format!("sym_{}", N.fetch_add(1, AtomicOrdering::SeqCst)));
|
||||||
|
if heap.insert(n) {
|
||||||
|
break n;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
drop(heap);
|
||||||
|
|
||||||
|
Symbol::from(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Symbol {
|
||||||
|
fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
|
||||||
|
Debug::fmt(self.s, fmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Symbol {
|
||||||
|
type Target = str;
|
||||||
|
fn deref(&self) -> &str {
|
||||||
|
self.s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Symbol {
|
||||||
|
fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
|
||||||
|
fmt.write_str(self.s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: AsRef<str>> From<S> for Symbol {
|
||||||
|
fn from(s: S) -> Symbol {
|
||||||
|
let s = s.as_ref();
|
||||||
|
{
|
||||||
|
let mut heap = SYMBOL_HEAP.lock();
|
||||||
|
if heap.get(s).is_none() {
|
||||||
|
heap.insert(leak_string(s.to_owned()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let s = {
|
||||||
|
let heap = SYMBOL_HEAP.lock();
|
||||||
|
heap.get(s).unwrap().clone()
|
||||||
|
};
|
||||||
|
Symbol { s }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for Symbol {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
let l = self.addr();
|
||||||
|
let r = other.addr();
|
||||||
|
l.cmp(&r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Symbol {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.cmp(other) == Ordering::Equal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: AsRef<str>> PartialEq<S> for Symbol {
|
||||||
|
fn eq(&self, other: &S) -> bool {
|
||||||
|
self.partial_cmp(&other.as_ref()) == Some(Ordering::Equal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: AsRef<str>> PartialOrd<S> for Symbol {
|
||||||
|
fn partial_cmp(&self, other: &S) -> Option<Ordering> {
|
||||||
|
self.s.partial_cmp(other.as_ref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leak_string(s: String) -> &'static str {
|
||||||
|
let out = unsafe { transmute(&s as &str) };
|
||||||
|
forget(s);
|
||||||
|
out
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ extern crate stdweb;
|
||||||
|
|
||||||
mod backend;
|
mod backend;
|
||||||
|
|
||||||
use stdweb::web::{document, Element, INode, IElement, INonElementParentNode};
|
use stdweb::web::{document, Element, IElement, INode, INonElementParentNode};
|
||||||
|
|
||||||
use crate::backend::{Backend, Web};
|
use crate::backend::{Backend, Web};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue