tiger_lib/parse/
ignore.rs1use std::sync::LazyLock;
2
3use lalrpop_util::lalrpop_mod;
4
5use crate::report::ErrorKey;
6
7lalrpop_mod! {
8 #[allow(clippy::pedantic)]
9 #[allow(clippy::if_then_some_else_none)]
10 parser, "/parse/ignore/parser.rs"
11}
12static COMMENT_PARSER: LazyLock<parser::CommentParser> = LazyLock::new(parser::CommentParser::new);
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
15pub enum IgnoreSize {
16 #[default]
17 Line,
18 Block,
19 File,
20 Begin,
21 End,
22}
23
24#[derive(Debug, Clone, Default)]
25pub struct IgnoreFilter {
26 key: Option<ErrorKey>,
27 text: Option<String>,
28}
29
30#[derive(Debug, Clone, Default)]
31pub struct IgnoreSpec {
32 pub size: IgnoreSize,
33 pub filter: IgnoreFilter,
34}
35
36pub fn parse_comment(comment: &str) -> Option<IgnoreSpec> {
37 if !comment.trim_start().starts_with("tiger-ignore") {
39 return None;
40 }
41 COMMENT_PARSER.parse(comment).ok()
42}
43
44impl IgnoreSpec {
45 fn set_key(mut self, key: ErrorKey) -> Self {
46 self.filter.key = Some(key);
47 self
48 }
49
50 fn set_text(mut self, text: String) -> Self {
51 self.filter.text = Some(text);
52 self
53 }
54
55 fn merge(mut self, other: Self) -> Self {
56 if other.size != IgnoreSize::Line {
57 self.size = other.size;
58 }
59 if other.filter.key.is_some() {
60 self.filter.key = other.filter.key;
61 }
62 if other.filter.text.is_some() {
63 self.filter.text = other.filter.text;
64 }
65 self
66 }
67}
68
69impl IgnoreFilter {
70 pub fn matches(&self, other_key: ErrorKey, other_text: &str) -> bool {
71 if let Some(key) = self.key {
72 if key != other_key {
73 return false;
74 }
75 }
76 if let Some(text) = &self.text {
77 if !other_text.contains(text) {
78 return false;
79 }
80 }
81 true
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88
89 #[test]
90 fn test_bare() {
91 let result = parse_comment("tiger-ignore");
92 assert!(result.is_some());
93 if let Some(spec) = result {
94 assert_eq!(spec.size, IgnoreSize::Line);
95 assert!(spec.filter.key.is_none());
96 assert!(spec.filter.text.is_none());
97 }
98 }
99
100 #[test]
101 fn test_non_ignore() {
102 let result = parse_comment("a random comment");
103 assert!(result.is_none());
104 }
105
106 #[test]
107 fn test_bare_trailing() {
108 let result = parse_comment("tiger-ignore with explanation");
109 assert!(result.is_some());
110 if let Some(spec) = result {
111 assert_eq!(spec.size, IgnoreSize::Line);
112 assert!(spec.filter.key.is_none());
113 assert!(spec.filter.text.is_none());
114 }
115 }
116
117 #[test]
118 fn test_block() {
119 let result = parse_comment("tiger-ignore(block)");
120 assert!(result.is_some());
121 if let Some(spec) = result {
122 assert_eq!(spec.size, IgnoreSize::Block);
123 assert!(spec.filter.key.is_none());
124 assert!(spec.filter.text.is_none());
125 }
126 }
127
128 #[test]
129 fn test_file() {
130 let result = parse_comment("tiger-ignore(file)");
131 assert!(result.is_some());
132 if let Some(spec) = result {
133 assert_eq!(spec.size, IgnoreSize::File);
134 assert!(spec.filter.key.is_none());
135 assert!(spec.filter.text.is_none());
136 }
137 }
138
139 #[test]
140 fn test_begin() {
141 let result = parse_comment("tiger-ignore(begin)");
142 assert!(result.is_some());
143 if let Some(spec) = result {
144 assert_eq!(spec.size, IgnoreSize::Begin);
145 assert!(spec.filter.key.is_none());
146 assert!(spec.filter.text.is_none());
147 }
148 }
149
150 #[test]
151 fn test_end() {
152 let result = parse_comment("tiger-ignore(end)");
153 assert!(result.is_some());
154 if let Some(spec) = result {
155 assert_eq!(spec.size, IgnoreSize::End);
156 assert!(spec.filter.key.is_none());
157 assert!(spec.filter.text.is_none());
158 }
159 }
160
161 #[test]
162 fn test_block_with_key() {
163 let result = parse_comment("tiger-ignore(block, key=missing-item)");
164 assert!(result.is_some());
165 if let Some(spec) = result {
166 assert_eq!(spec.size, IgnoreSize::Block);
167 assert_eq!(spec.filter.key, Some(ErrorKey::MissingItem));
168 assert!(spec.filter.text.is_none());
169 }
170 }
171
172 #[test]
173 fn test_block_with_quoted_text() {
174 let result = parse_comment("tiger-ignore(block, text=\"missing english\")");
175 assert!(result.is_some());
176 if let Some(spec) = result {
177 assert_eq!(spec.size, IgnoreSize::Block);
178 assert!(spec.filter.key.is_none());
179 assert_eq!(spec.filter.text, Some("missing english".to_owned()));
180 }
181 }
182}