Refactor warnings

This commit is contained in:
imaqtkatt 2024-01-30 09:08:06 -03:00
parent 9f5a9b5df6
commit 02435adf44
3 changed files with 87 additions and 61 deletions

View File

@ -98,20 +98,21 @@ pub fn run_book(
parallel: bool,
debug: bool,
linear: bool,
fatal_warnings: bool,
warning_opts: WarningOpts,
opts: Opts,
) -> Result<(Term, DefNames, RunInfo), String> {
let CompileResult { core_book, hvmc_names, labels, warnings } = compile_book(&mut book, opts)?;
let warnings = warning_opts.filter(warnings);
if !warnings.is_empty() {
let warnings = warnings.iter().join("\n");
if fatal_warnings {
return Err(format!("{warnings}\nCould not run the code because of the previous warnings"));
} else {
eprintln!("{warnings}");
}
let warns = warning_opts.filter(&warnings, WarnState::Warn);
if !warns.is_empty() {
let warns = warns.iter().join("\n");
eprintln!("{}", format!("Warnings:\n{warns}"));
}
let denies = warning_opts.filter(&warnings, WarnState::Deny);
if !denies.is_empty() {
let denies = denies.iter().join("\n");
return Err(format!("{denies}\nCould not run the code because of the previous warnings"));
}
fn debug_hook(net: &Net, book: &Book, hvmc_names: &HvmcNames, labels: &Labels, linear: bool) {
@ -244,51 +245,69 @@ impl Opts {
#[derive(Default, Clone, Copy)]
pub struct WarningOpts {
pub match_only_vars: bool,
pub unused_defs: bool,
pub match_only_vars: WarnState,
pub unused_defs: WarnState,
}
#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum WarnState {
#[default]
Warn,
Allow,
Deny,
}
#[derive(clap::ValueEnum, Clone, Debug)]
pub enum WarningArgs {
All,
UnusedDefs,
MatchOnlyVars,
}
impl WarningOpts {
pub fn all() -> Self {
Self { match_only_vars: true, unused_defs: true }
pub fn deny_all() -> Self {
Self { match_only_vars: WarnState::Deny, unused_defs: WarnState::Deny }
}
fn iter_vals(&mut self, values: Vec<String>, all: Self, switch: bool) -> Result<(), String> {
for value in values {
match value.as_ref() {
"all" => *self = all,
"unused-defs" => self.unused_defs = switch,
"match-only-vars" => self.match_only_vars = switch,
other => return Err(format!("Unknown option '{other}'.")),
}
}
Ok(())
pub fn allow_all() -> Self {
Self { match_only_vars: WarnState::Allow, unused_defs: WarnState::Allow }
}
// TODO(refactor): this kind of code does not look good
pub fn deny(&mut self, values: Vec<String>) -> Result<(), String> {
self.iter_vals(values, Self::all(), true)
fn iter_vals(&mut self, values: Vec<WarningArgs>, all: Self, switch: WarnState) -> Result<(), String> {
for value in values {
match value {
WarningArgs::All => *self = all,
WarningArgs::UnusedDefs => self.unused_defs = switch,
WarningArgs::MatchOnlyVars => self.match_only_vars = switch,
}
}
Ok(())
}
pub fn allow(&mut self, values: Vec<String>) -> Result<(), String> {
self.iter_vals(values, Self::default(), false)
pub fn allow(&mut self, values: Vec<WarningArgs>) -> Result<(), String> {
self.iter_vals(values, Self::allow_all(), WarnState::Allow)
}
pub fn warn(&mut self, values: Vec<WarningArgs>) -> Result<(), String> {
self.iter_vals(values, Self::default(), WarnState::Warn)
}
pub fn deny(&mut self, values: Vec<WarningArgs>) -> Result<(), String> {
self.iter_vals(values, Self::deny_all(), WarnState::Deny)
}
/// Filters warnings based on the enabled flags.
pub fn filter(&self, wrns: Vec<Warning>) -> Vec<Warning> {
wrns.into_iter().filter(|w| self.is_warning_enabled(w)).collect_vec()
}
pub fn is_warning_enabled(&self, w: &Warning) -> bool {
!self.is_warning_denied(w)
}
pub fn is_warning_denied(&self, w: &Warning) -> bool {
match w {
Warning::MatchOnlyVars { .. } => self.match_only_vars,
Warning::UnusedDefinition { .. } => self.unused_defs,
}
pub fn filter<'a>(&'a self, wrns: &'a Vec<Warning>, ws: WarnState) -> Vec<&Warning> {
wrns
.into_iter()
.filter(|w| {
(match w {
Warning::MatchOnlyVars { .. } => self.match_only_vars,
Warning::UnusedDefinition { .. } => self.unused_defs,
}) == ws
})
.collect()
}
}

View File

@ -15,6 +15,16 @@ struct Args {
#[arg(short, long)]
pub verbose: bool,
#[arg(
short = 'W',
long = "warn",
value_delimiter = ' ',
action = clap::ArgAction::Append,
long_help = r#"Show compilation warnings
all, unused-defs, match-only-vars"#
)]
pub warns: Vec<hvml::WarningArgs>,
#[arg(
short = 'D',
long = "deny",
@ -23,7 +33,7 @@ struct Args {
long_help = r#"Deny compilation warnings
all, unused-defs, match-only-vars"#
)]
pub deny_warnings: Vec<String>,
pub denies: Vec<hvml::WarningArgs>,
#[arg(
short = 'A',
@ -33,7 +43,7 @@ struct Args {
long_help = r#"Allow compilation warnings
all, unused-defs, match-only-vars"#
)]
pub allow_warnings: Vec<String>,
pub allows: Vec<hvml::WarningArgs>,
#[arg(long, help = "Stops if any warning was produced")]
pub fatal_warnings: bool,
@ -101,9 +111,11 @@ fn main() {
let args = Args::parse();
let mut opts = Opts::light();
Opts::from_vec(&mut opts, args.opts)?;
let mut warning_opts = WarningOpts::default();
WarningOpts::deny(&mut warning_opts, args.deny_warnings)?;
WarningOpts::allow(&mut warning_opts, args.allow_warnings)?;
WarningOpts::allow(&mut warning_opts, args.allows)?;
WarningOpts::deny(&mut warning_opts, args.denies)?;
WarningOpts::warn(&mut warning_opts, args.warns)?;
let mut book = load_file_to_book(&args.path)?;
if args.verbose {
@ -111,9 +123,7 @@ fn main() {
}
match args.mode {
Mode::Check => {
check_book(book)?;
}
Mode::Check => check_book(book)?,
Mode::Compile => {
let compiled = compile_book(&mut book, opts)?;
@ -129,16 +139,8 @@ fn main() {
}
Mode::Run => {
let mem_size = args.mem / std::mem::size_of::<(hvmc::run::APtr, hvmc::run::APtr)>();
let (res_term, def_names, info) = run_book(
book,
mem_size,
!args.single_core,
args.debug,
args.linear,
args.fatal_warnings,
warning_opts,
opts,
)?;
let (res_term, def_names, info) =
run_book(book, mem_size, !args.single_core, args.debug, args.linear, warning_opts, opts)?;
let RunInfo { stats, readback_errors, net: lnet } = info;
let total_rewrites = total_rewrites(&stats.rewrites) as f64;
let rps = total_rewrites / stats.run_time / 1_000_000.0;

View File

@ -1,12 +1,16 @@
use hvmc::ast::{parse_net, show_net};
use hvml::{
compile_book, encode_pattern_matching, net::{hvmc_to_net::hvmc_to_net, net_to_hvmc::net_to_hvmc}, run_book, term::{
compile_book, encode_pattern_matching,
net::{hvmc_to_net::hvmc_to_net, net_to_hvmc::net_to_hvmc},
run_book,
term::{
net_to_term::net_to_term,
parser::{parse_definition_book, parse_term, parser::error_to_msg},
term_to_compat_net,
transform::{encode_lists::BuiltinList, encode_strs::BuiltinString},
Book, DefId, Term,
}, Opts, WarningOpts
},
Opts, WarningOpts,
};
use insta::assert_snapshot;
use itertools::Itertools;
@ -112,7 +116,8 @@ fn run_file() {
run_golden_test_dir(function_name!(), &|code| {
let book = do_parse_book(code)?;
// 1 million nodes for the test runtime. Smaller doesn't seem to make it any faster
let (res, def_names, info) = run_book(book, 1 << 20, true, false, false, true, WarningOpts::default(), Opts::heavy())?;
let (res, def_names, info) =
run_book(book, 1 << 20, true, false, false, WarningOpts::deny_all(), Opts::heavy())?;
Ok(format!("{}{}", info.readback_errors.display(&def_names), res.display(&def_names)))
})
}