first kind2-hvm2 program run! sum-tree via fold

This commit is contained in:
Victor Taelin 2024-03-15 23:06:44 -03:00
parent 70288ef011
commit 9201bebc01
36 changed files with 180 additions and 3498 deletions

1
.gitignore vendored
View File

@ -9,3 +9,4 @@ demo/
.check.hs
guide.txt
.hvm
.hvm/

16
book/.hvm/Cargo.lock generated
View File

@ -1,16 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "hvm-core"
version = "0.2.18"
dependencies = [
"nohash-hasher",
]
[[package]]
name = "nohash-hasher"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"

View File

@ -1,31 +0,0 @@
[package]
name = "hvm-core"
version = "0.2.18"
edition = "2021"
description = "HVM-Core is a massively parallel Interaction Combinator evaluator."
license = "MIT"
[[bin]]
name = "hvmc"
path = "src/main.rs"
bench = false
[lib]
name = "hvmc"
path = "src/lib.rs"
bench = false
[profile.release]
codegen-units = 1
lto = "fat"
opt-level = 3
panic = "abort"
[features]
default = []
hvm_cli_options = []
lazy_mode = []
[dependencies]
nohash-hasher = "0.2.0"

View File

@ -1,799 +0,0 @@
// An interaction combinator language
// ----------------------------------
// This file implements a textual syntax to interact with the runtime. It includes a pure AST for
// nets, as well as functions for parsing, stringifying, and converting pure ASTs to runtime nets.
// On the runtime, a net is represented by a list of active trees, plus a root tree. The textual
// syntax reflects this representation. The grammar is specified on this repo's README.
use crate::run;
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::collections::HashSet;
use std::iter::Peekable;
use std::str::Chars;
// AST
// ---
#[derive(Clone, Hash, PartialEq, Eq, Debug)]
pub enum Tree {
Era,
Con { lft: Box<Tree>, rgt: Box<Tree> },
Tup { lft: Box<Tree>, rgt: Box<Tree> },
Dup { lab: run::Lab, lft: Box<Tree>, rgt: Box<Tree> },
Var { nam: String },
Ref { nam: run::Val },
Num { val: run::Val },
Op1 { opr: run::Lab, lft: run::Val, rgt: Box<Tree> },
Op2 { opr: run::Lab, lft: Box<Tree>, rgt: Box<Tree> },
Mat { sel: Box<Tree>, ret: Box<Tree> },
}
type Redex = Vec<(Tree, Tree)>;
#[derive(Clone, Hash, PartialEq, Eq, Debug)]
pub struct Net {
pub root: Tree,
pub rdex: Redex,
}
pub type Book = BTreeMap<String, Net>;
// Parser
// ------
// FIXME: remove after skip is fixed
fn skip_spaces(chars: &mut Peekable<Chars>) {
while let Some(c) = chars.peek() {
if !c.is_ascii_whitespace() {
break;
} else {
chars.next();
}
}
}
// FIXME: detect two '/' for comments, allowing us to remove 'skip_spaces'
fn skip(chars: &mut Peekable<Chars>) {
while let Some(c) = chars.peek() {
if *c == '/' {
chars.next();
while let Some(c) = chars.peek() {
if *c == '\n' {
break;
}
chars.next();
}
} else if !c.is_ascii_whitespace() {
break;
} else {
chars.next();
}
}
}
pub fn consume(chars: &mut Peekable<Chars>, text: &str) -> Result<(), String> {
skip(chars);
for c in text.chars() {
if chars.next() != Some(c) {
return Err(format!("Expected '{}', found {:?}", text, chars.peek()));
}
}
return Ok(());
}
pub fn parse_decimal(chars: &mut Peekable<Chars>) -> Result<u64, String> {
let mut num: u64 = 0;
skip(chars);
if !chars.peek().map_or(false, |c| c.is_digit(10)) {
return Err(format!("Expected a decimal number, found {:?}", chars.peek()));
}
while let Some(c) = chars.peek() {
if !c.is_digit(10) {
break;
}
num = num * 10 + c.to_digit(10).unwrap() as u64;
chars.next();
}
Ok(num)
}
pub fn parse_name(chars: &mut Peekable<Chars>) -> Result<String, String> {
let mut txt = String::new();
skip(chars);
if !chars.peek().map_or(false, |c| c.is_alphanumeric() || *c == '_' || *c == '.') {
return Err(format!("Expected a name character, found {:?}", chars.peek()))
}
while let Some(c) = chars.peek() {
if !c.is_alphanumeric() && *c != '_' && *c != '.' {
break;
}
txt.push(*c);
chars.next();
}
Ok(txt)
}
pub fn parse_opx_lit(chars: &mut Peekable<Chars>) -> Result<String, String> {
let mut opx = String::new();
skip_spaces(chars);
while let Some(c) = chars.peek() {
if !"+-=*/%<>|&^!?".contains(*c) {
break;
}
opx.push(*c);
chars.next();
}
Ok(opx)
}
fn parse_opr(chars: &mut Peekable<Chars>) -> Result<run::Lab, String> {
let opx = parse_opx_lit(chars)?;
match opx.as_str() {
"+" => Ok(run::ADD),
"-" => Ok(run::SUB),
"*" => Ok(run::MUL),
"/" => Ok(run::DIV),
"%" => Ok(run::MOD),
"==" => Ok(run::EQ),
"!=" => Ok(run::NE),
"<" => Ok(run::LT),
">" => Ok(run::GT),
"<=" => Ok(run::LTE),
">=" => Ok(run::GTE),
"&&" => Ok(run::AND),
"||" => Ok(run::OR),
"^" => Ok(run::XOR),
"!" => Ok(run::NOT),
"<<" => Ok(run::LSH),
">>" => Ok(run::RSH),
_ => Err(format!("Unknown operator: {}", opx)),
}
}
pub fn parse_tree(chars: &mut Peekable<Chars>) -> Result<Tree, String> {
skip(chars);
match chars.peek() {
Some('*') => {
chars.next();
Ok(Tree::Era)
}
Some('(') => {
chars.next();
let lft = Box::new(parse_tree(chars)?);
let rgt = Box::new(parse_tree(chars)?);
consume(chars, ")")?;
Ok(Tree::Con { lft, rgt })
}
Some('[') => {
chars.next();
let lab = 1;
let lft = Box::new(parse_tree(chars)?);
let rgt = Box::new(parse_tree(chars)?);
consume(chars, "]")?;
Ok(Tree::Tup { lft, rgt })
}
Some('{') => {
chars.next();
let lab = parse_decimal(chars)? as run::Lab;
let lft = Box::new(parse_tree(chars)?);
let rgt = Box::new(parse_tree(chars)?);
consume(chars, "}")?;
Ok(Tree::Dup { lab, lft, rgt })
}
Some('@') => {
chars.next();
skip(chars);
let name = parse_name(chars)?;
Ok(Tree::Ref { nam: name_to_val(&name) })
}
Some('#') => {
chars.next();
Ok(Tree::Num { val: parse_decimal(chars)? })
}
Some('<') => {
chars.next();
if chars.peek().map_or(false, |c| c.is_digit(10)) {
let lft = parse_decimal(chars)?;
let opr = parse_opr(chars)?;
let rgt = Box::new(parse_tree(chars)?);
consume(chars, ">")?;
Ok(Tree::Op1 { opr, lft, rgt })
} else {
let opr = parse_opr(chars)?;
let lft = Box::new(parse_tree(chars)?);
let rgt = Box::new(parse_tree(chars)?);
consume(chars, ">")?;
Ok(Tree::Op2 { opr, lft, rgt })
}
}
Some('?') => {
chars.next();
consume(chars, "<")?;
let sel = Box::new(parse_tree(chars)?);
let ret = Box::new(parse_tree(chars)?);
consume(chars, ">")?;
Ok(Tree::Mat { sel, ret })
}
_ => {
Ok(Tree::Var { nam: parse_name(chars)? })
},
}
}
pub fn parse_net(chars: &mut Peekable<Chars>) -> Result<Net, String> {
let mut rdex = Vec::new();
let root = parse_tree(chars)?;
while let Some(c) = { skip(chars); chars.peek() } {
if *c == '&' {
chars.next();
let tree1 = parse_tree(chars)?;
consume(chars, "~")?;
let tree2 = parse_tree(chars)?;
rdex.push((tree1, tree2));
} else {
break;
}
}
Ok(Net { root, rdex })
}
pub fn parse_book(chars: &mut Peekable<Chars>) -> Result<Book, String> {
let mut book = BTreeMap::new();
while let Some(c) = { skip(chars); chars.peek() } {
if *c == '@' {
chars.next();
let name = parse_name(chars)?;
consume(chars, "=")?;
let net = parse_net(chars)?;
book.insert(name, net);
} else {
break;
}
}
Ok(book)
}
fn do_parse<T>(code: &str, parse_fn: impl Fn(&mut Peekable<Chars>) -> Result<T, String>) -> T {
let chars = &mut code.chars().peekable();
match parse_fn(chars) {
Ok(result) => {
if chars.next().is_none() {
result
} else {
eprintln!("Unable to parse the whole input. Is this not an hvmc file?");
std::process::exit(1);
}
}
Err(err) => {
eprintln!("{}", err);
std::process::exit(1);
}
}
}
pub fn do_parse_tree(code: &str) -> Tree {
do_parse(code, parse_tree)
}
pub fn do_parse_net(code: &str) -> Net {
do_parse(code, parse_net)
}
pub fn do_parse_book(code: &str) -> Book {
do_parse(code, parse_book)
}
// Stringifier
// -----------
pub fn show_opr(opr: run::Lab) -> String {
match opr {
run::ADD => "+".to_string(),
run::SUB => "-".to_string(),
run::MUL => "*".to_string(),
run::DIV => "/".to_string(),
run::MOD => "%".to_string(),
run::EQ => "==".to_string(),
run::NE => "!=".to_string(),
run::LT => "<".to_string(),
run::GT => ">".to_string(),
run::LTE => "<=".to_string(),
run::GTE => ">=".to_string(),
run::AND => "&&".to_string(),
run::OR => "||".to_string(),
run::XOR => "^".to_string(),
run::NOT => "!".to_string(),
run::LSH => "<<".to_string(),
run::RSH => ">>".to_string(),
_ => panic!("Unknown operator label."),
}
}
pub fn show_tree(tree: &Tree) -> String {
match tree {
Tree::Era => {
"*".to_string()
}
Tree::Con { lft, rgt } => {
format!("({} {})", show_tree(&*lft), show_tree(&*rgt))
}
Tree::Tup { lft, rgt } => {
format!("[{} {}]", show_tree(&*lft), show_tree(&*rgt))
}
Tree::Dup { lab, lft, rgt } => {
format!("{{{} {} {}}}", lab, show_tree(&*lft), show_tree(&*rgt))
}
Tree::Var { nam } => {
nam.clone()
}
Tree::Ref { nam } => {
format!("@{}", val_to_name(*nam))
}
Tree::Num { val } => {
format!("#{}", (*val).to_string())
}
Tree::Op1 { opr, lft, rgt } => {
format!("<{}{} {}>", lft, show_opr(*opr), show_tree(rgt))
}
Tree::Op2 { opr, lft, rgt } => {
format!("<{} {} {}>", show_opr(*opr), show_tree(&*lft), show_tree(&*rgt))
}
Tree::Mat { sel, ret } => {
format!("?<{} {}>", show_tree(&*sel), show_tree(&*ret))
}
}
}
pub fn show_net(net: &Net) -> String {
let mut result = String::new();
result.push_str(&format!("{}", show_tree(&net.root)));
for (a, b) in &net.rdex {
result.push_str(&format!("\n& {} ~ {}", show_tree(a), show_tree(b)));
}
return result;
}
pub fn show_book(book: &Book) -> String {
let mut result = String::new();
for (name, net) in book {
result.push_str(&format!("@{} = {}\n", name, show_net(net)));
}
return result;
}
pub fn show_runtime_tree<const LAZY: bool>(rt_net: &run::NetFields<LAZY>, ptr: run::Ptr) -> String where [(); LAZY as usize]:{
show_tree(&tree_from_runtime_go(rt_net, ptr, PARENT_ROOT, &mut HashMap::new(), &mut 0))
}
pub fn show_runtime_net<const LAZY: bool>(rt_net: &run::NetFields<LAZY>) -> String where [(); LAZY as usize]:{
show_net(&net_from_runtime(rt_net))
}
pub fn show_runtime_book(book: &run::Book) -> String {
show_book(&book_from_runtime(book))
}
// Conversion
// ----------
pub fn num_to_str(mut num: usize) -> String {
let mut txt = String::new();
num += 1;
while num > 0 {
num -= 1;
let c = ((num % 26) as u8 + b'a') as char;
txt.push(c);
num /= 26;
}
return txt.chars().rev().collect();
}
pub const fn tag_to_port(tag: run::Tag) -> run::Port {
match tag {
run::VR1 => run::P1,
run::VR2 => run::P2,
_ => unreachable!(),
}
}
pub fn port_to_tag(port: run::Port) -> run::Tag {
match port {
run::P1 => run::VR1,
run::P2 => run::VR2,
_ => unreachable!(),
}
}
pub fn name_to_letters(name: &str) -> Vec<u8> {
let mut letters = Vec::new();
for c in name.chars() {
letters.push(match c {
'0'..='9' => c as u8 - '0' as u8 + 0,
'A'..='Z' => c as u8 - 'A' as u8 + 10,
'a'..='z' => c as u8 - 'a' as u8 + 36,
'_' => 62,
'.' => 63,
_ => panic!("Invalid character in name"),
});
}
return letters;
}
pub fn letters_to_name(letters: Vec<u8>) -> String {
let mut name = String::new();
for letter in letters {
name.push(match letter {
0..= 9 => (letter - 0 + '0' as u8) as char,
10..=35 => (letter - 10 + 'A' as u8) as char,
36..=61 => (letter - 36 + 'a' as u8) as char,
62 => '_',
63 => '.',
_ => panic!("Invalid letter in name"),
});
}
return name;
}
pub fn val_to_letters(num: run::Val) -> Vec<u8> {
let mut letters = Vec::new();
let mut num = num;
while num > 0 {
letters.push((num % 64) as u8);
num /= 64;
}
letters.reverse();
return letters;
}
pub fn letters_to_val(letters: Vec<u8>) -> run::Val {
let mut num = 0;
for letter in letters {
num = num * 64 + letter as run::Val;
}
return num;
}
pub fn name_to_val(name: &str) -> run::Val {
letters_to_val(name_to_letters(name))
}
pub fn val_to_name(num: run::Val) -> String {
letters_to_name(val_to_letters(num))
}
// Injection and Readback
// ----------------------
// To runtime
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Parent {
Redex,
Node { loc: run::Loc, port: run::Port },
}
const PARENT_ROOT: Parent = Parent::Node { loc: run::ROOT.loc(), port: tag_to_port(run::ROOT.tag()) };
pub fn tree_to_runtime_go<const LAZY: bool>(rt_net: &mut run::NetFields<LAZY>, tree: &Tree, vars: &mut HashMap<String, Parent>, parent: Parent) -> run::Ptr where [(); LAZY as usize]: {
match tree {
Tree::Era => {
run::ERAS
}
Tree::Con { lft, rgt } => {
let loc = rt_net.alloc();
let p1 = tree_to_runtime_go(rt_net, &*lft, vars, Parent::Node { loc, port: run::P1 });
rt_net.heap.set(loc, run::P1, p1);
let p2 = tree_to_runtime_go(rt_net, &*rgt, vars, Parent::Node { loc, port: run::P2 });
rt_net.heap.set(loc, run::P2, p2);
run::Ptr::new(run::LAM, 0, loc)
}
Tree::Tup { lft, rgt } => {
let loc = rt_net.alloc();
let p1 = tree_to_runtime_go(rt_net, &*lft, vars, Parent::Node { loc, port: run::P1 });
rt_net.heap.set(loc, run::P1, p1);
let p2 = tree_to_runtime_go(rt_net, &*rgt, vars, Parent::Node { loc, port: run::P2 });
rt_net.heap.set(loc, run::P2, p2);
run::Ptr::new(run::TUP, 1, loc)
}
Tree::Dup { lab, lft, rgt } => {
let loc = rt_net.alloc();
let p1 = tree_to_runtime_go(rt_net, &*lft, vars, Parent::Node { loc, port: run::P1 });
rt_net.heap.set(loc, run::P1, p1);
let p2 = tree_to_runtime_go(rt_net, &*rgt, vars, Parent::Node { loc, port: run::P2 });
rt_net.heap.set(loc, run::P2, p2);
run::Ptr::new(run::DUP, *lab, loc)
}
Tree::Var { nam } => {
if let Parent::Redex = parent {
panic!("By definition, can't have variable on active pairs.");
};
match vars.get(nam) {
Some(Parent::Redex) => {
unreachable!();
}
Some(Parent::Node { loc: other_loc, port: other_port }) => {
match parent {
Parent::Redex => { unreachable!(); }
Parent::Node { loc, port } => rt_net.heap.set(*other_loc, *other_port, run::Ptr::new(port_to_tag(port), 0, loc)),
}
return run::Ptr::new(port_to_tag(*other_port), 0, *other_loc);
}
None => {
vars.insert(nam.clone(), parent);
run::NULL
}
}
}
Tree::Ref { nam } => {
run::Ptr::big(run::REF, *nam)
}
Tree::Num { val } => {
run::Ptr::big(run::NUM, *val)
}
Tree::Op1 { opr, lft, rgt } => {
let loc = rt_net.alloc();
let p1 = run::Ptr::big(run::NUM, *lft);
rt_net.heap.set(loc, run::P1, p1);
let p2 = tree_to_runtime_go(rt_net, rgt, vars, Parent::Node { loc, port: run::P2 });
rt_net.heap.set(loc, run::P2, p2);
run::Ptr::new(run::OP1, *opr, loc)
}
Tree::Op2 { opr, lft, rgt } => {
let loc = rt_net.alloc();
let p1 = tree_to_runtime_go(rt_net, &*lft, vars, Parent::Node { loc, port: run::P1 });
rt_net.heap.set(loc, run::P1, p1);
let p2 = tree_to_runtime_go(rt_net, &*rgt, vars, Parent::Node { loc, port: run::P2 });
rt_net.heap.set(loc, run::P2, p2);
run::Ptr::new(run::OP2, *opr, loc)
}
Tree::Mat { sel, ret } => {
let loc = rt_net.alloc();
let p1 = tree_to_runtime_go(rt_net, &*sel, vars, Parent::Node { loc, port: run::P1 });
rt_net.heap.set(loc, run::P1, p1);
let p2 = tree_to_runtime_go(rt_net, &*ret, vars, Parent::Node { loc, port: run::P2 });
rt_net.heap.set(loc, run::P2, p2);
run::Ptr::new(run::MAT, 0, loc)
}
}
}
pub fn tree_to_runtime<const LAZY: bool>(rt_net: &mut run::NetFields<LAZY>, tree: &Tree) -> run::Ptr where [(); LAZY as usize]: {
tree_to_runtime_go(rt_net, tree, &mut HashMap::new(), PARENT_ROOT)
}
pub fn net_to_runtime<const LAZY: bool>(rt_net: &mut run::NetFields<LAZY>, net: &Net) where [(); LAZY as usize]: {
let mut vars = HashMap::new();
let root = tree_to_runtime_go(rt_net, &net.root, &mut vars, PARENT_ROOT);
rt_net.heap.set_root(root);
for (tree1, tree2) in &net.rdex {
let ptr1 = tree_to_runtime_go(rt_net, tree1, &mut vars, Parent::Redex);
let ptr2 = tree_to_runtime_go(rt_net, tree2, &mut vars, Parent::Redex);
rt_net.rdex.push((ptr1, ptr2));
}
}
// Holds dup labels and ref ids used by a definition
type InsideLabs = HashSet<run::Lab, nohash_hasher::BuildNoHashHasher<run::Lab>>;
type InsideRefs = HashSet<run::Val>;
#[derive(Debug)]
pub struct Inside {
labs: InsideLabs,
refs: InsideRefs,
}
// Collects dup labels and ref ids used by a definition
pub fn runtime_def_get_inside(def: &run::Def) -> Inside {
let mut inside = Inside {
labs: HashSet::with_hasher(std::hash::BuildHasherDefault::default()),
refs: HashSet::new(),
};
fn register(inside: &mut Inside, ptr: run::Ptr) {
if ptr.is_dup() {
inside.labs.insert(ptr.lab());
}
if ptr.is_ref() {
inside.refs.insert(ptr.val());
}
}
for i in 0 .. def.node.len() {
register(&mut inside, def.node[i].1);
register(&mut inside, def.node[i].2);
}
for i in 0 .. def.rdex.len() {
register(&mut inside, def.rdex[i].0);
register(&mut inside, def.rdex[i].1);
}
return inside;
}
// Computes all dup labels used by a definition, direct or not.
// FIXME: memoize to avoid duplicated work
pub fn runtime_def_get_all_labs(labs: &mut InsideLabs, insides: &HashMap<run::Val, Inside>, fid: run::Val, seen: &mut HashSet<run::Val>) {
if seen.contains(&fid) {
return;
} else {
seen.insert(fid);
if let Some(fid_insides) = insides.get(&fid) {
for dup in &fid_insides.labs {
labs.insert(*dup);
}
for child_fid in &fid_insides.refs {
runtime_def_get_all_labs(labs, insides, *child_fid, seen);
}
}
}
}
// Converts a book from the pure AST representation to the runtime representation.
pub fn book_to_runtime(book: &Book) -> run::Book {
let mut rt_book = run::Book::new();
// Convert each net in 'book' to a runtime net and add to 'rt_book'
for (name, net) in book {
let fid = name_to_val(name);
let nodes = run::Heap::<false>::init(1 << 16);
let mut rt = run::NetFields::new(&nodes);
net_to_runtime(&mut rt, net);
rt_book.def(fid, runtime_net_to_runtime_def(&rt));
}
// Calculate the 'insides' of each runtime definition
let mut insides = HashMap::new();
for (fid, def) in &rt_book.defs {
insides.insert(*fid, runtime_def_get_inside(&def));
}
// Compute labs labels used in each runtime definition
let mut labs_by_fid = HashMap::new();
for (fid, _) in &rt_book.defs {
let mut labs = HashSet::with_hasher(std::hash::BuildHasherDefault::default());
let mut seen = HashSet::new();
runtime_def_get_all_labs(&mut labs, &insides, *fid, &mut seen);
labs_by_fid.insert(*fid, labs);
}
// Set the 'labs' field for each definition
for (fid, def) in &mut rt_book.defs {
def.labs = labs_by_fid.get(fid).unwrap().clone();
//println!("{} {:?}", val_to_name(*fid), def.labs);
}
rt_book
}
// Converts to a def.
pub fn runtime_net_to_runtime_def<const LAZY: bool>(net: &run::NetFields<LAZY>) -> run::Def where [(); LAZY as usize]: {
let mut node = vec![];
let mut rdex = vec![];
let labs = HashSet::with_hasher(std::hash::BuildHasherDefault::default());
for i in 0 .. net.heap.nodes.len() {
let p0 = run::APtr::new(run::Ptr(0));
let p1 = net.heap.get(node.len() as run::Loc, run::P1);
let p2 = net.heap.get(node.len() as run::Loc, run::P2);
if p1 != run::NULL || p2 != run::NULL {
node.push(((), p1, p2));
} else {
break;
}
}
for i in 0 .. net.rdex.len() {
let p1 = net.rdex[i].0;
let p2 = net.rdex[i].1;
rdex.push((p1, p2));
}
return run::Def { labs, rdex, node };
}
// Reads back from a def.
pub fn runtime_def_to_runtime_net<'a, const LAZY: bool>(nodes: &'a run::Nodes<LAZY>, def: &run::Def) -> run::NetFields<'a, LAZY> where [(); LAZY as usize]: {
let mut net = run::NetFields::new(&nodes);
for (i, &(p0, p1, p2)) in def.node.iter().enumerate() {
net.heap.set(i as run::Loc, run::P1, p1);
net.heap.set(i as run::Loc, run::P2, p2);
}
net.rdex = def.rdex.clone();
net
}
pub fn tree_from_runtime_go<const LAZY: bool>(rt_net: &run::NetFields<LAZY>, ptr: run::Ptr, parent: Parent, vars: &mut HashMap<Parent, String>, fresh: &mut usize) -> Tree where [(); LAZY as usize]: {
match ptr.tag() {
run::ERA => {
Tree::Era
}
run::REF => {
Tree::Ref { nam: ptr.val() }
}
run::NUM => {
Tree::Num { val: ptr.val() }
}
run::OP1 => {
let opr = ptr.lab();
let lft = tree_from_runtime_go(rt_net, rt_net.heap.get(ptr.loc(), run::P1), Parent::Node { loc: ptr.loc(), port: run::P1 }, vars, fresh);
let Tree::Num { val } = lft else { unreachable!() };
let rgt = tree_from_runtime_go(rt_net, rt_net.heap.get(ptr.loc(), run::P2), Parent::Node { loc: ptr.loc(), port: run::P2 }, vars, fresh);
Tree::Op1 { opr, lft: val, rgt: Box::new(rgt) }
}
run::OP2 => {
let opr = ptr.lab();
let lft = tree_from_runtime_go(rt_net, rt_net.heap.get(ptr.loc(), run::P1), Parent::Node { loc: ptr.loc(), port: run::P1 }, vars, fresh);
let rgt = tree_from_runtime_go(rt_net, rt_net.heap.get(ptr.loc(), run::P2), Parent::Node { loc: ptr.loc(), port: run::P2 }, vars, fresh);
Tree::Op2 { opr, lft: Box::new(lft), rgt: Box::new(rgt) }
}
run::MAT => {
let sel = tree_from_runtime_go(rt_net, rt_net.heap.get(ptr.loc(), run::P1), Parent::Node { loc: ptr.loc(), port: run::P1 }, vars, fresh);
let ret = tree_from_runtime_go(rt_net, rt_net.heap.get(ptr.loc(), run::P2), Parent::Node { loc: ptr.loc(), port: run::P2 }, vars, fresh);
Tree::Mat { sel: Box::new(sel), ret: Box::new(ret) }
}
run::VR1 | run::VR2 => {
let key = match ptr.tag() {
run::VR1 => Parent::Node { loc: ptr.loc(), port: run::P1 },
run::VR2 => Parent::Node { loc: ptr.loc(), port: run::P2 },
_ => unreachable!(),
};
if let Some(nam) = vars.get(&key) {
Tree::Var { nam: nam.clone() }
} else {
let nam = num_to_str(*fresh);
*fresh += 1;
vars.insert(parent, nam.clone());
Tree::Var { nam }
}
}
run::LAM => {
let p1 = rt_net.heap.get(ptr.loc(), run::P1);
let p2 = rt_net.heap.get(ptr.loc(), run::P2);
let lft = tree_from_runtime_go(rt_net, p1, Parent::Node { loc: ptr.loc(), port: run::P1 }, vars, fresh);
let rgt = tree_from_runtime_go(rt_net, p2, Parent::Node { loc: ptr.loc(), port: run::P2 }, vars, fresh);
Tree::Con { lft: Box::new(lft), rgt: Box::new(rgt) }
}
run::TUP => {
let p1 = rt_net.heap.get(ptr.loc(), run::P1);
let p2 = rt_net.heap.get(ptr.loc(), run::P2);
let lft = tree_from_runtime_go(rt_net, p1, Parent::Node { loc: ptr.loc(), port: run::P1 }, vars, fresh);
let rgt = tree_from_runtime_go(rt_net, p2, Parent::Node { loc: ptr.loc(), port: run::P2 }, vars, fresh);
Tree::Tup { lft: Box::new(lft), rgt: Box::new(rgt) }
}
run::DUP => {
let p1 = rt_net.heap.get(ptr.loc(), run::P1);
let p2 = rt_net.heap.get(ptr.loc(), run::P2);
let lft = tree_from_runtime_go(rt_net, p1, Parent::Node { loc: ptr.loc(), port: run::P1 }, vars, fresh);
let rgt = tree_from_runtime_go(rt_net, p2, Parent::Node { loc: ptr.loc(), port: run::P2 }, vars, fresh);
Tree::Dup { lab: ptr.lab(), lft: Box::new(lft), rgt: Box::new(rgt) }
}
_ => {
unreachable!()
}
}
}
pub fn tree_from_runtime<const LAZY: bool>(rt_net: &run::NetFields<LAZY>, ptr: run::Ptr) -> Tree where [(); LAZY as usize]: {
let mut vars = HashMap::new();
let mut fresh = 0;
tree_from_runtime_go(rt_net, ptr, PARENT_ROOT, &mut vars, &mut fresh)
}
pub fn net_from_runtime<const LAZY: bool>(rt_net: &run::NetFields<LAZY>) -> Net where [(); LAZY as usize]: {
let mut vars = HashMap::new();
let mut fresh = 0;
let mut rdex = Vec::new();
let root = tree_from_runtime_go(rt_net, rt_net.heap.get_root(), PARENT_ROOT, &mut vars, &mut fresh);
for &(a, b) in &rt_net.rdex {
let tree_a = tree_from_runtime_go(rt_net, a, Parent::Redex, &mut vars, &mut fresh);
let tree_b = tree_from_runtime_go(rt_net, b, Parent::Redex, &mut vars, &mut fresh);
rdex.push((tree_a, tree_b));
}
Net { root, rdex }
}
pub fn book_from_runtime(rt_book: &run::Book) -> Book {
let mut book = BTreeMap::new();
for (fid, def) in rt_book.defs.iter() {
if def.node.len() > 0 {
let name = val_to_name(*fid);
let nodes = run::Heap::<false>::init(def.node.len());
let net = net_from_runtime(&runtime_def_to_runtime_net(&nodes, &def));
book.insert(name, net);
}
}
book
}

View File

@ -1,355 +0,0 @@
use crate::run::{*};
pub const F___main : Val = 0xfbec24b31;
pub const F___foo : Val = 0x3efa9cb2;
pub const F_main : Val = 0xc24b31;
pub const F_a : Val = 0x000024;
pub const F__U60.fib : Val = 0xf9e180fe9b25;
pub const F_b : Val = 0x000025;
pub const F_d : Val = 0x000027;
pub const F_c : Val = 0x000026;
impl<'a, const LAZY: bool> NetFields<'a, LAZY> where [(); LAZY as usize]: {
pub fn call_native(&mut self, book: &Book, ptr: Ptr, x: Ptr) -> bool {
match ptr.val() {
F___main => { return self.F___main(ptr, Trg::Ptr(x)); }
F___foo => { return self.F___foo(ptr, Trg::Ptr(x)); }
F_main => { return self.F_main(ptr, Trg::Ptr(x)); }
F_a => { return self.F_a(ptr, Trg::Ptr(x)); }
F__U60.fib => { return self.F__U60.fib(ptr, Trg::Ptr(x)); }
F_b => { return self.F_b(ptr, Trg::Ptr(x)); }
F_d => { return self.F_d(ptr, Trg::Ptr(x)); }
F_c => { return self.F_c(ptr, Trg::Ptr(x)); }
_ => { return false; }
}
}
pub fn L___main(&mut self, lab: Lab) -> bool {
if lab == 0x5 { return true; }
if lab == 0x3 { return true; }
return false;
}
pub fn F___main(&mut self, ptr: Ptr, trg: Trg) -> bool {
if self.get(trg).is_dup() && !self.L___main(self.get(trg).lab()) {
self.copy(self.swap(trg, NULL), ptr);
return true;
}
let _k1 : Trg = Trg::Ptr(Ptr::big(REF, F__U60.fib));
let _k1x : Trg;
let _k1y : Trg;
// fast apply
if self.get(_k1).tag() == LAM {
self.rwts.anni += 1;
let got = self.swap(_k1, NULL);
_k1x = Trg::Dir(Ptr::new(VR1, 0, got.loc()));
_k1y = Trg::Dir(Ptr::new(VR2, 0, got.loc()));
} else {
let k2 = self.alloc();
_k1x = Trg::Ptr(Ptr::new(VR1, 0, k2));
_k1y = Trg::Ptr(Ptr::new(VR2, 0, k2));
self.safe_link(Trg::Ptr(Ptr::new(LAM, 0, k2)), _k1);
}
// fast erase
if self.get(_k1x).is_skp() {
self.swap(_k1x, NULL);
self.rwts.eras += 1;
} else {
self.safe_link(_k1x, Trg::Ptr(Ptr::new(NUM, 0x6, 0x0)));
}
self.safe_link(trg, _k1y);
return true;
}
pub fn L___foo(&mut self, lab: Lab) -> bool {
return false;
}
pub fn F___foo(&mut self, ptr: Ptr, trg: Trg) -> bool {
if self.get(trg).is_dup() && !self.L___foo(self.get(trg).lab()) {
self.copy(self.swap(trg, NULL), ptr);
return true;
}
// fast erase
if self.get(trg).is_skp() {
self.swap(trg, NULL);
self.rwts.eras += 1;
} else {
self.safe_link(trg, Trg::Ptr(Ptr::new(NUM, 0x2d, 0x0)));
}
return true;
}
pub fn L_main(&mut self, lab: Lab) -> bool {
if lab == 0x5 { return true; }
if lab == 0x3 { return true; }
return false;
}
pub fn F_main(&mut self, ptr: Ptr, trg: Trg) -> bool {
if self.get(trg).is_dup() && !self.L_main(self.get(trg).lab()) {
self.copy(self.swap(trg, NULL), ptr);
return true;
}
self.safe_link(trg, Trg::Ptr(Ptr::big(REF, F___main)));
return true;
}
pub fn L_a(&mut self, lab: Lab) -> bool {
if lab == 0x5 { return true; }
if lab == 0x3 { return true; }
return false;
}
pub fn F_a(&mut self, ptr: Ptr, trg: Trg) -> bool {
if self.get(trg).is_dup() && !self.L_a(self.get(trg).lab()) {
self.copy(self.swap(trg, NULL), ptr);
return true;
}
let trgx : Trg;
let trgy : Trg;
// fast apply
if self.get(trg).tag() == LAM {
self.rwts.anni += 1;
let got = self.swap(trg, NULL);
trgx = Trg::Dir(Ptr::new(VR1, 0, got.loc()));
trgy = Trg::Dir(Ptr::new(VR2, 0, got.loc()));
} else {
let k1 = self.alloc();
trgx = Trg::Ptr(Ptr::new(VR1, 0, k1));
trgy = Trg::Ptr(Ptr::new(VR2, 0, k1));
self.safe_link(Trg::Ptr(Ptr::new(LAM, 0, k1)), trg);
}
let trgxx : Trg;
let trgxy : Trg;
// fast copy
if self.get(trgx).tag() == NUM {
self.rwts.comm += 1;
let got = self.swap(trgx, NULL);
trgxx = Trg::Ptr(got);
trgxy = Trg::Ptr(got);
} else {
let k2 = self.alloc();
trgxx = Trg::Ptr(Ptr::new(VR1, 0, k2));
trgxy = Trg::Ptr(Ptr::new(VR2, 0, k2));
self.safe_link(Trg::Ptr(Ptr::new(DUP, 3, k2)), trgx);
}
let k3 = self.alloc();
let k4 = self.alloc();
self.safe_link(Trg::Ptr(Ptr::new(VR2, 0, k4)), trgy);
self.safe_link(Trg::Ptr(Ptr::new(VR1, 0, k4)), trgxy);
self.safe_link(Trg::Ptr(Ptr::new(LAM, 0, k4)), Trg::Ptr(Ptr::new(VR2, 0, k3)));
let k5 = self.alloc();
self.safe_link(Trg::Ptr(Ptr::new(VR2, 0, k5)), Trg::Ptr(Ptr::big(REF, F_b)));
self.safe_link(Trg::Ptr(Ptr::new(VR1, 0, k5)), Trg::Ptr(Ptr::big(REF, F_d)));
self.safe_link(Trg::Ptr(Ptr::new(LAM, 0, k5)), Trg::Ptr(Ptr::new(VR1, 0, k3)));
self.safe_link(Trg::Ptr(Ptr::new(MAT, 0, k3)), trgxx);
return true;
}
pub fn L__U60.fib(&mut self, lab: Lab) -> bool {
if lab == 0x5 { return true; }
if lab == 0x3 { return true; }
return false;
}
pub fn F__U60.fib(&mut self, ptr: Ptr, trg: Trg) -> bool {
if self.get(trg).is_dup() && !self.L__U60.fib(self.get(trg).lab()) {
self.copy(self.swap(trg, NULL), ptr);
return true;
}
let k1 : Trg;
let k2 : Trg;
// fast match
if self.get(trg).tag() == LAM && self.heap.get(self.get(trg).loc(), P1).is_num() {
self.rwts.anni += 2;
self.rwts.oper += 1;
let got = self.swap(trg, NULL);
let trgx = Trg::Dir(Ptr::new(VR1, 0, got.loc()));
let trgy = Trg::Dir(Ptr::new(VR2, 0, got.loc()));
if self.get(trgx).val() == 0 {
self.swap(trgx, NULL);
k1 = trgy;
k2 = Trg::Ptr(ERAS);
} else {
self.swap(trgx, Ptr::big(NUM, self.get(trgx).val() - 1));
k1 = Trg::Ptr(ERAS);
k2 = trg;
}
} else {
let k3 = self.alloc();
let k4 = self.alloc();
let k5 = self.alloc();
self.heap.set(k3, P1, Ptr::new(MAT, 0, k4));
self.heap.set(k3, P2, Ptr::new(VR2, 0, k4));
self.heap.set(k4, P1, Ptr::new(LAM, 0, k5));
self.heap.set(k4, P2, Ptr::new(VR2, 0, k3));
self.safe_link(Trg::Ptr(Ptr::new(LAM, 0, k3)), trg);
k1 = Trg::Ptr(Ptr::new(VR1, 0, k5));
k2 = Trg::Ptr(Ptr::new(VR2, 0, k5));
}
// fast erase
if self.get(k1).is_skp() {
self.swap(k1, NULL);
self.rwts.eras += 1;
} else {
self.safe_link(k1, Trg::Ptr(Ptr::new(NUM, 0x0, 0x0)));
}
self.safe_link(k2, Trg::Ptr(Ptr::big(REF, F_a)));
return true;
}
pub fn L_b(&mut self, lab: Lab) -> bool {
if lab == 0x5 { return true; }
if lab == 0x3 { return true; }
return false;
}
pub fn F_b(&mut self, ptr: Ptr, trg: Trg) -> bool {
if self.get(trg).is_dup() && !self.L_b(self.get(trg).lab()) {
self.copy(self.swap(trg, NULL), ptr);
return true;
}
let trgx : Trg;
let trgy : Trg;
// fast apply
if self.get(trg).tag() == LAM {
self.rwts.anni += 1;
let got = self.swap(trg, NULL);
trgx = Trg::Dir(Ptr::new(VR1, 0, got.loc()));
trgy = Trg::Dir(Ptr::new(VR2, 0, got.loc()));
} else {
let k1 = self.alloc();
trgx = Trg::Ptr(Ptr::new(VR1, 0, k1));
trgy = Trg::Ptr(Ptr::new(VR2, 0, k1));
self.safe_link(Trg::Ptr(Ptr::new(LAM, 0, k1)), trg);
}
self.safe_link(trgy, Trg::Ptr(Ptr::big(REF, F_c)));
// fast erase
if self.get(trgx).is_skp() {
self.swap(trgx, NULL);
self.rwts.eras += 1;
} else {
self.safe_link(trgx, Trg::Ptr(Ptr::new(ERA, 0x0, 0x0)));
}
return true;
}
pub fn L_d(&mut self, lab: Lab) -> bool {
return false;
}
pub fn F_d(&mut self, ptr: Ptr, trg: Trg) -> bool {
if self.get(trg).is_dup() && !self.L_d(self.get(trg).lab()) {
self.copy(self.swap(trg, NULL), ptr);
return true;
}
let trgx : Trg;
let trgy : Trg;
// fast apply
if self.get(trg).tag() == LAM {
self.rwts.anni += 1;
let got = self.swap(trg, NULL);
trgx = Trg::Dir(Ptr::new(VR1, 0, got.loc()));
trgy = Trg::Dir(Ptr::new(VR2, 0, got.loc()));
} else {
let k1 = self.alloc();
trgx = Trg::Ptr(Ptr::new(VR1, 0, k1));
trgy = Trg::Ptr(Ptr::new(VR2, 0, k1));
self.safe_link(Trg::Ptr(Ptr::new(LAM, 0, k1)), trg);
}
// fast erase
if self.get(trgy).is_skp() {
self.swap(trgy, NULL);
self.rwts.eras += 1;
} else {
self.safe_link(trgy, Trg::Ptr(Ptr::new(NUM, 0x1, 0x0)));
}
// fast erase
if self.get(trgx).is_skp() {
self.swap(trgx, NULL);
self.rwts.eras += 1;
} else {
self.safe_link(trgx, Trg::Ptr(Ptr::new(ERA, 0x0, 0x0)));
}
return true;
}
pub fn L_c(&mut self, lab: Lab) -> bool {
if lab == 0x5 { return true; }
if lab == 0x3 { return true; }
return false;
}
pub fn F_c(&mut self, ptr: Ptr, trg: Trg) -> bool {
if self.get(trg).is_dup() && !self.L_c(self.get(trg).lab()) {
self.copy(self.swap(trg, NULL), ptr);
return true;
}
let _k1 : Trg = Trg::Ptr(Ptr::big(REF, F__U60.fib));
let _k1x : Trg;
let _k1y : Trg;
// fast apply
if self.get(_k1).tag() == LAM {
self.rwts.anni += 1;
let got = self.swap(_k1, NULL);
_k1x = Trg::Dir(Ptr::new(VR1, 0, got.loc()));
_k1y = Trg::Dir(Ptr::new(VR2, 0, got.loc()));
} else {
let k2 = self.alloc();
_k1x = Trg::Ptr(Ptr::new(VR1, 0, k2));
_k1y = Trg::Ptr(Ptr::new(VR2, 0, k2));
self.safe_link(Trg::Ptr(Ptr::new(LAM, 0, k2)), _k1);
}
let k3 = self.alloc();
self.safe_link(Trg::Ptr(Ptr::new(OP2, 0, k3)), _k1y);
let _k4 : Trg = Trg::Ptr(Ptr::big(REF, F__U60.fib));
let _k4x : Trg;
let _k4y : Trg;
// fast apply
if self.get(_k4).tag() == LAM {
self.rwts.anni += 1;
let got = self.swap(_k4, NULL);
_k4x = Trg::Dir(Ptr::new(VR1, 0, got.loc()));
_k4y = Trg::Dir(Ptr::new(VR2, 0, got.loc()));
} else {
let k5 = self.alloc();
_k4x = Trg::Ptr(Ptr::new(VR1, 0, k5));
_k4y = Trg::Ptr(Ptr::new(VR2, 0, k5));
self.safe_link(Trg::Ptr(Ptr::new(LAM, 0, k5)), _k4);
}
self.safe_link(_k4y, Trg::Ptr(Ptr::new(VR1, 0, k3)));
let trgx : Trg;
let trgy : Trg;
// fast apply
if self.get(trg).tag() == LAM {
self.rwts.anni += 1;
let got = self.swap(trg, NULL);
trgx = Trg::Dir(Ptr::new(VR1, 0, got.loc()));
trgy = Trg::Dir(Ptr::new(VR2, 0, got.loc()));
} else {
let k6 = self.alloc();
trgx = Trg::Ptr(Ptr::new(VR1, 0, k6));
trgy = Trg::Ptr(Ptr::new(VR2, 0, k6));
self.safe_link(Trg::Ptr(Ptr::new(LAM, 0, k6)), trg);
}
self.safe_link(trgy, Trg::Ptr(Ptr::new(VR2, 0, k3)));
let trgxx : Trg;
let trgxy : Trg;
// fast copy
if self.get(trgx).tag() == NUM {
self.rwts.comm += 1;
let got = self.swap(trgx, NULL);
trgxx = Trg::Ptr(got);
trgxy = Trg::Ptr(got);
} else {
let k7 = self.alloc();
trgxx = Trg::Ptr(Ptr::new(VR1, 0, k7));
trgxy = Trg::Ptr(Ptr::new(VR2, 0, k7));
self.safe_link(Trg::Ptr(Ptr::new(DUP, 5, k7)), trgx);
}
let k8 = self.alloc();
self.safe_link(Trg::Ptr(Ptr::new(VR2, 0, k8)), _k4x);
self.safe_link(Trg::Ptr(Ptr::new(VR1, 0, k8)), Trg::Ptr(Ptr::new(NUM, 0x2, 0x0)));
self.safe_link(Trg::Ptr(Ptr::new(OP2, 1, k8)), trgxy);
let k9 = self.alloc();
self.safe_link(Trg::Ptr(Ptr::new(VR2, 0, k9)), _k1x);
self.safe_link(Trg::Ptr(Ptr::new(VR1, 0, k9)), Trg::Ptr(Ptr::new(NUM, 0x1, 0x0)));
self.safe_link(Trg::Ptr(Ptr::new(OP2, 1, k9)), trgxx);
return true;
}
}

View File

@ -1,452 +0,0 @@
// Despite the file name, this is not actually a JIT (yet).
use crate::run;
use crate::ast;
use std::collections::HashMap;
pub fn compile_book(book: &run::Book) -> String {
let mut code = String::new();
code.push_str(&format!("use crate::run::{{*}};\n"));
code.push_str(&format!("\n"));
for (fid, def) in book.defs.iter() {
if def.node.len() > 0 {
let name = &ast::val_to_name(*fid as run::Val);
code.push_str(&format!("pub const F_{:4} : Val = 0x{:06x};\n", name, fid));
}
}
code.push_str(&format!("\n"));
code.push_str(&format!("impl<'a, const LAZY: bool> NetFields<'a, LAZY> where [(); LAZY as usize]: {{\n"));
code.push_str(&format!("\n"));
code.push_str(&format!("{}pub fn call_native(&mut self, book: &Book, ptr: Ptr, x: Ptr) -> bool {{\n", ident(1)));
code.push_str(&format!("{}match ptr.val() {{\n", ident(2)));
for (fid, def) in book.defs.iter() {
if def.node.len() > 0 {
let fun = ast::val_to_name(*fid);
code.push_str(&format!("{}F_{} => {{ return self.F_{}(ptr, Trg::Ptr(x)); }}\n", ident(3), fun, fun));
}
}
code.push_str(&format!("{}_ => {{ return false; }}\n", ident(3)));
code.push_str(&format!("{}}}\n", ident(2)));
code.push_str(&format!("{}}}\n", ident(1)));
code.push_str(&format!("\n"));
for (fid, def) in book.defs.iter() {
if def.node.len() > 0 {
code.push_str(&compile_term(&book, 1, *fid));
code.push_str(&format!("\n"));
}
}
code.push_str(&format!("}}"));
return code;
}
pub fn ident(tab: usize) -> String {
return " ".repeat(tab);
}
pub fn tag(tag: run::Tag) -> &'static str {
match tag {
run::VR1 => "VR1",
run::VR2 => "VR2",
run::RD1 => "RD1",
run::RD2 => "RD2",
run::REF => "REF",
run::ERA => "ERA",
run::NUM => "NUM",
run::OP2 => "OP2",
run::OP1 => "OP1",
run::MAT => "MAT",
run::LAM => "LAM",
run::TUP => "TUP",
run::DUP => "DUP",
_ => unreachable!(),
}
}
pub fn atom(ptr: run::Ptr) -> String {
if ptr.is_ref() {
return format!("Ptr::big(REF, F_{})", ast::val_to_name(ptr.val()));
} else {
return format!("Ptr::new({}, 0x{:x}, 0x{:x})", tag(ptr.tag()), ptr.lab(), ptr.loc());
}
}
struct Target {
nam: String
}
impl Target {
fn show(&self) -> String {
format!("{}", self.nam)
}
fn get(&self) -> String {
format!("self.get({})", self.nam)
}
fn swap(&self, value: &str) -> String {
format!("self.swap({}, {})", self.nam, value)
}
fn take(&self) -> String {
self.swap(&"NULL")
}
}
pub fn compile_term(book: &run::Book, tab: usize, fid: run::Val) -> String {
// returns a fresh variable: 'v<NUM>'
fn fresh(newx: &mut usize) -> String {
*newx += 1;
format!("k{}", newx)
}
fn call_redex(
book : &run::Book,
tab : usize,
newx : &mut usize,
vars : &mut HashMap<run::Ptr, String>,
def : &run::Def,
rdex : (run::Ptr, run::Ptr),
) -> String {
let (rf, rx) = adjust_redex(rdex.0, rdex.1);
let rf_name = format!("_{}", fresh(newx));
let mut code = String::new();
code.push_str(&format!("{}let {} : Trg = Trg::Ptr({});\n", ident(tab), rf_name, &atom(rf)));
code.push_str(&burn(book, tab, None, newx, vars, def, rx, &Target { nam: rf_name }));
return code;
}
fn call(
book : &run::Book,
tab : usize,
tail : Option<run::Val>,
newx : &mut usize,
vars : &mut HashMap<run::Ptr, String>,
fid : run::Val,
trg : &Target,
) -> String {
//let newx = &mut 0;
//let vars = &mut HashMap::new();
let def = &book.get(fid).unwrap();
// Tail call
// TODO: when I manually edited a file to implement tail call, the single-core performance
// increased a lot, but it resulted in a single thread withholding all redexes and, thus,
// the program went single-core mode again. I believe a smarter redex sharing structure is
// necessary for us to implement tail calls in a way that doesn't sacrify parallelism.
//if tail.is_some() && def.rdex.len() > 0 && def.rdex[0].0.is_ref() && def.rdex[0].0.loc() == tail.unwrap() {
//println!("tco {}", ast::val_to_name(tail.unwrap() as run::Val));
//let mut code = String::new();
//for rdex in &def.rdex[1..] {
//code.push_str(&call_redex(book, tab, newx, vars, def, *rdex));
//}
//code.push_str(&burn(book, tab, Some(fid), newx, vars, def, def.node[0].1, &trg));
//code.push_str(&call_redex(book, tab, newx, vars, def, def.rdex[0]));
//return code;
//}
// Normal call
let mut code = String::new();
for rdex in &def.rdex {
code.push_str(&call_redex(book, tab, newx, vars, def, *rdex));
}
code.push_str(&burn(book, tab, Some(fid), newx, vars, def, def.node[0].2, &trg));
return code;
}
fn burn(
book : &run::Book,
tab : usize,
tail : Option<run::Val>,
newx : &mut usize,
vars : &mut HashMap<run::Ptr, String>,
def : &run::Def,
ptr : run::Ptr,
trg : &Target,
) -> String {
//println!("burn {:08x} {}", ptr.0, x);
let mut code = String::new();
// (<?(ifz ifs) ret> ret) ~ (#X R)
// ------------------------------- fast match
// if X == 0:
// ifz ~ R
// ifs ~ *
// else:
// ifz ~ *
// ifs ~ (#(X-1) R)
// When ifs is REF, tail-call optimization is applied.
if ptr.tag() == run::LAM {
let mat = def.node[ptr.loc() as usize].1;
let rty = def.node[ptr.loc() as usize].2;
if mat.tag() == run::MAT {
let cse = def.node[mat.loc() as usize].1;
let rtx = def.node[mat.loc() as usize].2;
let got = def.node[rty.loc() as usize];
let rtz = if rty.tag() == run::VR1 { got.1 } else { got.2 };
if cse.tag() == run::LAM && rtx.is_var() && rtx == rtz {
let ifz = def.node[cse.loc() as usize].1;
let ifs = def.node[cse.loc() as usize].2;
let c_z = Target { nam: fresh(newx) };
let c_s = Target { nam: fresh(newx) };
let num = Target { nam: format!("{}x", trg.show()) };
let res = Target { nam: format!("{}y", trg.show()) };
let lam = fresh(newx);
let mat = fresh(newx);
let cse = fresh(newx);
code.push_str(&format!("{}let {} : Trg;\n", ident(tab), &c_z.show()));
code.push_str(&format!("{}let {} : Trg;\n", ident(tab), &c_s.show()));
code.push_str(&format!("{}// fast match\n", ident(tab)));
code.push_str(&format!("{}if {}.tag() == LAM && self.heap.get({}.loc(), P1).is_num() {{\n", ident(tab), trg.get(), trg.get()));
code.push_str(&format!("{}self.rwts.anni += 2;\n", ident(tab+1)));
code.push_str(&format!("{}self.rwts.oper += 1;\n", ident(tab+1)));
code.push_str(&format!("{}let got = {};\n", ident(tab+1), trg.take()));
code.push_str(&format!("{}let {} = Trg::Dir(Ptr::new(VR1, 0, got.loc()));\n", ident(tab+1), num.show()));
code.push_str(&format!("{}let {} = Trg::Dir(Ptr::new(VR2, 0, got.loc()));\n", ident(tab+1), res.show()));
code.push_str(&format!("{}if {}.val() == 0 {{\n", ident(tab+1), num.get()));
code.push_str(&format!("{}{};\n", ident(tab+2), num.take()));
code.push_str(&format!("{}{} = {};\n", ident(tab+2), &c_z.show(), res.show()));
code.push_str(&format!("{}{} = Trg::Ptr({});\n", ident(tab+2), &c_s.show(), "ERAS"));
code.push_str(&format!("{}}} else {{\n", ident(tab+1)));
code.push_str(&format!("{}{};\n", ident(tab+2), num.swap(&format!("Ptr::big(NUM, {}.val() - 1)", num.get()))));
code.push_str(&format!("{}{} = Trg::Ptr({});\n", ident(tab+2), &c_z.show(), "ERAS"));
code.push_str(&format!("{}{} = {};\n", ident(tab+2), &c_s.show(), trg.show()));
code.push_str(&format!("{}}}\n", ident(tab+1)));
code.push_str(&format!("{}}} else {{\n", ident(tab)));
code.push_str(&format!("{}let {} = self.alloc();\n", ident(tab+1), lam));
code.push_str(&format!("{}let {} = self.alloc();\n", ident(tab+1), mat));
code.push_str(&format!("{}let {} = self.alloc();\n", ident(tab+1), cse));
code.push_str(&format!("{}self.heap.set({}, P1, Ptr::new(MAT, 0, {}));\n", ident(tab+1), lam, mat));
code.push_str(&format!("{}self.heap.set({}, P2, Ptr::new(VR2, 0, {}));\n", ident(tab+1), lam, mat));
code.push_str(&format!("{}self.heap.set({}, P1, Ptr::new(LAM, 0, {}));\n", ident(tab+1), mat, cse));
code.push_str(&format!("{}self.heap.set({}, P2, Ptr::new(VR2, 0, {}));\n", ident(tab+1), mat, lam));
code.push_str(&format!("{}self.safe_link(Trg::Ptr(Ptr::new(LAM, 0, {})), {});\n", ident(tab+1), lam, trg.show()));
code.push_str(&format!("{}{} = Trg::Ptr(Ptr::new(VR1, 0, {}));\n", ident(tab+1), &c_z.show(), cse));
code.push_str(&format!("{}{} = Trg::Ptr(Ptr::new(VR2, 0, {}));\n", ident(tab+1), &c_s.show(), cse));
code.push_str(&format!("{}}}\n", ident(tab)));
code.push_str(&burn(book, tab, None, newx, vars, def, ifz, &c_z));
code.push_str(&burn(book, tab, tail, newx, vars, def, ifs, &c_s));
return code;
}
}
}
// #A ~ <+ #B r>
// ----------------- fast op
// r <~ #(op(+,A,B))
if ptr.is_op2() {
let val = def.node[ptr.loc() as usize].1;
let ret = def.node[ptr.loc() as usize].2;
if let Some(val) = got(vars, def, val) {
let val = Target { nam: val };
let nxt = Target { nam: fresh(newx) };
let op2 = fresh(newx);
code.push_str(&format!("{}let {} : Trg;\n", ident(tab), &nxt.show()));
code.push_str(&format!("{}// fast op\n", ident(tab)));
code.push_str(&format!("{}if {}.is_num() && {}.is_num() {{\n", ident(tab), trg.get(), val.get()));
code.push_str(&format!("{}self.rwts.oper += 2;\n", ident(tab+1))); // OP2 + OP1
code.push_str(&format!("{}let vx = {};\n", ident(tab+1), trg.take()));
code.push_str(&format!("{}let vy = {};\n", ident(tab+1), val.take()));
code.push_str(&format!("{}{} = Trg::Ptr(Ptr::big(NUM, self.op({},vx.val(),vy.val())));\n", ident(tab+1), &nxt.show(), ptr.lab()));
code.push_str(&format!("{}}} else {{\n", ident(tab)));
code.push_str(&format!("{}let {} = self.alloc();\n", ident(tab+1), op2));
code.push_str(&format!("{}self.safe_link(Trg::Ptr(Ptr::new(VR1, 0, {})), {});\n", ident(tab+1), op2, val.show()));
code.push_str(&format!("{}self.safe_link(Trg::Ptr(Ptr::new(OP2, {}, {})), {});\n", ident(tab+1), ptr.lab(), op2, trg.show()));
code.push_str(&format!("{}{} = Trg::Ptr(Ptr::new(VR2, 0, {}));\n", ident(tab+1), &nxt.show(), op2));
code.push_str(&format!("{}}}\n", ident(tab)));
code.push_str(&burn(book, tab, None, newx, vars, def, ret, &nxt));
return code;
}
}
// {p1 p2} <~ #N
// ------------- fast copy
// p1 <~ #N
// p2 <~ #N
if ptr.is_dup() {
let x1 = Target { nam: format!("{}x", trg.show()) };
let x2 = Target { nam: format!("{}y", trg.show()) };
let p1 = def.node[ptr.loc() as usize].1;
let p2 = def.node[ptr.loc() as usize].2;
let lc = fresh(newx);
code.push_str(&format!("{}let {} : Trg;\n", ident(tab), &x1.show()));
code.push_str(&format!("{}let {} : Trg;\n", ident(tab), &x2.show()));
code.push_str(&format!("{}// fast copy\n", ident(tab)));
code.push_str(&format!("{}if {}.tag() == NUM {{\n", ident(tab), trg.get()));
code.push_str(&format!("{}self.rwts.comm += 1;\n", ident(tab+1)));
code.push_str(&format!("{}let got = {};\n", ident(tab+1), trg.take()));
code.push_str(&format!("{}{} = Trg::Ptr(got);\n", ident(tab+1), &x1.show()));
code.push_str(&format!("{}{} = Trg::Ptr(got);\n", ident(tab+1), &x2.show()));
code.push_str(&format!("{}}} else {{\n", ident(tab)));
code.push_str(&format!("{}let {} = self.alloc();\n", ident(tab+1), lc));
code.push_str(&format!("{}{} = Trg::Ptr(Ptr::new(VR1, 0, {}));\n", ident(tab+1), &x1.show(), lc));
code.push_str(&format!("{}{} = Trg::Ptr(Ptr::new(VR2, 0, {}));\n", ident(tab+1), &x2.show(), lc));
code.push_str(&format!("{}self.safe_link(Trg::Ptr(Ptr::new({}, {}, {})), {});\n", ident(tab+1), tag(ptr.tag()), ptr.lab(), lc, trg.show()));
code.push_str(&format!("{}}}\n", ident(tab)));
code.push_str(&burn(book, tab, None, newx, vars, def, p2, &x2));
code.push_str(&burn(book, tab, None, newx, vars, def, p1, &x1));
return code;
}
// (p1 p2) <~ (x1 x2)
// ------------------ fast apply
// p1 <~ x1
// p2 <~ x2
if ptr.is_ctr() && ptr.tag() == run::LAM {
let x1 = Target { nam: format!("{}x", trg.show()) };
let x2 = Target { nam: format!("{}y", trg.show()) };
let p1 = def.node[ptr.loc() as usize].1;
let p2 = def.node[ptr.loc() as usize].2;
let lc = fresh(newx);
code.push_str(&format!("{}let {} : Trg;\n", ident(tab), &x1.show()));
code.push_str(&format!("{}let {} : Trg;\n", ident(tab), &x2.show()));
code.push_str(&format!("{}// fast apply\n", ident(tab)));
code.push_str(&format!("{}if {}.tag() == {} {{\n", ident(tab), trg.get(), tag(ptr.tag())));
code.push_str(&format!("{}self.rwts.anni += 1;\n", ident(tab+1)));
code.push_str(&format!("{}let got = {};\n", ident(tab+1), trg.take()));
code.push_str(&format!("{}{} = Trg::Dir(Ptr::new(VR1, 0, got.loc()));\n", ident(tab+1), &x1.show()));
code.push_str(&format!("{}{} = Trg::Dir(Ptr::new(VR2, 0, got.loc()));\n", ident(tab+1), &x2.show()));
code.push_str(&format!("{}}} else {{\n", ident(tab)));
code.push_str(&format!("{}let {} = self.alloc();\n", ident(tab+1), lc));
code.push_str(&format!("{}{} = Trg::Ptr(Ptr::new(VR1, 0, {}));\n", ident(tab+1), &x1.show(), lc));
code.push_str(&format!("{}{} = Trg::Ptr(Ptr::new(VR2, 0, {}));\n", ident(tab+1), &x2.show(), lc));
code.push_str(&format!("{}self.safe_link(Trg::Ptr(Ptr::new({}, 0, {})), {});\n", ident(tab+1), tag(ptr.tag()), lc, trg.show()));
code.push_str(&format!("{}}}\n", ident(tab)));
code.push_str(&burn(book, tab, None, newx, vars, def, p2, &x2));
code.push_str(&burn(book, tab, None, newx, vars, def, p1, &x1));
return code;
}
//// TODO: implement inlining correctly
//// NOTE: enabling this makes dec_bits_tree hang; investigate
//if ptr.is_ref() && tail.is_some() {
//code.push_str(&format!("{}// inline @{}\n", ident(tab), ast::val_to_name(ptr.loc() as run::Val)));
//code.push_str(&format!("{}if !{}.is_skp() {{\n", ident(tab), trg.get()));
//code.push_str(&format!("{}self.rwts.dref += 1;\n", ident(tab+1)));
//code.push_str(&call(book, tab+1, tail, newx, &mut HashMap::new(), ptr.loc(), trg));
//code.push_str(&format!("{}}} else {{\n", ident(tab)));
//code.push_str(&make(tab+1, newx, vars, def, ptr, &trg.show()));
//code.push_str(&format!("{}}}\n", ident(tab)));
//return code;
//}
// ATOM <~ *
// --------- fast erase
// nothing
if ptr.is_num() || ptr.is_era() {
code.push_str(&format!("{}// fast erase\n", ident(tab)));
code.push_str(&format!("{}if {}.is_skp() {{\n", ident(tab), trg.get()));
code.push_str(&format!("{}{};\n", ident(tab+1), trg.take()));
code.push_str(&format!("{}self.rwts.eras += 1;\n", ident(tab+1)));
code.push_str(&format!("{}}} else {{\n", ident(tab)));
code.push_str(&make(tab+1, newx, vars, def, ptr, &trg.show()));
code.push_str(&format!("{}}}\n", ident(tab)));
return code;
}
code.push_str(&make(tab, newx, vars, def, ptr, &trg.show()));
return code;
}
fn make(
tab : usize,
newx : &mut usize,
vars : &mut HashMap<run::Ptr, String>,
def : &run::Def,
ptr : run::Ptr,
trg : &String,
) -> String {
//println!("make {:08x} {}", ptr.0, x);
let mut code = String::new();
if ptr.is_nod() {
let lc = fresh(newx);
let p1 = def.node[ptr.loc() as usize].1;
let p2 = def.node[ptr.loc() as usize].2;
code.push_str(&format!("{}let {} = self.alloc();\n", ident(tab), lc));
code.push_str(&make(tab, newx, vars, def, p2, &format!("Trg::Ptr(Ptr::new(VR2, 0, {}))", lc)));
code.push_str(&make(tab, newx, vars, def, p1, &format!("Trg::Ptr(Ptr::new(VR1, 0, {}))", lc)));
code.push_str(&format!("{}self.safe_link(Trg::Ptr(Ptr::new({}, {}, {})), {});\n", ident(tab), tag(ptr.tag()), ptr.lab(), lc, trg));
} else if ptr.is_var() {
match got(vars, def, ptr) {
None => {
//println!("-var fst");
vars.insert(ptr, trg.clone());
},
Some(got) => {
//println!("-var snd");
code.push_str(&format!("{}self.safe_link({}, {});\n", ident(tab), trg, got));
}
}
} else {
code.push_str(&format!("{}self.safe_link({}, Trg::Ptr({}));\n", ident(tab), trg, atom(ptr)));
}
return code;
}
fn got(
vars : &HashMap<run::Ptr, String>,
def : &run::Def,
ptr : run::Ptr,
) -> Option<String> {
if ptr.is_var() {
let got = def.node[ptr.loc() as usize];
let slf = if ptr.tag() == run::VR1 { got.1 } else { got.2 };
return vars.get(&slf).cloned();
} else {
return None;
}
}
let fun = ast::val_to_name(fid);
let def = &book.get(fid).unwrap();
let mut code = String::new();
// Given a label, returns true if the definition contains that dup label, directly or not
code.push_str(&format!("{}pub fn L_{}(&mut self, lab: Lab) -> bool {{\n", ident(tab), fun));
for dup in &def.labs {
code.push_str(&format!("{}if lab == 0x{:x} {{ return true; }}\n", ident(tab+1), dup));
}
code.push_str(&format!("{}return false;\n", ident(tab+1)));
code.push_str(&format!("{}}}\n", ident(tab)));
// Calls the definition, performing inline rewrites when possible, and expanding it when not
code.push_str(&format!("{}pub fn F_{}(&mut self, ptr: Ptr, trg: Trg) -> bool {{\n", ident(tab), fun));
code.push_str(&format!("{}if self.get(trg).is_dup() && !self.L_{}(self.get(trg).lab()) {{\n", ident(tab+1), fun));
code.push_str(&format!("{}self.copy(self.swap(trg, NULL), ptr);\n", ident(tab+2)));
code.push_str(&format!("{}return true;\n", ident(tab+2)));
code.push_str(&format!("{}}}\n", ident(tab+1)));
code.push_str(&call(book, tab+1, None, &mut 0, &mut HashMap::new(), fid, &Target { nam: "trg".to_string() }));
code.push_str(&format!("{}return true;\n", ident(tab+1)));
code.push_str(&format!("{}}}\n", ident(tab)));
return code;
}
// TODO: HVM-Lang must always output in this form.
fn adjust_redex(rf: run::Ptr, rx: run::Ptr) -> (run::Ptr, run::Ptr) {
if rf.is_skp() && !rx.is_skp() {
return (rf, rx);
} else if !rf.is_skp() && rx.is_skp() {
return (rx, rf);
} else {
println!("Invalid redex. Compiled HVM requires that ALL defs are in the form:");
println!("@name = ROOT");
println!(" & ATOM ~ TERM");
println!(" & ATOM ~ TERM");
println!(" & ATOM ~ TERM");
println!(" ...");
println!("Where ATOM must be either a ref (`@foo`), a num (`#123`), or an era (`*`).");
println!("If you used HVM-Lang, please report on https://github.com/HigherOrderCO/hvm-lang.");
panic!("Invalid HVMC file.");
}
}

View File

@ -1,14 +0,0 @@
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
#![allow(dead_code)]
#![allow(unused_variables)]
#![allow(unused_imports)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
pub mod ast;
pub mod fns;
pub mod jit;
pub mod run;
pub mod u60;

View File

@ -1,256 +0,0 @@
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
#![allow(dead_code)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(unused_imports)]
#![allow(unused_variables)]
use std::env;
use std::fs;
use hvmc::ast;
use hvmc::fns;
use hvmc::jit;
use hvmc::run;
use hvmc::u60;
use std::collections::HashSet;
struct Args {
func: String,
argm: String,
opts: HashSet<String>,
}
fn get_args() -> Args {
let args: Vec<String> = env::args().collect();
let func = args.get(1).unwrap_or(&"help".to_string()).to_string();
let argm = args.get(2).unwrap_or(&"".to_string()).to_string();
let opts = args.iter().skip(3).map(|s| s.to_string()).collect::<HashSet<_>>();
return Args { func, argm, opts };
}
// Runs 'main' without showing the CLI options
fn run_without_cli(args: Args) {
let lazy = args.opts.contains("-L");
let seq = lazy || args.opts.contains("-1");
let file = args.argm;
let book = run::Book::new();
let mut net = run::Net::new(1 << 28, false);
let begin = std::time::Instant::now();
if lazy { todo!() }
if seq {
net.normal(&book);
} else {
net.parallel_normal(&book);
}
println!("{}", net.show());
print_stats(&net, begin);
}
fn run_with_cli(args: Args) -> Result<(), Box<dyn std::error::Error>> {
let lazy = args.opts.contains("-L");
let seq = lazy || args.opts.contains("-1");
match args.func.as_str() {
"run" => {
if args.argm.len() > 0 {
let file = args.argm;
let book = load_book(&file);
let mut net = run::Net::new(1 << 28, lazy);
let begin = std::time::Instant::now();
if seq {
net.normal(&book);
} else {
net.parallel_normal(&book);
}
//println!("{}", net.show());
println!("{}", net.show());
if args.opts.contains("-s") {
print_stats(&net, begin);
}
} else {
println!("Usage: hvmc run <file.hvmc> [-s]");
std::process::exit(1);
}
}
"compile" => {
if args.argm.len() > 0 {
let file = args.argm;
let book = load_book(&file);
let net = run::Net::new(1 << 28, lazy);
let begin = std::time::Instant::now();
compile_book_to_rust_crate(&file, &book)?;
compile_rust_crate_to_executable(&file)?;
} else {
println!("Usage: hvmc compile <file.hvmc>");
std::process::exit(1);
}
}
"gen-cuda-book" => {
if args.argm.len() > 0 {
let file = args.argm;
let book = load_book(&file);
let net = run::Net::new(1 << 28, lazy);
let begin = std::time::Instant::now();
println!("{}", gen_cuda_book(&book));
} else {
println!("Usage: hvmc gen-cuda-book <file.hvmc>");
std::process::exit(1);
}
}
_ => {
println!("Usage: hvmc <cmd> <file.hvmc> [-s]");
println!("Commands:");
println!(" run - Run the given file");
println!(" compile - Compile the given file to an executable");
println!(" gen-cuda-book - Generate a CUDA book from the given file");
println!("Options:");
println!(" [-s] Show stats, including rewrite count");
println!(" [-1] Single-core mode (no parallelism)");
}
}
Ok(())
}
#[cfg(not(feature = "hvm_cli_options"))]
fn main() {
run_without_cli(get_args())
}
#[cfg(feature = "hvm_cli_options")]
fn main() -> Result<(), Box<dyn std::error::Error>> {
run_with_cli(get_args())
}
fn print_stats(net: &run::Net, begin: std::time::Instant) {
let rewrites = net.get_rewrites();
println!("RWTS : {}", rewrites.total());
println!("- ANNI : {}", rewrites.anni);
println!("- COMM : {}", rewrites.comm);
println!("- ERAS : {}", rewrites.eras);
println!("- DREF : {}", rewrites.dref);
println!("- OPER : {}", rewrites.oper);
println!("TIME : {:.3} s", (begin.elapsed().as_millis() as f64) / 1000.0);
println!("RPS : {:.3} m", (rewrites.total() as f64) / (begin.elapsed().as_millis() as f64) / 1000.0);
}
// Load file
fn load_book(file: &str) -> run::Book {
let Ok(file) = fs::read_to_string(file) else {
eprintln!("Input file not found");
std::process::exit(1);
};
return ast::book_to_runtime(&ast::do_parse_book(&file));
}
pub fn compile_book_to_rust_crate(f_name: &str, book: &run::Book) -> Result<(), std::io::Error> {
let fns_rs = jit::compile_book(book);
let outdir = ".hvm";
if std::path::Path::new(&outdir).exists() {
fs::remove_dir_all(&outdir)?;
}
let cargo_toml = include_str!("../Cargo.toml");
let cargo_toml = cargo_toml.split("##--COMPILER-CUTOFF--##").next().unwrap();
let cargo_toml = cargo_toml.replace("\"hvm_cli_options\"", "");
fs::create_dir_all(&format!("{}/src", outdir))?;
fs::write(".hvm/Cargo.toml", cargo_toml)?;
fs::write(".hvm/src/ast.rs", include_str!("../src/ast.rs"))?;
fs::write(".hvm/src/jit.rs", include_str!("../src/jit.rs"))?;
fs::write(".hvm/src/lib.rs", include_str!("../src/lib.rs"))?;
fs::write(".hvm/src/main.rs", include_str!("../src/main.rs"))?;
fs::write(".hvm/src/run.rs", include_str!("../src/run.rs"))?;
fs::write(".hvm/src/u60.rs", include_str!("../src/u60.rs"))?;
fs::write(".hvm/src/fns.rs", fns_rs)?;
return Ok(());
}
pub fn compile_rust_crate_to_executable(f_name: &str) -> Result<(), std::io::Error> {
let output = std::process::Command::new("cargo").current_dir("./.hvm").arg("build").arg("--release").output()?;
let target = format!("./{}", f_name.replace(".hvmc", ""));
if std::path::Path::new(&target).exists() {
fs::remove_file(&target)?;
}
fs::copy("./.hvm/target/release/hvmc", target)?;
return Ok(());
}
// TODO: move to hvm-cuda repo
pub fn gen_cuda_book(book: &run::Book) -> String {
use std::collections::BTreeMap;
// Sort the book.defs by key
let mut defs = BTreeMap::new();
for (fid, def) in book.defs.iter() {
if def.node.len() > 0 {
defs.insert(fid, def.clone());
}
}
// Initializes code
let mut code = String::new();
// Generate function ids
for (i, id) in defs.keys().enumerate() {
code.push_str(&format!("const u32 F_{} = 0x{:x};\n", crate::ast::val_to_name(**id), id));
}
code.push_str("\n");
// Create book
code.push_str("u32 BOOK_DATA[] = {\n");
// Generate book data
for (i, (id, net)) in defs.iter().enumerate() {
let node_len = net.node.len();
let rdex_len = net.rdex.len();
code.push_str(&format!(" // @{}\n", crate::ast::val_to_name(**id)));
// Collect all pointers from root, nodes and rdex into a single buffer
code.push_str(&format!(" // .nlen\n"));
code.push_str(&format!(" 0x{:08X},\n", node_len));
code.push_str(&format!(" // .rlen\n"));
code.push_str(&format!(" 0x{:08X},\n", rdex_len));
// .node
code.push_str(" // .node\n");
for (i, node) in net.node.iter().enumerate() {
code.push_str(&format!(" 0x{:08X},", node.1.0));
code.push_str(&format!(" 0x{:08X},", node.2.0));
if (i + 1) % 4 == 0 {
code.push_str("\n");
}
}
if node_len % 4 != 0 {
code.push_str("\n");
}
// .rdex
code.push_str(" // .rdex\n");
for (i, (a, b)) in net.rdex.iter().enumerate() {
code.push_str(&format!(" 0x{:08X},", a.0));
code.push_str(&format!(" 0x{:08X},", b.0));
if (i + 1) % 4 == 0 {
code.push_str("\n");
}
}
if rdex_len % 4 != 0 {
code.push_str("\n");
}
}
code.push_str("};\n\n");
code.push_str("u32 JUMP_DATA[] = {\n");
let mut index = 0;
for (i, fid) in defs.keys().enumerate() {
code.push_str(&format!(" 0x{:08X}, 0x{:08X}, // @{}\n", fid, index, crate::ast::val_to_name(**fid)));
index += 2 + 2 * defs[fid].node.len() as u32 + 2 * defs[fid].rdex.len() as u32;
}
code.push_str("};");
return code;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,113 +0,0 @@
// Implements u48: 48-bit unsigned integers using u64 and u128
type U60 = u64;
#[inline(always)]
pub fn new(a: u64) -> U60 {
return a & 0xFFF_FFFF_FFFF_FFFF;
}
#[inline(always)]
pub fn val(a: u64) -> U60 {
return a;
}
#[inline(always)]
pub fn add(a: U60, b: U60) -> U60 {
return new(a + b);
}
#[inline(always)]
pub fn sub(a: U60, b: U60) -> U60 {
return if a >= b { a - b } else { 0x1000000000000000 - (b - a) };
}
#[inline(always)]
pub fn mul(a: U60, b: U60) -> U60 {
return new((a as u128 * b as u128) as u64);
}
#[inline(always)]
pub fn div(a: U60, b: U60) -> U60 {
return a / b;
}
#[inline(always)]
pub fn rem(a: U60, b: U60) -> U60 {
return a % b;
}
#[inline(always)]
pub fn and(a: U60, b: U60) -> U60 {
return a & b;
}
#[inline(always)]
pub fn or(a: U60, b: U60) -> U60 {
return a | b;
}
#[inline(always)]
pub fn xor(a: U60, b: U60) -> U60 {
return a ^ b;
}
#[inline(always)]
pub fn lsh(a: U60, b: U60) -> U60 {
return new(a << b);
}
#[inline(always)]
pub fn rsh(a: U60, b: U60) -> U60 {
return a >> b;
}
#[inline(always)]
pub fn lt(a: U60, b: U60) -> U60 {
return if a < b { 1 } else { 0 };
}
#[inline(always)]
pub fn gt(a: U60, b: U60) -> U60 {
return if a > b { 1 } else { 0 };
}
#[inline(always)]
pub fn lte(a: U60, b: U60) -> U60 {
return if a <= b { 1 } else { 0 };
}
#[inline(always)]
pub fn gte(a: U60, b: U60) -> U60 {
return if a >= b { 1 } else { 0 };
}
#[inline(always)]
pub fn eq(a: U60, b: U60) -> U60 {
return if a == b { 1 } else { 0 };
}
#[inline(always)]
pub fn ne(a: U60, b: U60) -> U60 {
return if a != b { 1 } else { 0 };
}
#[inline(always)]
pub fn min(a: U60, b: U60) -> U60 {
return if a < b { a } else { b };
}
#[inline(always)]
pub fn max(a: U60, b: U60) -> U60 {
return if a > b { a } else { b };
}
#[inline(always)]
pub fn not(a: U60) -> U60 {
return !a & 0xFFF_FFFF_FFFF_FFFF;
}
#[inline(always)]
pub fn show(a: U60) -> String {
return format!("{}", a);
}

View File

@ -1 +0,0 @@
{"rustc_fingerprint":4802413464031946296,"outputs":{"15729799797837862367":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.dylib\nlib___.dylib\nlib___.a\nlib___.dylib\n/Users/v/.rustup/toolchains/nightly-aarch64-apple-darwin\noff\npacked\nunpacked\n___\ndebug_assertions\noverflow_checks\npanic=\"unwind\"\nproc_macro\nrelocation_model=\"pic\"\ntarget_abi=\"\"\ntarget_arch=\"aarch64\"\ntarget_endian=\"little\"\ntarget_env=\"\"\ntarget_family=\"unix\"\ntarget_feature=\"aes\"\ntarget_feature=\"crc\"\ntarget_feature=\"dit\"\ntarget_feature=\"dotprod\"\ntarget_feature=\"dpb\"\ntarget_feature=\"dpb2\"\ntarget_feature=\"fcma\"\ntarget_feature=\"fhm\"\ntarget_feature=\"flagm\"\ntarget_feature=\"fp16\"\ntarget_feature=\"frintts\"\ntarget_feature=\"jsconv\"\ntarget_feature=\"lor\"\ntarget_feature=\"lse\"\ntarget_feature=\"neon\"\ntarget_feature=\"paca\"\ntarget_feature=\"pacg\"\ntarget_feature=\"pan\"\ntarget_feature=\"pmuv3\"\ntarget_feature=\"ras\"\ntarget_feature=\"rcpc\"\ntarget_feature=\"rcpc2\"\ntarget_feature=\"rdm\"\ntarget_feature=\"sb\"\ntarget_feature=\"sha2\"\ntarget_feature=\"sha3\"\ntarget_feature=\"ssbs\"\ntarget_feature=\"v8.1a\"\ntarget_feature=\"v8.2a\"\ntarget_feature=\"v8.3a\"\ntarget_feature=\"v8.4a\"\ntarget_feature=\"vh\"\ntarget_has_atomic\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_has_atomic_equal_alignment=\"128\"\ntarget_has_atomic_equal_alignment=\"16\"\ntarget_has_atomic_equal_alignment=\"32\"\ntarget_has_atomic_equal_alignment=\"64\"\ntarget_has_atomic_equal_alignment=\"8\"\ntarget_has_atomic_equal_alignment=\"ptr\"\ntarget_has_atomic_load_store\ntarget_has_atomic_load_store=\"128\"\ntarget_has_atomic_load_store=\"16\"\ntarget_has_atomic_load_store=\"32\"\ntarget_has_atomic_load_store=\"64\"\ntarget_has_atomic_load_store=\"8\"\ntarget_has_atomic_load_store=\"ptr\"\ntarget_os=\"macos\"\ntarget_pointer_width=\"64\"\ntarget_thread_local\ntarget_vendor=\"apple\"\nunix\n","stderr":""},"4614504638168534921":{"success":true,"status":"","code":0,"stdout":"rustc 1.76.0-nightly (9a66e4471 2023-11-19)\nbinary: rustc\ncommit-hash: 9a66e4471f71283fd54d80ef8147630d34756332\ncommit-date: 2023-11-19\nhost: aarch64-apple-darwin\nrelease: 1.76.0-nightly\nLLVM version: 17.0.5\n","stderr":""}},"successes":{}}

View File

@ -1,3 +0,0 @@
Signature: 8a477f597d28d172789f06886806bc55
# This file is a cache directory tag created by cargo.
# For information about cache directory tags see https://bford.info/cachedir/

View File

@ -1 +0,0 @@
This file has an mtime of when this was started.

View File

@ -1,5 +0,0 @@
{"message":"expected one of `:`, `;`, `<`, `=`, or `where`, found `.`","code":null,"level":"error","spans":[{"file_name":"src/fns.rs","byte_start":186,"byte_end":187,"line_start":7,"line_end":7,"column_start":17,"column_end":18,"is_primary":true,"text":[{"text":"pub const F__U60.fib : Val = 0xf9e180fe9b25;","highlight_start":17,"highlight_end":18}],"label":"expected one of `:`, `;`, `<`, `=`, or `where`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"\u001b[0m\u001b[1m\u001b[38;5;9merror\u001b[0m\u001b[0m\u001b[1m: expected one of `:`, `;`, `<`, `=`, or `where`, found `.`\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0msrc/fns.rs:7:17\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n\u001b[0m\u001b[1m\u001b[38;5;12m7\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0mpub const F__U60.fib : Val = 0xf9e180fe9b25;\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9m^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9mexpected one of `:`, `;`, `<`, `=`, or `where`\u001b[0m\n\n"}
{"message":"no method named `call_native` found for mutable reference `&mut NetFields<'a, LAZY>` in the current scope","code":{"code":"E0599","explanation":"This error occurs when a method is used on a type which doesn't implement it:\n\nErroneous code example:\n\n```compile_fail,E0599\nstruct Mouth;\n\nlet x = Mouth;\nx.chocolate(); // error: no method named `chocolate` found for type `Mouth`\n // in the current scope\n```\n\nIn this case, you need to implement the `chocolate` method to fix the error:\n\n```\nstruct Mouth;\n\nimpl Mouth {\n fn chocolate(&self) { // We implement the `chocolate` method here.\n println!(\"Hmmm! I love chocolate!\");\n }\n}\n\nlet x = Mouth;\nx.chocolate(); // ok!\n```\n"},"level":"error","spans":[{"file_name":"src/run.rs","byte_start":30344,"byte_end":30355,"line_start":993,"line_end":993,"column_start":24,"column_end":35,"is_primary":true,"text":[{"text":" if !LAZY && self.call_native(book, ptr, trg) {","highlight_start":24,"highlight_end":35}],"label":"method not found in `&mut NetFields<'a, LAZY>`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"\u001b[0m\u001b[1m\u001b[38;5;9merror[E0599]\u001b[0m\u001b[0m\u001b[1m: no method named `call_native` found for mutable reference `&mut NetFields<'a, LAZY>` in the current scope\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0msrc/run.rs:993:24\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n\u001b[0m\u001b[1m\u001b[38;5;12m993\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m if !LAZY && self.call_native(book, ptr, trg) {\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9m^^^^^^^^^^^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9mmethod not found in `&mut NetFields<'a, LAZY>`\u001b[0m\n\n"}
{"message":"missing type for `const` item","code":null,"level":"error","spans":[{"file_name":"src/fns.rs","byte_start":186,"byte_end":186,"line_start":7,"line_end":7,"column_start":17,"column_end":17,"is_primary":true,"text":[{"text":"pub const F__U60.fib : Val = 0xf9e180fe9b25;","highlight_start":17,"highlight_end":17}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"provide a type for the item","code":null,"level":"help","spans":[{"file_name":"src/fns.rs","byte_start":186,"byte_end":186,"line_start":7,"line_end":7,"column_start":17,"column_end":17,"is_primary":true,"text":[{"text":"pub const F__U60.fib : Val = 0xf9e180fe9b25;","highlight_start":17,"highlight_end":17}],"label":null,"suggested_replacement":": <type>","suggestion_applicability":"HasPlaceholders","expansion":null}],"children":[],"rendered":null}],"rendered":"\u001b[0m\u001b[1m\u001b[38;5;9merror\u001b[0m\u001b[0m\u001b[1m: missing type for `const` item\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0msrc/fns.rs:7:17\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n\u001b[0m\u001b[1m\u001b[38;5;12m7\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0mpub const F__U60.fib : Val = 0xf9e180fe9b25;\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9m^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9mhelp: provide a type for the item: `: <type>`\u001b[0m\n\n"}
{"message":"aborting due to 3 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"\u001b[0m\u001b[1m\u001b[38;5;9merror\u001b[0m\u001b[0m\u001b[1m: aborting due to 3 previous errors\u001b[0m\n\n"}
{"message":"For more information about this error, try `rustc --explain E0599`.","code":null,"level":"failure-note","spans":[],"children":[],"rendered":"\u001b[0m\u001b[1mFor more information about this error, try `rustc --explain E0599`.\u001b[0m\n"}

View File

@ -1 +0,0 @@
This file has an mtime of when this was started.

View File

@ -1 +0,0 @@
{"rustc":15865603277963313838,"features":"[\"default\", \"std\"]","target":2117364898282992337,"profile":15536308671813986309,"path":6587989396380489126,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release/.fingerprint/nohash-hasher-dc8a50f19f38f70e/dep-lib-nohash-hasher"}}],"rustflags":[],"metadata":8492774112348001440,"config":2202906307356721367,"compile_kind":0}

View File

@ -1,12 +0,0 @@
/Users/v/vic/dev/kind2/book/.hvm/target/release/deps/libhvmc-5d3b356175a8b321.rmeta: src/lib.rs src/ast.rs src/fns.rs src/jit.rs src/run.rs src/u60.rs
/Users/v/vic/dev/kind2/book/.hvm/target/release/deps/libhvmc-5d3b356175a8b321.rlib: src/lib.rs src/ast.rs src/fns.rs src/jit.rs src/run.rs src/u60.rs
/Users/v/vic/dev/kind2/book/.hvm/target/release/deps/hvmc-5d3b356175a8b321.d: src/lib.rs src/ast.rs src/fns.rs src/jit.rs src/run.rs src/u60.rs
src/lib.rs:
src/ast.rs:
src/fns.rs:
src/jit.rs:
src/run.rs:
src/u60.rs:

View File

@ -1,7 +0,0 @@
/Users/v/vic/dev/kind2/book/.hvm/target/release/deps/libnohash_hasher-dc8a50f19f38f70e.rmeta: /Users/v/.cargo/registry/src/index.crates.io-6f17d22bba15001f/nohash-hasher-0.2.0/src/lib.rs
/Users/v/vic/dev/kind2/book/.hvm/target/release/deps/libnohash_hasher-dc8a50f19f38f70e.rlib: /Users/v/.cargo/registry/src/index.crates.io-6f17d22bba15001f/nohash-hasher-0.2.0/src/lib.rs
/Users/v/vic/dev/kind2/book/.hvm/target/release/deps/nohash_hasher-dc8a50f19f38f70e.d: /Users/v/.cargo/registry/src/index.crates.io-6f17d22bba15001f/nohash-hasher-0.2.0/src/lib.rs
/Users/v/.cargo/registry/src/index.crates.io-6f17d22bba15001f/nohash-hasher-0.2.0/src/lib.rs:

3
book/Tree.kind2 Normal file
View File

@ -0,0 +1,3 @@
data Tree A
| node (val: A) (lft: (Tree A)) (rgt: (Tree A))
| leaf

7
book/Tree/fold.kind2 Normal file
View File

@ -0,0 +1,7 @@
use Tree/{node,leaf}
Tree/fold <A> <B> (bm: (Tree A)) (nd: A -> B -> B -> B) (lf: B) : B =
match bm with (nd: A -> B -> B -> B) (lf: B) {
node: (nd bm.val (Tree/fold bm.lft nd lf) (Tree/fold bm.rgt nd lf))
leaf: lf
}

7
book/Tree/gen.kind2 Normal file
View File

@ -0,0 +1,7 @@
use Tree/{node,leaf}
gen (n: U60) (x: U60) : (Tree U60) =
switch n {
0: leaf
_: (node x (gen n-1 (+ (* x 2) 1)) (gen n-1 (+ (* x 2) 2)))
}

3
book/Tree/leaf.kind2 Normal file
View File

@ -0,0 +1,3 @@
leaf <A> : (Tree A) =
~λP λnode λleaf
leaf

3
book/Tree/node.kind2 Normal file
View File

@ -0,0 +1,3 @@
node <A> (val: A) (lft: (Tree A)) (rgt: (Tree A)) : (Tree A) =
~λP λnode λleaf
(node val lft rgt)

18
book/Tree/sum.kind2 Normal file
View File

@ -0,0 +1,18 @@
use Tree/{node,leaf}
// Sums a binary tree in parallel, using fold
// __(1)__
// / \ __(1)__
// (1) (2) => / \ => (14)
// / \ / \ (4) (9)
// (1) (2) (3) (4)
sum (x: (Tree U60)) : U60 =
fold x {
node: (+ x.val (+ x.lft x.rgt))
leaf: 0
}

BIN
book/_main Executable file

Binary file not shown.

View File

@ -1,21 +1,33 @@
//WARNING: unsolved metas_
//WARNING: unsolved metas_
_Char = 0
_List = λ_T 0
_List.Folder = λ_T 0
_List.cons = λ_T λ_head λ_tail λ_P λ_cons λ_nil ((_cons _head) _tail)
_List.fold = λ_list
let _list.P = 0
let _list.cons = λ_list.head λ_list.tail λ_P λ_c λ_n ((_c _list.head) (((((_List.fold) _list.tail) _P) _c) _n))
let _list.nil = λ_P λ_c λ_n _n
(((_list _list.P) _list.cons) _list.nil)
_List.map = λ_A λ_B λ_xs λ_f (((((_List.fold) _xs) 0) λ_h λ_t (((_List.cons 0) (_f _h)) _t)) (_List.nil 0))
_List.nil = λ_T λ_P λ_cons λ_nil _nil
_List_cons = λ_head λ_tail λ_P λ_cons λ_nil ((_cons _head) _tail)
_List_nil = λ_P λ_cons λ_nil _nil
_Nat = 0
_Nat.succ = λ_n λ_P λ_succ λ_zero (_succ _n)
_Nat.zero = λ_P λ_succ λ_zero _zero
_Nat_succ = λ_n λ_P λ_succ λ_zero (_succ _n)
_Nat_zero = λ_P λ_succ λ_zero _zero
_String = (_List _Char)
_String.cons = λ_head λ_tail λ_P λ_cons λ_nil ((_cons _head) _tail)
_String.nil = λ_P λ_cons λ_nil _nil
__main = ((((_List.map 0) 0) (((_List.cons 0) 1) (((_List.cons 0) 2) (((_List.cons 0) 3) (_List.nil 0))))) λ_x (+ _x 1))
_String_cons = λ_head λ_tail λ_P λ_cons λ_nil ((_cons _head) _tail)
_String_nil = λ_P λ_cons λ_nil _nil
_Tree = λ_A 0
_Tree_fold = λ_bm λ_nd λ_lf
let _bm_P = 0
let _bm_node = λ_bm_val λ_bm_lft λ_bm_rgt λ_nd λ_lf (((_nd _bm_val) (((_Tree_fold _bm_lft) _nd) _lf)) (((_Tree_fold _bm_rgt) _nd) _lf))
let _bm_leaf = λ_nd λ_lf _lf
(((((_bm _bm_P) _bm_node) _bm_leaf) _nd) _lf)
_Tree_gen = λ_n λ_x match _n = _n {
0: _Tree_leaf
1+: let _n-1 = _n-1
(((_Tree_node _x) ((_Tree_gen _n-1) (+ (* _x 2) 1))) ((_Tree_gen _n-1) (+ (* _x 2) 2)))
}
_Tree_leaf = λ_P λ_node λ_leaf _leaf
_Tree_node = λ_val λ_lft λ_rgt λ_P λ_node λ_leaf (((_node _val) _lft) _rgt)
_Tree_sum = λ_x
let _x_P = 0
let _x_node = λ_x_val λ_x_lft λ_x_rgt (+ _x_val (+ _x_lft _x_rgt))
let _x_leaf = 0
(((_Tree_fold _x) _x_node) _x_leaf)
__main = (_Tree_sum ((_Tree_gen 22) 0))
main = __main

View File

@ -1,17 +1,37 @@
@cons = (a (b ((a (b c)) (* c))))
@foo = ({3 (a b) c} (a (d e)))
& @cons ~ (b (f e))
& @map ~ (c (d f))
@main = a
& @map ~ ((<+ #1 b> b) (c a))
& @cons ~ (#1 (d c))
& @cons ~ (#2 (e d))
& @cons ~ (#3 (@nil e))
@map = (a ((b (@nil c)) c))
& @foo ~ (a b)
@nil = (* (a a))
@_chr = #0
@_ls = (* #0)
@_ls_cn = (a (b (* ((a (b c)) (* c)))))
@_ls_nl = (* @_ls_nl_0)
@_ls_nl_0 = (* (a a))
@_N = #0
@_N_s = (a (* ((a b) (* b))))
@_N_z = (* @_N_z_0)
@_N_z_0 = (* (a a))
@_str = a
& @_ls ~ (@_chr a)
@_str_cn = (a (b (* ((a (b c)) (* c)))))
@_str_nl = (* @_str_nl_0)
@_str_nl_0 = (* (a a))
@_T = (* #0)
@_T_f = ((#0 (@_T_f_0 (@_T_f_1 (a (b c))))) (a (b c)))
@_T_f_0 = (a (b (c ({7 (a (d (e f))) {7 g h}} ({9 i j} f)))))
& @_T_f ~ (c (h (j e)))
& @_T_f ~ (b (g (i d)))
@_T_f_1 = (* (a a))
@_T_gn = (?<(@_T_gn_0 @_T_gn_1) (a b)> (a b))
@_T_gn_0 = (* @_T_lf)
@_T_gn_1 = ({5 a b} ({3 c {3 <* #2 <+ #1 d>> <* #2 <+ #2 e>>}} f))
& @_T_nd ~ (c (g (h f)))
& @_T_gn ~ (b (e h))
& @_T_gn ~ (a (d g))
@_T_lf = (* @_T_lf_0)
@_T_lf_0 = (* (a a))
@_T_nd = (a (b (c (* ((a (b (c d))) (* d))))))
@_T_sum = (a b)
& @_T_f ~ (a (@_T_sum_0 (#0 b)))
@_T_sum_0 = (<+ a b> (<+ c a> (c b)))
@__main = a
& @_T_sum ~ (b a)
& @_T_gn ~ (#22 (#0 b))
@main = @__main

36
book/_main.js Normal file
View File

@ -0,0 +1,36 @@
let _Char = 0;
let _List = (_T) => 0;
let _List_cons = (_head) => (_tail) => (_P) => (_cons) => (_nil) => ((_cons(_head))(_tail));
let _List_nil = (_P) => (_cons) => (_nil) => _nil;
let _Nat = 0;
let _Nat_succ = (_n) => (_P) => (_succ) => (_zero) => (_succ(_n));
let _Nat_zero = (_P) => (_succ) => (_zero) => _zero;
let _String = (_List(_Char));
let _String_cons = (_head) => (_tail) => (_P) => (_cons) => (_nil) => ((_cons(_head))(_tail));
let _String_nil = (_P) => (_cons) => (_nil) => _nil;
let _Tree = (_A) => 0;
let _Tree_fold = (_bm) => (_nd) => (_lf) => {
let _bm_P = 0;
let _bm_node = (_bm_val) => (_bm_lft) => (_bm_rgt) => (_nd) => (_lf) => (((_nd(_bm_val))(((_Tree_fold(_bm_lft))(_nd))(_lf)))(((_Tree_fold(_bm_rgt))(_nd))(_lf)));
let _bm_leaf = (_nd) => (_lf) => _lf;
return (((((_bm(_bm_P))(_bm_node))(_bm_leaf))(_nd))(_lf));
};
let _Tree_gen = (_n) => (_x) => {
if (_n === 0) {
return _Tree_leaf;
} else {
let _n_1 = _n - 1;
return (((_Tree_node(_x))((_Tree_gen(_n_1))(((_x * 2) + 1))))((_Tree_gen(_n_1))(((_x * 2) + 2))));
}
};
let _Tree_leaf = (_P) => (_node) => (_leaf) => _leaf;
let _Tree_node = (_val) => (_lft) => (_rgt) => (_P) => (_node) => (_leaf) => (((_node(_val))(_lft))(_rgt));
let _Tree_sum = (_x) => {
let _x_P = 0;
let _x_node = (_x_val) => (_x_lft) => (_x_rgt) => (_x_val + (_x_lft + _x_rgt));
let _x_leaf = 0;
return (((_Tree_fold(_x))(_x_node))(_x_leaf));
};
let __main = (_Tree_sum((_Tree_gen(22))(0)));
console.log(__main)

View File

@ -1,11 +1,40 @@
//data Vector A (len: Nat)
//| cons (len: Nat) (head: A) (tail: (Vector A len)) : (Vector A (Nat.succ len))
//| nil : (Vector A Nat.zero)
//// Sums a binary tree in parallel, using fold
//// __(1)__
//// / \ __(1)__
//// (1) (2) => / \ => (14)
//// / \ / \ (4) (9)
//// (1) (2) (3) (4)
//use Tree/{node,leaf}
//data Tree A
//| node (val: A) (lft: (Tree A)) (rgt: (Tree A))
//| leaf
//sum (x: (Tree U60)) : U60 =
//fold x {
//node: (+ x.val (+ x.lft x.rgt))
//leaf: 0
//}
//gen (n: U60) (x: U60) : (Tree U60) =
//switch n {
//0: leaf
//_: (node x (gen n-1 (+ (* x 2) 1)) (gen n-1 (+ (* x 2) 2)))
//}
//main = (sum (gen 16 0))
use Tree/{node,leaf,gen,sum}
_main: U60 =
(sum (gen 16 0))
//use Nat.{succ,zero}
_main: (List U60) =
(List.map _ _ (List.cons _ 1 (List.cons _ 2 (List.cons _ 3 (List.nil _)))) λx(+ x 1))
//_main: (List U60) =
//(List.map _ _ (List.cons _ 1 (List.cons _ 2 (List.cons _ 3 (List.nil _)))) λx(+ x 1))
//_main : (Maybe U60) =
//(Maybe.bind _ _ (Maybe.some _ 1) λx

View File

@ -922,9 +922,9 @@ impl Term {
// 3. Make `(~x <motive>)` or `(Type/fold/ _ <motive> x)`
if mat.fold {
term = Term::App {
era: true,
era: false,
fun: Box::new(Term::App {
era: false,
era: true,
fun: Box::new(Term::App {
era: true,
fun: Box::new(Term::Var { nam: format!("{}/fold/", adt.name) }),
@ -936,7 +936,7 @@ impl Term {
};
} else {
term = Term::App {
era: true,
era: false,
fun: Box::new(Term::Ins {
val: Box::new(mat.expr.clone())
}),

View File

@ -300,7 +300,7 @@ impl Term {
let x = x.to_hvm2();
let z = z.to_hvm2();
let s = s.to_hvm2();
format!("match {} = {} {{ 0: {} +: {} }}", Term::to_hvm2_name(nam), x, z, s)
format!("match {} = {} {{ 0: {} 1+: {} }}", Term::to_hvm2_name(nam), x, z, s)
},
Term::Let { nam, val, bod } => {
let val = val.to_hvm2();
@ -339,7 +339,7 @@ impl Term {
}
pub fn to_hvm2_name(name: &str) -> String {
format!("_{}", name)
format!("_{}", name.replace("/","."))
}