bend/hvm/
add_recursive_priority.rs1use super::tree_children;
2use crate::maybe_grow;
3use hvm::ast::{Book, Net, Tree};
4use std::collections::{HashMap, HashSet};
5
6pub fn add_recursive_priority(book: &mut Book) {
7 let deps = book.defs.iter().map(|(nam, net)| (nam.clone(), dependencies(net))).collect::<HashMap<_, _>>();
9 let cycles = cycles(&deps);
11
12 for cycle in cycles {
13 for i in 0..cycle.len() {
16 let cur = book.defs.get_mut(&cycle[i]).unwrap();
17 let nxt = &cycle[(i + 1) % cycle.len()];
18 add_priority_next_in_cycle(cur, nxt);
19 }
20 }
21}
22
23fn add_priority_next_in_cycle(net: &mut Net, nxt: &String) {
24 let mut count = 0;
25
26 for (_, a, b) in net.rbag.iter() {
28 if let Tree::Ref { nam } = a {
29 if nam == nxt {
30 count += 1;
31 }
32 }
33 if let Tree::Ref { nam } = b {
34 if nam == nxt {
35 count += 1;
36 }
37 }
38 }
39
40 if count > 1 {
42 for (pri, a, b) in net.rbag.iter_mut().rev() {
43 if let Tree::Ref { nam } = a {
44 if nam == nxt {
45 *pri = true;
46 }
47 }
48 if let Tree::Ref { nam } = b {
49 if nam == nxt {
50 *pri = true;
51 }
52 }
53 }
54 }
55}
56
57type DepGraph = HashMap<String, HashSet<String>>;
58type Cycles = Vec<Vec<String>>;
59
60pub fn cycles(deps: &DepGraph) -> Cycles {
62 let mut cycles = vec![];
63 let mut stack = vec![];
64 let mut visited = HashSet::new();
65 for nam in deps.keys() {
66 if !visited.contains(nam) {
67 find_cycles(deps, nam, &mut visited, &mut stack, &mut cycles);
68 }
69 }
70 cycles
71}
72
73fn find_cycles(
74 deps: &DepGraph,
75 nam: &String,
76 visited: &mut HashSet<String>,
77 stack: &mut Vec<String>,
78 cycles: &mut Cycles,
79) {
80 maybe_grow(|| {
81 if let Some(cycle_start) = stack.iter().position(|n| n == nam) {
83 cycles.push(stack[cycle_start..].to_vec());
85 return;
86 }
87 if visited.insert(nam.clone()) {
89 stack.push(nam.clone());
91 if let Some(dependencies) = deps.get(nam) {
93 for dep in dependencies {
95 find_cycles(deps, dep, visited, stack, cycles);
96 }
97 }
98 stack.pop();
99 }
100 })
101}
102
103fn dependencies(net: &Net) -> HashSet<String> {
105 let mut deps = HashSet::new();
106 dependencies_tree(&net.root, &mut deps);
107 for (_, a, b) in &net.rbag {
108 dependencies_tree(a, &mut deps);
109 dependencies_tree(b, &mut deps);
110 }
111 deps
112}
113
114fn dependencies_tree(tree: &Tree, deps: &mut HashSet<String>) {
115 if let Tree::Ref { nam, .. } = tree {
116 deps.insert(nam.clone());
117 } else {
118 for subtree in tree_children(tree) {
119 dependencies_tree(subtree, deps);
120 }
121 }
122}