aimx/expressions/
conditional.rs1use crate::{
9 aim::{ContextLike, WriterLike, Writer},
10 expressions::{
11 Coalesce, Expression, ExpressionLike, Primary, parse_coalesce, parse_expression,
12 },
13 literals::Literal,
14 values::Value,
15};
16use anyhow::Result;
17use nom::{
18 IResult, Parser,
19 character::complete::{char, multispace0}, sequence::{delimited, preceded},
20};
21use std::{
22 fmt,
23 sync::Arc,
24};
25
26#[derive(Debug, Clone, PartialEq)]
33pub enum Conditional {
34 Ternary(Coalesce, Box<Expression>, Box<Conditional>),
35 Primary(Box<Primary>),
37}
38
39impl Conditional {
40 pub fn print(&self, writer: &mut Writer) {
41 match self {
42 Conditional::Ternary(condition, true_expr, false_expr) => {
43 condition.print(writer);
44 writer.write_str(" ? ");
45 true_expr.print(writer);
46 writer.write_str(" : ");
47 false_expr.print(writer);
48 }
49 Conditional::Primary(primary) => primary.print(writer),
50 }
51 }
52}
53
54fn ternary_operator(input: &str) -> IResult<&str, (Expression, Conditional)> {
59 let (input, _) = preceded(
60 multispace0,
61 char('?')
62 ).parse(input)?;
63
64 let (input, expression) = delimited(
65 multispace0,
66 parse_expression,
67 multispace0
68 ).parse(input)?;
69
70 let (input, conditional) = preceded(
71 char(':'),
72 preceded(multispace0, parse_conditional)
73 ).parse(input)?;
74 Ok((input, (expression, conditional)))
75}
76
77pub fn parse_conditional(input: &str) -> IResult<&str, Conditional> {
84 let (input, first) = parse_coalesce(input)?;
85 if let Ok((input, (expression, conditional))) = ternary_operator(input) {
86 let ternary = Conditional::Ternary(first, Box::new(expression), Box::new(conditional));
87 Ok((input, ternary))
88 } else {
89 let conditional = match first {
90 Coalesce::Primary(primary) => Conditional::Primary(primary),
91 _ => Conditional::Primary(Box::new(Primary::Coalesce(first))),
92 };
93 Ok((input, conditional))
94 }
95}
96
97impl ExpressionLike for Conditional {
98 fn evaluate(&self, context: &mut dyn ContextLike) -> Result<Arc<Value>> {
99 match self {
100 Conditional::Ternary(condition, true_expr, false_expr) => {
101 let value = condition.evaluate(context)?;
102 if value.is_error() {
103 return Ok(value);
104 }
105 match &*value.to_bool() {
106 Value::Literal(Literal::Bool(true)) => true_expr.evaluate(context),
107 _ => false_expr.evaluate(context),
108 }
109 }
110 Conditional::Primary(primary) => primary.evaluate(context),
111 }
112 }
113
114 fn to_formula(&self) -> String {
116 let mut writer = Writer::formulizer();
117 self.print(&mut writer);
118 writer.finish()
119 }
120}
121
122impl WriterLike for Conditional {
123 fn write(&self, writer: &mut Writer) {
124 self.print(writer);
125 }
126}
127
128impl fmt::Display for Conditional {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 write!(f, "{}", self.to_stringized())
131 }
132}