sieve/compiler/grammar/tests/
test_string.rs1use crate::compiler::{
10 grammar::{instruction::CompilerState, Capability, Comparator},
11 lexer::{word::Word, Token},
12 CompileError, Value,
13};
14
15use crate::compiler::grammar::{test::Test, MatchType};
16
17#[derive(Debug, Clone, PartialEq, Eq)]
18#[cfg_attr(
19 any(test, feature = "serde"),
20 derive(serde::Serialize, serde::Deserialize)
21)]
22#[cfg_attr(
23 feature = "rkyv",
24 derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)
25)]
26pub(crate) struct TestString {
27 pub match_type: MatchType,
28 pub comparator: Comparator,
29 pub source: Vec<Value>,
30 pub key_list: Vec<Value>,
31 pub is_not: bool,
32}
33
34impl CompilerState<'_> {
35 pub(crate) fn parse_test_string(&mut self) -> Result<Test, CompileError> {
36 let mut match_type = MatchType::Is;
37 let mut comparator = Comparator::AsciiCaseMap;
38 let mut source = None;
39 let mut key_list: Vec<Value>;
40
41 loop {
42 let token_info = self.tokens.unwrap_next()?;
43 match token_info.token {
44 Token::Tag(
45 word @ (Word::Is
46 | Word::Contains
47 | Word::Matches
48 | Word::Value
49 | Word::Count
50 | Word::Regex
51 | Word::List),
52 ) => {
53 self.validate_argument(
54 1,
55 match word {
56 Word::Value | Word::Count => Capability::Relational.into(),
57 Word::Regex => Capability::Regex.into(),
58 Word::List => Capability::ExtLists.into(),
59 _ => None,
60 },
61 token_info.line_num,
62 token_info.line_pos,
63 )?;
64
65 match_type = self.parse_match_type(word)?;
66 }
67 Token::Tag(Word::Comparator) => {
68 self.validate_argument(2, None, token_info.line_num, token_info.line_pos)?;
69 comparator = self.parse_comparator()?;
70 }
71 _ => {
72 if source.is_none() {
73 source = self.parse_strings_token(token_info)?.into();
74 } else {
75 key_list = self.parse_strings_token(token_info)?;
76 break;
77 }
78 }
79 }
80 }
81 self.validate_match(&match_type, &mut key_list)?;
82
83 Ok(Test::String(TestString {
84 source: source.unwrap(),
85 key_list,
86 match_type,
87 comparator,
88 is_not: false,
89 }))
90 }
91}