aimx/expressions/
branch.rs

1//! Branch rule expression node.
2//!
3//! Represents `(condition) -> target_rule` rules used by the rule parser, not
4//! general-purpose expressions.
5//! - `condition`: parsed as a [`Coalesce`] expression in parentheses.
6//! - `target_rule`: identifier for the rule to branch to.
7//!
8//! Evaluation:
9//! - If `condition` evaluates to `Bool(true)`, returns `Value::Branch(target_rule)`.
10//! - If `condition` yields any other non-error value, returns `Value::Empty`.
11//! - If `condition` evaluation yields an error or `Value::Errata`, it is propagated.
12
13use crate::{
14    aim::{ContextLike, WriterLike, Writer},
15    expressions::{Coalesce, ExpressionLike, parse_coalesce, parse_arc_identifier},
16    literals::Literal,
17    values::Value,
18};
19use anyhow::Result;
20use nom::{
21    IResult, Parser, bytes::complete::tag, character::complete::multispace0, sequence::{delimited, preceded}
22};
23use std::{
24    fmt,
25    sync::Arc,
26};
27
28#[derive(Debug, Clone, PartialEq)]
29pub struct Branch {
30    condition: Coalesce,
31    target: Arc<str>,
32}
33
34impl Branch {
35    pub fn new(condition: Coalesce, target: Arc<str>) -> Self {
36        Self {
37            condition,
38            target,
39        }
40    }
41
42    pub fn condition(&self) -> &dyn ExpressionLike {
43        &self.condition
44    }
45
46    pub fn target(&self) -> Arc<str> {
47        self.target.clone()
48    }
49
50    pub fn print(&self, writer: &mut Writer) {
51        self.condition.print(writer);
52        writer.write_str(" -> ");
53        writer.write_str(&self.target);
54    }
55}
56
57pub fn parse_branch(input: &str) -> IResult<&str, Branch> {
58    let (input, (condition, target)) = delimited(
59        multispace0,
60        // Inner content: condition -> target
61        (
62            parse_coalesce,
63            preceded(
64                (multispace0, tag("->"), multispace0),
65                parse_arc_identifier
66            ),
67        ),
68        multispace0,
69    ).parse(input)?;
70
71    Ok((input, Branch::new(condition, target)))
72}
73
74impl ExpressionLike for Branch {
75    fn evaluate(&self, context: &mut dyn ContextLike) -> Result<Arc<Value>> {
76        let value = self.condition.evaluate(context)?;
77        if value.clone().is_error() {
78            return Ok(value);
79        }
80        match &*value.to_bool() {
81            Value::Literal(Literal::Bool(true)) => Ok(Arc::new(Value::Branch(self.target.clone()))),
82            _ => Ok(Value::empty()),
83        }
84    }
85
86    /// Return the formula-string representation (round-trippable by the parser).
87    fn to_formula(&self) -> String {
88        let mut writer = Writer::formulizer();
89        self.print(&mut writer);
90        writer.finish()
91    }
92}
93
94impl WriterLike for Branch {
95    fn write(&self, writer: &mut Writer) {
96        self.print(writer);
97    }
98}
99
100impl fmt::Display for Branch {
101    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        write!(f, "{}", self.to_stringized())
103    }
104}