use cranelift_codegen::data_value::{self, DataValue, DisplayDataValues};
use std::fmt::{self, Display, Formatter};
#[derive(PartialEq, Debug)]
pub enum RunCommand {
Print(Invocation),
Run(Invocation, Comparison, Vec<DataValue>),
}
impl RunCommand {
pub fn run<F>(&self, invoke_fn: F) -> Result<(), String>
where
F: FnOnce(&str, &[DataValue]) -> Result<Vec<DataValue>, String>,
{
match self {
RunCommand::Print(invoke) => {
let actual = invoke_fn(&invoke.func, &invoke.args)?;
println!("{} -> {}", invoke, DisplayDataValues(&actual))
}
RunCommand::Run(invoke, compare, expected) => {
let actual = invoke_fn(&invoke.func, &invoke.args)?;
let matched = Self::compare_results(compare, &actual, expected);
if !matched {
let actual = DisplayDataValues(&actual);
return Err(format!("Failed test: {}, actual: {}", self, actual));
}
}
}
Ok(())
}
fn compare_results(
compare: &Comparison,
actual: &Vec<DataValue>,
expected: &Vec<DataValue>,
) -> bool {
let are_equal = actual.len() == expected.len()
&& actual
.into_iter()
.zip(expected.into_iter())
.all(|(a, b)| a.bitwise_eq(b));
match compare {
Comparison::Equals => are_equal,
Comparison::NotEquals => !are_equal,
}
}
}
impl Display for RunCommand {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
RunCommand::Print(invocation) => write!(f, "print: {}", invocation),
RunCommand::Run(invocation, comparison, expected) => {
let expected = DisplayDataValues(expected);
write!(f, "run: {} {} {}", invocation, comparison, expected)
}
}
}
}
#[derive(Debug, PartialEq)]
pub struct Invocation {
pub func: String,
pub args: Vec<DataValue>,
}
impl Invocation {
pub(crate) fn new(func: &str, args: Vec<DataValue>) -> Self {
let func = func.to_string();
Self { func, args }
}
}
impl Display for Invocation {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "%{}(", self.func)?;
data_value::write_data_value_list(f, &self.args)?;
write!(f, ")")
}
}
#[allow(missing_docs)]
#[derive(Debug, PartialEq)]
pub enum Comparison {
Equals,
NotEquals,
}
impl Display for Comparison {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Comparison::Equals => write!(f, "=="),
Comparison::NotEquals => write!(f, "!="),
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::parse_run_command;
use cranelift_codegen::ir::{types, AbiParam, Signature};
use cranelift_codegen::isa::CallConv;
#[test]
fn run_a_command() {
let mut signature = Signature::new(CallConv::Fast);
signature.returns.push(AbiParam::new(types::I32));
let command = parse_run_command(";; run: %return42() == 42 ", &signature)
.unwrap()
.unwrap();
assert!(command.run(|_, _| Ok(vec![DataValue::I32(42)])).is_ok());
assert!(command.run(|_, _| Ok(vec![DataValue::I32(43)])).is_err());
}
}