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::ir::immediates::{Ieee32, Ieee64};
10 use cranelift_codegen::ir::ConstantData;
11 use std::fmt::{Display, Formatter, Result};
12 
13 /// A run command appearing in a test file.
14 ///
15 /// For parsing, see
16 /// [Parser::parse_run_command](crate::parser::Parser::parse_run_command).
17 #[derive(PartialEq, Debug)]
18 pub enum RunCommand {
19     /// Invoke a function and print its result.
20     Print(Invocation),
21     /// Invoke a function and compare its result to a value sequence.
22     Run(Invocation, Comparison, Vec<DataValue>),
23 }
24 
25 impl Display for RunCommand {
26     fn fmt(&self, f: &mut Formatter) -> Result {
27         match self {
28             RunCommand::Print(invocation) => write!(f, "print: {}", invocation),
29             RunCommand::Run(invocation, comparison, expected) => {
30                 write!(f, "run: {} {} ", invocation, comparison)?;
31                 if expected.len() == 1 {
32                     write!(f, "{}", expected[0])
33                 } else {
34                     write!(f, "[")?;
35                     write_data_value_list(f, expected)?;
36                     write!(f, "]")
37                 }
38             }
39         }
40     }
41 }
42 
43 /// Represent a function call; [RunCommand]s invoke a CLIF function using an [Invocation].
44 #[derive(Debug, PartialEq)]
45 pub struct Invocation {
46     /// The name of the function to call. Note: this field is for mostly included for informational
47     /// purposes and may not always be necessary for identifying which function to call.
48     pub func: String,
49     /// The arguments to be passed to the function when invoked.
50     pub args: Vec<DataValue>,
51 }
52 
53 impl Invocation {
54     pub(crate) fn new(func: &str, args: Vec<DataValue>) -> Self {
55         let func = func.to_string();
56         Self { func, args }
57     }
58 }
59 
60 impl Display for Invocation {
61     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
62         write!(f, "%{}(", self.func)?;
63         write_data_value_list(f, &self.args)?;
64         write!(f, ")")
65     }
66 }
67 
68 /// Represent a data value. Where [Value] is an SSA reference, [DataValue] is the type + value
69 /// that would be referred to by a [Value].
70 ///
71 /// [Value]: cranelift_codegen::ir::Value
72 #[allow(missing_docs)]
73 #[derive(Clone, Debug, PartialEq)]
74 pub enum DataValue {
75     B(bool),
76     I8(i8),
77     I16(i16),
78     I32(i32),
79     I64(i64),
80     F32(f32),
81     F64(f64),
82     V128([u8; 16]),
83 }
84 
85 /// Helper for creating [From] implementations for [DataValue]
86 macro_rules! from_data {
87     ( $ty:ty, $variant:ident ) => {
88         impl From<$ty> for DataValue {
89             fn from(data: $ty) -> Self {
90                 DataValue::$variant(data)
91             }
92         }
93     };
94 }
95 from_data!(bool, B);
96 from_data!(i8, I8);
97 from_data!(i16, I16);
98 from_data!(i32, I32);
99 from_data!(i64, I64);
100 from_data!(f32, F32);
101 from_data!(f64, F64);
102 from_data!([u8; 16], V128);
103 
104 impl Display for DataValue {
105     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
106         match self {
107             DataValue::B(dv) => write!(f, "{}", dv),
108             DataValue::I8(dv) => write!(f, "{}", dv),
109             DataValue::I16(dv) => write!(f, "{}", dv),
110             DataValue::I32(dv) => write!(f, "{}", dv),
111             DataValue::I64(dv) => write!(f, "{}", dv),
112             // Use the Ieee* wrappers here to maintain a consistent syntax.
113             DataValue::F32(dv) => write!(f, "{}", Ieee32::from(*dv)),
114             DataValue::F64(dv) => write!(f, "{}", Ieee64::from(*dv)),
115             // Again, for syntax consistency, use ConstantData, which in this case displays as hex.
116             DataValue::V128(dv) => write!(f, "{}", ConstantData::from(&dv[..])),
117         }
118     }
119 }
120 
121 /// Helper function for displaying `Vec<DataValue>`.
122 fn write_data_value_list(f: &mut Formatter<'_>, list: &[DataValue]) -> Result {
123     match list.len() {
124         0 => Ok(()),
125         1 => write!(f, "{}", list[0]),
126         _ => {
127             write!(f, "{}", list[0])?;
128             for dv in list.iter().skip(1) {
129                 write!(f, ", {}", dv)?;
130             }
131             Ok(())
132         }
133     }
134 }
135 
136 /// A CLIF comparison operation; e.g. `==`.
137 #[allow(missing_docs)]
138 #[derive(Debug, PartialEq)]
139 pub enum Comparison {
140     Equals,
141     NotEquals,
142 }
143 
144 impl Display for Comparison {
145     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
146         match self {
147             Comparison::Equals => write!(f, "=="),
148             Comparison::NotEquals => write!(f, "!="),
149         }
150     }
151 }
152