cranelift_reader/
run_command.rs1use cranelift_codegen::data_value::{self, DataValue, DisplayDataValues};
10use std::fmt::{self, Display, Formatter};
11
12#[derive(PartialEq, Debug)]
16pub enum RunCommand {
17 Print(Invocation),
19 Run(Invocation, Comparison, Vec<DataValue>),
21}
22
23impl RunCommand {
24 pub fn run<F>(&self, invoke_fn: F) -> Result<(), String>
32 where
33 F: FnOnce(&str, &[DataValue]) -> Result<Vec<DataValue>, String>,
34 {
35 match self {
36 RunCommand::Print(invoke) => {
37 let actual = invoke_fn(&invoke.func, &invoke.args)?;
38 println!("{} -> {}", invoke, DisplayDataValues(&actual))
39 }
40 RunCommand::Run(invoke, compare, expected) => {
41 let actual = invoke_fn(&invoke.func, &invoke.args)?;
42 let matched = Self::compare_results(compare, &actual, expected);
43 if !matched {
44 let actual = DisplayDataValues(&actual);
45 return Err(format!("Failed test: {self}, actual: {actual}"));
46 }
47 }
48 }
49 Ok(())
50 }
51
52 fn compare_results(
53 compare: &Comparison,
54 actual: &Vec<DataValue>,
55 expected: &Vec<DataValue>,
56 ) -> bool {
57 let are_equal = actual.len() == expected.len()
58 && actual
59 .into_iter()
60 .zip(expected.into_iter())
61 .all(|(a, b)| a.bitwise_eq(b));
62
63 match compare {
64 Comparison::Equals => are_equal,
65 Comparison::NotEquals => !are_equal,
66 }
67 }
68}
69
70impl Display for RunCommand {
71 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
72 match self {
73 RunCommand::Print(invocation) => write!(f, "print: {invocation}"),
74 RunCommand::Run(invocation, comparison, expected) => {
75 let expected = DisplayDataValues(expected);
76 write!(f, "run: {invocation} {comparison} {expected}")
77 }
78 }
79 }
80}
81
82#[derive(Debug, PartialEq)]
84pub struct Invocation {
85 pub func: String,
88 pub args: Vec<DataValue>,
90}
91
92impl Invocation {
93 pub(crate) fn new(func: &str, args: Vec<DataValue>) -> Self {
94 let func = func.to_string();
95 Self { func, args }
96 }
97}
98
99impl Display for Invocation {
100 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
101 write!(f, "%{}(", self.func)?;
102 data_value::write_data_value_list(f, &self.args)?;
103 write!(f, ")")
104 }
105}
106
107#[expect(missing_docs, reason = "self-describing variants")]
109#[derive(Debug, PartialEq)]
110pub enum Comparison {
111 Equals,
112 NotEquals,
113}
114
115impl Display for Comparison {
116 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
117 match self {
118 Comparison::Equals => write!(f, "=="),
119 Comparison::NotEquals => write!(f, "!="),
120 }
121 }
122}
123
124#[cfg(test)]
125mod test {
126 use super::*;
127 use crate::parse_run_command;
128 use cranelift_codegen::ir::{types, AbiParam, Signature};
129 use cranelift_codegen::isa::CallConv;
130
131 #[test]
132 fn run_a_command() {
133 let mut signature = Signature::new(CallConv::Fast);
134 signature.returns.push(AbiParam::new(types::I32));
135 let command = parse_run_command(";; run: %return42() == 42 ", &signature)
136 .unwrap()
137 .unwrap();
138
139 assert!(command.run(|_, _| Ok(vec![DataValue::I32(42)])).is_ok());
140 assert!(command.run(|_, _| Ok(vec![DataValue::I32(43)])).is_err());
141 }
142}