Merge pull request #162 from HigherOrderCO/feature/sc-415/improve-skip-warnings-cli-flag

[sc-415] Improve skip_warnings cli flag
This commit is contained in:
Nicolas Abril 2024-01-30 18:21:54 +01:00 committed by GitHub
commit 958dec51cc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 139 additions and 18 deletions

View File

@ -7,7 +7,7 @@ use hvmc::{
use hvmc_net::{pre_reduce::pre_reduce_book, prune::prune_defs};
use itertools::Itertools;
use net::{hvmc_to_net::hvmc_to_net, net_to_hvmc::nets_to_hvmc};
use std::time::Instant;
use std::{time::Instant, vec::IntoIter};
use term::{
book_to_nets, net_to_term,
term_to_net::{HvmcNames, Labels},
@ -98,18 +98,21 @@ pub fn run_book(
parallel: bool,
debug: bool,
linear: bool,
skip_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)?;
if !warnings.is_empty() {
let warnings = warnings.iter().join("\n");
if !skip_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!("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) {
@ -240,6 +243,75 @@ impl Opts {
}
}
#[derive(Default, Clone, Copy)]
pub struct WarningOpts {
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 from_cli_opts(
&mut self,
wopts_id_seq: Vec<&clap::Id>,
allows: &mut IntoIter<WarningArgs>,
denies: &mut IntoIter<WarningArgs>,
warns: &mut IntoIter<WarningArgs>,
) {
for id in wopts_id_seq {
match id.as_ref() {
"allows" => self.set(allows.next().unwrap(), Self::allow_all(), WarnState::Allow),
"denies" => self.set(denies.next().unwrap(), Self::deny_all(), WarnState::Deny),
"warns" => self.set(warns.next().unwrap(), Self::default(), WarnState::Warn),
_ => {}
}
}
}
pub fn allow_all() -> Self {
Self { match_only_vars: WarnState::Allow, unused_defs: WarnState::Allow }
}
fn set(&mut self, val: WarningArgs, all: Self, switch: WarnState) {
match val {
WarningArgs::All => *self = all,
WarningArgs::UnusedDefs => self.unused_defs = switch,
WarningArgs::MatchOnlyVars => self.match_only_vars = switch,
}
}
pub fn deny_all() -> Self {
Self { match_only_vars: WarnState::Deny, unused_defs: WarnState::Deny }
}
/// Filters warnings based on the enabled flags.
pub fn filter<'a>(&'a self, wrns: &'a [Warning], ws: WarnState) -> Vec<&Warning> {
wrns
.iter()
.filter(|w| {
(match w {
Warning::MatchOnlyVars { .. } => self.match_only_vars,
Warning::UnusedDefinition { .. } => self.unused_defs,
}) == ws
})
.collect()
}
}
pub struct CompileResult {
pub core_book: hvmc::ast::Book,
pub hvmc_names: HvmcNames,

View File

@ -1,7 +1,8 @@
use clap::{Parser, ValueEnum};
use clap::{CommandFactory, Parser, ValueEnum};
use hvmc::ast::{show_book, show_net};
use hvml::{
check_book, compile_book, desugar_book, load_file_to_book, run_book, total_rewrites, Opts, RunInfo,
WarningOpts,
};
use std::path::PathBuf;
@ -14,8 +15,8 @@ struct Args {
#[arg(short, long)]
pub verbose: bool,
#[arg(short = 'w', help = "Skip compilation warnings")]
pub skip_warnings: bool,
#[command(flatten)]
pub wopts: WOpts,
#[arg(short, long, help = "Shows runtime stats and rewrite counts")]
pub stats: bool,
@ -48,6 +49,40 @@ struct Args {
pub path: PathBuf,
}
#[derive(clap::Args, Debug)]
#[group(multiple = true)]
struct WOpts {
#[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",
value_delimiter = ' ',
action = clap::ArgAction::Append,
long_help = r#"Deny compilation warnings
all, unused-defs, match-only-vars"#
)]
pub denies: Vec<hvml::WarningArgs>,
#[arg(
short = 'A',
long = "allow",
value_delimiter = ' ',
action = clap::ArgAction::Append,
long_help = r#"Allow compilation warnings
all, unused-defs, match-only-vars"#
)]
pub allows: Vec<hvml::WarningArgs>,
}
#[derive(ValueEnum, Clone, Debug)]
enum Mode {
/// Checks that the program is syntactically and semantically correct.
@ -72,6 +107,20 @@ fn mem_parser(arg: &str) -> Result<usize, String> {
Ok(base * mult)
}
impl WOpts {
fn get_warning_opts(self) -> WarningOpts {
let mut warning_opts = WarningOpts::default();
let argm = Args::command().get_matches();
if let Some(wopts_id_seq) = argm.get_many::<clap::Id>("WOpts") {
let allows = &mut self.allows.into_iter();
let denies = &mut self.denies.into_iter();
let warns = &mut self.warns.into_iter();
WarningOpts::from_cli_opts(&mut warning_opts, wopts_id_seq.collect(), allows, denies, warns);
}
warning_opts
}
}
fn main() {
fn run() -> Result<(), String> {
#[cfg(not(feature = "cli"))]
@ -80,6 +129,7 @@ fn main() {
let args = Args::parse();
let mut opts = Opts::light();
Opts::from_vec(&mut opts, args.opts)?;
let warning_opts = args.wopts.get_warning_opts();
let mut book = load_file_to_book(&args.path)?;
if args.verbose {
@ -87,9 +137,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)?;
@ -106,7 +154,7 @@ 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.skip_warnings, opts)?;
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

@ -10,7 +10,7 @@ use hvml::{
transform::{encode_lists::BuiltinList, encode_strs::BuiltinString},
Book, DefId, Term,
},
Opts,
Opts, WarningOpts,
};
use insta::assert_snapshot;
use itertools::Itertools;
@ -117,7 +117,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, false, 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)))
})
}