1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
//! Parsed representation of `set` and `isa` commands.
//!
//! A test case file can contain `set` commands that set ISA-independent settings, and it can
//! contain `isa` commands that select an ISA and applies ISA-specific settings.
//!
//! If a test case file contains `isa` commands, the tests will only be run against the specified
//! ISAs. If the file contains no `isa` commands, the tests will be run against all supported ISAs.
use crate::error::{Location, ParseError};
use crate::testcommand::TestOption;
use cranelift_codegen::isa::{OwnedTargetIsa, TargetIsa};
use cranelift_codegen::settings::{Configurable, Flags, SetError};
/// The ISA specifications in a `.clif` file.
pub enum IsaSpec {
/// The parsed file does not contain any `isa` commands, but it may contain `set` commands
/// which are reflected in the finished `Flags` object.
None(Flags),
/// The parsed file does contain `isa` commands.
/// Each `isa` command is used to configure a `TargetIsa` trait object.
Some(Vec<OwnedTargetIsa>),
}
impl IsaSpec {
/// If the `IsaSpec` contains exactly 1 `TargetIsa` we return a reference to it
pub fn unique_isa(&self) -> Option<&dyn TargetIsa> {
if let Self::Some(ref isa_vec) = *self {
if isa_vec.len() == 1 {
return Some(&*isa_vec[0]);
}
}
None
}
}
/// An error type returned by `parse_options`.
pub enum ParseOptionError {
/// A generic ParseError.
Generic(ParseError),
/// An unknown flag was used, with the given name at the given location.
UnknownFlag {
/// Location where the flag was given.
loc: Location,
/// Name of the unknown flag.
name: String,
},
/// An unknown value was used, with the given name at the given location.
UnknownValue {
/// Location where the flag was given.
loc: Location,
/// Name of the unknown value.
name: String,
/// Value of the unknown value.
value: String,
},
}
impl From<ParseOptionError> for ParseError {
fn from(err: ParseOptionError) -> Self {
match err {
ParseOptionError::Generic(err) => err,
ParseOptionError::UnknownFlag { loc, name } => Self {
location: loc,
message: format!("unknown setting '{}'", name),
is_warning: false,
},
ParseOptionError::UnknownValue { loc, name, value } => Self {
location: loc,
message: format!("unknown setting '{}={}'", name, value),
is_warning: false,
},
}
}
}
macro_rules! option_err {
( $loc:expr, $fmt:expr, $( $arg:expr ),+ ) => {
Err($crate::ParseOptionError::Generic($crate::ParseError {
location: $loc.clone(),
message: format!( $fmt, $( $arg ),+ ),
is_warning: false,
}))
};
}
/// Parse an iterator of command line options and apply them to `config`.
///
/// Note that parsing terminates after the first error is encountered.
pub fn parse_options<'a, I>(
iter: I,
config: &mut dyn Configurable,
loc: Location,
) -> Result<(), ParseOptionError>
where
I: Iterator<Item = &'a str>,
{
for opt in iter {
parse_option(opt, config, loc)?;
}
Ok(())
}
/// Parse an single command line options and apply it to `config`.
pub fn parse_option(
opt: &str,
config: &mut dyn Configurable,
loc: Location,
) -> Result<(), ParseOptionError> {
match TestOption::new(opt) {
TestOption::Flag(name) => match config.enable(name) {
Ok(_) => Ok(()),
Err(SetError::BadName(name)) => Err(ParseOptionError::UnknownFlag { loc, name }),
Err(_) => option_err!(loc, "not a boolean flag: '{}'", opt),
},
TestOption::Value(name, value) => match config.set(name, value) {
Ok(_) => Ok(()),
Err(SetError::BadName(name)) => Err(ParseOptionError::UnknownValue {
loc,
name,
value: value.to_string(),
}),
Err(SetError::BadType) => option_err!(loc, "invalid setting type: '{}'", opt),
Err(SetError::BadValue(expected)) => {
option_err!(
loc,
"invalid setting value for '{}', expected {}",
opt,
expected
)
}
},
}
}