Add merge definitions pass

This commit is contained in:
LunaAmora 2024-01-29 16:03:05 -03:00
parent 1b932afeba
commit a1a90486c5
12 changed files with 96 additions and 27 deletions

View File

@ -41,10 +41,7 @@ pub fn compile_book(book: &mut Book, opts: Opts) -> Result<CompileResult, String
Ok(CompileResult { core_book, hvmc_names, labels, warnings })
}
pub fn desugar_book(
book: &mut Book,
Opts { eta, ref_to_ref, prune, supercombinators, simplify_main, .. }: Opts,
) -> Result<(DefId, Vec<Warning>), String> {
pub fn desugar_book(book: &mut Book, opts: Opts) -> Result<(DefId, Vec<Warning>), String> {
let mut warnings = Vec::new();
let main = book.check_has_main()?;
book.check_shared_names()?;
@ -57,19 +54,22 @@ pub fn desugar_book(
book.check_unbound_vars()?;
book.make_var_names_unique();
book.linearize_vars();
book.eta_reduction(eta);
book.eta_reduction(opts.eta);
// sanity check
book.check_unbound_vars()?;
if supercombinators {
if opts.supercombinators {
book.detach_supercombinators(main);
}
if ref_to_ref {
if opts.ref_to_ref {
book.simplify_ref_to_ref()?;
}
if simplify_main {
if opts.simplify_main {
book.simplify_main_ref(main);
}
book.prune(Some(main), prune, &mut warnings);
if opts.merge_definitions {
book.merge_definition(main);
}
book.prune(Some(main), opts.prune, &mut warnings);
Ok((main, warnings))
}
@ -190,8 +190,11 @@ pub struct Opts {
/// Enables [term::transform::simplify_main_ref].
pub simplify_main: bool,
/// Enables dereferences in `pre_reduce` pass.
/// Enables dereferences in [hvmc_net::pre_reduce] pass.
pub pre_reduce_refs: bool,
/// Enables [term::transform::definition_merge]
pub merge_definitions: bool,
}
impl Opts {
@ -205,6 +208,7 @@ impl Opts {
supercombinators: true,
simplify_main: true,
pre_reduce_refs: true,
merge_definitions: true,
}
}
@ -234,6 +238,8 @@ impl Opts {
"no-simplify-main" => self.simplify_main = false,
"pre-reduce-refs" => self.pre_reduce_refs = true,
"no-pre-reduce-refs" => self.pre_reduce_refs = false,
"merge-defnitions" => self.merge_definitions = true,
"no-merge-defnitions" => self.merge_definitions = false,
other => return Err(format!("Unknown option '{other}'.")),
}
}

View File

@ -41,6 +41,7 @@ struct Args {
all, eta, no-eta, prune, no-prune, ref-to-ref, no-ref-to-ref,
supercombinators (enabled by default), no-supercombinators,
simplify-main, no-simplify-main, pre-reduce-refs, no-pre-reduce-refs
merge-definitions, no-merge-definitions
"#,
)]
pub opts: Vec<String>,

View File

@ -34,8 +34,8 @@ pub struct Book {
#[derive(Debug, Clone, Default)]
pub struct DefNames {
id_to_name: IndexMap<DefId, Name>,
name_to_id: IndexMap<Name, DefId>,
pub id_to_name: IndexMap<DefId, Name>,
pub name_to_id: IndexMap<Name, DefId>,
id_count: DefId,
}
@ -63,13 +63,13 @@ pub enum Origin {
Generated,
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum MatchNum {
Zero,
Succ(Option<Option<Name>>),
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Tag {
Named(Name),
Numeric(u32),
@ -77,7 +77,7 @@ pub enum Tag {
Static,
}
#[derive(Debug, Clone, Default)]
#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
pub enum Term {
Lam {
tag: Tag,
@ -149,7 +149,7 @@ pub enum Term {
Era,
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Pattern {
Var(Option<Name>),
Ctr(Name, Vec<Pattern>),
@ -158,7 +158,7 @@ pub enum Pattern {
List(Vec<Pattern>),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Op {
ADD,
SUB,

View File

@ -0,0 +1,48 @@
use super::simplify_ref_to_ref::subst_ref_to_ref;
use crate::term::{Book, DefId, Name, Term};
use std::collections::HashMap;
impl Book {
/// Merges definitions that have the same structure into one definintion.
/// Expects variables to be linear.
pub fn merge_definition(&mut self, main: DefId) {
let mut term_to_defid: HashMap<Term, DefId> = HashMap::new();
let mut defid_map: HashMap<DefId, DefId> = HashMap::new();
for (id, def) in &mut self.defs {
if id == &main {
continue;
}
def.assert_no_pattern_matching_rules();
let term = std::mem::take(&mut def.rules[0].body);
if let Some(new) = term_to_defid.get(&term) {
defid_map.insert(*id, *new);
} else {
term_to_defid.insert(term, *id);
}
}
for (term, id) in term_to_defid {
self.defs.get_mut(&id).unwrap().rules[0].body = term;
}
for (old, new) in &defid_map {
let old_name = self.def_names.id_to_name.remove(old).unwrap();
let new_name = self.def_names.name(new).unwrap();
let merged_name = Name(format!("{}${}", new_name, old_name));
self.def_names.id_to_name.insert(*new, merged_name.clone());
self.def_names.name_to_id.insert(merged_name, *new);
self.def_names.name_to_id.remove(&old_name);
self.defs.remove(old);
}
for def in self.defs.values_mut() {
subst_ref_to_ref(&mut def.rules[0].body, &defid_map);
}
}
}

View File

@ -1,3 +1,4 @@
pub mod definition_merge;
pub mod definition_pruning;
pub mod desugar_implicit_match_binds;
pub mod desugar_let_destructors;

View File

@ -43,7 +43,7 @@ impl Book {
}
}
fn subst_ref_to_ref(term: &mut Term, ref_map: &HashMap<DefId, DefId>) {
pub fn subst_ref_to_ref(term: &mut Term, ref_map: &HashMap<DefId, DefId>) {
match term {
Term::Ref { def_id } => {
if let Some(target_id) = ref_map.get(def_id) {

View File

@ -0,0 +1,6 @@
true = @t @f t
false = @t @f f
fst = @a @b a
snd = @a @b b
main = @* (fst true (snd false *))

View File

@ -2,10 +2,9 @@
source: tests/golden_tests.rs
input_file: tests/golden_tests/compile_file_o_all/adt_option_and.hvm
---
@A = ({2 @H {2 @G a}} a)
@A = ({2 @H {2 @C a}} a)
@C = (* @None)
@D = {4 a (b {2 {4 [b a] c} {2 * c}})}
@G = (* @None)
@H = {4 a ({2 @D {2 @C (a b)}} b)}
@None = {2 * {2 a a}}
@Some = (a {2 {4 a b} {2 * b}})

View File

@ -2,9 +2,9 @@
source: tests/golden_tests.rs
input_file: tests/golden_tests/compile_file_o_all/ex0.hvm
---
@1 = (* (a a))
@C_2 = ({3 (a b) (c a)} (c b))
@S = (a ((a b) (* b)))
@Z = (* (a a))
@main = a
& @C_2 ~ (@S (@Z a))
& @C_2 ~ (@S (@1 a))

View File

@ -0,0 +1,10 @@
---
source: tests/golden_tests.rs
input_file: tests/golden_tests/compile_file_o_all/merge_definitions.hvm
---
@1 = (a (* a))
@2 = (* (a a))
@main = (* a)
& @1 ~ (@1 (b a))
& @2 ~ (@2 (* b))

View File

@ -4,8 +4,7 @@ input_file: tests/golden_tests/compile_file_o_all/nested_adt_match.hvm
---
@8 = ({2 @C {2 @A a}} a)
@A = #0
@C = {4 {2 @G {2 @E a}} a}
@E = #0
@C = {4 {2 @G {2 @A a}} a}
@G = {4 a a}
@Some = (a {2 {4 a b} {2 * b}})
@main = a

View File

@ -2,9 +2,8 @@
source: tests/golden_tests.rs
input_file: tests/golden_tests/compile_file_o_all/tagged_sup.hvm
---
@a = {3 (a a) (b b)}
@b = {3 (a a) (b b)}
@1 = {3 (a a) (b b)}
@c = {5 (a a) (b b)}
@main = a
& @a ~ (@b (@c a))
& @1 ~ (@1 (@c a))