1use std::borrow::Cow;
2
3use crate::ParseOptions;
4use crate::common::Range;
5use crate::errors::*;
6use crate::scanner::Scanner;
7use crate::scanner::ScannerOptions;
8use crate::tokens::Token;
9
10pub(crate) enum ObjectKey<'a> {
11 String(Cow<'a, str>),
12 Word(&'a str),
13}
14
15impl<'a> ObjectKey<'a> {
16 pub fn into_cow(self) -> Cow<'a, str> {
19 match self {
20 ObjectKey::String(s) => s,
21 ObjectKey::Word(s) => Cow::Borrowed(s),
22 }
23 }
24}
25
26pub(crate) struct JsoncParser<'a> {
30 pub scanner: Scanner<'a>,
31 #[allow(dead_code)] pub text: &'a str,
33 allow_comments: bool,
34 allow_trailing_commas: bool,
35 allow_missing_commas: bool,
36 allow_loose_object_property_names: bool,
37 depth: usize,
38 pending_token: Option<Token<'a>>,
39}
40
41impl<'a> JsoncParser<'a> {
42 pub fn new(text: &'a str, options: &ParseOptions) -> Self {
43 Self {
44 scanner: Scanner::new(
45 text,
46 &ScannerOptions {
47 allow_single_quoted_strings: options.allow_single_quoted_strings,
48 allow_hexadecimal_numbers: options.allow_hexadecimal_numbers,
49 allow_unary_plus_numbers: options.allow_unary_plus_numbers,
50 },
51 ),
52 text,
53 allow_comments: options.allow_comments,
54 allow_trailing_commas: options.allow_trailing_commas,
55 allow_missing_commas: options.allow_missing_commas,
56 allow_loose_object_property_names: options.allow_loose_object_property_names,
57 depth: 0,
58 pending_token: None,
59 }
60 }
61
62 pub fn scan(&mut self) -> Result<Option<Token<'a>>, ParseError> {
65 if let Some(token) = self.pending_token.take() {
66 return Ok(Some(token));
67 }
68 loop {
69 match self.scanner.scan()? {
70 Some(Token::CommentLine(_) | Token::CommentBlock(_)) => {
71 if !self.allow_comments {
72 return Err(
73 self
74 .scanner
75 .create_error_for_current_token(ParseErrorKind::CommentsNotAllowed),
76 );
77 }
78 continue;
79 }
80 token => return Ok(token),
81 }
82 }
83 }
84
85 #[cfg(feature = "serde")]
87 pub fn put_back(&mut self, token: Token<'a>) {
88 debug_assert!(self.pending_token.is_none(), "put_back called with pending token");
89 self.pending_token = Some(token);
90 }
91
92 pub fn enter_container(&mut self) -> Result<(), ParseError> {
94 self.depth += 1;
95 if self.depth > 512 {
96 self.depth -= 1;
97 Err(
98 self
99 .scanner
100 .create_error_for_current_token(ParseErrorKind::NestingDepthExceeded),
101 )
102 } else {
103 Ok(())
104 }
105 }
106
107 pub fn exit_container(&mut self) {
109 self.depth -= 1;
110 }
111
112 pub fn unexpected_token_error(&self, token: &Token) -> ParseError {
114 let kind = match token {
115 Token::CloseBracket => ParseErrorKind::UnexpectedCloseBracket,
116 Token::CloseBrace => ParseErrorKind::UnexpectedCloseBrace,
117 Token::Comma => ParseErrorKind::UnexpectedComma,
118 Token::Colon => ParseErrorKind::UnexpectedColon,
119 Token::Word(_) => ParseErrorKind::UnexpectedWord,
120 _ => ParseErrorKind::UnexpectedToken,
121 };
122 self.scanner.create_error_for_current_token(kind)
123 }
124
125 pub fn scan_object_entry(&mut self, first: bool) -> Result<Option<ObjectKey<'a>>, ParseError> {
128 if first {
129 return self.scan_object_key();
130 }
131
132 let after_value_end = self.scanner.token_end();
133 let token = self.scan()?;
134 match token {
135 Some(Token::Comma) => {
136 let comma_range = Range::new(self.scanner.token_start(), self.scanner.token_end());
137 let key = self.scan_object_key()?;
138 if key.is_none() && !self.allow_trailing_commas {
139 return Err(
140 self
141 .scanner
142 .create_error_for_range(comma_range, ParseErrorKind::TrailingCommasNotAllowed),
143 );
144 }
145 Ok(key)
146 }
147 Some(Token::CloseBrace) => Ok(None),
148 Some(Token::String(s)) if self.allow_missing_commas => Ok(Some(ObjectKey::String(s))),
149 Some(Token::Word(s) | Token::Number(s)) if self.allow_missing_commas => {
150 if !self.allow_loose_object_property_names {
151 return Err(
152 self
153 .scanner
154 .create_error_for_current_token(ParseErrorKind::ExpectedStringObjectProperty),
155 );
156 }
157 Ok(Some(ObjectKey::Word(s)))
158 }
159 Some(Token::String(_) | Token::Word(_) | Token::Number(_)) => {
160 let range = Range::new(after_value_end, after_value_end);
161 Err(
162 self
163 .scanner
164 .create_error_for_range(range, ParseErrorKind::ExpectedComma),
165 )
166 }
167 None => Err(
168 self
169 .scanner
170 .create_error_for_current_token(ParseErrorKind::UnterminatedObject),
171 ),
172 _ => Err(
173 self
174 .scanner
175 .create_error_for_current_token(ParseErrorKind::UnexpectedTokenInObject),
176 ),
177 }
178 }
179
180 pub fn scan_object_colon(&mut self) -> Result<(), ParseError> {
182 match self.scan()? {
183 Some(Token::Colon) => Ok(()),
184 _ => Err(
185 self
186 .scanner
187 .create_error_for_current_token(ParseErrorKind::ExpectedColonAfterObjectKey),
188 ),
189 }
190 }
191
192 pub fn scan_array_comma(&mut self) -> Result<Option<Token<'a>>, ParseError> {
195 debug_assert!(self.pending_token.is_none(), "the previous value must be consumed");
196 let after_value_end = self.scanner.token_end();
197 match self.scan()? {
198 Some(Token::Comma) => {
199 let comma_range = Range::new(self.scanner.token_start(), self.scanner.token_end());
200 let next = self.scan()?;
201 if matches!(&next, Some(Token::CloseBracket)) && !self.allow_trailing_commas {
202 return Err(
203 self
204 .scanner
205 .create_error_for_range(comma_range, ParseErrorKind::TrailingCommasNotAllowed),
206 );
207 }
208 Ok(next)
209 }
210 Some(token) if !self.allow_missing_commas && token.is_value_start() => {
211 let range = Range::new(after_value_end, after_value_end);
212 Err(
213 self
214 .scanner
215 .create_error_for_range(range, ParseErrorKind::ExpectedComma),
216 )
217 }
218 token => Ok(token),
219 }
220 }
221
222 fn scan_object_key(&mut self) -> Result<Option<ObjectKey<'a>>, ParseError> {
223 match self.scan()? {
224 Some(Token::CloseBrace) => Ok(None),
225 Some(Token::String(s)) => Ok(Some(ObjectKey::String(s))),
226 Some(Token::Word(s) | Token::Number(s)) => {
227 if !self.allow_loose_object_property_names {
228 return Err(
229 self
230 .scanner
231 .create_error_for_current_token(ParseErrorKind::ExpectedStringObjectProperty),
232 );
233 }
234 Ok(Some(ObjectKey::Word(s)))
235 }
236 None => Err(
237 self
238 .scanner
239 .create_error_for_current_token(ParseErrorKind::UnterminatedObject),
240 ),
241 _ => Err(
242 self
243 .scanner
244 .create_error_for_current_token(ParseErrorKind::UnexpectedTokenInObject),
245 ),
246 }
247 }
248}