aimx/expressions/
logical_or.rs1use crate::{
8 aim::{ContextLike, WriterLike, Writer},
9 expressions::{ExpressionLike, LogicalAnd, Primary, parse_and},
10 literals::Literal,
11 values::Value,
12};
13use anyhow::{Result, anyhow};
14use nom::{
15 IResult, Parser, branch::alt, bytes::complete::tag, character::complete::multispace0,
16 multi::many0, sequence::preceded,
17};
18use std::{
19 fmt,
20 sync::Arc,
21};
22
23#[derive(Debug, Clone, PartialEq)]
28pub enum LogicalOr {
29 Or(Box<LogicalOr>, LogicalAnd),
30 Primary(Box<Primary>),
32}
33
34impl LogicalOr {
35 pub fn print(&self, writer: &mut Writer) {
36 match self {
37 LogicalOr::Or(left, right) => {
38 writer.write_binary_op(left.as_ref(), " | ", right);
39 }
40 LogicalOr::Primary(primary) => primary.print(writer),
41 }
42 }
43}
44
45fn or_operator(input: &str) -> IResult<&str, LogicalAnd> {
47 preceded(
48 (
49 multispace0,
50 alt((tag("||"), tag("|"))),
51 multispace0,
52 ),
53 parse_and
54 ).parse(input)
55}
56
57pub fn parse_or(input: &str) -> IResult<&str, LogicalOr> {
59 let (input, first) = parse_and(input)?;
60 let (input, logical_chain) = many0(or_operator).parse(input)?;
61
62 let or = logical_chain.into_iter().fold(
63 match first {
64 LogicalAnd::Primary(primary) => LogicalOr::Primary(primary),
65 _ => LogicalOr::Primary(Box::new(Primary::LogicalAnd(first))),
66 },
67 |acc, next| LogicalOr::Or(Box::new(acc), next),
68 );
69
70 Ok((input, or))
71}
72
73impl ExpressionLike for LogicalOr {
74 fn evaluate(&self, context: &mut dyn ContextLike) -> Result<Arc<Value>> {
75 match self {
76 LogicalOr::Or(left, right) => {
77 let left_val = left.evaluate(context)?;
79 if left_val.is_error() {
80 return Ok(left_val);
81 }
82
83 let left_bool = left_val.clone().as_bool();
85 if !left_bool.is_bool() {
86 return Err(anyhow!(
87 "Expected Bool, found {}~{}",
88 left_val.type_as_string(),
89 self.to_formula(),
90 ));
91 }
92
93 let left_lit = left_bool.to_literal();
94 let Literal::Bool(l) = left_lit else {
95 return Err(anyhow!(
96 "Expected Bool, found {}~{}",
97 left_val.type_as_string(),
98 self.to_formula(),
99 ));
100 };
101
102 if l {
104 return Ok(Arc::new(Value::Literal(Literal::Bool(true))));
105 }
106
107 let right_val = right.evaluate(context)?;
109 if right_val.is_error() {
110 return Ok(right_val);
111 }
112
113 let right_bool = right_val.clone().as_bool();
114 if !right_bool.is_bool() {
115 return Err(anyhow!(
116 "Expected Bool, found {} | {}~{}",
117 left_val.type_as_string(),
118 right_val.type_as_string(),
119 self.to_formula(),
120 ));
121 }
122
123 let right_lit = right_bool.to_literal();
124 let Literal::Bool(r) = right_lit else {
125 return Err(anyhow!(
126 "Expected Bool, found {} | {}~{}",
127 left_val.type_as_string(),
128 right_val.type_as_string(),
129 self.to_formula(),
130 ));
131 };
132
133 Ok(Arc::new(Value::Literal(Literal::Bool(l || r))))
134 }
135 LogicalOr::Primary(primary) => primary.evaluate(context),
136 }
137 }
138
139 fn to_formula(&self) -> String {
141 let mut writer = Writer::formulizer();
142 self.print(&mut writer);
143 writer.finish()
144 }
145}
146
147impl WriterLike for LogicalOr {
148 fn write(&self, writer: &mut Writer) {
149 self.print(writer);
150 }
151}
152
153impl fmt::Display for LogicalOr {
154 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155 write!(f, "{}", self.to_stringized())
156 }
157}
158