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