mirror of
https://github.com/HigherOrderCO/Bend.git
synced 2024-11-05 04:51:40 +03:00
Add custom entrypoint option
This commit is contained in:
parent
05c31c55eb
commit
7a38b42645
@ -1,9 +1,7 @@
|
||||
// Reduce the compiled networks, solving any annihilations and commutations.
|
||||
// This is a useful optimization on its own, but also required by an hvm-core optimization.
|
||||
|
||||
use crate::{
|
||||
expand, net_from_runtime, net_to_runtime, rdex, reduce, runtime_net_to_runtime_def, ENTRY_POINT,
|
||||
};
|
||||
use crate::{expand, net_from_runtime, net_to_runtime, rdex, reduce, runtime_net_to_runtime_def};
|
||||
use hvmc::{
|
||||
ast::{book_from_runtime, name_to_val, Book},
|
||||
run::{Net, Ptr, OP2, REF},
|
||||
@ -14,7 +12,7 @@ const MAX_ITERS: usize = 100_000;
|
||||
/// Reduces the definitions in the book individually, except for main.
|
||||
/// If cross_refs, will deref and try to find the smallest net.
|
||||
/// Otherwise, just apply node~node interactions.
|
||||
pub fn pre_reduce_book(book: &mut Book, cross_refs: bool) -> Result<(), String> {
|
||||
pub fn pre_reduce_book(book: &mut Book, cross_refs: bool, entrypoint: String) -> Result<(), String> {
|
||||
let rt_book = &mut hvmc::ast::book_to_runtime(book);
|
||||
for (nam, net) in book.iter() {
|
||||
// Skip unnecessary work
|
||||
@ -26,7 +24,7 @@ pub fn pre_reduce_book(book: &mut Book, cross_refs: bool) -> Result<(), String>
|
||||
boot(rt, fid);
|
||||
expand(rt, rt_book);
|
||||
|
||||
let fully_reduce = cross_refs && nam != ENTRY_POINT;
|
||||
let fully_reduce = cross_refs && *nam != entrypoint;
|
||||
let iters = if fully_reduce {
|
||||
let mut iters = 0;
|
||||
// TODO: If I just call `rt.normal` some terms expand infinitely, so I put this workaround.
|
||||
|
@ -1,14 +1,13 @@
|
||||
use crate::ENTRY_POINT;
|
||||
use hvmc::{
|
||||
ast::{val_to_name, Book, Tree},
|
||||
run::Val,
|
||||
};
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub fn prune_defs(book: &mut Book) {
|
||||
pub fn prune_defs(book: &mut Book, entrypoint: String) {
|
||||
let mut used_defs = HashSet::new();
|
||||
// On hvmc, the entry point is always "main"
|
||||
let mut to_visit = vec![ENTRY_POINT.to_string()];
|
||||
// Start visiting the given entrypoint
|
||||
let mut to_visit = vec![entrypoint.clone()];
|
||||
|
||||
while let Some(nam) = to_visit.pop() {
|
||||
let def = &book[&nam];
|
||||
@ -19,7 +18,7 @@ pub fn prune_defs(book: &mut Book) {
|
||||
}
|
||||
}
|
||||
let used_defs = used_defs.into_iter().map(val_to_name).collect::<HashSet<_>>();
|
||||
book.retain(|nam, _| used_defs.contains(nam) || nam == ENTRY_POINT);
|
||||
book.retain(|nam, _| used_defs.contains(nam) || *nam == entrypoint);
|
||||
}
|
||||
|
||||
fn used_defs_in_tree(tree: &Tree, used_defs: &mut HashSet<Val>, to_visit: &mut Vec<String>) {
|
||||
|
28
src/lib.rs
28
src/lib.rs
@ -13,7 +13,7 @@ use term::{
|
||||
book_to_nets, net_to_term,
|
||||
net_to_term::ReadbackErrors,
|
||||
term_to_net::{HvmcNames, Labels},
|
||||
Book, DefName, Term,
|
||||
Book, DefName, Name, Term,
|
||||
};
|
||||
|
||||
pub mod hvmc_net;
|
||||
@ -27,26 +27,34 @@ pub const HVM1_ENTRY_POINT: &str = "Main";
|
||||
|
||||
pub fn check_book(mut book: Book) -> Result<(), String> {
|
||||
// TODO: Do the checks without having to do full compilation
|
||||
compile_book(&mut book, CompileOpts::light())?;
|
||||
compile_book(&mut book, CompileOpts::light(), None)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compile_book(book: &mut Book, opts: CompileOpts) -> Result<CompileResult, String> {
|
||||
let (main, warnings) = desugar_book(book, opts)?;
|
||||
pub fn compile_book(
|
||||
book: &mut Book,
|
||||
opts: CompileOpts,
|
||||
entrypoint: Option<Name>,
|
||||
) -> Result<CompileResult, String> {
|
||||
let (main, warnings) = desugar_book(book, opts, entrypoint)?;
|
||||
let (nets, hvmc_names, labels) = book_to_nets(book, &main);
|
||||
let mut core_book = nets_to_hvmc(nets, &hvmc_names)?;
|
||||
if opts.pre_reduce {
|
||||
pre_reduce_book(&mut core_book, opts.pre_reduce_refs)?;
|
||||
pre_reduce_book(&mut core_book, opts.pre_reduce_refs, book.entrypoint())?;
|
||||
}
|
||||
if opts.prune {
|
||||
prune_defs(&mut core_book);
|
||||
prune_defs(&mut core_book, book.entrypoint());
|
||||
}
|
||||
Ok(CompileResult { core_book, hvmc_names, labels, warnings })
|
||||
}
|
||||
|
||||
pub fn desugar_book(book: &mut Book, opts: CompileOpts) -> Result<(DefName, Vec<Warning>), String> {
|
||||
pub fn desugar_book(
|
||||
book: &mut Book,
|
||||
opts: CompileOpts,
|
||||
entrypoint: Option<Name>,
|
||||
) -> Result<(DefName, Vec<Warning>), String> {
|
||||
let mut warnings = Vec::new();
|
||||
let main = book.check_has_main()?;
|
||||
let main = book.check_has_entrypoint(entrypoint)?;
|
||||
book.check_shared_names()?;
|
||||
book.generate_scott_adts();
|
||||
book.encode_builtins();
|
||||
@ -104,8 +112,10 @@ pub fn run_book(
|
||||
run_opts: RunOpts,
|
||||
warning_opts: WarningOpts,
|
||||
compile_opts: CompileOpts,
|
||||
entrypoint: Option<Name>,
|
||||
) -> Result<(Term, RunInfo), String> {
|
||||
let CompileResult { core_book, hvmc_names, labels, warnings } = compile_book(&mut book, compile_opts)?;
|
||||
let CompileResult { core_book, hvmc_names, labels, warnings } =
|
||||
compile_book(&mut book, compile_opts, entrypoint)?;
|
||||
|
||||
display_warnings(warning_opts, &warnings)?;
|
||||
|
||||
|
12
src/main.rs
12
src/main.rs
@ -1,8 +1,7 @@
|
||||
use clap::{Args, CommandFactory, Parser, Subcommand};
|
||||
use hvmc::ast::{show_book, show_net};
|
||||
use hvml::{
|
||||
check_book, compile_book, desugar_book, load_file_to_book, run_book, CompileOpts, RunInfo, RunOpts,
|
||||
WarnState, WarningOpts,
|
||||
check_book, compile_book, desugar_book, load_file_to_book, run_book, term::Name, CompileOpts, RunInfo, RunOpts, WarnState, WarningOpts
|
||||
};
|
||||
use std::{path::PathBuf, vec::IntoIter};
|
||||
|
||||
@ -14,6 +13,9 @@ struct Cli {
|
||||
|
||||
#[arg(short, long, global = true)]
|
||||
pub verbose: bool,
|
||||
|
||||
#[arg(short = 'e', long, global = true)]
|
||||
pub entrypoint: Option<Name>,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Clone, Debug)]
|
||||
@ -168,14 +170,14 @@ fn execute_cli_mode(cli: Cli, verbose: &dyn Fn(&hvml::term::Book)) -> Result<(),
|
||||
|
||||
let mut book = load_file_to_book(&path)?;
|
||||
verbose(&book);
|
||||
let compiled = compile_book(&mut book, opts)?;
|
||||
let compiled = compile_book(&mut book, opts, cli.entrypoint)?;
|
||||
hvml::display_warnings(warning_opts, &compiled.warnings)?;
|
||||
print!("{}", show_book(&compiled.core_book));
|
||||
}
|
||||
Mode::Desugar { path } => {
|
||||
let mut book = load_file_to_book(&path)?;
|
||||
verbose(&book);
|
||||
desugar_book(&mut book, CompileOpts::default())?;
|
||||
desugar_book(&mut book, CompileOpts::default(), None)?;
|
||||
println!("{book}");
|
||||
}
|
||||
Mode::Run { path, mem, debug, mut single_core, linear, arg_stats, cli_opts, wopts, lazy_mode } => {
|
||||
@ -198,7 +200,7 @@ fn execute_cli_mode(cli: Cli, verbose: &dyn Fn(&hvml::term::Book)) -> Result<(),
|
||||
let mem_size = mem / std::mem::size_of::<(hvmc::run::APtr, hvmc::run::APtr)>();
|
||||
let run_opts = RunOpts { single_core, debug, linear, lazy_mode };
|
||||
let (res_term, RunInfo { stats, readback_errors, net }) =
|
||||
run_book(book, mem_size, run_opts, warning_opts, opts)?;
|
||||
run_book(book, mem_size, run_opts, warning_opts, opts, cli.entrypoint)?;
|
||||
|
||||
let total_rewrites = stats.rewrites.total() as f64;
|
||||
let rps = total_rewrites / stats.run_time / 1_000_000.0;
|
||||
|
@ -1,10 +1,20 @@
|
||||
use crate::{
|
||||
term::{Book, DefName},
|
||||
term::{Book, DefName, Name},
|
||||
ENTRY_POINT, HVM1_ENTRY_POINT,
|
||||
};
|
||||
|
||||
impl Book {
|
||||
pub fn check_has_main(&self) -> Result<DefName, String> {
|
||||
pub fn check_has_entrypoint(&mut self, nam: Option<Name>) -> Result<DefName, String> {
|
||||
if let Some(nam) = nam {
|
||||
match self.defs.get(&nam) {
|
||||
Some(_) => {
|
||||
self.main = Some(nam.clone());
|
||||
return Ok(nam);
|
||||
}
|
||||
None => return Err(format!("File has no '{nam}' definition")),
|
||||
}
|
||||
}
|
||||
|
||||
match (self.defs.get(&DefName::new(ENTRY_POINT)), self.defs.get(&DefName::new(HVM1_ENTRY_POINT))) {
|
||||
(None, None) => Err("File has no 'main' definition".to_string()),
|
||||
(Some(_), Some(_)) => Err("File has both 'Main' and 'main' definitions".to_string()),
|
||||
@ -14,6 +24,7 @@ impl Book {
|
||||
} else if !main.rules[0].pats.is_empty() {
|
||||
Err("Main definition can't have any arguments".to_string())
|
||||
} else {
|
||||
self.main = None;
|
||||
Ok(main.name.clone())
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
pub mod ctrs_arities;
|
||||
pub mod exhaustiveness;
|
||||
pub mod has_main;
|
||||
pub mod has_entrypoint;
|
||||
pub mod shared_names;
|
||||
pub mod type_check;
|
||||
pub mod unbound_pats;
|
||||
|
@ -16,7 +16,7 @@ pub mod transform;
|
||||
pub use net_to_term::{net_to_term, ReadbackError};
|
||||
pub use term_to_net::{book_to_nets, term_to_compat_net};
|
||||
|
||||
use crate::term::builtins::*;
|
||||
use crate::{term::builtins::*, ENTRY_POINT};
|
||||
|
||||
/// The representation of a program.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
@ -29,6 +29,9 @@ pub struct Book {
|
||||
|
||||
/// To which type does each constructor belong to.
|
||||
pub ctrs: IndexMap<DefName, DefName>,
|
||||
|
||||
/// A custom or default entrypoint.
|
||||
pub main: Option<Name>,
|
||||
}
|
||||
|
||||
/// A pattern matching function definition.
|
||||
@ -786,3 +789,9 @@ impl Deref for Name {
|
||||
self.0.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl Book {
|
||||
pub fn entrypoint(&self) -> String {
|
||||
if let Some(nam) = &self.main { nam.to_string() } else { ENTRY_POINT.to_string() }
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ pub fn book_to_nets(book: &Book, main: &DefName) -> (HashMap<String, INet>, Hvmc
|
||||
for rule in def.rules.iter() {
|
||||
let net = term_to_compat_net(&rule.body, &mut labels);
|
||||
|
||||
let name = if def.name == *main {
|
||||
let name = if def.name == *main && book.main.is_none() {
|
||||
ENTRY_POINT.to_string()
|
||||
} else {
|
||||
def_name_to_hvmc_name(&def.name, &nets, &mut generated_count)
|
||||
|
@ -96,7 +96,7 @@ fn compile_term() {
|
||||
fn compile_file_o_all() {
|
||||
run_golden_test_dir(function_name!(), &|code, path| {
|
||||
let mut book = do_parse_book(code, path)?;
|
||||
let compiled = compile_book(&mut book, CompileOpts::heavy())?;
|
||||
let compiled = compile_book(&mut book, CompileOpts::heavy(), None)?;
|
||||
Ok(format!("{:?}", compiled))
|
||||
})
|
||||
}
|
||||
@ -104,7 +104,7 @@ fn compile_file_o_all() {
|
||||
fn compile_file() {
|
||||
run_golden_test_dir(function_name!(), &|code, path| {
|
||||
let mut book = do_parse_book(code, path)?;
|
||||
let compiled = compile_book(&mut book, CompileOpts::light())?;
|
||||
let compiled = compile_book(&mut book, CompileOpts::light(), None)?;
|
||||
Ok(format!("{:?}", compiled))
|
||||
})
|
||||
}
|
||||
@ -115,7 +115,7 @@ fn run_file() {
|
||||
let book = do_parse_book(code, path)?;
|
||||
// 1 million nodes for the test runtime. Smaller doesn't seem to make it any faster
|
||||
let (res, info) =
|
||||
run_book(book, 1 << 20, RunOpts::default(), WarningOpts::deny_all(), CompileOpts::heavy())?;
|
||||
run_book(book, 1 << 20, RunOpts::default(), WarningOpts::deny_all(), CompileOpts::heavy(), None)?;
|
||||
Ok(format!("{}{}", info.readback_errors.display(), res.display()))
|
||||
})
|
||||
}
|
||||
@ -130,7 +130,7 @@ fn run_lazy() {
|
||||
desugar_opts.lazy_mode();
|
||||
|
||||
// 1 million nodes for the test runtime. Smaller doesn't seem to make it any faster
|
||||
let (res, info) = run_book(book, 1 << 20, run_opts, WarningOpts::deny_all(), desugar_opts)?;
|
||||
let (res, info) = run_book(book, 1 << 20, run_opts, WarningOpts::deny_all(), desugar_opts, None)?;
|
||||
Ok(format!("{}{}", info.readback_errors.display(), res.display()))
|
||||
})
|
||||
}
|
||||
@ -150,7 +150,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_main().ok();
|
||||
let main = book.check_has_entrypoint(None).ok();
|
||||
book.check_shared_names()?;
|
||||
book.encode_builtins();
|
||||
book.resolve_ctrs_in_pats();
|
||||
@ -177,7 +177,7 @@ fn parse_file() {
|
||||
fn encode_pattern_match() {
|
||||
run_golden_test_dir(function_name!(), &|code, path| {
|
||||
let mut book = do_parse_book(code, path)?;
|
||||
let main = book.check_has_main().ok();
|
||||
let main = book.check_has_entrypoint(None).ok();
|
||||
book.check_shared_names()?;
|
||||
book.generate_scott_adts();
|
||||
book.encode_builtins();
|
||||
@ -192,7 +192,7 @@ fn encode_pattern_match() {
|
||||
fn desugar_file() {
|
||||
run_golden_test_dir(function_name!(), &|code, path| {
|
||||
let mut book = do_parse_book(code, path)?;
|
||||
desugar_book(&mut book, CompileOpts::light())?;
|
||||
desugar_book(&mut book, CompileOpts::light(), None)?;
|
||||
Ok(book.to_string())
|
||||
})
|
||||
}
|
||||
@ -208,7 +208,8 @@ fn hangs() {
|
||||
let lck = Arc::new(RwLock::new(false));
|
||||
let got = lck.clone();
|
||||
std::thread::spawn(move || {
|
||||
let _ = run_book(book, 1 << 20, RunOpts::default(), WarningOpts::deny_all(), CompileOpts::heavy());
|
||||
let _ =
|
||||
run_book(book, 1 << 20, RunOpts::default(), WarningOpts::deny_all(), CompileOpts::heavy(), None);
|
||||
*got.write().unwrap() = true;
|
||||
});
|
||||
std::thread::sleep(std::time::Duration::from_secs(expected_normalization_time));
|
||||
@ -216,4 +217,3 @@ fn hangs() {
|
||||
if !*lck.read().unwrap() { Ok("Hangs".into()) } else { Err("Doesn't hang".into()) }
|
||||
})
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user