mirror of
https://github.com/HigherOrderCO/Bend.git
synced 2024-11-05 04:51:40 +03:00
Improve entrypoint related functions to use the book.entrypoint field
This commit is contained in:
parent
18d9218d09
commit
3846d7c75f
32
src/lib.rs
32
src/lib.rs
@ -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,
|
||||
|
@ -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> {
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
};
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user