1use std::fmt;
2
3use crate::ParseStringErrorKind;
4
5use super::common::Range;
6
7#[derive(Debug, Clone, PartialEq, Eq, Hash)]
8pub enum ParseErrorKind {
9 CommentsNotAllowed,
10 ExpectedColonAfterObjectKey,
11 ExpectedObjectValue,
12 ExpectedDigit,
13 ExpectedDigitFollowingNegativeSign,
14 ExpectedPlusMinusOrDigitInNumberLiteral,
15 ExpectedStringObjectProperty,
16 MultipleRootJsonValues,
17 String(ParseStringErrorKind),
18 TrailingCommasNotAllowed,
19 UnexpectedCloseBrace,
20 UnexpectedCloseBracket,
21 UnexpectedColon,
22 UnexpectedComma,
23 UnexpectedToken,
24 UnexpectedTokenInObject,
25 UnexpectedWord,
26 UnterminatedArray,
27 UnterminatedCommentBlock,
28 UnterminatedObject,
29}
30
31impl std::fmt::Display for ParseErrorKind {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 use ParseErrorKind::*;
34 match self {
35 CommentsNotAllowed => {
36 write!(f, "Comments are not allowed")
37 }
38 ExpectedColonAfterObjectKey => {
39 write!(f, "Expected colon after the string or word in object property")
40 }
41 ExpectedDigit => {
42 write!(f, "Expected digit")
43 }
44 ExpectedDigitFollowingNegativeSign => {
45 write!(f, "Expected digit following negative sign")
46 }
47 ExpectedPlusMinusOrDigitInNumberLiteral => {
48 write!(f, "Expected plus, minus, or digit in number literal")
49 }
50 ExpectedObjectValue => {
51 write!(f, "Expected value after colon in object property")
52 }
53 ExpectedStringObjectProperty => {
54 write!(f, "Expected string for object property")
55 }
56 MultipleRootJsonValues => {
57 write!(f, "Text cannot contain more than one JSON value")
58 }
59 String(kind) => kind.fmt(f),
60 TrailingCommasNotAllowed => {
61 write!(f, "Trailing commas are not allowed")
62 }
63 UnexpectedCloseBrace => {
64 write!(f, "Unexpected close brace")
65 }
66 UnexpectedCloseBracket => {
67 write!(f, "Unexpected close bracket")
68 }
69 UnexpectedColon => {
70 write!(f, "Unexpected colon")
71 }
72 UnexpectedComma => {
73 write!(f, "Unexpected comma")
74 }
75 UnexpectedWord => {
76 write!(f, "Unexpected word")
77 }
78 UnexpectedToken => {
79 write!(f, "Unexpected token")
80 }
81 UnexpectedTokenInObject => {
82 write!(f, "Unexpected token in object")
83 }
84 UnterminatedArray => {
85 write!(f, "Unterminated array")
86 }
87 UnterminatedCommentBlock => {
88 write!(f, "Unterminated comment block")
89 }
90 UnterminatedObject => {
91 write!(f, "Unterminated object")
92 }
93 }
94 }
95}
96
97#[derive(Debug, Clone, PartialEq)]
98struct ParseErrorInner {
99 range: Range,
100 line_display: usize,
101 column_display: usize,
102 kind: ParseErrorKind,
103}
104
105#[derive(Debug, Clone, PartialEq)]
107pub struct ParseError(Box<ParseErrorInner>);
108
109impl std::error::Error for ParseError {}
110
111impl ParseError {
112 pub(crate) fn new(range: Range, kind: ParseErrorKind, file_text: &str) -> ParseError {
113 let (line_display, column_display) = get_line_and_column_display(range, file_text);
114 ParseError(Box::new(ParseErrorInner {
115 range,
116 line_display,
117 column_display,
118 kind,
119 }))
120 }
121
122 pub fn range(&self) -> Range {
124 self.0.range
125 }
126
127 pub fn line_display(&self) -> usize {
129 self.0.line_display
130 }
131
132 pub fn column_display(&self) -> usize {
138 self.0.column_display
139 }
140
141 pub fn kind(&self) -> &ParseErrorKind {
143 &self.0.kind
144 }
145}
146
147impl fmt::Display for ParseError {
148 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
149 let inner = &*self.0;
150 write!(
151 f,
152 "{} on line {} column {}",
153 inner.kind, inner.line_display, inner.column_display
154 )
155 }
156}
157
158fn get_line_and_column_display(range: Range, file_text: &str) -> (usize, usize) {
159 let mut line_index = 0;
160 let mut column_index = 0;
161 for c in file_text[..range.start].chars() {
162 if c == '\n' {
163 line_index += 1;
164 column_index = 0;
165 } else {
166 #[cfg(feature = "error_unicode_width")]
167 {
168 if let Some(width) = unicode_width::UnicodeWidthChar::width_cjk(c) {
169 column_index += width;
170 }
171 }
172 #[cfg(not(feature = "error_unicode_width"))]
173 {
174 column_index += 1;
175 }
176 }
177 }
178 (line_index + 1, column_index + 1)
179}