Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/reader/src/run_command.rs
2450 views
1
//! Run commands.
2
//!
3
//! Functions in a `.clif` file can have *run commands* appended that control how a function is
4
//! invoked and tested within the `test run` context. The general syntax is:
5
//!
6
//! - `; run`: this assumes the function has a signature like `() -> b*`.
7
//! - `; run: %fn(42, 4.2) == false`: this syntax specifies the parameters and return values.
8
9
use cranelift_codegen::data_value::{self, DataValue, DisplayDataValues};
10
use std::fmt::{self, Display, Formatter};
11
12
/// A run command appearing in a test file.
13
///
14
/// For parsing, see `Parser::parse_run_command`
15
#[derive(PartialEq, Debug)]
16
pub enum RunCommand {
17
/// Invoke a function and print its result.
18
Print(Invocation),
19
/// Invoke a function and compare its result to a value sequence.
20
Run(Invocation, Comparison, Vec<DataValue>),
21
}
22
23
impl RunCommand {
24
/// Run the [RunCommand]:
25
/// - for [RunCommand::Print], print the returned values from invoking the function.
26
/// - for [RunCommand::Run], compare the returned values from the invoked function and
27
/// return an `Err` with a descriptive string if the comparison fails.
28
///
29
/// Accepts a function used for invoking the actual execution of the command. This function,
30
/// `invoked_fn`, is passed the _function name_ and _function arguments_ of the [Invocation].
31
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)
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
70
impl 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
/// Represent a function call; [RunCommand]s invoke a CLIF function using an [Invocation].
83
#[derive(Debug, PartialEq)]
84
pub struct Invocation {
85
/// The name of the function to call. Note: this field is for mostly included for informational
86
/// purposes and may not always be necessary for identifying which function to call.
87
pub func: String,
88
/// The arguments to be passed to the function when invoked.
89
pub args: Vec<DataValue>,
90
}
91
92
impl 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
99
impl 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
/// A CLIF comparison operation; e.g. `==`.
108
#[expect(missing_docs, reason = "self-describing variants")]
109
#[derive(Debug, PartialEq)]
110
pub enum Comparison {
111
Equals,
112
NotEquals,
113
}
114
115
impl 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)]
125
mod test {
126
use super::*;
127
use crate::parse_run_command;
128
use cranelift_codegen::ir::{AbiParam, Signature, types};
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
}
143
144