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 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
use std::str::FromStr;
use crate::common::*;
use super::CheckModifier;
#[derive(Debug)]
pub enum InvalidCheckTypeError {
Unrecognized,
InvalidCount(core::num::ParseIntError),
}
/// This enum represents the kind of directive that was parsed
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
pub enum Check {
/// Not used after parsing, represents a line with no directives
#[default]
None,
/// The base CHECK directive, i.e. match the pattern is somewhere in the file
Plain,
/// The CHECK-NEXT directive, i.e. the pattern must match on the next line
/// from the previous pattern.
Next,
/// The CHECK-SAME directive, i.e. the pattern must match on the same line
/// as the previous pattern.
Same,
/// The CHECK-NOT directive, i.e. the pattern must _not_ match between this
/// directive and the next positive match directive, or the end of file. This
/// is the only negative match assertion supported.
Not,
/// The CHECK-DAG directive, i.e. like CHECK, but may match in any order relative
/// to other CHECK-DAG directives which are all part of a single consecutive
/// grouping. A non-CHECK-DAG directive between two sets of CHECK-DAG directives
/// cause the two sets to be split into two logical groups, where the ordering
/// between the groups is strict, but within the group it is not.
Dag,
/// The CHECK-LABEL directive, i.e. a regular CHECK, with the additional restriction
/// that the pattern may not contain references to (or bind) variables. This
/// directive type divides the checks (and input) into logical "blocks". Checks other
/// than CHECK-LABEL belong to the block defined by their preceding CHECK-LABEL. Checks
/// before the first CHECK-LABEL are part of an implicit prologue block.
///
/// CHECK-LABEL divides up the input into blocks as well, by first matching all of the
/// CHECK-LABEL patterns, and then block-by-block, matching all of the checks "owned"
/// by each CHECK-LABEL, rejecting any matches that would match outside the region
/// of input assigned to the block.
Label,
/// The CHECK-EMPTY directive, i.e. the next line must be empty, containing nothing
/// but a newline, no other whitespace.
Empty,
/// This is only used during parsing, but represents CHECK-COUNT-N, i.e. a CHECK
/// that is repeated N times. N must be non-zero.
Count(usize),
/// The COM directive, i.e. a comment.
///
/// This is only used during parsing.
Comment,
}
impl Check {
pub fn suffix(&self) -> Option<&'static str> {
match self {
Self::Plain => Some(""),
Self::Next => Some("-NEXT"),
Self::Same => Some("-SAME"),
Self::Not => Some("-NOT"),
Self::Dag => Some("-DAG"),
Self::Label => Some("-LABEL"),
Self::Empty => Some("-EMPTY"),
Self::Count(_) => Some("-COUNT"),
Self::Comment | Self::None => None,
}
}
}
impl fmt::Display for Check {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::None => f.write_str("CHECK-NONE"),
Self::Plain => f.write_str("CHECK"),
Self::Next => f.write_str("CHECK-NEXT"),
Self::Same => f.write_str("CHECK-SAME"),
Self::Not => f.write_str("CHECK-NOT"),
Self::Dag => f.write_str("CHECK-DAG"),
Self::Label => f.write_str("CHECK-LABEL"),
Self::Empty => f.write_str("CHECK-EMPTY"),
Self::Count(n) => write!(f, "CHECK-COUNT-{n}"),
Self::Comment => f.write_str("COM"),
}
}
}
impl FromStr for Check {
type Err = InvalidCheckTypeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"" => Ok(Self::Plain),
"NEXT" | "next" => Ok(Self::Next),
"SAME" | "same" => Ok(Self::Same),
"NOT" | "not" => Ok(Self::Not),
"DAG" | "dag" => Ok(Self::Dag),
"LABEL" | "label" => Ok(Self::Label),
"EMPTY" | "empty" => Ok(Self::Empty),
_ => match s
.strip_prefix("COUNT-")
.or_else(|| s.strip_prefix("count-"))
{
None => Err(InvalidCheckTypeError::Unrecognized),
Some(count) => count
.parse::<usize>()
.map_err(InvalidCheckTypeError::InvalidCount)
.map(Self::Count),
},
}
}
}
/// This represents the complete type of a CHECK* directive
#[derive(Debug)]
pub struct CheckType {
span: SourceSpan,
/// The kind of directive represented
pub kind: Check,
/// Any modifiers applied to this directive
pub modifiers: Span<CheckModifier>,
}
impl Default for CheckType {
fn default() -> Self {
Self::new(SourceSpan::from(0..0), Default::default())
}
}
impl Spanned for CheckType {
fn span(&self) -> SourceSpan {
self.span
}
}
impl CheckType {
pub fn new(span: SourceSpan, kind: Check) -> Self {
Self {
span,
kind,
modifiers: Span::new(span, Default::default()),
}
}
pub fn with_modifiers(mut self, modifiers: Span<CheckModifier>) -> Self {
self.modifiers = modifiers;
self
}
pub fn is_literal_match(&self) -> bool {
self.modifiers.contains(CheckModifier::LITERAL)
}
pub fn count(&self) -> usize {
self.modifiers.count()
}
}
impl Eq for CheckType {}
impl PartialEq for CheckType {
fn eq(&self, other: &Self) -> bool {
self.kind == other.kind && self.modifiers == other.modifiers
}
}