ferrobridge_fhirpath/eval/error.rs
1// SPDX-FileCopyrightText: Cadasto B.V.
2// SPDX-License-Identifier: BUSL-1.1
3
4//! The evaluation errors: every case where N1 says "the evaluation will end
5//! and signal an error to the calling environment", and the seams' failures.
6//! An error is never an empty result.
7
8use crate::seam::SeamError;
9use crate::temporal::arithmetic::ArithmeticError;
10
11/// Why an evaluation ended without a result.
12#[derive(Debug, thiserror::Error)]
13pub enum EvalError {
14 /// An operation that takes one item met several (N1 §4.5).
15 #[error("{operation} expects a single item, the collection holds {count}")]
16 Singleton {
17 /// The operator or function.
18 operation: String,
19 /// The number of items found.
20 count: usize,
21 },
22 /// An operation met an item of a type it does not take.
23 #[error("{operation} does not apply to {found}")]
24 Type {
25 /// The operator or function.
26 operation: String,
27 /// What it met.
28 found: String,
29 },
30 /// A function N1 and FHIR R4 do not define.
31 #[error("the function {name}() is not defined")]
32 UnknownFunction {
33 /// The function name.
34 name: String,
35 },
36 /// A function called with the wrong number of arguments.
37 #[error("{function}() takes {expected} argument(s), {found} given")]
38 Arity {
39 /// The function name.
40 function: String,
41 /// The admitted counts.
42 expected: &'static str,
43 /// The count given.
44 found: usize,
45 },
46 /// A member no type of the input defines (N1 §3).
47 #[error("{type_name} has no element {element}")]
48 UnknownElement {
49 /// The type, or the types, navigated from.
50 type_name: String,
51 /// The member name.
52 element: String,
53 },
54 /// The expression starts with a type name that is not the context's
55 /// type (N1 §3).
56 #[error("the expression names the type {named}, the context is a {context}")]
57 ContextType {
58 /// The type the expression names.
59 named: String,
60 /// The type of the context.
61 context: String,
62 },
63 /// A type specifier that names no type (N1 §6.3.1).
64 #[error("{name} names no type of the model")]
65 UnknownType {
66 /// The specifier as written.
67 name: String,
68 },
69 /// An environment variable the environment does not define (N1 §9).
70 #[error("the environment variable %{name} is not defined")]
71 UnknownVariable {
72 /// The variable name.
73 name: String,
74 },
75 /// A function whose seam the environment does not supply.
76 #[error("{function}() needs a seam the environment does not supply")]
77 NoSeam {
78 /// The function name.
79 function: &'static str,
80 },
81 /// A seam failed.
82 #[error("the seam behind {function}() failed")]
83 Seam {
84 /// The function name.
85 function: &'static str,
86 /// The seam's failure.
87 #[source]
88 source: SeamError,
89 },
90 /// A regular expression that does not compile.
91 #[error("the regular expression {pattern:?} does not compile")]
92 Regex {
93 /// The pattern.
94 pattern: String,
95 /// The compiler's failure.
96 #[source]
97 source: regex::Error,
98 },
99 /// Date and time arithmetic outside its rules (N1 §6.7).
100 #[error("date and time arithmetic failed")]
101 Arithmetic {
102 /// The failure.
103 #[source]
104 source: ArithmeticError,
105 },
106 /// The document contradicts the model, as a string where an object
107 /// belongs.
108 #[error("the element {element} contradicts the model: {reason}")]
109 Document {
110 /// The element path.
111 element: String,
112 /// What is wrong.
113 reason: String,
114 },
115 /// An element carries a modifier extension `checkModifiers()` does not
116 /// admit (FHIR R4 §2.9.1.5).
117 #[error("the element carries the modifier extension {url}, which the call does not admit")]
118 Modifier {
119 /// The extension's url.
120 url: String,
121 },
122 /// An order-dependent operation over a collection whose order N1 §3.1
123 /// leaves undefined, refused in the strict ordering mode.
124 #[error(
125 "{operation} needs an ordered input, and the order of a collection derived from children() or descendants() is undefined"
126 )]
127 Unordered {
128 /// The function name, or `[]` for the indexer.
129 operation: String,
130 },
131 /// An argument outside what the function admits.
132 #[error("{function}() received an invalid argument: {reason}")]
133 Argument {
134 /// The function name.
135 function: String,
136 /// What is wrong.
137 reason: String,
138 },
139}
140
141impl EvalError {
142 /// A type error for `operation` meeting `found`.
143 pub(crate) fn type_error(operation: impl Into<String>, found: impl Into<String>) -> Self {
144 Self::Type {
145 operation: operation.into(),
146 found: found.into(),
147 }
148 }
149
150 /// A singleton error for `operation` meeting `count` items.
151 pub(crate) fn singleton(operation: impl Into<String>, count: usize) -> Self {
152 Self::Singleton {
153 operation: operation.into(),
154 count,
155 }
156 }
157}