use bytes::Bytes;
use std::fmt;
#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
pub enum DcaMode {
#[default]
None,
Esi,
}
#[derive(Debug, PartialEq, Clone)]
pub struct IncludeAttributes {
pub src: Expr,
pub alt: Option<Expr>,
pub continue_on_error: bool,
pub dca: DcaMode,
pub ttl: Option<String>,
pub maxwait: Option<u32>,
pub no_store: bool,
pub method: Option<Expr>,
pub entity: Option<Expr>,
pub appendheaders: Vec<Expr>,
pub removeheaders: Vec<Expr>,
pub setheaders: Vec<Expr>,
pub params: Vec<(String, Expr)>,
}
#[derive(Debug, PartialEq, Clone)]
pub struct WhenBranch {
pub test: Expr,
pub match_name: Option<String>,
pub content: Vec<Element>,
}
#[derive(Debug, PartialEq, Clone)]
pub enum Tag {
Include {
attrs: IncludeAttributes,
},
Eval {
attrs: IncludeAttributes,
},
Try {
attempt_events: Vec<Vec<Element>>,
except_events: Vec<Element>,
},
Assign {
name: String,
subscript: Option<Expr>,
value: Expr,
},
Vars {
name: Option<String>,
},
When {
test: String,
match_name: Option<String>,
},
Choose {
when_branches: Vec<WhenBranch>,
otherwise_events: Vec<Element>,
},
Attempt(Vec<Element>),
Except(Vec<Element>),
Otherwise,
Foreach {
collection: Expr,
item: Option<String>,
content: Vec<Element>,
},
Break,
Function {
name: String,
body: Vec<Element>,
},
Return {
value: Expr,
},
}
#[derive(Debug, PartialEq, Clone)]
pub enum Element {
Esi(Tag),
Expr(Expr),
Html(Bytes),
Content(Bytes),
}
#[derive(Debug, Clone, PartialEq)]
pub enum Expr {
Integer(i32),
String(Option<Bytes>),
Variable(String, Option<Box<Expr>>, Option<Box<Expr>>),
Comparison {
left: Box<Expr>,
operator: Operator,
right: Box<Expr>,
},
Call(String, Vec<Expr>),
Not(Box<Expr>),
Interpolated(Vec<Element>),
DictLiteral(Vec<(Expr, Expr)>),
ListLiteral(Vec<Expr>),
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Operator {
Matches,
MatchesInsensitive,
Has,
HasInsensitive,
Equals,
NotEquals,
LessThan,
LessThanOrEqual,
GreaterThan,
GreaterThanOrEqual,
And,
Or,
Add,
Subtract,
Multiply,
Divide,
Modulo,
Range,
}
impl fmt::Display for Operator {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Self::Matches => "matches",
Self::MatchesInsensitive => "matches_i",
Self::Has => "has",
Self::HasInsensitive => "has_i",
Self::Equals => "==",
Self::NotEquals => "!=",
Self::LessThan => "<",
Self::LessThanOrEqual => "<=",
Self::GreaterThan => ">",
Self::GreaterThanOrEqual => ">=",
Self::And => "&",
Self::Or => "|",
Self::Add => "+",
Self::Subtract => "-",
Self::Multiply => "*",
Self::Divide => "/",
Self::Modulo => "%",
Self::Range => "..",
})
}
}
impl fmt::Display for Expr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Integer(i) => write!(f, "{i}"),
Self::String(None) => f.write_str("''"),
Self::String(Some(b)) => {
let s = String::from_utf8_lossy(b.as_ref());
if s.len() > 60 {
write!(f, "'{:.60}…'", s)
} else {
write!(f, "'{s}'")
}
}
Self::Variable(name, None, None) => write!(f, "$({name})"),
Self::Variable(name, Some(key), None) => write!(f, "$({name}{{{key}}})"),
Self::Variable(name, None, Some(default)) => {
write!(f, "$({name}|{default})")
}
Self::Variable(name, Some(key), Some(default)) => {
write!(f, "$({name}{{{key}}}|{default})")
}
Self::Comparison {
left,
operator,
right,
} => write!(f, "{left} {operator} {right}"),
Self::Call(name, args) => {
write!(f, "${name}(")?;
for (i, arg) in args.iter().enumerate() {
if i > 0 {
f.write_str(", ")?;
}
write!(f, "{arg}")?;
}
f.write_str(")")
}
Self::Not(inner) => write!(f, "!({inner})"),
Self::Interpolated(elements) => {
for elem in elements {
match elem {
Element::Content(b) | Element::Html(b) => {
let s = String::from_utf8_lossy(b.as_ref());
f.write_str(&s)?;
}
Element::Expr(expr) => write!(f, "{expr}")?,
Element::Esi(_) => f.write_str("<esi:…>")?,
}
}
Ok(())
}
Self::DictLiteral(pairs) => {
f.write_str("{")?;
for (i, (k, v)) in pairs.iter().enumerate() {
if i > 0 {
f.write_str(", ")?;
}
if i >= 3 {
write!(f, "…+{}", pairs.len() - 3)?;
break;
}
write!(f, "{k}: {v}")?;
}
f.write_str("}")
}
Self::ListLiteral(items) => {
f.write_str("[")?;
for (i, item) in items.iter().enumerate() {
if i > 0 {
f.write_str(", ")?;
}
if i >= 5 {
write!(f, "…+{}", items.len() - 5)?;
break;
}
write!(f, "{item}")?;
}
f.write_str("]")
}
}
}
}