1use std::fmt;
4
5#[derive(Debug, Clone, PartialEq)]
7pub struct JmespathError {
8 pub offset: usize,
10 pub expression: String,
12 pub reason: ErrorReason,
14}
15
16impl JmespathError {
17 pub fn new(expression: &str, offset: usize, reason: ErrorReason) -> Self {
19 Self {
20 offset,
21 expression: expression.to_owned(),
22 reason,
23 }
24 }
25
26 pub fn from_ctx(ctx: &crate::Context<'_>, reason: ErrorReason) -> Self {
28 Self {
29 offset: ctx.offset,
30 expression: ctx.expression.to_owned(),
31 reason,
32 }
33 }
34
35 pub fn line(&self) -> usize {
37 self.expression[..self.offset.min(self.expression.len())]
38 .chars()
39 .filter(|c| *c == '\n')
40 .count()
41 + 1
42 }
43
44 pub fn column(&self) -> usize {
46 let before = &self.expression[..self.offset.min(self.expression.len())];
47 match before.rfind('\n') {
48 Some(pos) => self.offset - pos - 1,
49 None => self.offset,
50 }
51 }
52}
53
54impl fmt::Display for JmespathError {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 let col = self.column();
57 write!(
58 f,
59 "{}\n{}\n{}",
60 self.reason,
61 self.expression,
62 " ".repeat(col)
63 )?;
64 write!(f, "^")
65 }
66}
67
68impl std::error::Error for JmespathError {}
69
70#[derive(Debug, Clone, PartialEq)]
72pub enum ErrorReason {
73 Parse(String),
75 Runtime(RuntimeError),
77}
78
79impl fmt::Display for ErrorReason {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 match self {
82 ErrorReason::Parse(msg) => write!(f, "Parse error: {msg}"),
83 ErrorReason::Runtime(err) => write!(f, "Runtime error: {err}"),
84 }
85 }
86}
87
88#[derive(Debug, Clone, PartialEq, thiserror::Error)]
90pub enum RuntimeError {
91 #[error("Invalid slice: step cannot be 0")]
93 InvalidSlice,
94 #[error("Too many arguments: expected {expected}, got {actual}")]
96 TooManyArguments { expected: usize, actual: usize },
97 #[error("Not enough arguments: expected {expected}, got {actual}")]
99 NotEnoughArguments { expected: usize, actual: usize },
100 #[error("Unknown function: {0}")]
102 UnknownFunction(String),
103 #[error("Invalid type at position {position}: expected {expected}, got {actual}")]
105 InvalidType {
106 expected: String,
107 actual: String,
108 position: usize,
109 },
110 #[error(
112 "Invalid return type at position {position}, invocation {invocation}: expected {expected}, got {actual}"
113 )]
114 InvalidReturnType {
115 expected: String,
116 actual: String,
117 position: usize,
118 invocation: usize,
119 },
120}