litcheck_filecheck/ast/
directive.rs

1use std::str::FromStr;
2
3use crate::common::*;
4
5use super::CheckModifier;
6
7#[derive(Debug)]
8pub enum InvalidCheckTypeError {
9    Unrecognized,
10    InvalidCount(core::num::ParseIntError),
11}
12
13/// This enum represents the kind of directive that was parsed
14#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
15pub enum Check {
16    /// Not used after parsing, represents a line with no directives
17    #[default]
18    None,
19    /// The base CHECK directive, i.e. match the pattern is somewhere in the file
20    Plain,
21    /// The CHECK-NEXT directive, i.e. the pattern must match on the next line
22    /// from the previous pattern.
23    Next,
24    /// The CHECK-SAME directive, i.e. the pattern must match on the same line
25    /// as the previous pattern.
26    Same,
27    /// The CHECK-NOT directive, i.e. the pattern must _not_ match between this
28    /// directive and the next positive match directive, or the end of file. This
29    /// is the only negative match assertion supported.
30    Not,
31    /// The CHECK-DAG directive, i.e. like CHECK, but may match in any order relative
32    /// to other CHECK-DAG directives which are all part of a single consecutive
33    /// grouping. A non-CHECK-DAG directive between two sets of CHECK-DAG directives
34    /// cause the two sets to be split into two logical groups, where the ordering
35    /// between the groups is strict, but within the group it is not.
36    Dag,
37    /// The CHECK-LABEL directive, i.e. a regular CHECK, with the additional restriction
38    /// that the pattern may not contain references to (or bind) variables. This
39    /// directive type divides the checks (and input) into logical "blocks". Checks other
40    /// than CHECK-LABEL belong to the block defined by their preceding CHECK-LABEL. Checks
41    /// before the first CHECK-LABEL are part of an implicit prologue block.
42    ///
43    /// CHECK-LABEL divides up the input into blocks as well, by first matching all of the
44    /// CHECK-LABEL patterns, and then block-by-block, matching all of the checks "owned"
45    /// by each CHECK-LABEL, rejecting any matches that would match outside the region
46    /// of input assigned to the block.
47    Label,
48    /// The CHECK-EMPTY directive, i.e. the next line must be empty, containing nothing
49    /// but a newline, no other whitespace.
50    Empty,
51    /// This is only used during parsing, but represents CHECK-COUNT-N, i.e. a CHECK
52    /// that is repeated N times. N must be non-zero.
53    Count(usize),
54    /// The COM directive, i.e. a comment.
55    ///
56    /// This is only used during parsing.
57    Comment,
58}
59impl Check {
60    pub fn suffix(&self) -> Option<&'static str> {
61        match self {
62            Self::Plain => Some(""),
63            Self::Next => Some("-NEXT"),
64            Self::Same => Some("-SAME"),
65            Self::Not => Some("-NOT"),
66            Self::Dag => Some("-DAG"),
67            Self::Label => Some("-LABEL"),
68            Self::Empty => Some("-EMPTY"),
69            Self::Count(_) => Some("-COUNT"),
70            Self::Comment | Self::None => None,
71        }
72    }
73}
74impl fmt::Display for Check {
75    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
76        match self {
77            Self::None => f.write_str("CHECK-NONE"),
78            Self::Plain => f.write_str("CHECK"),
79            Self::Next => f.write_str("CHECK-NEXT"),
80            Self::Same => f.write_str("CHECK-SAME"),
81            Self::Not => f.write_str("CHECK-NOT"),
82            Self::Dag => f.write_str("CHECK-DAG"),
83            Self::Label => f.write_str("CHECK-LABEL"),
84            Self::Empty => f.write_str("CHECK-EMPTY"),
85            Self::Count(n) => write!(f, "CHECK-COUNT-{n}"),
86            Self::Comment => f.write_str("COM"),
87        }
88    }
89}
90impl FromStr for Check {
91    type Err = InvalidCheckTypeError;
92
93    fn from_str(s: &str) -> Result<Self, Self::Err> {
94        match s {
95            "" => Ok(Self::Plain),
96            "NEXT" | "next" => Ok(Self::Next),
97            "SAME" | "same" => Ok(Self::Same),
98            "NOT" | "not" => Ok(Self::Not),
99            "DAG" | "dag" => Ok(Self::Dag),
100            "LABEL" | "label" => Ok(Self::Label),
101            "EMPTY" | "empty" => Ok(Self::Empty),
102            _ => match s
103                .strip_prefix("COUNT-")
104                .or_else(|| s.strip_prefix("count-"))
105            {
106                None => Err(InvalidCheckTypeError::Unrecognized),
107                Some(count) => count
108                    .parse::<usize>()
109                    .map_err(InvalidCheckTypeError::InvalidCount)
110                    .map(Self::Count),
111            },
112        }
113    }
114}
115
116/// This represents the complete type of a CHECK* directive
117#[derive(Debug)]
118pub struct CheckType {
119    span: SourceSpan,
120    /// The kind of directive represented
121    pub kind: Check,
122    /// Any modifiers applied to this directive
123    pub modifiers: Span<CheckModifier>,
124}
125impl Default for CheckType {
126    fn default() -> Self {
127        Self::new(SourceSpan::from(0..0), Default::default())
128    }
129}
130impl Spanned for CheckType {
131    fn span(&self) -> SourceSpan {
132        self.span
133    }
134}
135impl CheckType {
136    pub fn new(span: SourceSpan, kind: Check) -> Self {
137        Self {
138            span,
139            kind,
140            modifiers: Span::new(span, Default::default()),
141        }
142    }
143
144    pub fn with_modifiers(mut self, modifiers: Span<CheckModifier>) -> Self {
145        self.modifiers = modifiers;
146        self
147    }
148
149    pub fn is_literal_match(&self) -> bool {
150        self.modifiers.contains(CheckModifier::LITERAL)
151    }
152
153    pub fn count(&self) -> usize {
154        self.modifiers.count()
155    }
156}
157impl Eq for CheckType {}
158impl PartialEq for CheckType {
159    fn eq(&self, other: &Self) -> bool {
160        self.kind == other.kind && self.modifiers == other.modifiers
161    }
162}