#![doc = include_str!("../README.md")]
mod model_check;
mod precision;
mod proposition;
mod refinery;
mod space;
use log::{error, info, log_enabled, trace};
use machine_check_common::{ExecError, ExecResult};
use mck::concr::FullMachine;
use clap::{ArgGroup, Parser};
use proposition::Proposition;
use refinery::Refinery;
#[derive(Parser, Debug)]
#[clap(group(ArgGroup::new("property-group")
.required(true)
.multiple(true)
.args(&["property", "inherent"]),
))]
struct Args {
#[arg(short, long)]
batch: bool,
#[arg(short, long, action = clap::ArgAction::Count)]
verbose: u8,
#[arg(long)]
property: Option<String>,
#[arg(long)]
inherent: bool,
#[arg(long)]
use_decay: bool,
}
pub fn run<M: FullMachine>(system: M) {
run_with_args(system, std::env::args())
}
pub fn run_with_args<M: FullMachine>(system: M, args: impl Iterator<Item = String>) {
if let Err(err) = run_inner(system, args) {
error!("{:#?}", err);
std::process::exit(-1);
}
}
fn run_inner<M: FullMachine>(
system: M,
args: impl Iterator<Item = String>,
) -> Result<ExecResult, anyhow::Error> {
let args = Args::parse_from(args);
let filter_level = match args.verbose {
0 => log::LevelFilter::Info,
1 => log::LevelFilter::Debug,
_ => log::LevelFilter::Trace,
};
env_logger::builder().filter_level(filter_level).init();
info!("Starting verification.");
let verification_result = verify(system, args.property.as_ref(), args.use_decay);
if log_enabled!(log::Level::Trace) {
trace!("Verification result: {:?}", verification_result);
}
if log_enabled!(log::Level::Info) {
match verification_result.result {
Ok(_) => info!("Verification ended."),
Err(_) => error!("Verification failed."),
}
}
serde_json::to_writer(std::io::stdout(), &verification_result)?;
Ok(verification_result)
}
fn verify<M: FullMachine>(system: M, property: Option<&String>, use_decay: bool) -> ExecResult {
let mut refinery = Refinery::<M>::new(system, use_decay);
let proposition = select_proposition(property);
let result = match proposition {
Ok(proposition) => refinery.verify_property(&proposition),
Err(err) => Err(err),
};
ExecResult {
result,
stats: refinery.info(),
}
}
fn select_proposition(property: Option<&String>) -> Result<Proposition, ExecError> {
if let Some(property_str) = property {
Proposition::parse(property_str)
} else {
Ok(Proposition::Const(true))
}
}