mirror of
https://github.com/HigherOrderCO/Bend.git
synced 2024-09-17 14:47:21 +03:00
Merge pull request #539 from HigherOrderCO/dont-expand-recursive-generated-functions
Dont expand generated recursive definitions
This commit is contained in:
commit
19d7972a4a
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -62,7 +62,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bend-lang"
|
name = "bend-lang"
|
||||||
version = "0.2.29"
|
version = "0.2.30"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"TSPL",
|
"TSPL",
|
||||||
"clap",
|
"clap",
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
name = "bend-lang"
|
name = "bend-lang"
|
||||||
description = "A high-level, massively parallel programming language"
|
description = "A high-level, massively parallel programming language"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
version = "0.2.29"
|
version = "0.2.30"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.74"
|
rust-version = "1.74"
|
||||||
exclude = ["tests/"]
|
exclude = ["tests/"]
|
||||||
|
@ -1,24 +1,106 @@
|
|||||||
|
use std::collections::{BTreeSet, HashMap, HashSet};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
fun::{Book, Term},
|
fun::{Book, Name, Term},
|
||||||
maybe_grow,
|
maybe_grow,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Dereferences any generated definitions in the term.
|
/// Dereferences any non recursive generated definitions in the term.
|
||||||
/// Used after readback.
|
/// Used after readback.
|
||||||
impl Term {
|
impl Term {
|
||||||
pub fn expand_generated(&mut self, book: &Book) {
|
pub fn expand_generated(&mut self, book: &Book, recursive_defs: &RecursiveDefs) {
|
||||||
maybe_grow(|| {
|
maybe_grow(|| {
|
||||||
if let Term::Ref { nam } = &*self {
|
if let Term::Ref { nam } = &*self {
|
||||||
if nam.is_generated() {
|
if nam.is_generated() && !recursive_defs.contains(nam) {
|
||||||
*self = book.defs.get(nam).unwrap().rule().body.clone();
|
*self = book.defs.get(nam).unwrap().rule().body.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: this assumes that there will never be a loop of generated functions.
|
|
||||||
// This is true right now, but not necessarily in the future.
|
|
||||||
for child in self.children_mut() {
|
for child in self.children_mut() {
|
||||||
child.expand_generated(book);
|
child.expand_generated(book, recursive_defs);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DepGraph = HashMap<Name, HashSet<Name>>;
|
||||||
|
type Cycles = Vec<Vec<Name>>;
|
||||||
|
type RecursiveDefs = BTreeSet<Name>;
|
||||||
|
|
||||||
|
impl Book {
|
||||||
|
pub fn recursive_defs(&self) -> RecursiveDefs {
|
||||||
|
let mut cycle_map = BTreeSet::new();
|
||||||
|
let deps = book_def_deps(self);
|
||||||
|
let cycles = cycles(&deps);
|
||||||
|
|
||||||
|
for cycle in cycles {
|
||||||
|
for name in cycle {
|
||||||
|
cycle_map.insert(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cycle_map
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Find all cycles in the dependency graph.
|
||||||
|
fn cycles(deps: &DepGraph) -> Cycles {
|
||||||
|
let mut cycles = vec![];
|
||||||
|
let mut visited = HashSet::new();
|
||||||
|
// let mut stack = vec![];
|
||||||
|
for nam in deps.keys() {
|
||||||
|
if !visited.contains(nam) {
|
||||||
|
find_cycles(deps, nam, &mut visited, &mut cycles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cycles
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_cycles(deps: &DepGraph, nam: &Name, visited: &mut HashSet<Name>, cycles: &mut Cycles) {
|
||||||
|
let mut stack = vec![(nam.clone(), vec![])];
|
||||||
|
while let Some((current, path)) = stack.pop() {
|
||||||
|
if visited.contains(¤t) {
|
||||||
|
// Check if the current ref is already in the stack, which indicates a cycle.
|
||||||
|
if let Some(cycle_start) = path.iter().position(|n| n == ¤t) {
|
||||||
|
// If found, add the cycle to the cycles vector.
|
||||||
|
cycles.push(path[cycle_start..].to_vec());
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the ref has not been visited yet, mark it as visited.
|
||||||
|
visited.insert(current.clone());
|
||||||
|
// Add the current ref to the stack to keep track of the path.
|
||||||
|
let mut new_path = path.clone();
|
||||||
|
new_path.push(current.clone());
|
||||||
|
|
||||||
|
// Search for cycles from each dependency.
|
||||||
|
if let Some(deps) = deps.get(¤t) {
|
||||||
|
for dep in deps {
|
||||||
|
stack.push((dep.clone(), new_path.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn book_def_deps(book: &Book) -> DepGraph {
|
||||||
|
book.defs.iter().map(|(nam, def)| (nam.clone(), def_deps(def))).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn def_deps(def: &crate::fun::Definition) -> HashSet<Name> {
|
||||||
|
fn collect_refs(term: &Term, set: &mut HashSet<Name>) {
|
||||||
|
if let Term::Ref { nam } = term {
|
||||||
|
set.insert(nam.clone());
|
||||||
|
}
|
||||||
|
for children in term.children() {
|
||||||
|
collect_refs(children, set);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut set = HashSet::new();
|
||||||
|
let term = &def.rule().body;
|
||||||
|
|
||||||
|
collect_refs(term, &mut set);
|
||||||
|
|
||||||
|
set
|
||||||
|
}
|
||||||
|
@ -191,7 +191,8 @@ pub fn readback_hvm_net(
|
|||||||
let mut diags = Diagnostics::default();
|
let mut diags = Diagnostics::default();
|
||||||
let net = hvm_to_net(net);
|
let net = hvm_to_net(net);
|
||||||
let mut term = net_to_term(&net, book, labels, linear, &mut diags);
|
let mut term = net_to_term(&net, book, labels, linear, &mut diags);
|
||||||
term.expand_generated(book);
|
let recursive_cycles = book.recursive_defs();
|
||||||
|
term.expand_generated(book, &recursive_cycles);
|
||||||
term.resugar_strings(adt_encoding);
|
term.resugar_strings(adt_encoding);
|
||||||
term.resugar_lists(adt_encoding);
|
term.resugar_lists(adt_encoding);
|
||||||
(term, diags)
|
(term, diags)
|
||||||
|
Loading…
Reference in New Issue
Block a user