vrl/compiler/expression/
if_statement.rs

1use std::fmt;
2
3use crate::value::Value;
4
5use crate::compiler::state::{TypeInfo, TypeState};
6use crate::compiler::{
7    Context, Expression,
8    expression::{Block, Predicate, Resolved},
9    value::VrlValueConvert,
10};
11
12#[derive(Debug, Clone, PartialEq)]
13pub struct IfStatement {
14    pub predicate: Predicate,
15    pub if_block: Block,
16    pub else_block: Option<Block>,
17}
18
19impl Expression for IfStatement {
20    fn resolve(&self, ctx: &mut Context) -> Resolved {
21        let predicate = self.predicate.resolve(ctx)?.try_boolean()?;
22
23        if predicate {
24            self.if_block.resolve(ctx)
25        } else {
26            self.else_block
27                .as_ref()
28                .map_or(Ok(Value::Null), |block| block.resolve(ctx))
29        }
30    }
31
32    fn type_info(&self, state: &TypeState) -> TypeInfo {
33        let mut state = state.clone();
34        let predicate_info = self.predicate.apply_type_info(&mut state);
35
36        let if_info = self.if_block.type_info(&state);
37
38        if let Some(else_block) = &self.else_block {
39            let else_info = else_block.type_info(&state);
40
41            // final state will be from either the "if" or "else" block, but not the original
42            let final_state = if_info.state.merge(else_info.state);
43
44            // result is from either "if" or the "else" block
45            let mut result = if_info.result.union(else_info.result);
46
47            // predicate can also return
48            result
49                .returns_mut()
50                .merge_keep(predicate_info.returns().clone(), false);
51
52            TypeInfo::new(final_state, result)
53        } else {
54            // state changes from the "if block" are optional, so merge it with the original
55            let final_state = if_info.state.merge(state);
56
57            // if the predicate is false, "null" is returned.
58            let mut result = if_info.result.or_null();
59
60            // predicate can also return
61            result
62                .returns_mut()
63                .merge_keep(predicate_info.returns().clone(), false);
64
65            TypeInfo::new(final_state, result)
66        }
67    }
68}
69
70impl fmt::Display for IfStatement {
71    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72        f.write_str("if ")?;
73        self.predicate.fmt(f)?;
74        f.write_str(" ")?;
75        self.if_block.fmt(f)?;
76
77        if let Some(alt) = &self.else_block {
78            f.write_str(" else")?;
79            alt.fmt(f)?;
80        }
81
82        Ok(())
83    }
84}