Improve entrypoint related functions to use the book.entrypoint field

This commit is contained in:
LunaAmora 2024-02-20 12:50:10 -03:00
parent 18d9218d09
commit 3846d7c75f
10 changed files with 53 additions and 49 deletions

View File

@ -14,7 +14,7 @@ use term::{
display::{display_readback_errors, DisplayJoin},
net_to_term::net_to_term,
term_to_net::{HvmcNames, Labels},
AdtEncoding, Book, Name, ReadbackError, Term,
AdtEncoding, Book, ReadbackError, Term,
};
pub mod diagnostics;
@ -34,8 +34,8 @@ pub fn check_book(book: Book) -> Result<(), String> {
}
pub fn compile_book(mut book: Book, opts: CompileOpts) -> Result<CompileResult, String> {
let main = desugar_book(&mut book, opts)?;
let (nets, hvmc_names, labels) = book_to_nets(&mut book, &main);
desugar_book(&mut book, opts)?;
let (nets, hvmc_names, labels) = book_to_nets(&mut book);
let mut core_book = nets_to_hvmc(nets, &hvmc_names)?;
if opts.pre_reduce {
pre_reduce_book(&mut core_book, opts.pre_reduce_refs, book.hvmc_entrypoint())?;
@ -46,12 +46,12 @@ pub fn compile_book(mut book: Book, opts: CompileOpts) -> Result<CompileResult,
Ok(CompileResult { book, core_book, hvmc_names, labels })
}
pub fn desugar_book(book: &mut Book, opts: CompileOpts) -> Result<Name, String> {
let main = book.check_has_entrypoint();
pub fn desugar_book(book: &mut Book, opts: CompileOpts) -> Result<(), String> {
book.set_entrypoint();
book.check_shared_names();
book.encode_adts(opts.adt_encoding);
book.encode_builtins();
encode_pattern_matching(book, main.as_ref(), opts.adt_encoding)?;
encode_pattern_matching(book, opts.adt_encoding)?;
// sanity check
book.check_unbound_vars()?;
book.normalize_native_matches()?;
@ -63,37 +63,33 @@ pub fn desugar_book(book: &mut Book, opts: CompileOpts) -> Result<Name, String>
book.check_unbound_vars()?;
if opts.supercombinators {
book.detach_supercombinators(main.as_ref());
book.detach_supercombinators();
}
if opts.ref_to_ref {
book.simplify_ref_to_ref()?;
}
if main.as_ref().is_some() && opts.simplify_main {
book.simplify_main_ref(main.as_ref().unwrap());
if opts.simplify_main {
book.simplify_main_ref();
}
book.prune(main.as_ref(), opts.prune, opts.adt_encoding);
book.prune(opts.prune, opts.adt_encoding);
if opts.inline {
book.inline();
}
if opts.merge {
book.merge_definitions(main.as_ref());
book.merge_definitions();
}
if book.info.errs.is_empty() { Ok(main.unwrap()) } else { Err(book.info.take_errs()) }
if book.info.errs.is_empty() { Ok(()) } else { Err(book.info.take_errs()) }
}
pub fn encode_pattern_matching(
book: &mut Book,
main: Option<&Name>,
adt_encoding: AdtEncoding,
) -> Result<(), String> {
pub fn encode_pattern_matching(book: &mut Book, adt_encoding: AdtEncoding) -> Result<(), String> {
book.check_arity()?;
book.resolve_ctrs_in_pats();
book.check_unbound_pats()?;
book.check_ctrs_arities()?;
book.resolve_refs(main)?;
book.resolve_refs()?;
book.desugar_let_destructors();
book.desugar_implicit_match_binds();
// This call to unbound vars needs to be after desugar_implicit_match_binds,

View File

@ -29,7 +29,7 @@ impl Display for EntryErr {
}
impl Book {
pub fn check_has_entrypoint(&mut self) -> Option<Name> {
pub fn set_entrypoint(&mut self) {
let mut main = None;
match self.get_possible_entry_points() {
@ -67,7 +67,7 @@ impl Book {
}
}
main
self.entrypoint = main;
}
fn validate_entry_point(&self, entry: &Definition) -> Result<Name, EntryErr> {

View File

@ -786,6 +786,9 @@ impl AsRef<str> for Name {
impl Book {
pub fn hvmc_entrypoint(&self) -> String {
if let Some(nam) = &self.entrypoint { nam.to_string() } else { ENTRY_POINT.to_string() }
match self.entrypoint.as_ref().map(|e| e.0.as_ref()) {
Some("main" | "Main") | None => ENTRY_POINT.to_string(),
Some(nam) => nam.to_string(),
}
}
}

View File

@ -15,18 +15,19 @@ pub struct HvmcNames {
pub hvmc_to_hvml: HashMap<Val, Name>,
}
pub fn book_to_nets(book: &Book, main: &Name) -> (HashMap<String, INet>, HvmcNames, Labels) {
pub fn book_to_nets(book: &Book) -> (HashMap<String, INet>, HvmcNames, Labels) {
let mut nets = HashMap::new();
let mut hvmc_names = HvmcNames::default();
let mut labels = Labels::default();
let mut generated_count = 0;
let main = book.entrypoint.as_ref().unwrap();
for def in book.defs.values() {
for rule in def.rules.iter() {
let net = term_to_compat_net(&rule.body, &mut labels);
let name = if def.name == *main && book.entrypoint.is_none() {
ENTRY_POINT.to_string()
let name = if def.name == *main {
book.hvmc_entrypoint()
} else {
def_name_to_hvmc_name(&def.name, &nets, &mut generated_count)
};

View File

@ -10,16 +10,18 @@ impl Book {
///
/// Ignores origin of the rules when merging,
/// Should not be preceded by passes that cares about the origins.
pub fn merge_definitions(&mut self, main: Option<&Name>) {
pub fn merge_definitions(&mut self) {
let defs: Vec<_> = self.defs.keys().cloned().collect();
self.merge(main, defs.into_iter());
self.merge(defs.into_iter());
}
/// Checks and merges identical definitions given by `defs`.
/// We never merge the entrypoint function with something else.
fn merge(&mut self, main: Option<&Name>, defs: impl Iterator<Item = Name>) {
fn merge(&mut self, defs: impl Iterator<Item = Name>) {
let name = self.entrypoint.clone();
// Sets of definitions that are identical, indexed by the body term.
let equal_terms = self.collect_terms(defs.filter(|def_name| !main.is_some_and(|m| m == def_name)));
let equal_terms =
self.collect_terms(defs.filter(|def_name| !name.as_ref().is_some_and(|m| m == def_name)));
// Map of old name to new merged name
let mut name_map = BTreeMap::new();
@ -49,7 +51,7 @@ impl Book {
def.rule_mut().body = term;
}
}
self.update_refs(&name_map, main);
self.update_refs(&name_map);
}
fn collect_terms(&mut self, def_entries: impl Iterator<Item = Name>) -> IndexMap<Term, IndexSet<Name>> {
@ -64,7 +66,7 @@ impl Book {
equal_terms
}
fn update_refs(&mut self, name_map: &BTreeMap<Name, Name>, main: Option<&Name>) {
fn update_refs(&mut self, name_map: &BTreeMap<Name, Name>) {
let mut updated_defs = Vec::new();
for def in self.defs.values_mut() {
@ -74,7 +76,7 @@ impl Book {
}
if !updated_defs.is_empty() {
self.merge(main, updated_defs.into_iter());
self.merge(updated_defs.into_iter());
}
}
}

View File

@ -27,10 +27,10 @@ type Definitions = HashMap<Name, Used>;
impl Book {
/// If `prune_all`, removes all unused definitions and adts starting from Main.
/// Otherwise, prunes only the builtins not accessible from any non-built-in definition
pub fn prune(&mut self, main: Option<&Name>, prune_all: bool, adt_encoding: AdtEncoding) {
pub fn prune(&mut self, prune_all: bool, adt_encoding: AdtEncoding) {
let mut used = Definitions::new();
if let Some(main) = main {
if let Some(main) = &self.entrypoint {
let def = self.defs.get(main).unwrap();
used.insert(main.clone(), Used::Main);
self.find_used_definitions(&def.rule().body, Used::Main, &mut used, adt_encoding);

View File

@ -7,11 +7,11 @@ use std::{
/// Replaces closed Terms (i.e. without free variables) with a Ref to the extracted term
/// Precondition: Vars must have been sanitized
impl Book {
pub fn detach_supercombinators(&mut self, main: Option<&Name>) {
pub fn detach_supercombinators(&mut self) {
let mut combinators = Combinators::new();
for (def_name, def) in self.defs.iter_mut() {
if main.is_some_and(|m| m == def_name) {
if self.entrypoint.as_ref().is_some_and(|m| m == def_name) {
continue;
}

View File

@ -20,7 +20,7 @@ impl Book {
/// Decides if names inside a term belong to a Var or to a Ref.
/// Precondition: Refs are encoded as vars, Constructors are resolved.
/// Postcondition: Refs are encoded as refs, with the correct def id.
pub fn resolve_refs(&mut self, main: Option<&Name>) -> Result<(), String> {
pub fn resolve_refs(&mut self) -> Result<(), String> {
self.info.start_pass();
let def_names = self.defs.keys().cloned().collect::<HashSet<_>>();
@ -32,7 +32,7 @@ impl Book {
push_scope(Some(name), &mut scope);
}
let res = rule.body.resolve_refs(&def_names, main, &mut scope);
let res = rule.body.resolve_refs(&def_names, self.entrypoint.as_ref(), &mut scope);
self.info.errs.extend(res.map_err(|e| Error::MainRef(def_name.clone(), e)).err());
}
}

View File

@ -1,14 +1,16 @@
use crate::term::{Book, Name, Term};
use crate::term::{Book, Term};
impl Book {
/// When main is simply directly calling another function, we substitute the ref with a copy of its body.
///
/// This is performed because Hvm-Core produces inconsistent outputs in the parallel mode when such pattern is present
pub fn simplify_main_ref(&mut self, main: &Name) {
while let Term::Ref { nam: def_name } = &self.defs[main].rule().body {
let rule_body = self.defs[def_name].rule().body.clone();
let main_body = &mut self.defs.get_mut(main).unwrap().rule_mut().body;
*main_body = rule_body;
pub fn simplify_main_ref(&mut self) {
if let Some(main) = &self.entrypoint {
while let Term::Ref { nam: def_name } = &self.defs[main].rule().body {
let rule_body = self.defs[def_name].rule().body.clone();
let main_body = &mut self.defs.get_mut(main).unwrap().rule_mut().body;
*main_body = rule_body;
}
}
}
}

View File

@ -157,7 +157,7 @@ fn readback_lnet() {
fn flatten_rules() {
run_golden_test_dir(function_name!(), &|code, path| {
let mut book = do_parse_book(code, path)?;
let main = book.check_has_entrypoint();
book.set_entrypoint();
book.check_shared_names();
book.encode_builtins();
book.resolve_ctrs_in_pats();
@ -167,7 +167,7 @@ fn flatten_rules() {
book.check_unbound_pats()?;
book.extract_adt_matches()?;
book.flatten_rules();
book.prune(main.as_ref(), false, AdtEncoding::TaggedScott);
book.prune(false, AdtEncoding::TaggedScott);
Ok(book.to_string())
})
}
@ -186,13 +186,13 @@ fn encode_pattern_match() {
let mut result = String::new();
for adt_encoding in [AdtEncoding::TaggedScott, AdtEncoding::Scott] {
let mut book = do_parse_book(code, path)?;
let main = book.check_has_entrypoint();
book.set_entrypoint();
book.check_shared_names();
book.encode_adts(adt_encoding);
book.encode_builtins();
encode_pattern_matching(&mut book, main.as_ref(), adt_encoding)?;
book.prune(main.as_ref(), false, adt_encoding);
book.merge_definitions(main.as_ref());
encode_pattern_matching(&mut book, adt_encoding)?;
book.prune(false, adt_encoding);
book.merge_definitions();
writeln!(result, "{adt_encoding:?}:").unwrap();
writeln!(result, "{book}\n").unwrap();