use std::fmt::Display;
use nom::Parser;
use nom::bytes::complete::tag_no_case;
use nom::{
IResult, branch::alt, bytes::complete::tag, combinator::map, multi::many0, sequence::preceded,
};
use super::term::{Term, parse_term};
use super::wsi::wsi;
pub type Expression = OrExpression;
#[derive(Debug, PartialEq, Clone)]
pub enum AndExpression {
AndTerm(Term),
AndExpression(Vec<Term>),
}
#[derive(Debug, PartialEq, Clone)]
pub enum OrExpression {
OrTerm(AndExpression),
OrExpression(Vec<AndExpression>),
}
impl Display for AndExpression {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AndExpression::AndTerm(t) => write!(f, "{t}"),
AndExpression::AndExpression(e) => write!(
f,
"{}",
e.iter()
.map(std::string::ToString::to_string)
.collect::<Vec<_>>()
.join(" && ")
),
}
}
}
impl Display for OrExpression {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
OrExpression::OrTerm(t) => write!(f, "{t}"),
OrExpression::OrExpression(t) => write!(
f,
"{}",
t.iter()
.map(std::string::ToString::to_string)
.collect::<Vec<_>>()
.join(" || ")
),
}
}
}
impl OrExpression {
pub(crate) fn is_empty(&self) -> bool {
match self {
OrExpression::OrTerm(_) => false,
OrExpression::OrExpression(v) => v.is_empty(),
}
}
}
pub(crate) fn parse_or_expression(input: &str) -> IResult<&str, OrExpression> {
if input.trim().is_empty() {
return Ok(("", Expression::OrExpression(vec![])));
}
map(
(
wsi(parse_and_expression),
many0(preceded(
wsi(alt((tag("||"), tag("or")))),
wsi(parse_and_expression),
)),
),
|(l, ee)| {
if ee.is_empty() {
OrExpression::OrTerm(l)
} else {
let mut ll = vec![l];
ll.extend(ee);
OrExpression::OrExpression(ll)
}
},
)
.parse(input)
}
pub(crate) fn parse_and_expression(input: &str) -> IResult<&str, AndExpression> {
map(
(
wsi(parse_term),
many0(preceded(
wsi(alt((tag("&&"), tag_no_case("and")))),
wsi(parse_term),
)),
),
|(l, ee)| {
if ee.is_empty() {
AndExpression::AndTerm(l)
} else {
let mut ll = vec![l];
ll.extend(ee);
AndExpression::AndExpression(ll)
}
},
)
.parse(input)
}