vrl/compiler/expression/
predicate.rs1use std::fmt;
2
3use crate::diagnostic::{DiagnosticMessage, Label, Note, Urls};
4
5use crate::compiler::expression::Block;
6use crate::compiler::{
7 Context, Expression, Span,
8 expression::{Expr, Resolved},
9 parser::Node,
10 state::{TypeInfo, TypeState},
11 value::Kind,
12};
13
14pub(crate) type Result = std::result::Result<Predicate, Error>;
15
16#[derive(Clone, PartialEq)]
17pub struct Predicate {
18 inner: Block,
19}
20
21impl Predicate {
22 pub(crate) fn new(
23 node: Node<Vec<Expr>>,
24 state: &TypeState,
25 fallible_predicate: Option<&dyn DiagnosticMessage>,
26 ) -> Result {
27 let (span, exprs) = node.take();
28
29 if let Some(error) = fallible_predicate {
30 return Err(Error::Fallible {
31 code: error.code(),
32 labels: error.labels(),
33 notes: error.notes(),
34 });
35 }
36
37 let block = Block::new_inline(exprs);
38 let type_def = block.type_info(state).result;
39 if !type_def.is_boolean() {
40 return Err(Error::NonBoolean {
41 kind: type_def.into(),
42 span,
43 });
44 }
45
46 Ok(Self { inner: block })
47 }
48
49 #[must_use]
50 pub fn new_unchecked(inner: Vec<Expr>) -> Self {
51 Self {
52 inner: Block::new_inline(inner),
53 }
54 }
55}
56
57impl Expression for Predicate {
58 fn resolve(&self, ctx: &mut Context) -> Resolved {
59 self.inner.resolve(ctx)
60 }
61
62 fn type_info(&self, state: &TypeState) -> TypeInfo {
63 self.inner.type_info(state)
64 }
65}
66
67impl fmt::Display for Predicate {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 if self.inner.exprs().len() > 1 {
70 f.write_str("(")?;
71 }
72
73 let mut iter = self.inner.exprs().iter().peekable();
74 while let Some(expr) = iter.next() {
75 expr.fmt(f)?;
76
77 if iter.peek().is_some() {
78 f.write_str("; ")?;
79 }
80 }
81
82 if self.inner.exprs().len() > 1 {
83 f.write_str("(")?;
84 }
85
86 Ok(())
87 }
88}
89
90impl fmt::Debug for Predicate {
91 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92 f.write_str("Predicate(")?;
93
94 let mut iter = self.inner.exprs().iter().peekable();
95 while let Some(expr) = iter.next() {
96 expr.fmt(f)?;
97
98 if iter.peek().is_some() {
99 f.write_str("; ")?;
100 }
101 }
102
103 f.write_str(")")
104 }
105}
106
107#[derive(thiserror::Error, Debug)]
110pub(crate) enum Error {
111 #[error("non-boolean predicate")]
112 NonBoolean { kind: Kind, span: Span },
113
114 #[error("fallible predicate")]
115 Fallible {
116 code: usize,
117 labels: Vec<Label>,
118 notes: Vec<Note>,
119 },
120}
121
122impl DiagnosticMessage for Error {
123 fn code(&self) -> usize {
124 use Error::{Fallible, NonBoolean};
125
126 match self {
127 NonBoolean { .. } => 102,
128 Fallible { code, .. } => *code,
129 }
130 }
131
132 fn labels(&self) -> Vec<Label> {
133 use Error::{Fallible, NonBoolean};
134
135 match self {
136 NonBoolean { kind, span } => vec![
137 Label::primary("this predicate must resolve to a boolean", span),
138 Label::context(format!("instead it resolves to {kind}"), span),
139 ],
140 Fallible { labels, .. } => labels.clone(),
141 }
142 }
143
144 fn notes(&self) -> Vec<Note> {
145 use Error::{Fallible, NonBoolean};
146
147 match self {
148 NonBoolean { .. } => vec![
149 Note::CoerceValue,
150 Note::SeeDocs(
151 "if expressions".to_owned(),
152 Urls::expression_docs_url("#if"),
153 ),
154 ],
155 Fallible { notes, .. } => notes.clone(),
156 }
157 }
158}