1use crate::{
7 aim::{ContextLike, WriterLike, Writer},
8 expressions::{Additive, ExpressionLike, Primary, evaluate_and_promote, parse_additive},
9 literals::Literal,
10 values::Value,
11};
12use anyhow::{Result, anyhow};
13use nom::{
14 IResult, Parser,
15 branch::alt,
16 bytes::complete::tag,
17 character::complete::{char, multispace0},
18 combinator::{map, opt},
19};
20use std::{
21 fmt,
22 sync::Arc,
23};
24
25#[derive(Debug, Clone, PartialEq)]
27pub enum Relational {
28 Less(Additive, Additive),
30 LessOrEqual(Additive, Additive),
32 Greater(Additive, Additive),
34 GreaterOrEqual(Additive, Additive),
36 Primary(Box<Primary>),
38}
39
40impl Relational {
41 pub fn print(&self, writer: &mut Writer) {
42 match self {
43 Relational::Less(left, right) => {
44 writer.write_binary_op(left, " < ", right);
45 }
46 Relational::LessOrEqual(left, right) => {
47 writer.write_binary_op(left, " <= ", right);
48 }
49 Relational::Greater(left, right) => {
50 writer.write_binary_op(left, " > ", right);
51 }
52 Relational::GreaterOrEqual(left, right) => {
53 writer.write_binary_op(left, " >= ", right);
54 }
55 Relational::Primary(primary) => primary.print(writer),
56 }
57 }
58}
59
60#[derive(Debug, Clone, Copy, PartialEq)]
62enum RelationalOp {
63 Less,
65 LessOrEqual,
67 Greater,
69 GreaterOrEqual,
71}
72
73pub fn parse_relational(input: &str) -> IResult<&str, Relational> {
81 let (input, first) = parse_additive(input)?;
82
83 let (input, maybe_relational) = opt((
84 multispace0,
85 alt((
86 map(tag("<="), |_| RelationalOp::LessOrEqual),
87 map(tag(">="), |_| RelationalOp::GreaterOrEqual),
88 map(char('<'), |_| RelationalOp::Less),
89 map(char('>'), |_| RelationalOp::Greater),
90 )),
91 multispace0,
92 parse_additive,
93 ))
94 .parse(input)?;
95
96 let result = match maybe_relational {
97 Some((_, op, _, second)) => match op {
98 RelationalOp::Less => Relational::Less(first, second),
99 RelationalOp::LessOrEqual => Relational::LessOrEqual(first, second),
100 RelationalOp::Greater => Relational::Greater(first, second),
101 RelationalOp::GreaterOrEqual => Relational::GreaterOrEqual(first, second),
102 },
103 None => match first {
104 Additive::Primary(primary) => Relational::Primary(primary),
105 _ => Relational::Primary(Box::new(Primary::Additive(first))),
106 },
107 };
108
109 Ok((input, result))
110}
111
112impl ExpressionLike for Relational {
113 fn evaluate(&self, context: &mut dyn ContextLike) -> Result<Arc<Value>> {
115 match self {
116 Relational::Less(left, right) => {
117 let (left_val, right_val) = evaluate_and_promote(context, left, right)?;
118 if left_val.is_error() {
119 return Ok(left_val);
120 }
121 if right_val.is_error() {
122 return Ok(right_val);
123 }
124 match (&*left_val, &*right_val) {
125 (Value::Literal(Literal::Bool(l)), Value::Literal(Literal::Bool(r))) => {
126 Ok(Arc::new(Value::Literal(Literal::Bool(l < r))))
127 }
128 (Value::Literal(Literal::Date(l)), Value::Literal(Literal::Date(r))) => {
129 Ok(Arc::new(Value::Literal(Literal::Bool(l < r))))
130 }
131 (Value::Literal(Literal::Number(l)), Value::Literal(Literal::Number(r))) => {
132 Ok(Arc::new(Value::Literal(Literal::Bool(l < r))))
133 }
134 (Value::Literal(Literal::Task(_, _)), Value::Literal(Literal::Task(_, _))) => {
135 let l = left_val.to_number()?;
136 let r = right_val.to_number()?;
137 Ok(Arc::new(Value::Literal(Literal::Bool(l < r))))
138 }
139 (Value::Literal(Literal::Text(l)), Value::Literal(Literal::Text(r))) => {
140 Ok(Arc::new(Value::Literal(Literal::Bool(l < r))))
141 }
142 _ => Err(anyhow!(
143 "Expected comparable operands, found {} < {}~{}",
144 left_val.type_as_string(),
145 right_val.type_as_string(),
146 self.to_formula(),
147 )),
148 }
149 }
150 Relational::LessOrEqual(left, right) => {
151 let (left_val, right_val) = evaluate_and_promote(context, left, right)?;
152 if left_val.is_error() {
153 return Ok(left_val);
154 }
155 if right_val.is_error() {
156 return Ok(right_val);
157 }
158 match (&*left_val, &*right_val) {
159 (Value::Literal(Literal::Bool(l)), Value::Literal(Literal::Bool(r))) => {
160 Ok(Arc::new(Value::Literal(Literal::Bool(l <= r))))
161 }
162 (Value::Literal(Literal::Date(l)), Value::Literal(Literal::Date(r))) => {
163 Ok(Arc::new(Value::Literal(Literal::Bool(l <= r))))
164 }
165 (Value::Literal(Literal::Number(l)), Value::Literal(Literal::Number(r))) => {
166 Ok(Arc::new(Value::Literal(Literal::Bool(l <= r))))
167 }
168 (Value::Literal(Literal::Task(_, _)), Value::Literal(Literal::Task(_, _))) => {
169 let l = left_val.to_number()?;
170 let r = right_val.to_number()?;
171 Ok(Arc::new(Value::Literal(Literal::Bool(l <= r))))
172 }
173 (Value::Literal(Literal::Text(l)), Value::Literal(Literal::Text(r))) => {
174 Ok(Arc::new(Value::Literal(Literal::Bool(l <= r))))
175 }
176 _ => Err(anyhow!(
177 "Expected comparable operands, found {} <= {}~{}",
178 left_val.type_as_string(),
179 right_val.type_as_string(),
180 self.to_formula(),
181 )),
182 }
183 }
184 Relational::Greater(left, right) => {
185 let (left_val, right_val) = evaluate_and_promote(context, left, right)?;
186 if left_val.is_error() {
187 return Ok(left_val);
188 }
189 if right_val.is_error() {
190 return Ok(right_val);
191 }
192 match (&*left_val, &*right_val) {
193 (Value::Literal(Literal::Bool(l)), Value::Literal(Literal::Bool(r))) => {
194 Ok(Arc::new(Value::Literal(Literal::Bool(l > r))))
195 }
196 (Value::Literal(Literal::Date(l)), Value::Literal(Literal::Date(r))) => {
197 Ok(Arc::new(Value::Literal(Literal::Bool(l > r))))
198 }
199 (Value::Literal(Literal::Number(l)), Value::Literal(Literal::Number(r))) => {
200 Ok(Arc::new(Value::Literal(Literal::Bool(l > r))))
201 }
202 (Value::Literal(Literal::Task(_, _)), Value::Literal(Literal::Task(_, _))) => {
203 let l = left_val.to_number()?;
204 let r = right_val.to_number()?;
205 Ok(Arc::new(Value::Literal(Literal::Bool(l > r))))
206 }
207 (Value::Literal(Literal::Text(l)), Value::Literal(Literal::Text(r))) => {
208 Ok(Arc::new(Value::Literal(Literal::Bool(l > r))))
209 }
210 _ => Err(anyhow!(
211 "Expected comparable operands, found {} > {}~{}",
212 left_val.type_as_string(),
213 right_val.type_as_string(),
214 self.to_formula(),
215 )),
216 }
217 }
218 Relational::GreaterOrEqual(left, right) => {
219 let (left_val, right_val) = evaluate_and_promote(context, left, right)?;
220 if left_val.is_error() {
221 return Ok(left_val);
222 }
223 if right_val.is_error() {
224 return Ok(right_val);
225 }
226 match (&*left_val, &*right_val) {
227 (Value::Literal(Literal::Bool(l)), Value::Literal(Literal::Bool(r))) => {
228 Ok(Arc::new(Value::Literal(Literal::Bool(l >= r))))
229 }
230 (Value::Literal(Literal::Date(l)), Value::Literal(Literal::Date(r))) => {
231 Ok(Arc::new(Value::Literal(Literal::Bool(l >= r))))
232 }
233 (Value::Literal(Literal::Number(l)), Value::Literal(Literal::Number(r))) => {
234 Ok(Arc::new(Value::Literal(Literal::Bool(l >= r))))
235 }
236 (Value::Literal(Literal::Task(_, _)), Value::Literal(Literal::Task(_, _))) => {
237 let l = left_val.to_number()?;
238 let r = right_val.to_number()?;
239 Ok(Arc::new(Value::Literal(Literal::Bool(l >= r))))
240 }
241 (Value::Literal(Literal::Text(l)), Value::Literal(Literal::Text(r))) => {
242 Ok(Arc::new(Value::Literal(Literal::Bool(l >= r))))
243 }
244 _ => Err(anyhow!(
245 "Expected comparable operands, found {} >= {}~{}",
246 left_val.type_as_string(),
247 right_val.type_as_string(),
248 self.to_formula(),
249 )),
250 }
251 }
252 Relational::Primary(primary) => primary.evaluate(context),
253 }
254 }
255
256 fn to_formula(&self) -> String {
258 let mut writer = Writer::formulizer();
259 self.print(&mut writer);
260 writer.finish()
261 }
262}
263
264impl WriterLike for Relational {
265 fn write(&self, writer: &mut Writer) {
266 self.print(writer);
267 }
268}
269
270impl fmt::Display for Relational {
271 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
272 write!(f, "{}", self.to_stringized())
273 }
274}