use crate::{
common::Tag,
dnf::{DisjunctiveNormalForm, Formula, Litteral, LitteralTrait},
};
use std::{fmt::Display, str::FromStr};
peg::parser! {
grammar query_parser() for str {
rule and() = ( _ ("and" / "AND" / "&" / "&&") _) / _
rule or() = _ ("or" / "OR" / "|" / "||") _
rule not() = ("not" / "NOT" / "!" / "-") _
use BooleanFormula::{Or, And, Not};
rule expression() -> BooleanQuery = precedence! {
l:@ or() r:(@) { Or(Box::new(l), Box::new(r)) }
--
l:@ and() r:(@) { And(Box::new(l), Box::new(r)) }
--
not() e:@ { Not(Box::new(e)) }
--
"(" _opt() e:expression() _opt() ")" { e }
"tag:" t:$([^ ' ' | '\t' | '(' | ')']+) { BooleanQuery::Litteral(Tag::from(t.to_string())) }
}
rule _() = quiet!{[' ' | '\t']+}
rule _opt() = quiet!{[' ' | '\t']*}
pub rule expr() -> BooleanQuery = _opt() e:expression() _opt() { e }
}
}
#[derive(Debug, Clone)]
pub enum BooleanFormula<T> {
And(Box<Self>, Box<Self>),
Or(Box<Self>, Box<Self>),
Not(Box<Self>),
Litteral(T),
}
pub type BooleanQuery = BooleanFormula<Tag>;
impl BooleanQuery {
fn symbolic_repr(&self) -> String {
use BooleanFormula::*;
match self {
And(l, r) => format!("({}) ∧ ({})", l.symbolic_repr(), r.symbolic_repr()),
Or(l, r) => format!("({}) ∨ ({})", l.symbolic_repr(), r.symbolic_repr()),
Litteral(tag) => format!("#{}", tag.as_str()),
Not(p) => format!("¬({})", p.symbolic_repr()),
}
}
}
impl<T: LitteralTrait> From<BooleanFormula<T>> for DisjunctiveNormalForm<T> {
fn from(value: BooleanFormula<T>) -> Self {
match value {
BooleanFormula::Litteral(t) => Litteral::Val(t).into(),
BooleanFormula::Or(l, r) => DisjunctiveNormalForm::from(*l).or(r.as_ref()),
BooleanFormula::And(l, r) => DisjunctiveNormalForm::from(*l).and(r.as_ref()),
BooleanFormula::Not(p) => DisjunctiveNormalForm::from(*p).not(),
}
}
}
impl Display for BooleanQuery {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.symbolic_repr())
}
}
impl FromStr for BooleanQuery {
type Err = peg::error::ParseError<<str as peg::Parse>::PositionRepr>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
query_parser::expr(s)
}
}