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