vrl/compiler/expression/
abort.rs1use std::fmt;
2
3use crate::compiler::{
4 Context, Expression, Span, TypeDef,
5 expression::{ExpressionError, Resolved},
6 state::{TypeInfo, TypeState},
7 value::{Kind, VrlValueConvert},
8};
9use crate::diagnostic::{DiagnosticMessage, Label, Note, Urls};
10use crate::parser::ast::Node;
11
12use super::Expr;
13
14#[derive(Debug, Clone, PartialEq)]
15pub struct Abort {
16 span: Span,
17 message: Option<Box<Expr>>,
18}
19
20impl Abort {
21 pub fn new(span: Span, message: Option<Node<Expr>>, state: &TypeState) -> Result<Self, Error> {
26 let message = message
27 .map(|node| {
28 let (expr_span, expr) = node.take();
29 let type_def = expr.type_info(state).result;
30
31 if type_def.is_fallible() {
32 Err(Error {
33 variant: ErrorVariant::FallibleExpr,
34 expr_span,
35 })
36 } else if !type_def.is_bytes() {
37 Err(Error {
38 variant: ErrorVariant::NonString(type_def.into()),
39 expr_span,
40 })
41 } else {
42 Ok(Box::new(expr))
43 }
44 })
45 .transpose()?;
46
47 Ok(Self { span, message })
48 }
49}
50
51impl Expression for Abort {
52 fn resolve(&self, ctx: &mut Context) -> Resolved {
53 let message = self
54 .message
55 .as_ref()
56 .map::<Result<_, ExpressionError>, _>(|expr| {
57 Ok(expr.resolve(ctx)?.try_bytes_utf8_lossy()?.to_string())
58 })
59 .transpose()?;
60
61 Err(ExpressionError::Abort {
62 span: self.span,
63 message,
64 })
65 }
66
67 fn type_info(&self, state: &TypeState) -> TypeInfo {
68 let returns = self.message.as_ref().map_or(Kind::never(), |message| {
69 message.type_info(state).result.returns().to_owned()
70 });
71 TypeInfo::new(state, TypeDef::never().with_returns(returns))
72 }
73}
74
75impl fmt::Display for Abort {
76 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77 write!(f, "abort")
78 }
79}
80
81#[derive(Debug)]
84pub struct Error {
85 variant: ErrorVariant,
86 expr_span: Span,
87}
88
89#[derive(thiserror::Error, Debug)]
90pub(crate) enum ErrorVariant {
91 #[error("unhandled fallible expression")]
92 FallibleExpr,
93 #[error("non-string abort message")]
94 NonString(Kind),
95}
96
97impl fmt::Display for Error {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 write!(f, "{:#}", self.variant)
100 }
101}
102
103impl std::error::Error for Error {
104 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
105 Some(&self.variant)
106 }
107}
108
109impl DiagnosticMessage for Error {
110 fn code(&self) -> usize {
111 use ErrorVariant::{FallibleExpr, NonString};
112
113 match self.variant {
114 FallibleExpr => 631,
115 NonString(_) => 300,
116 }
117 }
118
119 fn labels(&self) -> Vec<Label> {
120 match &self.variant {
121 ErrorVariant::FallibleExpr => vec![
122 Label::primary(
123 "abort only accepts an infallible expression argument",
124 self.expr_span,
125 ),
126 Label::context(
127 "handle errors before using the expression as an abort message",
128 self.expr_span,
129 ),
130 ],
131 ErrorVariant::NonString(kind) => vec![
132 Label::primary(
133 "abort only accepts an expression argument resolving to a string",
134 self.expr_span,
135 ),
136 Label::context(
137 format!("this expression resolves to {kind}"),
138 self.expr_span,
139 ),
140 ],
141 }
142 }
143
144 fn notes(&self) -> Vec<Note> {
145 match self.variant {
146 ErrorVariant::FallibleExpr => vec![Note::SeeErrorDocs],
147 ErrorVariant::NonString(_) => vec![
148 Note::CoerceValue,
149 Note::SeeDocs(
150 "type coercion".to_owned(),
151 Urls::func_docs("#coerce-functions"),
152 ),
153 ],
154 }
155 }
156}