1use crate::{
10 aim::{ContextLike, WriterLike, Writer},
11 expressions::{ExpressionLike, Primary, Relational, evaluate_and_promote, parse_relational},
12 literals::Literal,
13 values::Value,
14};
15use anyhow::{Result, anyhow};
16use nom::{
17 IResult, Parser, branch::alt, bytes::complete::tag, character::complete::multispace0,
18 combinator::value, sequence::{preceded, separated_pair},
19};
20use std::{
21 fmt,
22 sync::Arc,
23};
24
25#[derive(Debug, Clone, PartialEq)]
30pub enum Equality {
31 Equal(Relational, Relational),
32 NotEqual(Relational, Relational),
33 Primary(Box<Primary>),
35}
36
37impl Equality {
38 pub fn print(&self, writer: &mut Writer) {
40 match self {
41 Equality::Equal(left, right) => {
42 writer.write_binary_op(left, " == ", right);
43 }
44 Equality::NotEqual(left, right) => {
45 writer.write_binary_op(left, " != ", right);
46 }
47 Equality::Primary(primary) => primary.print(writer),
48 }
49 }
50}
51
52#[derive(Debug, Clone, Copy, PartialEq)]
54enum EqualityOp {
55 Equal,
56 NotEqual,
57}
58
59fn equality_operator(input: &str) -> IResult<&str, (EqualityOp, Relational)> {
61 separated_pair(
62 preceded(
63 multispace0,
64 alt((
65 value(EqualityOp::NotEqual, tag("!=")),
66 value(EqualityOp::Equal, tag("==")),
67 ))
68 ),
69 multispace0,
70 parse_relational
71 ).parse(input)
72}
73
74pub fn parse_equality(input: &str) -> IResult<&str, Equality> {
78 let (input, first) = parse_relational(input)?;
79 if let Ok((input, (equality_op, second))) = equality_operator(input) {
80 let equality = match equality_op {
81 EqualityOp::Equal => Equality::Equal(first, second),
82 EqualityOp::NotEqual => Equality::NotEqual(first, second),
83 };
84 Ok((input, equality))
85 } else {
86 let equality = match first {
87 Relational::Primary(primary) => Equality::Primary(primary),
88 _ => Equality::Primary(Box::new(Primary::Relational(first))),
89 };
90 Ok((input, equality))
91 }
92}
93
94impl ExpressionLike for Equality {
95 fn evaluate(&self, context: &mut dyn ContextLike) -> Result<Arc<Value>> {
97 match self {
98 Equality::Equal(left, right) => {
99 let (left_val, right_val) = evaluate_and_promote(context, left, right)?;
100 if left_val.is_error() {
101 return Ok(left_val);
102 }
103 if right_val.is_error() {
104 return Ok(right_val);
105 }
106 let result = match (&*left_val, &*right_val) {
107 (Value::Literal(Literal::Bool(l)), Value::Literal(Literal::Bool(r))) => l == r,
108 (Value::Literal(Literal::Date(l)), Value::Literal(Literal::Date(r))) => l == r,
109 (Value::Literal(Literal::Number(l)), Value::Literal(Literal::Number(r))) => {
110 l == r
111 }
112 (Value::Literal(Literal::Text(l)), Value::Literal(Literal::Text(r))) => l == r,
113 (Value::Literal(Literal::Task(_, l)), Value::Literal(Literal::Task(_, r))) => {
114 l == r
115 }
116 _ => {
117 return Err(anyhow!(
118 "Expected Bool, Date, Number, Task or Text, found {} == {}~{}",
119 left_val.type_as_string(),
120 right_val.type_as_string(),
121 self.to_formula(),
122 ));
123 }
124 };
125 Ok(Arc::new(Value::Literal(Literal::Bool(result))))
126 }
127 Equality::NotEqual(left, right) => {
128 let (left_val, right_val) = evaluate_and_promote(context, left, right)?;
129 if left_val.is_error() {
130 return Ok(left_val);
131 }
132 if right_val.is_error() {
133 return Ok(right_val);
134 }
135 let result = match (&*left_val, &*right_val) {
136 (Value::Literal(Literal::Bool(l)), Value::Literal(Literal::Bool(r))) => l != r,
137 (Value::Literal(Literal::Date(l)), Value::Literal(Literal::Date(r))) => l != r,
138 (Value::Literal(Literal::Number(l)), Value::Literal(Literal::Number(r))) => {
139 l != r
140 }
141 (Value::Literal(Literal::Text(l)), Value::Literal(Literal::Text(r))) => l != r,
142 (Value::Literal(Literal::Task(_, l)), Value::Literal(Literal::Task(_, r))) => {
143 l != r
144 }
145 _ => {
146 return Err(anyhow!(
147 "Expected Bool, Date, Number, Task or Text, found {} != {}~{}",
148 left_val.type_as_string(),
149 right_val.type_as_string(),
150 self.to_formula(),
151 ));
152 }
153 };
154 Ok(Arc::new(Value::Literal(Literal::Bool(result))))
155 }
156 Equality::Primary(primary) => primary.evaluate(context),
157 }
158 }
159
160 fn to_formula(&self) -> String {
162 let mut writer = Writer::formulizer();
163 self.print(&mut writer);
164 writer.finish()
165 }
166}
167
168impl WriterLike for Equality {
169 fn write(&self, writer: &mut Writer) {
170 self.print(writer);
171 }
172}
173
174impl fmt::Display for Equality {
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 write!(f, "{}", self.to_stringized())
177 }
178}