diff --git a/cranelift/src/libreader/lib.rs b/cranelift/src/libreader/lib.rs index 2d63e68264..4c53c79fa0 100644 --- a/cranelift/src/libreader/lib.rs +++ b/cranelift/src/libreader/lib.rs @@ -1,16 +1,12 @@ - -// ====------------------------------------------------------------------------------------==== // -// -// Cretonne file reader library. -// -// ====------------------------------------------------------------------------------------==== // -// -// The cton_reader library supports reading and writing .cton files. This functionality is needed -// for testing Cretonne, but is not essential for a JIT compiler. -// -// ====------------------------------------------------------------------------------------==== // +//! Cretonne file reader library. +//! +//! The cton_reader library supports reading .cton files. This functionality is needed for testing +//! Cretonne, but is not essential for a JIT compiler. extern crate cretonne; +pub use testcommand::{TestCommand, TestOption}; + pub mod lexer; pub mod parser; +mod testcommand; diff --git a/cranelift/src/libreader/testcommand.rs b/cranelift/src/libreader/testcommand.rs new file mode 100644 index 0000000000..3eba0d0a53 --- /dev/null +++ b/cranelift/src/libreader/testcommand.rs @@ -0,0 +1,88 @@ +//! Test commands. +//! +//! A `.cton` file can begin with one or more *test commands* which specify what is to be tested. +//! The general syntax is: +//! +//!
+//! test <command> [options]...
+//! 
+//! +//! The options are either a single identifier flag, or setting values like `identifier=value`. +//! +//! The parser does not understand the test commands or which options are alid. It simply parses +//! the general format into a `TestCommand` data structure. + +use std::fmt::{self, Display, Formatter}; + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct TestCommand<'a> { + pub command: &'a str, + pub options: Vec>, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum TestOption<'a> { + Flag(&'a str), + Value(&'a str, &'a str), +} + +impl<'a> TestCommand<'a> { + pub fn new(s: &'a str) -> TestCommand<'a> { + let mut parts = s.split_whitespace(); + let cmd = parts.next().unwrap_or(""); + TestCommand { + command: cmd, + options: parts.filter(|s| !s.is_empty()).map(TestOption::new).collect(), + } + } +} + +impl<'a> Display for TestCommand<'a> { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + try!(write!(f, "{}", self.command)); + for opt in &self.options { + try!(write!(f, " {}", opt)); + } + writeln!(f, "") + } +} + +impl<'a> TestOption<'a> { + pub fn new(s: &'a str) -> TestOption<'a> { + match s.find('=') { + None => TestOption::Flag(s), + Some(p) => TestOption::Value(&s[0..p], &s[p + 1..]), + } + } +} + +impl<'a> Display for TestOption<'a> { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match *self { + TestOption::Flag(s) => write!(f, "{}", s), + TestOption::Value(s, v) => write!(f, "{}={}", s, v), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse_option() { + assert_eq!(TestOption::new(""), TestOption::Flag("")); + assert_eq!(TestOption::new("foo"), TestOption::Flag("foo")); + assert_eq!(TestOption::new("foo=bar"), TestOption::Value("foo", "bar")); + } + + #[test] + fn parse_command() { + assert_eq!(&TestCommand::new("").to_string(), "\n"); + assert_eq!(&TestCommand::new("cat").to_string(), "cat\n"); + assert_eq!(&TestCommand::new("cat ").to_string(), "cat\n"); + assert_eq!(&TestCommand::new("cat 1 ").to_string(), "cat 1\n"); + assert_eq!(&TestCommand::new("cat one=4 two t").to_string(), + "cat one=4 two t\n"); + } +}