vrl/compiler/expression/
not.rs1use std::fmt;
2
3use crate::compiler::state::{TypeInfo, TypeState};
4use crate::compiler::{
5 Context, Expression, Span, TypeDef,
6 expression::{Expr, Resolved},
7 parser::Node,
8 value::{Kind, VrlValueConvert},
9};
10use crate::diagnostic::{DiagnosticMessage, Label, Note, Urls};
11
12pub(crate) type Result = std::result::Result<Not, Error>;
13
14#[derive(Debug, Clone, PartialEq)]
15pub struct Not {
16 inner: Box<Expr>,
17}
18
19impl Not {
20 pub fn new(node: Node<Expr>, not_span: Span, state: &TypeState) -> Result {
33 let (expr_span, expr) = node.take();
34 let type_def = expr.type_info(state).result;
35
36 if !type_def.is_boolean() {
37 return Err(Error {
38 variant: ErrorVariant::NonBoolean(type_def.into()),
39 not_span,
40 expr_span,
41 });
42 }
43
44 Ok(Self {
45 inner: Box::new(expr),
46 })
47 }
48}
49
50impl Expression for Not {
51 fn resolve(&self, ctx: &mut Context) -> Resolved {
52 Ok((!self.inner.resolve(ctx)?.try_boolean()?).into())
53 }
54
55 fn type_info(&self, state: &TypeState) -> TypeInfo {
56 let mut state = state.clone();
57 let result = self.inner.apply_type_info(&mut state);
58 TypeInfo::new(
59 state,
60 TypeDef::boolean()
61 .maybe_fallible(result.is_fallible())
62 .with_returns(result.returns().clone()),
63 )
64 }
65}
66
67impl fmt::Display for Not {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 write!(f, "!{}", self.inner)
70 }
71}
72
73#[derive(Debug)]
76pub struct Error {
77 pub(crate) variant: ErrorVariant,
78
79 not_span: Span,
80 expr_span: Span,
81}
82
83#[derive(thiserror::Error, Debug)]
84pub(crate) enum ErrorVariant {
85 #[error("non-boolean negation")]
86 NonBoolean(Kind),
87}
88
89impl fmt::Display for Error {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 write!(f, "{:#}", self.variant)
92 }
93}
94
95impl std::error::Error for Error {
96 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
97 Some(&self.variant)
98 }
99}
100
101impl DiagnosticMessage for Error {
102 fn code(&self) -> usize {
103 use ErrorVariant::NonBoolean;
104
105 match &self.variant {
106 NonBoolean(..) => 660,
107 }
108 }
109
110 fn labels(&self) -> Vec<Label> {
111 use ErrorVariant::NonBoolean;
112
113 match &self.variant {
114 NonBoolean(kind) => vec![
115 Label::primary("negation only works on boolean values", self.not_span),
116 Label::context(
117 format!("this expression resolves to {kind}"),
118 self.expr_span,
119 ),
120 ],
121 }
122 }
123
124 fn notes(&self) -> Vec<Note> {
125 use ErrorVariant::NonBoolean;
126
127 match &self.variant {
128 NonBoolean(..) => {
129 vec![
130 Note::CoerceValue,
131 Note::SeeDocs(
132 "type coercion".to_owned(),
133 Urls::func_docs("#coerce-functions"),
134 ),
135 ]
136 }
137 }
138 }
139}