use crate::{
compiler::{
grammar::{
instruction::{CompilerState, Instruction},
test::Test,
Capability,
},
lexer::{word::Word, Token},
CompileError, Value,
},
FileCarbonCopy,
};
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(
any(test, feature = "serde"),
derive(serde::Serialize, serde::Deserialize)
)]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)
)]
pub(crate) struct Vacation {
pub subject: Option<Value>,
pub from: Option<Value>,
pub mime: bool,
pub fcc: Option<FileCarbonCopy<Value>>,
pub reason: Value,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(
any(test, feature = "serde"),
derive(serde::Serialize, serde::Deserialize)
)]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)
)]
pub(crate) struct TestVacation {
pub addresses: Vec<Value>,
pub period: Period,
pub handle: Option<Value>,
pub reason: Value,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(
any(test, feature = "serde"),
derive(serde::Serialize, serde::Deserialize)
)]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)
)]
pub(crate) enum Period {
Days(u64),
Seconds(u64),
Default,
}
impl CompilerState<'_> {
pub(crate) fn parse_vacation(&mut self) -> Result<(), CompileError> {
let mut period = Period::Default;
let mut subject = None;
let mut from = None;
let mut handle = None;
let mut addresses = Vec::new();
let mut mime = false;
let reason;
let mut fcc = None;
let mut create = false;
let mut flags = Vec::new();
let mut special_use = None;
let mut mailbox_id = None;
loop {
let token_info = self.tokens.unwrap_next()?;
match token_info.token {
Token::Tag(Word::Mime) => {
self.validate_argument(1, None, token_info.line_num, token_info.line_pos)?;
mime = true;
}
Token::Tag(Word::Create) => {
self.validate_argument(
2,
Capability::Mailbox.into(),
token_info.line_num,
token_info.line_pos,
)?;
create = true;
}
Token::Tag(Word::Days) => {
self.validate_argument(3, None, token_info.line_num, token_info.line_pos)?;
period = Period::Days(self.tokens.expect_number(u64::MAX as usize)? as u64);
}
Token::Tag(Word::Seconds) => {
self.validate_argument(
3,
Capability::VacationSeconds.into(),
token_info.line_num,
token_info.line_pos,
)?;
period = Period::Seconds(self.tokens.expect_number(u64::MAX as usize)? as u64);
}
Token::Tag(Word::Subject) => {
self.validate_argument(4, None, token_info.line_num, token_info.line_pos)?;
subject = self.parse_string()?.into();
}
Token::Tag(Word::From) => {
self.validate_argument(5, None, token_info.line_num, token_info.line_pos)?;
from = self.parse_string()?.into();
}
Token::Tag(Word::Handle) => {
self.validate_argument(6, None, token_info.line_num, token_info.line_pos)?;
handle = self.parse_string()?.into();
}
Token::Tag(Word::SpecialUse) => {
self.validate_argument(
7,
Capability::SpecialUse.into(),
token_info.line_num,
token_info.line_pos,
)?;
special_use = self.parse_string()?.into();
}
Token::Tag(Word::MailboxId) => {
self.validate_argument(
8,
Capability::MailboxId.into(),
token_info.line_num,
token_info.line_pos,
)?;
mailbox_id = self.parse_string()?.into();
}
Token::Tag(Word::Fcc) => {
self.validate_argument(
9,
Capability::Fcc.into(),
token_info.line_num,
token_info.line_pos,
)?;
fcc = self.parse_string()?.into();
}
Token::Tag(Word::Flags) => {
self.validate_argument(
10,
Capability::Imap4Flags.into(),
token_info.line_num,
token_info.line_pos,
)?;
flags = self.parse_strings(false)?;
}
Token::Tag(Word::Addresses) => {
self.validate_argument(11, None, token_info.line_num, token_info.line_pos)?;
addresses = self.parse_strings(false)?;
}
_ => {
reason = self.parse_string_token(token_info)?;
break;
}
}
}
if fcc.is_none()
&& (create || !flags.is_empty() || special_use.is_some() || mailbox_id.is_some())
{
return Err(self.tokens.unwrap_next()?.missing_tag(":fcc"));
}
self.instructions
.push(Instruction::Test(Test::Vacation(TestVacation {
period,
handle,
reason: reason.clone(),
addresses,
})));
self.instructions
.push(Instruction::Jz(self.instructions.len() + 2));
self.instructions.push(Instruction::Vacation(Vacation {
reason,
subject,
from,
mime,
fcc: if let Some(fcc) = fcc {
FileCarbonCopy {
mailbox: fcc,
create,
flags,
special_use,
mailbox_id,
}
.into()
} else {
None
},
}));
Ok(())
}
}