jsonata_rs/
errors.rs

1use std::{char, error, fmt};
2
3/// User-facing error codes and messages. These codes are defined in the Javascript implementation here:
4/// <https://github.com/jsonata-js/jsonata/blob/9e6b8e6d081e34fbd72fe24ccd703afa9248fec5/src/jsonata.js#L1941>
5#[derive(Debug, PartialEq)]
6#[non_exhaustive]
7pub enum Error {
8    // Compile time errors
9    S0101UnterminatedStringLiteral(usize),
10    S0102LexedNumberOutOfRange(usize, String),
11    S0103UnsupportedEscape(usize, char),
12    S0104InvalidUnicodeEscape(usize),
13    S0105UnterminatedQuoteProp(usize),
14    S0106UnterminatedComment(usize),
15    S0201SyntaxError(usize, String),
16    S0202UnexpectedToken(usize, String, String),
17    S0204UnknownOperator(usize, String),
18    S0203ExpectedTokenBeforeEnd(usize, String),
19    S0208InvalidFunctionParam(usize, String),
20    S0209InvalidPredicate(usize),
21    S0210MultipleGroupBy(usize),
22    S0211InvalidUnary(usize, String),
23    S0212ExpectedVarLeft(usize),
24    S0213InvalidStep(usize, String),
25    S0214ExpectedVarRight(usize, String),
26    S0215BindingAfterPredicates(usize),
27    S0216BindingAfterSort(usize),
28    S0301EmptyRegex(usize),
29    S0302UnterminatedRegex(usize),
30    // This variant is not present in the JS implementation
31    S0303InvalidRegex(usize, String),
32
33    // Runtime errors
34    D1001NumberOfOutRange(f64),
35    D1002NegatingNonNumeric(usize, String),
36    D1004ZeroLengthMatch(usize),
37    D1009MultipleKeys(usize, String),
38    D2014RangeOutOfBounds(usize, isize),
39    D3001StringNotFinite(usize),
40    D3010EmptyPattern(usize),
41    D3011NegativeLimit(usize),
42    D3012InvalidReplacementType(usize),
43    D3020NegativeLimit(usize),
44    D3030NonNumericCast(usize, String),
45    D3050SecondArguement(String),
46    D3060SqrtNegative(usize, String),
47    D3061PowUnrepresentable(usize, String, String),
48    D3070InvalidDefaultSort(usize),
49    D3141Assert(String),
50    D3137Error(String),
51    D3138Error(String),
52    D3139Error(String),
53    D3133PictureStringNameModifierError(String),
54    D3134TooManyTzDigits(String),
55    D3135PictureStringNoClosingBracketError(String),
56
57    // Type errors
58    T0410ArgumentNotValid(usize, usize, String),
59    T0412ArgumentMustBeArrayOfType(usize, usize, String, String),
60    T1003NonStringKey(usize, String),
61    T1005InvokedNonFunctionSuggest(usize, String),
62    T1006InvokedNonFunction(usize),
63    T2001LeftSideNotNumber(usize, String),
64    T2002RightSideNotNumber(usize, String),
65    T2003LeftSideNotInteger(usize),
66    T2004RightSideNotInteger(usize),
67    T2006RightSideNotFunction(usize),
68    T2007CompareTypeMismatch(usize, String, String),
69    T2008InvalidOrderBy(usize),
70    T2009BinaryOpMismatch(usize, String, String, String),
71    T2010BinaryOpTypes(usize, String),
72    T2011UpdateNotObject(usize, String),
73    T2012DeleteNotStrings(usize, String),
74    T2013BadClone(usize),
75
76    // Expression timebox/depth errors
77    U1001StackOverflow,
78    U1001Timeout,
79}
80
81impl error::Error for Error {}
82
83impl Error {
84    /**
85     * Error codes
86     *
87     * Sxxxx    - Static errors (compile time)
88     * Txxxx    - Type errors
89     * Dxxxx    - Dynamic errors (evaluate time)
90     *  01xx    - tokenizer
91     *  02xx    - parser
92     *  03xx    - regex parser
93     *  04xx    - function signature parser/evaluator
94     *  10xx    - evaluator
95     *  20xx    - operators
96     *  3xxx    - functions (blocks of 10 for each function)
97     */
98    pub fn code(&self) -> &str {
99        match *self {
100            // Compile time errors
101            Error::S0101UnterminatedStringLiteral(..) => "S0101",
102            Error::S0102LexedNumberOutOfRange(..) => "S0102",
103            Error::S0103UnsupportedEscape(..) => "S0103",
104            Error::S0104InvalidUnicodeEscape(..) => "S0104",
105            Error::S0105UnterminatedQuoteProp(..) => "S0105",
106            Error::S0106UnterminatedComment(..) => "S0106",
107            Error::S0201SyntaxError(..) => "S0201",
108            Error::S0202UnexpectedToken(..) => "S0202",
109            Error::S0203ExpectedTokenBeforeEnd(..) => "S0203",
110            Error::S0204UnknownOperator(..) => "S0204",
111            Error::S0208InvalidFunctionParam(..) => "S0208",
112            Error::S0209InvalidPredicate(..) => "S0209",
113            Error::S0210MultipleGroupBy(..) => "S0210",
114            Error::S0211InvalidUnary(..) => "S0211",
115            Error::S0212ExpectedVarLeft(..) => "S0212",
116            Error::S0213InvalidStep(..) => "S0213",
117            Error::S0214ExpectedVarRight(..) => "S0214",
118            Error::S0215BindingAfterPredicates(..) => "S0215",
119            Error::S0216BindingAfterSort(..) => "S0216",
120            Error::S0301EmptyRegex(..) => "S0301",
121            Error::S0302UnterminatedRegex(..) => "S0302",
122            Error::S0303InvalidRegex(..) => "S0303",
123
124            // Runtime errors
125            Error::D1001NumberOfOutRange(..) => "D1001",
126            Error::D1002NegatingNonNumeric(..) => "D1002",
127            Error::D1004ZeroLengthMatch(..) => "D1004",
128            Error::D1009MultipleKeys(..) => "D1009",
129            Error::D2014RangeOutOfBounds(..) => "D2014",
130            Error::D3001StringNotFinite(..) => "D3001",
131            Error::D3010EmptyPattern(..) => "D3010",
132            Error::D3011NegativeLimit(..) => "D3011",
133            Error::D3012InvalidReplacementType(..) => "D3012",
134            Error::D3020NegativeLimit(..) => "D3020",
135            Error::D3030NonNumericCast(..) => "D3030",
136            Error::D3050SecondArguement(..) => "D3050",
137            Error::D3060SqrtNegative(..) => "D3060",
138            Error::D3061PowUnrepresentable(..) => "D3061",
139            Error::D3070InvalidDefaultSort(..) => "D3070",
140            Error::D3133PictureStringNameModifierError(..) => "D3133",
141            Error::D3134TooManyTzDigits(..) => "D3134",
142            Error::D3135PictureStringNoClosingBracketError(..) => "D3135",
143            Error::D3141Assert(..) => "D3141",
144            Error::D3137Error(..) => "D3137",
145            Error::D3138Error(..) => "D3138",
146            Error::D3139Error(..) => "D3139",
147
148            // Type errors
149            Error::T0410ArgumentNotValid(..) => "T0410",
150            Error::T0412ArgumentMustBeArrayOfType(..) => "T0412",
151            Error::T1003NonStringKey(..) => "T1003",
152            Error::T1005InvokedNonFunctionSuggest(..) => "T1005",
153            Error::T1006InvokedNonFunction(..) => "T1006",
154            Error::T2001LeftSideNotNumber(..) => "T2001",
155            Error::T2002RightSideNotNumber(..) => "T2002",
156            Error::T2003LeftSideNotInteger(..) => "T2003",
157            Error::T2004RightSideNotInteger(..) => "T2004",
158            Error::T2006RightSideNotFunction(..) => "T2006",
159            Error::T2007CompareTypeMismatch(..) => "T2007",
160            Error::T2008InvalidOrderBy(..) => "T2008",
161            Error::T2009BinaryOpMismatch(..) => "T2009",
162            Error::T2010BinaryOpTypes(..) => "T2010",
163            Error::T2011UpdateNotObject(..) => "T2011",
164            Error::T2012DeleteNotStrings(..) => "T2012",
165            Error::T2013BadClone(..) => "T2013",
166
167            // Expression timebox/depth errors
168            Error::U1001StackOverflow => "U1001",
169            Error::U1001Timeout => "U1001",
170        }
171    }
172}
173
174impl fmt::Display for Error {
175    #[allow(clippy::many_single_char_names)]
176    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
177        use Error::*;
178
179        write!(f, "{} @ ", self.code())?;
180
181        // These messages come from the Javascript implementation:
182        // <https://github.com/jsonata-js/jsonata/blob/9e6b8e6d081e34fbd72fe24ccd703afa9248fec5/src/jsonata.js#L1941>
183        match *self {
184            // Compile time errors
185            S0101UnterminatedStringLiteral(ref p) =>
186                write!(f, "{}: String literal must be terminated by a matching quote", p),
187            S0102LexedNumberOutOfRange(ref p, ref n) =>
188                write!(f, "{}: Number out of range: {}", p, n),
189            S0103UnsupportedEscape(ref p, ref c) =>
190                write!(f, "{}: Unsupported escape sequence: \\{}", p, c),
191            S0104InvalidUnicodeEscape(ref p) =>
192                write!(f, "{}: The escape sequence \\u must be followed by 4 hex digits", p),
193            S0105UnterminatedQuoteProp(ref p) =>
194                write!(f, "{}: Quoted property name must be terminated with a backquote (`)", p),
195            S0106UnterminatedComment(ref p) =>
196                write!(f, "{}: Comment has no closing tag", p),
197            S0201SyntaxError(ref p, ref t) =>
198                write!(f, "{}: Syntax error `{}`", p, t),
199            S0202UnexpectedToken(ref p, ref e, ref a) =>
200                write!(f, "{}: Expected `{}`, got `{}`", p, e, a),
201            S0203ExpectedTokenBeforeEnd(ref p, ref t) =>
202                write!(f, "{}: Expected `{}` before end of expression", p, t),
203            S0204UnknownOperator(ref p, ref t) =>
204                write!(f, "{}: Unknown operator: `{}`", p, t),
205            S0208InvalidFunctionParam(ref p, ref k) =>
206                write!(f, "{}: Parameter `{}` of function definition must be a variable name (start with $)", p, k),
207            S0209InvalidPredicate(ref p) =>
208                write!(f, "{}: A predicate cannot follow a grouping expression in a step", p),
209            S0210MultipleGroupBy(ref p) =>
210                write!(f, "{}: Each step can only have one grouping expression", p),
211            S0211InvalidUnary(ref p, ref k) =>
212                write!(f, "{}: The symbol `{}` cannot be used as a unary operator", p, k),
213            S0212ExpectedVarLeft(ref p) =>
214                write!(f, "{}: The left side of `:=` must be a variable name (start with $)", p),
215            S0213InvalidStep(ref p, ref k) =>
216                write!(f, "{}: The literal value `{}` cannot be used as a step within a path expression", p, k),
217            S0214ExpectedVarRight(ref p, ref k) =>
218                write!(f, "{}: The right side of `{}` must be a variable name (start with $)", p, k),
219            S0215BindingAfterPredicates(ref p) =>
220                write!(f, "{}: A context variable binding must precede any predicates on a step", p),
221            S0216BindingAfterSort(ref p) =>
222                write!(f, "{}: A context variable binding must precede the 'order-by' clause on a step", p),
223            S0301EmptyRegex(ref p) =>
224                write!(f, "{}: Empty regular expressions are not allowed", p),
225            S0302UnterminatedRegex(ref p) =>
226                write!(f, "{}: No terminating / in regular expression", p),
227            S0303InvalidRegex(ref p, ref message) =>
228                // The error message from `regress::Regex` a "regex parse error: " prefix, so don't be redundant here.
229                write!(f, "{}: {}", p, message),
230
231            // Runtime errors
232            D1001NumberOfOutRange(ref n) => write!(f, "Number out of range: {}", n),
233            D1002NegatingNonNumeric(ref p, ref v) =>
234                write!(f, "{}: Cannot negate a non-numeric value `{}`", p, v),
235            D1004ZeroLengthMatch(ref p) =>
236                write!(f, "{}: Regular expression matches zero length string", p),
237            D1009MultipleKeys(ref p, ref k) =>
238                write!(f, "{}: Multiple key definitions evaluate to same key: {}", p, k),
239            D2014RangeOutOfBounds(ref p, ref s) =>
240                write!(f, "{}: The size of the sequence allocated by the range operator (..) must not exceed 1e7.  Attempted to allocate {}", p, s),
241            D3001StringNotFinite(ref p) =>
242                write!(f, "{}: Attempting to invoke string function on Infinity or NaN", p),
243            D3010EmptyPattern(ref p) =>
244                write!(f, "{}: Second argument of replace function cannot be an empty string", p),
245            D3011NegativeLimit(ref p) =>
246                write!(f, "{}: Fourth argument of replace function must evaluate to a positive number", p),
247            D3012InvalidReplacementType(ref p) => write!(f, "{}: Attempted to replace a matched string with a non-string value", p),
248            D3020NegativeLimit(ref p) =>
249                write!(f, "{}: Third argument of split function must evaluate to a positive number", p),
250            D3030NonNumericCast(ref p, ref n) =>
251                write!(f, "{}: Unable to cast value to a number: {}", p, n),
252            D3050SecondArguement(ref p) =>
253                write!(f, "{}: The second argument of reduce function must be a function with at least two arguments", p),
254            D3060SqrtNegative(ref p, ref n) =>
255                write!(f, "{}: The sqrt function cannot be applied to a negative number: {}", p, n),
256            D3061PowUnrepresentable(ref p, ref b, ref e) =>
257                write!(f, "{}: The power function has resulted in a value that cannot be represented as a JSON number: base={}, exponent={}", p, b, e),
258            D3070InvalidDefaultSort(ref p) =>
259                write!(f, "{}: The single argument form of the sort function can only be applied to an array of strings or an array of numbers.  Use the second argument to specify a comparison function", p),
260            D3133PictureStringNameModifierError(ref m) =>
261                write!(f, "{}: The 'name' modifier can only be applied to months and days in the date/time picture string, not Y", m),
262            D3134TooManyTzDigits(ref m) =>
263                write!(f, "{}: The timezone integer format specifier cannot have more than four digits", m),
264            D3135PictureStringNoClosingBracketError(ref m) =>
265                write!(f, "{}: No matching closing bracket ']' in date/time picture string", m),
266            D3141Assert(ref m) =>
267                write!(f, "{}", m),
268            D3137Error(ref m) =>
269                write!(f, "{}", m),
270            D3138Error(ref m) =>
271                write!(f, "{}: The $single() function expected exactly 1 matching result.  Instead it matched more.", m),
272            D3139Error(ref m) =>
273                write!(f, "{}: The $single() function expected exactly 1 matching result.  Instead it matched 0.", m),
274            // Type errors
275            T0410ArgumentNotValid(ref p, ref i, ref t) =>
276                write!(f, "{}: Argument {} of function {} does not match function signature", p, i, t),
277            T0412ArgumentMustBeArrayOfType(ref p, ref i, ref t, ref ty) =>
278                write!(f, "{}: Argument {} of function {} must be an array of {}", p, i, t, ty),
279            T1003NonStringKey(ref p, ref v) =>
280                write!( f, "{}: Key in object structure must evaluate to a string; got: {}", p, v),
281            T1005InvokedNonFunctionSuggest(ref p, ref t) =>
282                write!(f, "{}: Attempted to invoke a non-function. Did you mean ${}?", p, t),
283            T1006InvokedNonFunction(ref p) =>
284                write!(f, "{}: Attempted to invoke a non-function", p),
285            T2001LeftSideNotNumber(ref p, ref o) =>
286                write!( f, "{}: The left side of the `{}` operator must evaluate to a number", p, o),
287            T2002RightSideNotNumber(ref p, ref o) =>
288                write!( f, "{}: The right side of the `{}` operator must evaluate to a number", p, o),
289            T2003LeftSideNotInteger(ref p) =>
290                write!(f, "{}: The left side of the range operator (..) must evaluate to an integer", p),
291            T2004RightSideNotInteger(ref p) =>
292                write!(f, "{}: The right side of the range operator (..) must evaluate to an integer", p),
293            T2006RightSideNotFunction(ref p) =>
294                write!(f, "{p} The right side of the function application operator ~> must be a function"),
295            T2007CompareTypeMismatch(ref p, ref a, ref b) =>
296                write!(f, "{p}: Type mismatch when comparing values {a} and {b} in order-by clause"),
297            T2008InvalidOrderBy(ref p) =>
298                write!(f, "{}: The expressions within an order-by clause must evaluate to numeric or string values", p),
299            T2009BinaryOpMismatch(ref p,ref l ,ref r ,ref o ) =>
300                write!(f, "{}: The values {} and {} either side of operator {} must be of the same data type", p, l, r, o),
301            T2010BinaryOpTypes(ref p, ref o) =>
302                write!(f, "{}: The expressions either side of operator `{}` must evaluate to numeric or string values", p, o),
303            T2011UpdateNotObject(ref p, ref v) =>
304                write!(f, "{p}: The insert/update clause of the transform expression must evaluate to an object: {v}"),
305            T2012DeleteNotStrings(ref p, ref v) =>
306                write!(f, "{p}: The delete clause of the transform expression must evaluate to a string or array of strings: {v}"),
307            T2013BadClone(ref p) =>
308                write!(f, "{p}: The transform expression clones the input object using the $clone() function.  This has been overridden in the current scope by a non-function."),
309            // Expression timebox/depth errors
310            U1001StackOverflow =>
311                write!(f, "Stack overflow error: Check for non-terminating recursive function.  Consider rewriting as tail-recursive."),
312            U1001Timeout =>
313                write!(f, "Expression evaluation timeout: Check for infinite loop")
314        }
315    }
316}
317
318// "S0205": "Unexpected token: {{token}}",
319// "S0206": "Unknown expression type: {{token}}",
320// "S0207": "Unexpected end of expression",
321// "S0217": "The object representing the 'parent' cannot be derived from this expression",
322
323// "S0301": "Empty regular expressions are not allowed",
324// "S0302": "No terminating / in regular expression",
325// "S0402": "Choice groups containing parameterized types are not supported",
326// "S0401": "Type parameters can only be applied to functions and arrays",
327// "S0500": "Attempted to evaluate an expression containing syntax error(s)",
328// "T0411": "Context value is not a compatible type with argument {{index}} of function {{token}}",
329// "D1004": "Regular expression matches zero length string",
330// "T1007": "Attempted to partially apply a non-function. Did you mean ${{{token}}}?",
331// "T1008": "Attempted to partially apply a non-function",
332// // "T1010": "The matcher function argument passed to function {{token}} does not return the correct object structure",
333// "D2005": "The left side of := must be a variable name (start with $)",  // defunct - replaced by S0212 parser error
334// define_error!(
335//     D2014,
336//     "The size of the sequence allocated by the range operator (..) must not exceed 1e7.  Attempted to allocate {}",
337//     value
338// );
339// "D3010": "Second argument of replace function cannot be an empty string",
340// "D3011": "Fourth argument of replace function must evaluate to a positive number",
341// "D3012": "Attempted to replace a matched string with a non-string value",
342// "D3020": "Third argument of split function must evaluate to a positive number",
343// "D3040": "Third argument of match function must evaluate to a positive number",
344// "D3050": "The second argument of reduce function must be a function with at least two arguments",
345// "D3080": "The picture string must only contain a maximum of two sub-pictures",
346// "D3081": "The sub-picture must not contain more than one instance of the 'decimal-separator' character",
347// "D3082": "The sub-picture must not contain more than one instance of the 'percent' character",
348// "D3083": "The sub-picture must not contain more than one instance of the 'per-mille' character",
349// "D3084": "The sub-picture must not contain both a 'percent' and a 'per-mille' character",
350// "D3085": "The mantissa part of a sub-picture must contain at least one character that is either an 'optional digit character' or a member of the 'decimal digit family'",
351// "D3086": "The sub-picture must not contain a passive character that is preceded by an active character and that is followed by another active character",
352// "D3087": "The sub-picture must not contain a 'grouping-separator' character that appears adjacent to a 'decimal-separator' character",
353// "D3088": "The sub-picture must not contain a 'grouping-separator' at the end of the integer part",
354// "D3089": "The sub-picture must not contain two adjacent instances of the 'grouping-separator' character",
355// "D3090": "The integer part of the sub-picture must not contain a member of the 'decimal digit family' that is followed by an instance of the 'optional digit character'",
356// "D3091": "The fractional part of the sub-picture must not contain an instance of the 'optional digit character' that is followed by a member of the 'decimal digit family'",
357// "D3092": "A sub-picture that contains a 'percent' or 'per-mille' character must not contain a character treated as an 'exponent-separator'",
358// "D3093": "The exponent part of the sub-picture must comprise only of one or more characters that are members of the 'decimal digit family'",
359// "D3100": "The radix of the formatBase function must be between 2 and 36.  It was given {{value}}",
360// "D3110": "The argument of the toMillis function must be an ISO 8601 formatted timestamp. Given {{value}}",
361// "D3120": "Syntax error in expression passed to function eval: {{value}}",
362// "D3121": "Dynamic error evaluating the expression passed to function eval: {{value}}",
363// "D3130": "Formatting or parsing an integer as a sequence starting with {{value}} is not supported by this implementation",
364// "D3131": "In a decimal digit pattern, all digits must be from the same decimal group",
365// "D3132": "Unknown component specifier {{value}} in date/time picture string",
366// "D3133": "The 'name' modifier can only be applied to months and days in the date/time picture string, not {{value}}",
367// "D3134": "The timezone integer format specifier cannot have more than four digits",
368// "D3135": "No matching closing bracket ']' in date/time picture string",
369// "D3136": "The date/time picture string is missing specifiers required to parse the timestamp",
370// "D3138": "The $single() function expected exactly 1 matching result.  Instead it matched more.",
371// "D3139": "The $single() function expected exactly 1 matching result.  Instead it matched 0.",
372// "D3140": "Malformed URL passed to ${{{functionName}}}(): {{value}}",