1use std::fmt;
2
3use crate::ParseStringErrorKind;
4
5use super::common::Range;
6
7#[derive(Debug)]
8pub enum ParseErrorKind {
9 BareDecimalPointNumbersNotAllowed,
10 CommentsNotAllowed,
11 ExpectedColonAfterObjectKey,
12 ExpectedObjectValue,
13 ExpectedDigit,
14 ExpectedDigitFollowingNegativeSign,
15 ExpectedPlusMinusOrDigitInNumberLiteral,
16 ExpectedStringObjectProperty,
17 HexadecimalNumbersNotAllowed,
18 ExpectedComma,
19 MultipleRootJsonValues,
20 NonFiniteNumbersNotAllowed,
21 SingleQuotedStringsNotAllowed,
22 String(ParseStringErrorKind),
23 TrailingCommasNotAllowed,
24 UnaryPlusNumbersNotAllowed,
25 UnexpectedCloseBrace,
26 UnexpectedCloseBracket,
27 UnexpectedColon,
28 UnexpectedComma,
29 UnexpectedToken,
30 UnexpectedTokenInObject,
31 UnexpectedWord,
32 UnterminatedArray,
33 UnterminatedCommentBlock,
34 UnterminatedObject,
35 NestingDepthExceeded,
36 #[cfg(feature = "serde")]
38 Custom(String),
39}
40
41impl std::fmt::Display for ParseErrorKind {
42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43 use ParseErrorKind::*;
44 match self {
45 BareDecimalPointNumbersNotAllowed => {
46 write!(f, "Leading or trailing decimal points on numbers are not allowed")
47 }
48 CommentsNotAllowed => {
49 write!(f, "Comments are not allowed")
50 }
51 ExpectedColonAfterObjectKey => {
52 write!(f, "Expected colon after the string or word in object property")
53 }
54 ExpectedDigit => {
55 write!(f, "Expected digit")
56 }
57 ExpectedDigitFollowingNegativeSign => {
58 write!(f, "Expected digit following negative sign")
59 }
60 ExpectedPlusMinusOrDigitInNumberLiteral => {
61 write!(f, "Expected plus, minus, or digit in number literal")
62 }
63 ExpectedObjectValue => {
64 write!(f, "Expected value after colon in object property")
65 }
66 ExpectedStringObjectProperty => {
67 write!(f, "Expected string for object property")
68 }
69 HexadecimalNumbersNotAllowed => {
70 write!(f, "Hexadecimal numbers are not allowed")
71 }
72 ExpectedComma => {
73 write!(f, "Expected comma")
74 }
75 MultipleRootJsonValues => {
76 write!(f, "Text cannot contain more than one JSON value")
77 }
78 NonFiniteNumbersNotAllowed => {
79 write!(f, "Infinity and NaN are not allowed")
80 }
81 SingleQuotedStringsNotAllowed => {
82 write!(f, "Single-quoted strings are not allowed")
83 }
84 String(kind) => kind.fmt(f),
85 TrailingCommasNotAllowed => {
86 write!(f, "Trailing commas are not allowed")
87 }
88 UnaryPlusNumbersNotAllowed => {
89 write!(f, "Unary plus on numbers is not allowed")
90 }
91 UnexpectedCloseBrace => {
92 write!(f, "Unexpected close brace")
93 }
94 UnexpectedCloseBracket => {
95 write!(f, "Unexpected close bracket")
96 }
97 UnexpectedColon => {
98 write!(f, "Unexpected colon")
99 }
100 UnexpectedComma => {
101 write!(f, "Unexpected comma")
102 }
103 UnexpectedWord => {
104 write!(f, "Unexpected word")
105 }
106 UnexpectedToken => {
107 write!(f, "Unexpected token")
108 }
109 UnexpectedTokenInObject => {
110 write!(f, "Unexpected token in object")
111 }
112 UnterminatedArray => {
113 write!(f, "Unterminated array")
114 }
115 UnterminatedCommentBlock => {
116 write!(f, "Unterminated comment block")
117 }
118 UnterminatedObject => {
119 write!(f, "Unterminated object")
120 }
121 NestingDepthExceeded => {
122 write!(f, "Maximum nesting depth exceeded")
123 }
124 #[cfg(feature = "serde")]
125 Custom(msg) => write!(f, "{}", msg),
126 }
127 }
128}
129
130#[derive(Debug)]
131struct ParseErrorInner {
132 range: Range,
133 line_display: usize,
134 column_display: usize,
135 kind: ParseErrorKind,
136}
137
138#[derive(Debug)]
140pub struct ParseError(Box<ParseErrorInner>);
141
142impl std::error::Error for ParseError {}
143
144impl ParseError {
145 pub(crate) fn new(range: Range, kind: ParseErrorKind, file_text: &str) -> ParseError {
146 let (line_display, column_display) = get_line_and_column_display(range, file_text);
147 ParseError(Box::new(ParseErrorInner {
148 range,
149 line_display,
150 column_display,
151 kind,
152 }))
153 }
154
155 pub fn range(&self) -> Range {
157 self.0.range
158 }
159
160 pub fn line_display(&self) -> usize {
162 self.0.line_display
163 }
164
165 pub fn column_display(&self) -> usize {
171 self.0.column_display
172 }
173
174 pub fn kind(&self) -> &ParseErrorKind {
176 &self.0.kind
177 }
178
179 #[cfg(feature = "serde")]
181 pub(crate) fn custom_err(msg: String) -> ParseError {
182 ParseError(Box::new(ParseErrorInner {
183 range: Range { start: 0, end: 0 },
184 line_display: 1,
185 column_display: 1,
186 kind: ParseErrorKind::Custom(msg),
187 }))
188 }
189
190 #[cfg(feature = "serde")]
192 pub(crate) fn with_position(mut self, range: Range, file_text: &str) -> ParseError {
193 if self.0.range.start == 0 && self.0.range.end == 0 {
194 let (line_display, column_display) = get_line_and_column_display(range, file_text);
195 self.0.range = range;
196 self.0.line_display = line_display;
197 self.0.column_display = column_display;
198 }
199 self
200 }
201}
202
203impl fmt::Display for ParseError {
204 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
205 let inner = &*self.0;
206 write!(
207 f,
208 "{} on line {} column {}",
209 inner.kind, inner.line_display, inner.column_display
210 )
211 }
212}
213
214fn get_line_and_column_display(range: Range, file_text: &str) -> (usize, usize) {
215 let mut line_index = 0;
216 let mut column_index = 0;
217 for (i, c) in file_text[..range.start].char_indices() {
218 if c == '\n' || c == '\r' && file_text.as_bytes().get(i + 1) != Some(&b'\n') {
220 line_index += 1;
221 column_index = 0;
222 } else {
223 #[cfg(feature = "error_unicode_width")]
224 {
225 if let Some(width) = unicode_width::UnicodeWidthChar::width_cjk(c) {
226 column_index += width;
227 }
228 }
229 #[cfg(not(feature = "error_unicode_width"))]
230 {
231 column_index += 1;
232 }
233 }
234 }
235 (line_index + 1, column_index + 1)
236}