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