bend/net/
hvm_to_net.rs

1use super::{INet, INode, INodes, NodeId, NodeKind::*, Port, SlotId, ROOT};
2use crate::{
3  fun::Name,
4  net::{CtrKind, NodeKind},
5};
6use hvm::ast::{Net, Tree};
7
8pub fn hvm_to_net(net: &Net) -> INet {
9  let inodes = hvm_to_inodes(net);
10  inodes_to_inet(&inodes)
11}
12
13fn hvm_to_inodes(net: &Net) -> INodes {
14  let mut inodes = vec![];
15  let mut n_vars = 0;
16  let net_root = if let Tree::Var { nam } = &net.root { nam } else { "" };
17
18  // If we have a tree attached to the net root, convert that first
19  if !matches!(&net.root, Tree::Var { .. }) {
20    let mut root = tree_to_inodes(&net.root, "_".to_string(), net_root, &mut n_vars);
21    inodes.append(&mut root);
22  }
23
24  // Convert all the trees forming active pairs.
25  for (i, (_, tree1, tree2)) in net.rbag.iter().enumerate() {
26    // This name cannot appear anywhere in the original net
27    let tree_root = format!("%a{i}");
28    let mut tree1 = tree_to_inodes(tree1, tree_root.clone(), net_root, &mut n_vars);
29    inodes.append(&mut tree1);
30    let mut tree2 = tree_to_inodes(tree2, tree_root, net_root, &mut n_vars);
31    inodes.append(&mut tree2);
32  }
33  inodes
34}
35
36fn new_var(n_vars: &mut NodeId) -> String {
37  // This name cannot appear anywhere in the original net
38  let new_var = format!("%x{n_vars}");
39  *n_vars += 1;
40  new_var
41}
42
43fn tree_to_inodes(tree: &Tree, tree_root: String, net_root: &str, n_vars: &mut NodeId) -> INodes {
44  fn process_node_subtree<'a>(
45    subtree: &'a Tree,
46    net_root: &str,
47    subtrees: &mut Vec<(String, &'a Tree)>,
48    n_vars: &mut NodeId,
49  ) -> String {
50    if let Tree::Var { nam } = subtree {
51      if nam == net_root {
52        "_".to_string()
53      } else {
54        nam.clone()
55      }
56    } else {
57      let var = new_var(n_vars);
58      subtrees.push((var.clone(), subtree));
59      var
60    }
61  }
62
63  let mut inodes = vec![];
64  let mut subtrees = vec![(tree_root, tree)];
65  while let Some((subtree_root, subtree)) = subtrees.pop() {
66    match subtree {
67      Tree::Era => {
68        let var = new_var(n_vars);
69        inodes.push(INode { kind: Era, ports: [subtree_root, var.clone(), var] });
70      }
71      Tree::Con { fst, snd } => {
72        let kind = NodeKind::Ctr(CtrKind::Con(None));
73        let fst = process_node_subtree(fst, net_root, &mut subtrees, n_vars);
74        let snd = process_node_subtree(snd, net_root, &mut subtrees, n_vars);
75        inodes.push(INode { kind, ports: [subtree_root, fst, snd] });
76      }
77      Tree::Dup { fst, snd } => {
78        let kind = NodeKind::Ctr(CtrKind::Dup(0));
79        let fst = process_node_subtree(fst, net_root, &mut subtrees, n_vars);
80        let snd = process_node_subtree(snd, net_root, &mut subtrees, n_vars);
81        inodes.push(INode { kind, ports: [subtree_root, fst, snd] });
82      }
83      Tree::Var { .. } => unreachable!(),
84      Tree::Ref { nam } => {
85        let kind = Ref { def_name: Name::new(nam) };
86        let var = new_var(n_vars);
87        inodes.push(INode { kind, ports: [subtree_root, var.clone(), var] });
88      }
89      Tree::Num { val } => {
90        let kind = Num { val: val.0 };
91        let var = new_var(n_vars);
92        inodes.push(INode { kind, ports: [subtree_root, var.clone(), var] });
93      }
94      Tree::Opr { fst, snd } => {
95        let kind = NodeKind::Opr;
96        let fst = process_node_subtree(fst, net_root, &mut subtrees, n_vars);
97        let snd = process_node_subtree(snd, net_root, &mut subtrees, n_vars);
98        inodes.push(INode { kind, ports: [subtree_root, fst, snd] });
99      }
100      Tree::Swi { fst, snd } => {
101        let kind = NodeKind::Swi;
102        let fst = process_node_subtree(fst, net_root, &mut subtrees, n_vars);
103        let snd = process_node_subtree(snd, net_root, &mut subtrees, n_vars);
104        inodes.push(INode { kind, ports: [subtree_root, fst, snd] });
105      }
106    }
107  }
108  inodes
109}
110
111// Converts INodes to an INet by linking ports based on names.
112fn inodes_to_inet(inodes: &INodes) -> INet {
113  let mut inet = INet::new();
114  // Maps named inode ports to numeric inet ports.
115  let mut name_map = std::collections::HashMap::new();
116
117  for inode in inodes {
118    let node = inet.new_node(inode.kind.clone());
119    for (j, name) in inode.ports.iter().enumerate() {
120      let p = Port(node, j as SlotId);
121      if name == "_" {
122        inet.link(p, ROOT);
123      } else if let Some(&q) = name_map.get(name) {
124        inet.link(p, q);
125        name_map.remove(name);
126      } else {
127        name_map.insert(name.clone(), p);
128      }
129    }
130  }
131
132  inet
133}