mirror of
https://github.com/HigherOrderCO/Bend.git
synced 2024-09-11 11:56:54 +03:00
Finish initial version of hvm-lang to hvm-core compilation
This commit is contained in:
parent
9f1ef68ea3
commit
7731d2487c
29
Cargo.lock
generated
29
Cargo.lock
generated
@ -161,6 +161,12 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "diff"
|
||||||
|
version = "0.1.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
@ -196,7 +202,9 @@ dependencies = [
|
|||||||
"ariadne",
|
"ariadne",
|
||||||
"chumsky",
|
"chumsky",
|
||||||
"clap",
|
"clap",
|
||||||
|
"itertools 0.11.0",
|
||||||
"logos",
|
"logos",
|
||||||
|
"pretty_assertions",
|
||||||
"shrinkwraprs",
|
"shrinkwraprs",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -209,6 +217,15 @@ dependencies = [
|
|||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.147"
|
version = "0.2.147"
|
||||||
@ -253,6 +270,16 @@ version = "1.18.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pretty_assertions"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66"
|
||||||
|
dependencies = [
|
||||||
|
"diff",
|
||||||
|
"yansi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.66"
|
version = "1.0.66"
|
||||||
@ -293,7 +320,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "e63e6744142336dfb606fe2b068afa2e1cca1ee6a5d8377277a92945d81fa331"
|
checksum = "e63e6744142336dfb606fe2b068afa2e1cca1ee6a5d8377277a92945d81fa331"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"itertools",
|
"itertools 0.8.2",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
|
@ -8,5 +8,9 @@ anyhow = "1.0.72"
|
|||||||
ariadne = "0.3.0"
|
ariadne = "0.3.0"
|
||||||
chumsky = "1.0.0-alpha.4"
|
chumsky = "1.0.0-alpha.4"
|
||||||
clap = { version = "4.4.1", features = ["derive"] }
|
clap = { version = "4.4.1", features = ["derive"] }
|
||||||
|
itertools = "0.11.0"
|
||||||
logos = "0.13.0"
|
logos = "0.13.0"
|
||||||
shrinkwraprs = "0.3.0"
|
shrinkwraprs = "0.3.0"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
pretty_assertions = "1.4.0"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
|
use super::DefId;
|
||||||
|
use itertools::Itertools;
|
||||||
use std::{collections::HashMap, fmt};
|
use std::{collections::HashMap, fmt};
|
||||||
|
|
||||||
use super::DefId;
|
|
||||||
pub struct Book {
|
pub struct Book {
|
||||||
pub defs: HashMap<DefId, LNet>,
|
pub defs: HashMap<DefId, LNet>,
|
||||||
}
|
}
|
||||||
@ -9,8 +10,8 @@ pub struct Book {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct LNet {
|
pub struct LNet {
|
||||||
root: LTree,
|
pub root: LTree,
|
||||||
acts: LActs,
|
pub acts: LActs,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -83,10 +84,10 @@ pub fn u32_to_name(num: u32) -> String {
|
|||||||
|
|
||||||
impl fmt::Display for LNet {
|
impl fmt::Display for LNet {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
writeln!(f, " $ {}", self.root)?;
|
write!(f, "$ {}", self.root)?;
|
||||||
for (a, b) in &self.acts {
|
for (a, b) in &self.acts {
|
||||||
writeln!(f, " & {}", a)?;
|
write!(f, "\n& {}", a)?;
|
||||||
writeln!(f, " ~ {}", b)?;
|
write!(f, "\n~ {}", b)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -108,24 +109,23 @@ impl fmt::Display for Book {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
for (id, net) in &self.defs {
|
for (id, net) in &self.defs {
|
||||||
writeln!(f, "{} =", u32_to_name(**id))?;
|
writeln!(f, "{} =", u32_to_name(**id))?;
|
||||||
writeln!(f, "{}\n", net)?;
|
writeln!(f, "{}\n", net.to_string().split('\n').map(|x| format!(" {x}")).join("\n"))?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Tag = u8;
|
pub type Tag = u8;
|
||||||
pub type Val = u32;
|
// Not used in hvm-core AST
|
||||||
|
// pub const NIL: Tag = 0x0; // empty node
|
||||||
pub const NIL: Tag = 0x0; // empty node
|
// pub const REF: Tag = 0x1; // reference to a definition (closed net)
|
||||||
pub const REF: Tag = 0x1; // reference to a definition (closed net)
|
// pub const NUM: Tag = 0x2; // unboxed number
|
||||||
pub const NUM: Tag = 0x2; // unboxed number
|
// pub const ERA: Tag = 0x3; // unboxed eraser
|
||||||
pub const ERA: Tag = 0x3; // unboxed eraser
|
// pub const VRR: Tag = 0x4; // variable pointing to root
|
||||||
pub const VRR: Tag = 0x4; // variable pointing to root
|
// pub const VR1: Tag = 0x5; // variable pointing to aux1 port of node
|
||||||
pub const VR1: Tag = 0x5; // variable pointing to aux1 port of node
|
// pub const VR2: Tag = 0x6; // variable pointing to aux2 port of node
|
||||||
pub const VR2: Tag = 0x6; // variable pointing to aux2 port of node
|
// pub const RDT: Tag = 0x7; // redirection to root
|
||||||
pub const RDT: Tag = 0x7; // redirection to root
|
// pub const RD1: Tag = 0x8; // redirection to aux1 port of node
|
||||||
pub const RD1: Tag = 0x8; // redirection to aux1 port of node
|
// pub const RD2: Tag = 0x9; // redirection to aux2 port of node
|
||||||
pub const RD2: Tag = 0x9; // redirection to aux2 port of node
|
|
||||||
pub const CON: Tag = 0xA; // points to main port of con node
|
pub const CON: Tag = 0xA; // points to main port of con node
|
||||||
pub const DUP: Tag = 0xB; // points to main port of dup node; higher labels also dups
|
pub const DUP: Tag = 0xB; // points to main port of dup node; higher labels also dups
|
||||||
|
@ -21,9 +21,9 @@ pub struct Rule {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Pattern {
|
pub enum Pattern {
|
||||||
Ctr(Name, Vec<Pattern>),
|
_Ctr(Name, Vec<Pattern>),
|
||||||
Num(Number),
|
_Num(Number),
|
||||||
Var(Name),
|
_Var(Name),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
4
src/lib.rs
Normal file
4
src/lib.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
pub mod ast;
|
||||||
|
pub mod loader;
|
||||||
|
pub mod parser;
|
||||||
|
pub mod to_core;
|
@ -1,10 +1,10 @@
|
|||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
mod ast;
|
pub mod ast;
|
||||||
mod loader;
|
pub mod loader;
|
||||||
mod parser;
|
pub mod parser;
|
||||||
mod to_core;
|
pub mod to_core;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(author, version, about, long_about = None)]
|
#[command(author, version, about, long_about = None)]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
mod lexer;
|
mod lexer;
|
||||||
mod parser;
|
mod parser;
|
||||||
|
|
||||||
pub use parser::parse_definition_book;
|
pub use parser::{parse_definition_book, parse_term};
|
||||||
|
@ -14,15 +14,6 @@ use chumsky::{
|
|||||||
};
|
};
|
||||||
use logos::Logos;
|
use logos::Logos;
|
||||||
|
|
||||||
pub fn parse_definition_book(code: &str) -> Result<DefinitionBook, Vec<Rich<Token>>> {
|
|
||||||
let token_iter = Token::lexer(code).spanned().map(|(token, span)| match token {
|
|
||||||
Ok(t) => (t, SimpleSpan::from(span)),
|
|
||||||
Err(e) => (Token::Error(e), SimpleSpan::from(span)),
|
|
||||||
});
|
|
||||||
let token_stream = Stream::from_iter(token_iter).spanned(SimpleSpan::from(code.len() .. code.len()));
|
|
||||||
book_parser().parse(token_stream).into_result()
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Pattern matching on rules
|
// TODO: Pattern matching on rules
|
||||||
// TODO: Other types of numbers
|
// TODO: Other types of numbers
|
||||||
/// <Name> ::= <name_token> // [_a-zA-Z][_a-zA-Z0-9]*
|
/// <Name> ::= <name_token> // [_a-zA-Z][_a-zA-Z0-9]*
|
||||||
@ -39,8 +30,28 @@ pub fn parse_definition_book(code: &str) -> Result<DefinitionBook, Vec<Rich<Toke
|
|||||||
/// <Rule> ::= "(" <Name> ")" "=" <newline_token>* <Term> <newline_token>*
|
/// <Rule> ::= "(" <Name> ")" "=" <newline_token>* <Term> <newline_token>*
|
||||||
/// <Def> ::= (<Rule> <NewLine>)+
|
/// <Def> ::= (<Rule> <NewLine>)+
|
||||||
/// <Book> ::= <Def>+
|
/// <Book> ::= <Def>+
|
||||||
|
pub fn parse_definition_book(code: &str) -> Result<DefinitionBook, Vec<Rich<Token>>> {
|
||||||
|
let token_iter = Token::lexer(code).spanned().map(|(token, span)| match token {
|
||||||
|
Ok(t) => (t, SimpleSpan::from(span)),
|
||||||
|
Err(e) => (Token::Error(e), SimpleSpan::from(span)),
|
||||||
|
});
|
||||||
|
let token_stream = Stream::from_iter(token_iter).spanned(SimpleSpan::from(code.len() .. code.len()));
|
||||||
|
book_parser().parse(token_stream).into_result()
|
||||||
|
}
|
||||||
|
|
||||||
fn rule_parser<'a, I>() -> impl Parser<'a, I, Rule, extra::Err<Rich<'a, Token>>>
|
pub fn parse_term(code: &str) -> Result<Term, Vec<Rich<Token>>> {
|
||||||
|
// TODO: Make a function that calls a parser. I couldn't figure out how to type it correctly.
|
||||||
|
let token_iter = Token::lexer(code).spanned().map(|(token, span)| match token {
|
||||||
|
Ok(t) => (t, SimpleSpan::from(span)),
|
||||||
|
Err(e) => (Token::Error(e), SimpleSpan::from(span)),
|
||||||
|
});
|
||||||
|
let token_stream = Stream::from_iter(token_iter).spanned(SimpleSpan::from(code.len() .. code.len()));
|
||||||
|
term_parser().parse(token_stream).into_result()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parsers
|
||||||
|
|
||||||
|
fn term_parser<'a, I>() -> impl Parser<'a, I, Term, extra::Err<Rich<'a, Token>>>
|
||||||
where
|
where
|
||||||
I: ValueInput<'a, Token = Token, Span = SimpleSpan>,
|
I: ValueInput<'a, Token = Token, Span = SimpleSpan>,
|
||||||
{
|
{
|
||||||
@ -69,7 +80,7 @@ where
|
|||||||
|
|
||||||
let var = name.map(|name| Term::Var { nam: name });
|
let var = name.map(|name| Term::Var { nam: name });
|
||||||
|
|
||||||
let term = recursive(|term| {
|
recursive(|term| {
|
||||||
let nested = term
|
let nested = term
|
||||||
.clone()
|
.clone()
|
||||||
.delimited_by(just(Token::LParen).then(new_line.clone()), just(Token::RParen).then(new_line.clone()));
|
.delimited_by(just(Token::LParen).then(new_line.clone()), just(Token::RParen).then(new_line.clone()));
|
||||||
@ -112,13 +123,21 @@ where
|
|||||||
});
|
});
|
||||||
|
|
||||||
choice((lam, app, dup, let_, num_op, item))
|
choice((lam, app, dup, let_, num_op, item))
|
||||||
});
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rule_parser<'a, I>() -> impl Parser<'a, I, Rule, extra::Err<Rich<'a, Token>>>
|
||||||
|
where
|
||||||
|
I: ValueInput<'a, Token = Token, Span = SimpleSpan>,
|
||||||
|
{
|
||||||
|
let name = select!(Token::Name(name) => Name(name.to_string()));
|
||||||
|
let new_line = just(Token::NewLine).repeated();
|
||||||
|
|
||||||
just(Token::LParen)
|
just(Token::LParen)
|
||||||
.ignore_then(name)
|
.ignore_then(name)
|
||||||
.then_ignore(just(Token::RParen))
|
.then_ignore(just(Token::RParen))
|
||||||
.then_ignore(just(Token::Equals))
|
.then_ignore(just(Token::Equals))
|
||||||
.then(term.delimited_by(new_line.clone(), new_line.clone()))
|
.then(term_parser().delimited_by(new_line.clone(), new_line.clone()))
|
||||||
.map(|(name, body)| Rule { name, pats: vec![], body })
|
.map(|(name, body)| Rule { name, pats: vec![], body })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::ast::{DefId, Name, Term};
|
use crate::ast::{
|
||||||
|
self,
|
||||||
|
core::{LNet, LTree},
|
||||||
|
DefId, Name, Term,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
/// Net representation used only as an intermediate for converting to hvm-core format
|
/// Net representation used only as an intermediate for converting to hvm-core format
|
||||||
@ -209,3 +213,128 @@ fn encode_term(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn compat_net_to_core(inet: &INet) -> anyhow::Result<LNet> {
|
||||||
|
let tree_roots = get_tree_roots(inet);
|
||||||
|
let mut port_to_var_id: HashMap<Port, VarId> = HashMap::new();
|
||||||
|
let root = compat_tree_to_hvm_tree(inet, tree_roots[1], &mut port_to_var_id);
|
||||||
|
let mut acts = vec![];
|
||||||
|
for active_pair in tree_roots[2 ..].chunks_exact(2) {
|
||||||
|
let act1 = compat_tree_to_hvm_tree(inet, active_pair[0], &mut port_to_var_id);
|
||||||
|
let act2 = compat_tree_to_hvm_tree(inet, active_pair[1], &mut port_to_var_id);
|
||||||
|
acts.push((act1, act2));
|
||||||
|
}
|
||||||
|
Ok(LNet { root, acts })
|
||||||
|
}
|
||||||
|
|
||||||
|
type TreeId = NodeId;
|
||||||
|
type VarId = u32;
|
||||||
|
|
||||||
|
/// Returns a list of all the tree node roots in the compat inet.
|
||||||
|
fn get_tree_roots(inet: &INet) -> Vec<NodeId> {
|
||||||
|
let mut node_to_tree_id: Vec<Option<TreeId>> = vec![None; inet.nodes.len() / 4];
|
||||||
|
let mut tree_roots: Vec<NodeId> = vec![addr(ROOT), addr(enter(inet, ROOT))];
|
||||||
|
let mut side_links: Vec<Port> = vec![]; // Links between trees
|
||||||
|
|
||||||
|
// Start by mapping the root tree
|
||||||
|
go_down_tree(inet, tree_roots[1], 0, &mut node_to_tree_id, &mut side_links);
|
||||||
|
// Check each side-link for a possible new tree pair;
|
||||||
|
while let Some(dest_port) = side_links.pop() {
|
||||||
|
let dest_node = addr(dest_port);
|
||||||
|
// Only go up unmarked trees
|
||||||
|
if node_to_tree_id[dest_node as usize].is_none() {
|
||||||
|
let (new_tree1, new_tree2) = go_up_tree(inet, dest_node);
|
||||||
|
go_down_tree(inet, new_tree1, tree_roots.len() as TreeId, &mut node_to_tree_id, &mut side_links);
|
||||||
|
tree_roots.push(new_tree1);
|
||||||
|
go_down_tree(inet, new_tree2, tree_roots.len() as TreeId, &mut node_to_tree_id, &mut side_links);
|
||||||
|
tree_roots.push(new_tree2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tree_roots
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Go down a node tree, marking all nodes with the tree_id and storing any side_links found.
|
||||||
|
fn go_down_tree(
|
||||||
|
inet: &INet,
|
||||||
|
root: NodeId,
|
||||||
|
tree_id: TreeId,
|
||||||
|
node_to_tree_id: &mut [Option<NodeId>],
|
||||||
|
side_links: &mut Vec<Port>,
|
||||||
|
) {
|
||||||
|
let mut nodes_to_check = vec![root];
|
||||||
|
while let Some(node) = nodes_to_check.pop() {
|
||||||
|
node_to_tree_id[node as usize] = Some(tree_id);
|
||||||
|
for down_slot in [1, 2] {
|
||||||
|
let down_port = enter(inet, port(node, down_slot));
|
||||||
|
if slot(down_port) == 0 {
|
||||||
|
// If this down-link is to a main port, this is a node of the same tree
|
||||||
|
nodes_to_check.push(addr(down_port));
|
||||||
|
} else {
|
||||||
|
// Otherwise it's a side-link
|
||||||
|
side_links.push(down_port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Goes up a node tree, starting from some given node.
|
||||||
|
/// Returns the root of this tree and the root of its active pair.
|
||||||
|
fn go_up_tree(inet: &INet, start_node: NodeId) -> (NodeId, NodeId) {
|
||||||
|
let mut crnt_node = start_node;
|
||||||
|
loop {
|
||||||
|
let up_port = enter(inet, port(crnt_node, 0));
|
||||||
|
let up_node = addr(up_port);
|
||||||
|
if slot(up_port) == 0 {
|
||||||
|
return (crnt_node, up_node);
|
||||||
|
} else {
|
||||||
|
crnt_node = up_node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compat_tree_to_hvm_tree(inet: &INet, root: NodeId, port_to_var_id: &mut HashMap<Port, VarId>) -> LTree {
|
||||||
|
let kind = kind(inet, root);
|
||||||
|
let tag = kind & TAG_MASK;
|
||||||
|
let label = kind & LABEL_MASK; // TODO: Check if label too high, do something about it.
|
||||||
|
match tag {
|
||||||
|
ERA => LTree::Era,
|
||||||
|
CON => LTree::Nod {
|
||||||
|
tag: ast::core::CON,
|
||||||
|
lft: Box::new(var_or_subtree(inet, port(root, 1), port_to_var_id)),
|
||||||
|
rgt: Box::new(var_or_subtree(inet, port(root, 2), port_to_var_id)),
|
||||||
|
},
|
||||||
|
DUP => LTree::Nod {
|
||||||
|
tag: ast::core::DUP + label as u8,
|
||||||
|
lft: Box::new(var_or_subtree(inet, port(root, 1), port_to_var_id)),
|
||||||
|
rgt: Box::new(var_or_subtree(inet, port(root, 2), port_to_var_id)),
|
||||||
|
},
|
||||||
|
REF => LTree::Ref { nam: label },
|
||||||
|
NUM => LTree::Num { val: enter(inet, port(root, 1)) },
|
||||||
|
NUMOP => todo!(), // TODO: HVM2 doesn't have numeric operator atm.
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn var_or_subtree(inet: &INet, src_port: Port, port_to_var_id: &mut HashMap<Port, VarId>) -> LTree {
|
||||||
|
let dst_port = enter(inet, src_port);
|
||||||
|
if slot(dst_port) == 0 {
|
||||||
|
// Subtree
|
||||||
|
compat_tree_to_hvm_tree(inet, addr(dst_port), port_to_var_id)
|
||||||
|
} else {
|
||||||
|
// Var
|
||||||
|
if let Some(&var_id) = port_to_var_id.get(&src_port) {
|
||||||
|
// Previously found var
|
||||||
|
LTree::Var { nam: var_id_to_name(var_id) }
|
||||||
|
} else {
|
||||||
|
// New var
|
||||||
|
let var_id = port_to_var_id.len() as u32;
|
||||||
|
port_to_var_id.insert(dst_port, var_id);
|
||||||
|
LTree::Var { nam: var_id_to_name(var_id) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn var_id_to_name(var_id: VarId) -> String {
|
||||||
|
format!("x{var_id}")
|
||||||
|
}
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
mod compat_net;
|
mod compat_net;
|
||||||
|
|
||||||
use self::compat_net::term_to_compat_net;
|
use self::compat_net::{compat_net_to_core, term_to_compat_net};
|
||||||
use crate::ast::{
|
use crate::ast::{self, core::name_to_u32, DefId, Definition, DefinitionBook, Name, Term};
|
||||||
self,
|
|
||||||
core::{name_to_u32, LNet},
|
|
||||||
DefId, Definition, DefinitionBook, Name,
|
|
||||||
};
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub fn book_to_hvm_core(book: &DefinitionBook) -> anyhow::Result<ast::core::Book> {
|
pub fn book_to_hvm_core(book: &DefinitionBook) -> anyhow::Result<ast::core::Book> {
|
||||||
@ -18,15 +14,15 @@ pub fn book_to_hvm_core(book: &DefinitionBook) -> anyhow::Result<ast::core::Book
|
|||||||
Ok(core_book)
|
Ok(core_book)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn definition_to_hvm_core(
|
pub fn definition_to_hvm_core(
|
||||||
definition: &Definition,
|
definition: &Definition,
|
||||||
def_to_id: &HashMap<Name, DefId>,
|
def_to_id: &HashMap<Name, DefId>,
|
||||||
) -> anyhow::Result<ast::core::LNet> {
|
) -> anyhow::Result<ast::core::LNet> {
|
||||||
let term = &definition.rules[0].body;
|
// TODO: Multiple rules, pattern matching, etc.
|
||||||
let compat_net = term_to_compat_net(term, def_to_id)?;
|
term_to_hvm_core(&definition.rules[0].body, def_to_id)
|
||||||
compat_net_to_core(compat_net)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compat_net_to_core(compat_net: compat_net::INet) -> anyhow::Result<LNet> {
|
pub fn term_to_hvm_core(term: &Term, def_to_id: &HashMap<Name, DefId>) -> anyhow::Result<ast::core::LNet> {
|
||||||
todo!()
|
let compat_net = term_to_compat_net(term, def_to_id)?;
|
||||||
|
compat_net_to_core(&compat_net)
|
||||||
}
|
}
|
||||||
|
27
tests/compile_terms.rs
Normal file
27
tests/compile_terms.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use hvm_lang::{parser::parse_term, to_core::term_to_hvm_core};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
fn check_single_term_compilation(code: &str, expected: &str) {
|
||||||
|
let term = parse_term(code).unwrap();
|
||||||
|
let net = term_to_hvm_core(&term, &HashMap::new()).unwrap();
|
||||||
|
assert_eq!(net.to_string(), expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn single_def_terms() {
|
||||||
|
let terms = [
|
||||||
|
("id", "λa a", "$ (0 x0 x0)"),
|
||||||
|
("dup apply", "λa dup a1 a2 = a; (a1 a2)", "$ (0 (1 (0 x0 x1) x0) x1)"),
|
||||||
|
("erased dup", "λa dup a1 a2 = a; a1", "$ (0 (1 x0 *) x0)"),
|
||||||
|
("c_z", "λs λz z", "$ (0 * (0 x0 x0))"),
|
||||||
|
(
|
||||||
|
"c_s",
|
||||||
|
"λk λs dup s0 s1 = s; λz (s0 ((k s1) z))",
|
||||||
|
"$ (0 (0 x0 (0 x1 x2)) (0 (1 (0 x2 x3) x0) (0 x1 x3)))",
|
||||||
|
),
|
||||||
|
];
|
||||||
|
for (_name, code, expected) in terms {
|
||||||
|
check_single_term_compilation(code, expected)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user