pub(crate) mod lexer;
mod parser;
use alloc::{string::String, vec::Vec};
use core::ops::Range;
#[derive(Debug, Clone, Copy)]
enum Func {
Not,
All(usize),
Any(usize),
}
#[derive(Debug, PartialEq, Eq)]
pub(crate) enum Predicate<'a> {
Flag(&'a str),
KeyValue { key: &'a str, val: &'a str },
}
#[derive(Clone, Debug)]
struct InnerPredicate {
identifier: Range<usize>,
value: Option<Range<usize>>,
}
impl InnerPredicate {
fn to_pred<'a>(&self, s: &'a str) -> Predicate<'a> {
match &self.value {
Some(vs) => {
Predicate::KeyValue { key: &s[self.identifier.clone()], val: &s[vs.clone()] }
}
None => Predicate::Flag(&s[self.identifier.clone()]),
}
}
}
#[derive(Clone, Debug)]
enum ExprNode {
Fn(Func),
Predicate(InnerPredicate),
}
#[derive(Clone, Debug)]
pub(crate) struct Expression {
expr: Vec<ExprNode>,
original: String,
}
impl Expression {
#[cfg(test)]
pub(crate) fn predicates(&self) -> impl Iterator<Item = Predicate<'_>> {
self.expr.iter().filter_map(move |item| match item {
ExprNode::Predicate(pred) => {
let pred = pred.clone().to_pred(&self.original);
Some(pred)
}
ExprNode::Fn(_) => None,
})
}
pub(crate) fn eval<EP, T>(&self, mut eval_predicate: EP) -> T
where
EP: FnMut(&Predicate<'_>) -> T,
T: Logic + core::fmt::Debug,
{
let mut result_stack = Vec::with_capacity(8);
for node in &self.expr {
match node {
ExprNode::Predicate(pred) => {
let pred = pred.to_pred(&self.original);
result_stack.push(eval_predicate(&pred));
}
ExprNode::Fn(Func::All(count)) => {
let mut result = T::top();
for _ in 0..*count {
let r = result_stack.pop().unwrap();
result = result.and(r);
}
result_stack.push(result);
}
ExprNode::Fn(Func::Any(count)) => {
let mut result = T::bottom();
for _ in 0..*count {
let r = result_stack.pop().unwrap();
result = result.or(r);
}
result_stack.push(result);
}
ExprNode::Fn(Func::Not) => {
let r = result_stack.pop().unwrap();
result_stack.push(r.not());
}
}
}
result_stack.pop().unwrap()
}
}
pub(crate) trait Logic {
fn top() -> Self;
fn bottom() -> Self;
fn and(self, other: Self) -> Self;
fn or(self, other: Self) -> Self;
fn not(self) -> Self;
}
impl Logic for bool {
#[inline]
fn top() -> Self {
true
}
#[inline]
fn bottom() -> Self {
false
}
#[inline]
fn and(self, other: Self) -> Self {
self && other
}
#[inline]
fn or(self, other: Self) -> Self {
self || other
}
#[inline]
fn not(self) -> Self {
!self
}
}
impl Logic for Option<bool> {
#[inline]
fn top() -> Self {
Some(true)
}
#[inline]
fn bottom() -> Self {
Some(false)
}
#[inline]
fn and(self, other: Self) -> Self {
match (self, other) {
(Some(false), _) | (_, Some(false)) => Some(false),
(Some(true), Some(true)) => Some(true),
_ => None,
}
}
#[inline]
fn or(self, other: Self) -> Self {
match (self, other) {
(Some(true), _) | (_, Some(true)) => Some(true),
(Some(false), Some(false)) => Some(false),
_ => None,
}
}
#[inline]
fn not(self) -> Self {
self.map(|v| !v)
}
}