aimx/expressions/
coalesce.rs1use crate::{
8 aim::{ContextLike, WriterLike, Writer},
9 expressions::{ExpressionLike, LogicalOr, Primary, parse_or},
10 values::Value,
11};
12use anyhow::Result;
13use nom::{IResult, Parser, bytes::complete::tag, character::complete::multispace0, multi::many0, sequence::delimited};
14use std::{
15 fmt,
16 sync::Arc,
17};
18
19#[derive(Debug, Clone, PartialEq)]
21pub enum Coalesce {
22 Coalesce(Box<Coalesce>, LogicalOr),
24 Primary(Box<Primary>),
26}
27
28impl Coalesce {
29 pub fn print(&self, writer: &mut Writer) {
30 match self {
31 Coalesce::Primary(primary) => primary.print(writer),
32 Coalesce::Coalesce(left, right) => {
33 left.print(writer);
34 writer.write_str(" ?? ");
35 right.print(writer);
36 }
37 }
38 }
39}
40
41fn coalesce_op(input: &str) -> IResult<&str, LogicalOr> {
42 let (input, _) = delimited(
43 multispace0,
44 tag("??"),
45 multispace0
46 ).parse(input)?;
47 parse_or(input)
48}
49
50pub fn parse_coalesce(input: &str) -> IResult<&str, Coalesce> {
57 let (input, first) = parse_or(input)?;
58 let (input, chain) = many0(coalesce_op).parse(input)?;
59
60 let node = chain.into_iter().fold(
61 match first {
62 LogicalOr::Primary(primary) => Coalesce::Primary(primary),
63 _ => Coalesce::Primary(Box::new(Primary::LogicalOr(first))),
64 },
65 |left, rhs| Coalesce::Coalesce(Box::new(left), rhs),
66 );
67
68 Ok((input, node))
69}
70
71impl ExpressionLike for Coalesce {
72 fn evaluate(&self, context: &mut dyn ContextLike) -> Result<Arc<Value>> {
73 match self {
74 Coalesce::Primary(primary) => primary.evaluate(context),
75 Coalesce::Coalesce(left, right) => {
76 let left_val = left.evaluate(context)?;
77 if left_val.is_error() || left_val.is_empty() {
78 let right_val = right.evaluate(context)?;
79 Ok(right_val)
80 } else {
81 Ok(left_val)
82 }
83 }
84 }
85 }
86
87 fn to_formula(&self) -> String {
89 let mut writer = Writer::formulizer();
90 self.print(&mut writer);
91 writer.finish()
92 }
93}
94
95impl WriterLike for Coalesce {
96 fn write(&self, writer: &mut Writer) {
97 self.print(writer);
98 }
99}
100
101impl fmt::Display for Coalesce {
102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 write!(f, "{}", self.to_stringized())
104 }
105}