ouais
This commit is contained in:
parent
fbd3d8ffd2
commit
0e95823708
7 changed files with 302 additions and 62 deletions
|
@ -4,7 +4,7 @@ extern crate quote;
|
|||
extern crate serde_derive;
|
||||
|
||||
pub mod model;
|
||||
mod tuple_map;
|
||||
mod utils;
|
||||
mod visitor;
|
||||
|
||||
use std::env;
|
||||
|
|
|
@ -30,7 +30,7 @@ pub fn convert_map<T: Ord>(map: BTreeMap<T, (syn::Type, syn::Expr)>) -> BTreeMap
|
|||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Component {
|
||||
pub name: String,
|
||||
#[serde(with = "crate::tuple_map")]
|
||||
#[serde(with = "crate::utils::tuple_map")]
|
||||
pub model: ModelMap,
|
||||
pub view: Vec<Rsx>,
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ impl ToTokens for TagRhs {
|
|||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct Elem<T> {
|
||||
pub tag: String,
|
||||
#[serde(with = "crate::tuple_map")]
|
||||
#[serde(with = "crate::utils::tuple_map")]
|
||||
pub attrs: BTreeMap<TagLhs, TagRhs>,
|
||||
pub inner: Option<Vec<T>>,
|
||||
}
|
||||
|
|
28
enterprise-compiler/src/utils/mod.rs
Normal file
28
enterprise-compiler/src/utils/mod.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
pub mod tuple_map;
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use symbol::Symbol;
|
||||
use syn::*;
|
||||
|
||||
pub fn get_pat_names(pat: &Pat) -> HashSet<Symbol> {
|
||||
let mut result = HashSet::new();
|
||||
match pat {
|
||||
Pat::Box(PatBox { pat, .. }) => {
|
||||
result.extend(get_pat_names(pat));
|
||||
}
|
||||
Pat::Ident(PatIdent { ident, subpat, .. }) => {
|
||||
result.insert(Symbol::from(ident.to_string()));
|
||||
if let Some((_, boxpat)) = subpat {
|
||||
result.extend(get_pat_names(boxpat));
|
||||
}
|
||||
}
|
||||
Pat::Tuple(PatTuple { elems, .. }) => {
|
||||
for pat in elems.iter() {
|
||||
result.extend(get_pat_names(pat));
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
result
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
//! Visitor that traverses a model and generates code.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
|
||||
|
||||
use petgraph::{dot::Dot, graphmap::DiGraphMap, visit::Dfs};
|
||||
use proc_macro2::{TokenStream, TokenTree};
|
||||
|
@ -10,29 +9,48 @@ use syn::{Expr, Type};
|
|||
use syn_serde::Syn;
|
||||
|
||||
use crate::model::{Elem, Id, ModelMap, Rsx, TagLhs, TagRhs, TaggedRsx};
|
||||
use crate::utils;
|
||||
use crate::Symbol;
|
||||
|
||||
/// A node within the dependency graph.
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
|
||||
pub enum DepNode {
|
||||
/// An anonymous code segment
|
||||
CodeSeg(Symbol),
|
||||
/// This is an attribute on an element
|
||||
///
|
||||
/// Not read-only
|
||||
RsxAttr(Symbol, Symbol),
|
||||
/// This is an "on:" attribute, representing an event handler
|
||||
RsxEvent(Symbol, Symbol),
|
||||
/// This is a text node (innertext)
|
||||
///
|
||||
/// These are read-only
|
||||
RsxSpan(Symbol),
|
||||
/// This is something in the model
|
||||
ModelValue(Symbol),
|
||||
ModelValue(ModelValue),
|
||||
/// This is an iterator (for-loop)
|
||||
Iterator(Symbol),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum DepAction {
|
||||
ValueChange,
|
||||
IndexChange(Symbol),
|
||||
SubmitEvt,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
|
||||
pub enum ModelValue {
|
||||
Index(Symbol, Symbol),
|
||||
Leaf(Symbol),
|
||||
}
|
||||
|
||||
impl DepNode {
|
||||
// Generates code for when this updates
|
||||
fn gen_update_code(&self, updates: &mut TokenStream, update_func: &mut TokenStream) {
|
||||
match self {
|
||||
DepNode::ModelValue(sym) => {
|
||||
DepNode::ModelValue(ModelValue::Leaf(sym)) => {
|
||||
let sym_name = format_ident!("{}", sym.to_string());
|
||||
let inner_lock = format_ident!("inner_lock_{}", Symbol::gensym().as_str());
|
||||
updates.extend(quote! {
|
||||
|
@ -56,22 +74,27 @@ impl DepNode {
|
|||
}
|
||||
});
|
||||
}
|
||||
DepNode::Iterator(id) => {
|
||||
let update_id = format_ident!("update_loop_{}", id.as_str());
|
||||
update_func.extend(quote! {
|
||||
self.#update_id();
|
||||
});
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type DependencyGraph = DiGraphMap<DepNode, ()>;
|
||||
type DependencyGraph = DiGraphMap<DepNode, DepAction>;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Visitor {
|
||||
idx: u32,
|
||||
pub(crate) deps: DependencyGraph,
|
||||
model: HashMap<Id, (Type, Expr)>,
|
||||
code_segments: HashMap<Id, Expr>,
|
||||
pub(crate) impl_code: TokenStream,
|
||||
elem_attr_map: HashMap<Id, HashSet<Id>>,
|
||||
// symbol maps
|
||||
// model_bimap: BiHashMap<Id, String>,
|
||||
}
|
||||
|
||||
impl Visitor {
|
||||
|
@ -85,19 +108,115 @@ impl Visitor {
|
|||
&self.impl_code
|
||||
}
|
||||
|
||||
pub fn code_segments(&self) -> &HashMap<Id, Expr> {
|
||||
&self.code_segments
|
||||
}
|
||||
|
||||
pub fn load_model(&mut self, model: &ModelMap) {
|
||||
for (key, (ty, init)) in model {
|
||||
let ty = Syn::from_adapter(&*ty);
|
||||
let init = Syn::from_adapter(&*init);
|
||||
let ty = syn::Type::from_adapter(ty);
|
||||
let init = syn::Expr::from_adapter(init);
|
||||
self.model.insert(key.clone(), (ty, init));
|
||||
}
|
||||
// self.model.extend(model.clone());
|
||||
}
|
||||
|
||||
pub fn dot(&self) -> Dot<&DependencyGraph> {
|
||||
Dot::new(&self.deps)
|
||||
}
|
||||
|
||||
fn hook_attrs(&mut self, node_id: Symbol, attrs: &BTreeMap<TagLhs, TagRhs>) {
|
||||
for (lhs, rhs) in attrs {
|
||||
match (lhs, rhs) {
|
||||
// If the left-hand side contains bind:attr="name", put that attribute as a dependency of name
|
||||
(TagLhs::Bind(attr), TagRhs::Text(text)) => {
|
||||
let text_sym = Symbol::from(text);
|
||||
// check if the model actually contains the key that you're trying to bind to
|
||||
if self.model.contains_key(&text_sym) {
|
||||
let attr_node = DepNode::RsxAttr(node_id, Symbol::from(attr));
|
||||
let model_node = DepNode::ModelValue(ModelValue::Leaf(text_sym));
|
||||
self.deps
|
||||
.add_edge(attr_node, model_node, DepAction::ValueChange);
|
||||
self.deps
|
||||
.add_edge(model_node, attr_node, DepAction::ValueChange);
|
||||
println!("Added elem attr to graph {:?} {:?}", attr_node, model_node);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
(TagLhs::On(evt), TagRhs::Code(expr)) => {
|
||||
let syn_expr = syn::Expr::from_adapter(expr);
|
||||
let code_node_id = self.hook_code_segment(&syn_expr);
|
||||
|
||||
// add hook from attr to the code segment
|
||||
let from = DepNode::RsxEvent(node_id, Symbol::from(evt));
|
||||
let to = DepNode::CodeSeg(code_node_id);
|
||||
self.deps.add_edge(from, to, DepAction::ValueChange);
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn hook_code_segment(&mut self, expr: &syn::Expr) -> Symbol {
|
||||
let code_node_id = Symbol::gensym();
|
||||
|
||||
// see if we need to parse i@, e@
|
||||
let actual_expr = if let syn::Expr::Closure(syn::ExprClosure { inputs, body, .. }) = expr {
|
||||
let mut has_io = false;
|
||||
for arg in inputs.iter() {
|
||||
if let syn::Pat::Ident(syn::PatIdent { ident, subpat: Some((_, subpat)), ..} ) = arg {
|
||||
let bind = ident.to_string();
|
||||
match (bind.as_ref(), &(**subpat)) {
|
||||
("i", syn::Pat::Ident(syn::PatIdent { ident, .. })) => {
|
||||
// input variable
|
||||
// this means the code segment depends on this variable
|
||||
let sym = Symbol::from(ident.to_string());
|
||||
let from = DepNode::ModelValue(ModelValue::Leaf(sym));
|
||||
let to = DepNode::CodeSeg(code_node_id);
|
||||
self.deps.add_edge(from, to, DepAction::ValueChange);
|
||||
has_io = true;
|
||||
}
|
||||
("o", syn::Pat::Ident(syn::PatIdent { ident, .. })) => {
|
||||
// output variable
|
||||
// this means the code segment propagates updates to the variable
|
||||
let sym = Symbol::from(ident.to_string());
|
||||
let from = DepNode::CodeSeg(code_node_id);
|
||||
let to = DepNode::ModelValue(ModelValue::Leaf(sym));
|
||||
self.deps.add_edge(from, to, DepAction::ValueChange);
|
||||
has_io = true;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
if has_io {
|
||||
(**body).clone()
|
||||
} else {
|
||||
expr.clone()
|
||||
}
|
||||
} else {
|
||||
expr.clone()
|
||||
};
|
||||
|
||||
self.code_segments.insert(code_node_id, expr.clone());
|
||||
|
||||
// look for model references in the code segment
|
||||
// let names = self.get_model_names();
|
||||
// let deps = self.extract_model_dependencies_from_expr(&expr, &names);
|
||||
// for dep in deps {
|
||||
// let from = DepNode::ModelValue(ModelValue::Leaf(dep));
|
||||
// let to = DepNode::CodeSeg(code_node_id);
|
||||
// self.deps.add_edge(from, to, DepAction::ValueChange);
|
||||
// }
|
||||
|
||||
code_node_id
|
||||
}
|
||||
|
||||
pub fn make_graph(&mut self, nodes: &[Rsx]) -> Vec<TaggedRsx> {
|
||||
let mut new_nodes = Vec::new();
|
||||
for node in nodes {
|
||||
|
@ -106,26 +225,9 @@ impl Visitor {
|
|||
// Process a < /> tag
|
||||
Rsx::Elem(Elem { tag, attrs, inner }) => {
|
||||
let tag_inner = inner.as_ref().map(|inner| self.make_graph(inner));
|
||||
for (lhs, rhs) in attrs {
|
||||
// If the left-hand side contains bind:attr="name", put that attribute as a dependency of name
|
||||
if let (TagLhs::Bind(attr), TagRhs::Text(text)) = (lhs, rhs) {
|
||||
let text_sym = Symbol::from(text);
|
||||
// check if the model actually contains the key that you're trying to bind to
|
||||
if self.model.contains_key(&text_sym) {
|
||||
let attr_node = DepNode::RsxAttr(node_id, Symbol::from(attr));
|
||||
let model_node = DepNode::ModelValue(text_sym);
|
||||
self.deps.add_edge(attr_node, model_node, ());
|
||||
self.deps.add_edge(model_node, attr_node, ());
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add deps for the attributes
|
||||
self.hook_attrs(node_id, attrs);
|
||||
TaggedRsx::Elem(
|
||||
node_id,
|
||||
Elem {
|
||||
|
@ -135,13 +237,16 @@ impl Visitor {
|
|||
},
|
||||
)
|
||||
}
|
||||
// Code changes are dependent on variables within the code segment in the model
|
||||
// Every time the model changes, the code segment must re-evaluate
|
||||
Rsx::Code(expr) => {
|
||||
let syn_expr = Syn::from_adapter(&*expr);
|
||||
let deps = self.extract_model_dependencies(&syn_expr);
|
||||
let names = self.get_model_names();
|
||||
let deps = self.extract_model_dependencies_from_expr(&syn_expr, &names);
|
||||
for dep in deps {
|
||||
let from = DepNode::ModelValue(dep);
|
||||
let from = DepNode::ModelValue(ModelValue::Leaf(dep));
|
||||
let to = DepNode::RsxSpan(node_id);
|
||||
self.deps.add_edge(from, to, ());
|
||||
self.deps.add_edge(from, to, DepAction::ValueChange);
|
||||
}
|
||||
|
||||
TaggedRsx::Code(node_id, Box::new(syn_expr.clone().to_adapter()))
|
||||
|
@ -151,17 +256,41 @@ impl Visitor {
|
|||
// The for-loop should exist by itself in the dep tree
|
||||
// Everything inside the for loop is a dependency
|
||||
Rsx::ForLoop(pat, expr, inner) => {
|
||||
let syn_pat = syn::Pat::from_adapter(&pat);
|
||||
let new_inner = self.make_graph(inner.as_ref());
|
||||
|
||||
let mut names = self.get_model_names();
|
||||
names.extend(utils::get_pat_names(&syn_pat));
|
||||
|
||||
// figure out which variables in the iterator that it depends on
|
||||
// for example, [for x in y] depends on y.
|
||||
// This says that whenever something in y changes, the iterator should also change
|
||||
let syn_expr = Syn::from_adapter(&*expr);
|
||||
let deps = self.extract_model_dependencies(&syn_expr);
|
||||
for dep in deps {
|
||||
let from = DepNode::ModelValue(dep);
|
||||
let to = DepNode::Iterator(node_id);
|
||||
self.deps.add_edge(from, to, ());
|
||||
let code_node_id = self.hook_code_segment(&syn_expr);
|
||||
let from = DepNode::CodeSeg(code_node_id);
|
||||
let to = DepNode::Iterator(node_id);
|
||||
self.deps.add_edge(from, to, DepAction::ValueChange);
|
||||
|
||||
// let deps = self.extract_model_dependencies_from_expr(&syn_expr, &names);
|
||||
// for dep in deps {
|
||||
// let from = DepNode::ModelValue(ModelValue::Leaf(dep));
|
||||
// let to = DepNode::Iterator(node_id);
|
||||
// self.deps
|
||||
// .add_edge(from, to, DepAction::IndexChange(node_id));
|
||||
// }
|
||||
|
||||
// all of its children are dependencies of the iterator
|
||||
// Every time the iterator updates, the children update
|
||||
// - Using the List iterator, there's an update method that uses keys
|
||||
for child in inner {
|
||||
let deps = self.extract_rsx_dependents(&child, &names);
|
||||
println!("children: {:?} {:?} => {:?}", names, child, deps);
|
||||
let from = DepNode::Iterator(node_id);
|
||||
for dep in deps {
|
||||
self.deps.add_edge(from, dep, DepAction::ValueChange);
|
||||
}
|
||||
}
|
||||
|
||||
TaggedRsx::ForLoop(node_id, pat.clone(), expr.clone(), new_inner)
|
||||
}
|
||||
unknown => unimplemented!("unknown rsx: {:?}", unknown),
|
||||
|
@ -187,7 +316,6 @@ impl Visitor {
|
|||
while let Some(nx) = dfs.next(&self.deps) {
|
||||
if nx != starting {
|
||||
nx.gen_update_code(
|
||||
// &self.model_bimap,
|
||||
&mut updates,
|
||||
&mut update_func,
|
||||
);
|
||||
|
@ -224,11 +352,12 @@ impl Visitor {
|
|||
let expr = syn::Expr::from_adapter(expr);
|
||||
let code_id = format_ident!("code_{}", node_str);
|
||||
self.impl_code.extend(quote! {
|
||||
/// Actual code
|
||||
fn #code_id(&self) -> impl std::string::ToString {
|
||||
#expr
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Code
|
||||
fn #make_node_id(&self) -> enterprise::stdweb::web::Node {
|
||||
use enterprise::stdweb::web::IElement;
|
||||
let el = enterprise::stdweb::web::document().create_element("span").expect("shouldn't fail");
|
||||
|
@ -240,26 +369,38 @@ impl Visitor {
|
|||
}
|
||||
TaggedRsx::Text(_, literal) => {
|
||||
self.impl_code.extend(quote! {
|
||||
#[inline]
|
||||
/// Text node
|
||||
fn #make_node_id(&self) -> enterprise::stdweb::web::Node {
|
||||
let text = enterprise::widgets::Text::new(#literal);
|
||||
text.render()
|
||||
// enterprise::stdweb::web::document().create_text_node(#literal)
|
||||
}
|
||||
});
|
||||
names.push(format!("{}", make_node_id));
|
||||
}
|
||||
TaggedRsx::ForLoop(_, _, _, inner) => {
|
||||
let init_loop_id = format_ident!("init_loop_{}", node_str);
|
||||
let update_loop_id = format_ident!("update_loop_{}", node_str);
|
||||
|
||||
// Generate code for the initial creation of the loop
|
||||
let mut func_calls = TokenStream::new();
|
||||
for name in self.gen_code(&inner) {
|
||||
let name = format_ident!("{}", name);
|
||||
func_calls.extend(quote! { self.#name(); });
|
||||
func_calls.extend(quote! {
|
||||
let sub = self.#name();
|
||||
el.append_child(sub);
|
||||
});
|
||||
}
|
||||
self.impl_code.extend(quote! {
|
||||
#[inline]
|
||||
/// Initialize for-loop
|
||||
fn #init_loop_id(&self) -> enterprise::stdweb::web::Node {
|
||||
let el = enterprise::stdweb::web::document().create_element("div").expect("shouldn't fail");
|
||||
#func_calls
|
||||
el.as_node()
|
||||
}
|
||||
|
||||
/// Update for-loop
|
||||
fn #update_loop_id(&self) {
|
||||
|
||||
}
|
||||
});
|
||||
names.push(format!("{}", init_loop_id));
|
||||
|
@ -270,19 +411,67 @@ impl Visitor {
|
|||
names
|
||||
}
|
||||
|
||||
/// Get the names that exist in the model right now
|
||||
fn get_model_names(&self) -> HashSet<Symbol> {
|
||||
self.model.keys().cloned().collect()
|
||||
}
|
||||
|
||||
fn extract_rsx_dependents(&self, rsx: &Rsx, names: &HashSet<Symbol>) -> HashSet<DepNode> {
|
||||
println!(">>>>>>>>>>>>Extract rsx from {:?}", rsx);
|
||||
let mut result = HashSet::new();
|
||||
match rsx {
|
||||
Rsx::Elem(elem) => {
|
||||
if let Some(inner) = &elem.inner {
|
||||
for child in inner.iter() {
|
||||
self.extract_rsx_dependents(child, names);
|
||||
}
|
||||
}
|
||||
}
|
||||
Rsx::Code(code) => {
|
||||
let code = syn::Expr::from_adapter(code);
|
||||
let code_deps = self
|
||||
.extract_model_dependencies_from_expr(&code, names)
|
||||
.into_iter()
|
||||
.map(|sym| DepNode::ModelValue(ModelValue::Leaf(sym)))
|
||||
.collect::<HashSet<_>>();
|
||||
result.extend(code_deps);
|
||||
}
|
||||
Rsx::ForLoop(_pat, _expr, inner) => {
|
||||
for child in inner.iter() {
|
||||
self.extract_rsx_dependents(child, names);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
println!("<<<<<<<<<<<<{:?}", result);
|
||||
result
|
||||
}
|
||||
|
||||
/// This is using a really dumb heuristic
|
||||
fn extract_model_dependencies(&self, expr: &Expr) -> HashSet<Symbol> {
|
||||
fn extract_model_dependencies_from_expr(
|
||||
&self,
|
||||
expr: &Expr,
|
||||
names: &HashSet<Symbol>,
|
||||
) -> HashSet<Symbol> {
|
||||
println!("Extracting {}", expr.to_token_stream());
|
||||
let tokens = expr.to_token_stream();
|
||||
let mut result = HashSet::new();
|
||||
|
||||
for token in tokens.into_iter() {
|
||||
if let TokenTree::Ident(ident) = token {
|
||||
// if let Some(id) = self.model_bimap.get_by_right(&ident.to_string()) {
|
||||
let sym = Symbol::from(ident.to_string());
|
||||
if self.model.contains_key(&sym) {
|
||||
result.insert(sym);
|
||||
let mut queue = tokens.into_iter().collect::<VecDeque<_>>();
|
||||
while !queue.is_empty() {
|
||||
let token = queue.pop_front().unwrap();
|
||||
// for token in tokens.into_iter() {
|
||||
match token {
|
||||
TokenTree::Ident(ident) => {
|
||||
let sym = Symbol::from(ident.to_string());
|
||||
if names.contains(&sym) {
|
||||
result.insert(sym);
|
||||
}
|
||||
}
|
||||
// result.insert(format!("{}", ident));
|
||||
TokenTree::Group(group) => {
|
||||
queue.extend(group.stream().into_iter());
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
result
|
||||
|
|
|
@ -6,6 +6,7 @@ use std::io::Write;
|
|||
|
||||
use enterprise_compiler::model::Component;
|
||||
use enterprise_compiler::Visitor;
|
||||
use quote::ToTokens;
|
||||
|
||||
component! {
|
||||
component TodoMVC {
|
||||
|
@ -15,10 +16,10 @@ component! {
|
|||
}
|
||||
|
||||
view {
|
||||
<input bind:value="value" on:submit={|| { todos.push(todo); }} />
|
||||
<input bind:value="value" on:submit={|i@value, o@todos| { todos.push(value); }} />
|
||||
<ul>
|
||||
[for (key, todo) in todos]
|
||||
<li>{todo} <a on:click={|_| { todos.remove(key); }}>"[x]"</a></li>
|
||||
[for (key, line) in todos]
|
||||
<li>{line} <a on:click={|o@todos| { todos.remove(key); }}>"[x]"</a></li>
|
||||
[/for]
|
||||
</ul>
|
||||
}
|
||||
|
@ -30,14 +31,28 @@ fn main() {
|
|||
|
||||
let mut visitor = Visitor::new();
|
||||
visitor.load_model(&component.model);
|
||||
let tagged_dom = visitor.make_graph(&component.view);
|
||||
visitor.make_graph(&component.view);
|
||||
// println!("Tagged dom: {:?}", tagged_dom);
|
||||
|
||||
let toplevel_names = visitor.gen_code(&tagged_dom);
|
||||
// let toplevel_names = visitor.gen_code(&tagged_dom);
|
||||
// println!("Toplevel names: {:?}", toplevel_names);
|
||||
println!("Impl code: {}", &visitor.impl_code());
|
||||
|
||||
let dot = visitor.dot();
|
||||
{
|
||||
let mut file = File::create("graph.dot").unwrap();
|
||||
write!(file, "{:?}", dot).unwrap();
|
||||
}
|
||||
|
||||
let all_code = enterprise_compiler::build(&component);
|
||||
let mut file = File::create("ouais.rs").unwrap();
|
||||
write!(file, "{}", all_code).unwrap();
|
||||
{
|
||||
let mut file = File::create("ouais.rs").unwrap();
|
||||
write!(file, "{}", all_code).unwrap();
|
||||
}
|
||||
|
||||
println!();
|
||||
println!("Code segments:");
|
||||
for (l, r) in visitor.code_segments() {
|
||||
println!("{:?}: {}", l, r.to_token_stream());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use std::collections::HashMap;
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Index;
|
||||
|
||||
use std::ptr::NonNull;
|
||||
|
||||
|
@ -93,6 +94,13 @@ impl<T: Debug> Debug for List<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Index<Symbol> for List<T> {
|
||||
type Output = T;
|
||||
fn index(&self, key: Symbol) -> &Self::Output {
|
||||
self.get(&key).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> List<T> {
|
||||
/// Creates a new List<T>
|
||||
pub fn new() -> Self {
|
||||
|
|
Loading…
Reference in a new issue