sieve/compiler/grammar/actions/
action_require.rs1use crate::compiler::{
8 grammar::{
9 instruction::{CompilerState, Instruction},
10 Capability,
11 },
12 lexer::Token,
13 CompileError,
14};
15
16impl CompilerState<'_> {
17 fn add_capability(&mut self, capabilities: &mut Vec<Capability>, capability: Capability) {
18 if !self.has_capability(&capability) {
19 let parent_capability = if matches!(&capability, Capability::SpamTestPlus) {
20 Some(Capability::SpamTest)
21 } else {
22 None
23 };
24 capabilities.push(capability.clone());
25 self.block.capabilities.insert(capability);
26
27 if let Some(capability) = parent_capability {
28 if !self.has_capability(&capability) {
29 capabilities.push(capability.clone());
30 self.block.capabilities.insert(capability);
31 }
32 }
33 }
34 }
35
36 pub(crate) fn parse_require(&mut self) -> Result<(), CompileError> {
37 let mut capabilities = Vec::new();
38
39 let token_info = self.tokens.unwrap_next()?;
40 match token_info.token {
41 Token::BracketOpen => loop {
42 let token_info = self.tokens.unwrap_next()?;
43 match token_info.token {
44 Token::StringConstant(value) => {
45 self.add_capability(
46 &mut capabilities,
47 Capability::parse(value.to_string().as_ref()),
48 );
49 let token_info = self.tokens.unwrap_next()?;
50 match token_info.token {
51 Token::Comma => (),
52 Token::BracketClose => break,
53 _ => {
54 return Err(token_info.expected("']' or ','"));
55 }
56 }
57 }
58 _ => {
59 return Err(token_info.expected("string"));
60 }
61 }
62 },
63 Token::StringConstant(value) => {
64 self.add_capability(
65 &mut capabilities,
66 Capability::parse(value.to_string().as_ref()),
67 );
68 }
69 _ => {
70 return Err(token_info.expected("'[' or string"));
71 }
72 }
73
74 if !capabilities.is_empty() {
75 if self.block.require_pos == usize::MAX {
76 self.block.require_pos = self.instructions.len();
77 self.instructions.push(Instruction::Require(capabilities));
78 } else if let Some(Instruction::Require(capabilties)) =
79 self.instructions.get_mut(self.block.require_pos)
80 {
81 capabilties.extend(capabilities)
82 } else {
83 #[cfg(test)]
84 panic!(
85 "Invalid require instruction position {}.",
86 self.block.require_pos
87 )
88 }
89 }
90
91 Ok(())
92 }
93}