Skip to content

Commit

Permalink
Some tweaks. Add test for with_argument.
Browse files Browse the repository at this point in the history
  • Loading branch information
FranchuFranchu committed Feb 27, 2024
1 parent 1302081 commit 36ef219
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 40 deletions.
80 changes: 52 additions & 28 deletions src/util.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::run::Rewrites;
use crate::{
ast::{Net, Tree},
run::Rewrites,
};
use std::time::Duration;

/// Creates a variable uniquely identified by `id`.
Expand All @@ -15,6 +18,7 @@ pub(crate) fn create_var(mut id: usize) -> String {
}

/// Inverse function of [`create_var`].
///
/// Returns None when the provided string is not an output of
/// `create_var`.
pub fn var_to_num(s: &str) -> Option<usize> {
Expand Down Expand Up @@ -151,44 +155,64 @@ macro_rules! deref {
};
}

impl crate::ast::Net {
/// Transforms the net `x & ...` into `y & x ~ (arg y) & ...`
pub fn with_argument(&mut self, arg: crate::ast::Tree) {
use crate::ast::Tree;
let mut fresh = 0usize;
fn ensure_no_conflicts(tree: &Tree, fresh: &mut usize) {
match tree {
Tree::Ctr { lft, rgt, .. } | Tree::Op2 { lft, rgt, .. } | Tree::Mat { sel: lft, ret: rgt } => {
ensure_no_conflicts(lft, fresh);
ensure_no_conflicts(rgt, fresh);
}
Tree::Op1 { rgt, .. } => {
ensure_no_conflicts(rgt, fresh);
}
Tree::Var { nam } => {
if let Some(var_num) = var_to_num(nam) {
*fresh = (*fresh).max(var_num);
}
pub(crate) use deref;

impl Tree {
/// Increases `fresh` until `create_var(*fresh)` does not conflict
/// with a [`Tree::Var`] in `tree`
///
/// This function can be called multiple times with many trees to
/// ensure that `fresh` does not conflict with any of them.
pub(crate) fn ensure_no_conflicts(&self, fresh: &mut usize) {
match self {
Tree::Var { nam } => {
if let Some(var_num) = var_to_num(nam) {
*fresh = (*fresh).max(var_num);
}
_ => (),
}
// Recurse on children
Tree::Ctr { lft, rgt, .. } | Tree::Op2 { lft, rgt, .. } | Tree::Mat { sel: lft, ret: rgt } => {
lft.ensure_no_conflicts(fresh);
rgt.ensure_no_conflicts(fresh);
}
Tree::Op1 { rgt, .. } => {
rgt.ensure_no_conflicts(fresh);
}
Tree::Era => (),
Tree::Num { .. } => (),
Tree::Ref { .. } => (),
}
ensure_no_conflicts(&self.root, &mut fresh);
for (l, r) in &self.rdex {
ensure_no_conflicts(l, &mut fresh);
ensure_no_conflicts(r, &mut fresh);
}
}

impl Net {
pub(crate) fn ensure_no_conflicts(&self, fresh: &mut usize) {
self.root.ensure_no_conflicts(fresh);
for (a, b) in &self.rdex {
a.ensure_no_conflicts(fresh);
b.ensure_no_conflicts(fresh);
}
}
/// Transforms the net `x & ...` into `y & x ~ (arg y) & ...`
///
/// The result is equivalent a λ-calculus application. Thus,
/// if the net is a λ-calculus term, then this function will
/// apply an argument to it.
#[allow(dead_code)] // used in tests
pub(crate) fn with_argument(&mut self, arg: Tree) {
let mut fresh = 0usize;
self.ensure_no_conflicts(&mut fresh);
arg.ensure_no_conflicts(&mut fresh);

let fresh_str = create_var(fresh + 1);

let fun = core::mem::take(&mut self.root);
let oth = Tree::Ctr { lab: 0, lft: Box::new(arg), rgt: Box::new(Tree::Var { nam: fresh_str.clone() }) };
let app = Tree::Ctr { lab: 0, lft: Box::new(arg), rgt: Box::new(Tree::Var { nam: fresh_str.clone() }) };
self.root = Tree::Var { nam: fresh_str };
self.rdex.push((fun, oth));
self.rdex.push((fun, app));
}
}

pub(crate) use deref;

pub fn show_rewrites(rwts: &Rewrites) -> String {
format!(
"{}{}{}{}{}{}",
Expand Down
59 changes: 59 additions & 0 deletions tests/api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//! Tests for front-facing APIs and interfaces
use hvmc::{
ast::{Book, Net, Tree},
host::Host,
};
use insta::assert_display_snapshot;

#[test]
fn test_with_argument() {
use hvmc::run;
fn eval_with_args(fun: &str, args: &[&str]) -> Net {
let area = run::Net::<run::Strict>::init_heap(1 << 10);

let mut fun: Net = fun.parse().unwrap();
for arg in args {
let arg: Tree = arg.parse().unwrap();
fun.with_argument(arg)
}
// TODO: When feature/sc-472/argument-passing, use encode_net instead.
let mut book = Book::default();
book.nets.insert("main".into(), fun);
let host = Host::new(&book);

let mut rnet = run::Net::<run::Strict>::new(&area);
rnet.boot(&host.defs["main"]);
rnet.normal();
let got_result = host.readback(&rnet);
got_result
}
assert_display_snapshot!(
eval_with_args("(a a)", &vec!["(a a)"]),
@"(a a)"
);
assert_display_snapshot!(
eval_with_args("b & (a b) ~ a", &vec!["(a a)"]),
@"a"
);
assert_display_snapshot!(
eval_with_args("(z0 z0)", &vec!["(z1 z1)"]),
@"(a a)"
);
assert_display_snapshot!(
eval_with_args("(* #1)", &vec!["(a a)"]),
@"#1"
);
assert_display_snapshot!(
eval_with_args("(<+ a b> (a b))", &vec!["#1", "#2"]),
@"#3"
);
assert_display_snapshot!(
eval_with_args("(<* a b> (a b))", &vec!["#2", "#3"]),
@"#6"
);
assert_display_snapshot!(
eval_with_args("(<* a b> (a b))", &vec!["#2"]),
@"(<2* a> a)"
);
}
8 changes: 4 additions & 4 deletions tests/lists.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ fn list_got(index: u32) -> Book {
let code = load_file("list_put_got.hvmc");
let mut book = parse_core(&code);
println!("{:#?}", book.keys().collect::<Vec<_>>());
let mut def = book.get_mut("GenGotIndex").unwrap();
core_apply(&mut def, hvmc::ast::Tree::Ref { nam: format!("S{index}") });
let mut def = book.get_mut("main").unwrap();
core_apply(&mut def, hvmc::ast::Tree::Ref { nam: format!("GenGotIndex") });
let def = book.get_mut("GenGotIndex").unwrap();
def.with_argument(hvmc::ast::Tree::Ref { nam: format!("S{index}") });
let def = book.get_mut("main").unwrap();
def.with_argument(hvmc::ast::Tree::Ref { nam: format!("GenGotIndex") });
book
}

Expand Down
8 changes: 0 additions & 8 deletions tests/loaders/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,6 @@ pub fn load_file(file: &str) -> String {
fs::read_to_string(path).unwrap()
}

pub fn core_apply(net: &mut Net, arg: Tree) {
let fun = core::mem::take(&mut net.root);
let var = format!("$_TEST_APP{:p}", net);
let oth = Tree::Ctr { lab: 0, lft: Box::new(arg), rgt: Box::new(Tree::Var { nam: var.clone() }) };
net.root = Tree::Var { nam: var };
net.rdex.push((fun, oth));
}

// Parses code and generate Book from hvm-core syntax
pub fn parse_core(code: &str) -> Book {
code.parse().unwrap()
Expand Down

0 comments on commit 36ef219

Please sign in to comment.