Skip to content

Commit

Permalink
Update hvm-lang to make it compatible with hvm-core n-ary nodes.
Browse files Browse the repository at this point in the history
  • Loading branch information
FranchuFranchu committed Mar 19, 2024
1 parent 13f08ea commit 5690bee
Show file tree
Hide file tree
Showing 19 changed files with 175 additions and 122 deletions.
25 changes: 16 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 7 additions & 8 deletions src/hvmc_net/mutual_recursion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,17 +95,16 @@ impl Graph {
fn collect_refs(current: Ref, tree: &Tree, graph: &mut Graph) {
match tree {
Tree::Ref { nam } => graph.add(current, nam.clone()),
Tree::Ctr { box lft, rgt, .. } => {
if let Tree::Ref { nam } = lft {
graph.add(current.clone(), nam.clone());
Tree::Ctr { ports, .. } => {
if let Some(last) = ports.last() {
collect_refs(current, last, graph);
}
collect_refs(current, rgt, graph);
}
Tree::Op { rhs: fst, out: snd, .. } | Tree::Mat { sel: fst, ret: snd } => {
collect_refs(current.clone(), fst, graph);
collect_refs(current, snd, graph);
tree => {
for subtree in tree.children() {
collect_refs(current.clone(), subtree, graph);
}
}
Tree::Era | Tree::Num { .. } | Tree::Var { .. } => (),
}
}

Expand Down
16 changes: 6 additions & 10 deletions src/hvmc_net/prune.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,12 @@ pub fn prune_defs(book: &mut Book, entrypoint: String) {
}

fn used_defs_in_tree(tree: &Tree, used_defs: &mut HashSet<String>, to_visit: &mut Vec<String>) {
match tree {
Tree::Ref { nam } => {
if used_defs.insert(nam.clone()) {
to_visit.push(nam.clone());
}
if let Tree::Ref { nam } = tree {
if used_defs.insert(nam.clone()) {
to_visit.push(nam.clone());
}
Tree::Ctr { lft, rgt, .. } | Tree::Op { rhs: lft, out: rgt, .. } | Tree::Mat { sel: lft, ret: rgt } => {
used_defs_in_tree(lft, used_defs, to_visit);
used_defs_in_tree(rgt, used_defs, to_visit);
}
Tree::Var { .. } | Tree::Num { .. } | Tree::Era => (),
}
for subtree in tree.children() {
used_defs_in_tree(subtree, used_defs, to_visit);
}
}
30 changes: 8 additions & 22 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use builtins::create_host;
use diagnostics::{DiagnosticOrigin, Diagnostics, DiagnosticsConfig, Severity};
use hvmc::{
ast::{self, Net},
ast::Net,
dispatch_dyn_net,
host::Host,
run::{DynNet, Heap, Rewrites},
Expand Down Expand Up @@ -196,27 +196,13 @@ pub fn count_nodes<'l>(net: &'l hvmc::ast::Net) -> usize {
visit.push(r);
}
while let Some(tree) = visit.pop() {
match tree {
ast::Tree::Ctr { lft, rgt, .. } => {
count += 1;
visit.push(lft);
visit.push(rgt);
}
ast::Tree::Op { rhs, out, .. } => {
count += 1;
visit.push(rhs);
visit.push(out);
}
ast::Tree::Mat { sel, ret } => {
count += 1;
visit.push(sel);
visit.push(ret);
}
ast::Tree::Var { .. } => (),
_ => {
count += 1;
}
};
// If it is not 0-ary, then we'll count it as a node.
if tree.children().next().is_some() {
count += 1;
}
for subtree in tree.children() {
visit.push(subtree);
}
}
count
}
Expand Down
110 changes: 81 additions & 29 deletions src/net/hvmc_to_net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ fn hvmc_to_inodes(net: &Net) -> INodes {
let mut root = tree_to_inodes(&net.root, "_".to_string(), net_root, &mut n_vars);
inodes.append(&mut root);
}

// Convert all the trees forming active pairs.
for (i, (tree1, tree2)) in net.redexes.iter().enumerate() {
let tree_root = format!("a{i}");
Expand All @@ -28,25 +29,77 @@ fn hvmc_to_inodes(net: &Net) -> INodes {
inodes
}

fn tree_to_inodes(tree: &Tree, tree_root: String, net_root: &str, n_vars: &mut NodeId) -> INodes {
fn new_var(n_vars: &mut NodeId) -> String {
let new_var = format!("x{n_vars}");
*n_vars += 1;
new_var
}
fn new_var(n_vars: &mut NodeId) -> String {
let new_var = format!("x{n_vars}");
*n_vars += 1;
new_var
}

fn tree_to_inodes(tree: &Tree, tree_root: String, net_root: &str, n_vars: &mut NodeId) -> INodes {
fn process_node_subtree<'a>(
subtree: &'a Tree,
net_root: &str,
subtrees: &mut Vec<(String, &'a Tree)>,
n_vars: &mut NodeId,
) -> String {
if let Tree::Var { nam } = subtree {
if nam == net_root { "_".to_string() } else { nam.clone() }
return if nam == net_root { "_".to_string() } else { nam.clone() };
}
if let Tree::Ctr { ports, .. } = subtree {
if ports.len() == 1 {
return process_node_subtree(&ports[0], net_root, subtrees, n_vars);
}
}

let var = new_var(n_vars);
subtrees.push((var.clone(), subtree));
var
}

fn process_ctr<'a>(
inodes: &mut Vec<INode>,
lab: u16,
ports: &'a [Tree],
net_root: &str,
principal: String,
subtrees: &mut Vec<(String, &'a Tree)>,
n_vars: &mut NodeId,
) {
fn process_sub_ctr<'a>(
inodes: &mut Vec<INode>,
lab: u16,
ports: &'a [Tree],
net_root: &str,
subtrees: &mut Vec<(String, &'a Tree)>,
n_vars: &mut NodeId,
) -> String {
if ports.len() == 1 {
process_node_subtree(&ports[0], net_root, subtrees, n_vars)
} else {
let principal = new_var(n_vars);
process_ctr(inodes, lab, ports, net_root, principal.clone(), subtrees, n_vars);
principal
}
}
if ports.is_empty() {
let inner = new_var(n_vars);
inodes.push(INode { kind: Era, ports: [principal, inner.clone(), inner] });
} else if ports.len() == 1 {
subtrees.push((principal, &ports[0]));
} else {
let var = new_var(n_vars);
subtrees.push((var.clone(), subtree));
var
// build a 2-ary node
let kind = if lab == 0 {
Con { lab: None }
} else if lab == 1 {
Tup
} else if lab & 1 == 0 {
Con { lab: Some((lab as u32 >> 1) - 1) }
} else {
Dup { lab: (lab as u32 >> 1) - 1 }
};
let rgt = process_sub_ctr(inodes, lab, &ports[1 ..], net_root, subtrees, n_vars);
let lft = process_node_subtree(&ports[0], net_root, subtrees, n_vars);
inodes.push(INode { kind, ports: [principal.clone(), lft.clone(), rgt.clone()] });
}
}

Expand All @@ -58,21 +111,8 @@ fn tree_to_inodes(tree: &Tree, tree_root: String, net_root: &str, n_vars: &mut N
let var = new_var(n_vars);
inodes.push(INode { kind: Era, ports: [subtree_root, var.clone(), var] });
}
Tree::Ctr { lft, rgt, lab } => {
let lft = process_node_subtree(lft, net_root, &mut subtrees, n_vars);
let rgt = process_node_subtree(rgt, net_root, &mut subtrees, n_vars);
inodes.push(INode {
kind: if *lab == 0 {
Con { lab: None }
} else if *lab == 1 {
Tup
} else if lab & 1 == 0 {
Con { lab: Some((*lab as u32 >> 1) - 1) }
} else {
Dup { lab: (*lab as u32 >> 1) - 1 }
},
ports: [subtree_root, lft, rgt],
});
Tree::Ctr { lab, ports } => {
process_ctr(&mut inodes, *lab, ports, net_root, subtree_root, &mut subtrees, n_vars)
}
Tree::Var { .. } => unreachable!(),
Tree::Ref { nam } => {
Expand All @@ -91,11 +131,23 @@ fn tree_to_inodes(tree: &Tree, tree_root: String, net_root: &str, n_vars: &mut N
let out = process_node_subtree(out, net_root, &mut subtrees, n_vars);
inodes.push(INode { kind, ports: [subtree_root, rhs, out] });
}
Tree::Mat { sel, ret } => {
Tree::Mat { zero, succ, out } => {
let kind = Mat;
let sel = process_node_subtree(sel, net_root, &mut subtrees, n_vars);
let ret = process_node_subtree(ret, net_root, &mut subtrees, n_vars);
inodes.push(INode { kind, ports: [subtree_root, sel, ret] });
let zero = process_node_subtree(zero, net_root, &mut subtrees, n_vars);
let succ = process_node_subtree(succ, net_root, &mut subtrees, n_vars);
let sel_var = new_var(n_vars);
inodes.push(INode { kind: Con { lab: None }, ports: [sel_var.clone(), zero, succ] });
let ret = process_node_subtree(out, net_root, &mut subtrees, n_vars);
inodes.push(INode { kind, ports: [subtree_root, sel_var, ret] });
}
Tree::Adt { .. } => {
// FIXME: hvm-core will implement a desugaring pass
// that will handle desugaring Adts nodes for us.
// It doesn't yet do this. However, we aren't creating Adt nodes
// either, so it's impossible for this to happen.

// should have been desugared earlier
unreachable!()
}
}
}
Expand Down
40 changes: 28 additions & 12 deletions src/net/net_to_hvmc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,24 +51,32 @@ fn net_tree_to_hvmc_tree(inet: &INet, tree_root: NodeId, port_to_var_id: &mut Ha
NodeKind::Era => Tree::Era,
NodeKind::Con { lab: None } => Tree::Ctr {
lab: 0,
lft: Box::new(var_or_subtree(inet, Port(tree_root, 1), port_to_var_id)),
rgt: Box::new(var_or_subtree(inet, Port(tree_root, 2), port_to_var_id)),
ports: vec![
var_or_subtree(inet, Port(tree_root, 1), port_to_var_id),
var_or_subtree(inet, Port(tree_root, 2), port_to_var_id),
],
},
NodeKind::Tup => Tree::Ctr {
lab: 1,
lft: Box::new(var_or_subtree(inet, Port(tree_root, 1), port_to_var_id)),
rgt: Box::new(var_or_subtree(inet, Port(tree_root, 2), port_to_var_id)),
ports: vec![
var_or_subtree(inet, Port(tree_root, 1), port_to_var_id),
var_or_subtree(inet, Port(tree_root, 2), port_to_var_id),
],
},
NodeKind::Con { lab: Some(lab) } => Tree::Ctr {
#[allow(clippy::identity_op)]
lab: (*lab as u16 + 1) << 1 | 0,
lft: Box::new(var_or_subtree(inet, Port(tree_root, 1), port_to_var_id)),
rgt: Box::new(var_or_subtree(inet, Port(tree_root, 2), port_to_var_id)),
ports: vec![
var_or_subtree(inet, Port(tree_root, 1), port_to_var_id),
var_or_subtree(inet, Port(tree_root, 2), port_to_var_id),
],
},
NodeKind::Dup { lab } => Tree::Ctr {
lab: (*lab as u16 + 1) << 1 | 1,
lft: Box::new(var_or_subtree(inet, Port(tree_root, 1), port_to_var_id)),
rgt: Box::new(var_or_subtree(inet, Port(tree_root, 2), port_to_var_id)),
ports: vec![
var_or_subtree(inet, Port(tree_root, 1), port_to_var_id),
var_or_subtree(inet, Port(tree_root, 2), port_to_var_id),
],
},
NodeKind::Ref { def_name } => Tree::Ref { nam: def_name.to_string() },
NodeKind::Num { val } => Tree::Num { val: *val },
Expand All @@ -77,10 +85,18 @@ fn net_tree_to_hvmc_tree(inet: &INet, tree_root: NodeId, port_to_var_id: &mut Ha
rhs: Box::new(var_or_subtree(inet, Port(tree_root, 1), port_to_var_id)),
out: Box::new(var_or_subtree(inet, Port(tree_root, 2), port_to_var_id)),
},
NodeKind::Mat => Tree::Mat {
sel: Box::new(var_or_subtree(inet, Port(tree_root, 1), port_to_var_id)),
ret: Box::new(var_or_subtree(inet, Port(tree_root, 2), port_to_var_id)),
},
NodeKind::Mat => {
let node = inet.node(inet.enter_port(Port(tree_root, 1)).node());
if node.kind != (NodeKind::Con { lab: None }) {
panic!("hvm-lang produced an INet where the first port is not a Con node. This is not supported.");
}

Tree::Mat {
zero: Box::new(var_or_subtree(inet, inet.enter_port(node.aux1), port_to_var_id)),
succ: Box::new(var_or_subtree(inet, inet.enter_port(node.aux2), port_to_var_id)),
out: Box::new(var_or_subtree(inet, Port(tree_root, 2), port_to_var_id)),
}
}
NodeKind::Rot => unreachable!(),
}
}
Expand Down
6 changes: 5 additions & 1 deletion tests/snapshots/cli__debug_u60_to_nat.hvm.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ input_file: tests/golden_tests/cli/debug_u60_to_nat.hvm
---
a (U60ToNat a) 4)
---------------------------------------
(U60ToNat 4)
a match a { 0: Z; 1+b: (S (U60ToNat b)) } 4)
---------------------------------------
match 4 { 0: Z; 1+a: (S (U60ToNat a)) }
---------------------------------------
a λb (S (U60ToNat b)) * 3)
---------------------------------------
a (S (U60ToNat a)) 3)
---------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
source: tests/golden_tests.rs
input_file: tests/golden_tests/compile_file/implicit_match_in_match_arg.hvm
---
@main = (?<(#0 (a a)) ?<(#0 (b b)) c>> c)
@main = (?<#0 (a a) ?<#0 (b b) c>> c)
Loading

0 comments on commit 5690bee

Please sign in to comment.