1use hermes_atom_table::AtomTable;
21use hermes_support::diag::Subsystem;
22use hermes_support::location::{SMRange, SourceId};
23use hermes_support::manager::SourceErrorManager;
24
25use crate::lexer::{GrammarContext, JSLexer};
26use crate::token::Token;
27use crate::token_kinds::TokenKind;
28
29use super::factory::Prop;
30use super::{JSONFactory, JSONValue};
31
32const CTX: GrammarContext = GrammarContext::AllowDiv;
34
35const MAX_RECURSION_DEPTH: u32 = if cfg!(debug_assertions) { 512 } else { 4096 };
51
52pub struct JSONParser<'a> {
55 factory: &'a JSONFactory<'a>,
56 lexer: JSLexer<'a>,
57 recursion_depth: u32,
60}
61
62impl<'a> JSONParser<'a> {
63 pub fn new(
66 factory: &'a JSONFactory<'a>,
67 buf_id: SourceId,
68 sm: &'a mut SourceErrorManager,
69 atoms: &'a AtomTable,
70 convert_surrogates: bool,
71 ) -> JSONParser<'a> {
72 let lexer =
73 JSLexer::new_with_convert_surrogates(buf_id, sm, atoms, CTX, convert_surrogates);
74 JSONParser {
75 factory,
76 lexer,
77 recursion_depth: 0,
78 }
79 }
80
81 pub fn error_count(&self) -> u32 {
84 self.lexer.get_source_mgr().error_count()
85 }
86
87 fn error(&mut self, msg: impl Into<String>) {
89 let range: SMRange = self.lexer.token().source_range();
90 self.lexer.get_source_mgr_mut().error_at(
91 range.start,
92 Some(range),
93 msg.into(),
94 Subsystem::Parser,
95 );
96 }
97
98 fn cur(&self) -> &Token {
100 self.lexer.token()
101 }
102
103 fn advance(&mut self) -> &Token {
105 self.lexer.advance(CTX)
106 }
107
108 pub fn parse(&mut self) -> Option<&'a JSONValue<'a>> {
110 self.advance();
111 let res = self.parse_value()?;
112 if self.lexer.get_source_mgr().error_count() != 0 {
113 return None;
114 }
115 Some(res)
116 }
117
118 fn parse_value(&mut self) -> Option<&'a JSONValue<'a>> {
121 if self.recursion_depth >= MAX_RECURSION_DEPTH {
122 self.error("Too many nested JSON values");
123 return None;
124 }
125 self.recursion_depth += 1;
126 let res = self.parse_value_impl();
127 self.recursion_depth -= 1;
128 res
129 }
130
131 fn parse_value_impl(&mut self) -> Option<&'a JSONValue<'a>> {
134 let mut needs_negation = false;
135 match self.cur().kind() {
136 TokenKind::string_literal => {
137 let lit = self.cur().get_string_literal();
140 self.advance();
141 Some(self.factory.get_string(lit))
142 }
143 TokenKind::minus => {
144 needs_negation = true;
145 self.advance();
146 if self.cur().kind() != TokenKind::numeric_literal {
147 self.error("No numeric literal following minus (-) token in value");
148 return None;
149 }
150 self.parse_number(needs_negation)
151 }
152 TokenKind::numeric_literal => self.parse_number(needs_negation),
153 TokenKind::l_brace => {
154 self.advance();
155 self.parse_object()
156 }
157 TokenKind::l_square => {
158 self.advance();
159 self.parse_array()
160 }
161 TokenKind::rw_true => {
162 self.advance();
163 Some(self.factory.get_boolean(true))
164 }
165 TokenKind::rw_false => {
166 self.advance();
167 Some(self.factory.get_boolean(false))
168 }
169 TokenKind::rw_null => {
170 self.advance();
171 Some(self.factory.get_null())
172 }
173 _ => {
174 self.error("JSON object or array expected");
175 None
176 }
177 }
178 }
179
180 fn parse_number(&mut self, needs_negation: bool) -> Option<&'a JSONValue<'a>> {
183 let v = self.cur().get_numeric_literal();
184 let res = self.factory.get_number(if needs_negation { -v } else { v });
185 self.advance();
186 Some(res)
187 }
188
189 fn parse_array(&mut self) -> Option<&'a JSONValue<'a>> {
191 let mut storage: Vec<&'a JSONValue<'a>> = Vec::new();
192 if self.cur().kind() != TokenKind::r_square {
193 loop {
194 let val = self.parse_value()?;
195 storage.push(val);
196 if self.cur().kind() == TokenKind::comma {
197 self.advance();
198 if self.cur().kind() == TokenKind::r_square {
199 break;
200 }
201 } else {
202 break;
203 }
204 }
205 if self.cur().kind() != TokenKind::r_square {
206 self.error("expected ']'");
207 return None;
208 }
209 }
210 self.advance(); Some(self.factory.new_array(&storage))
212 }
213
214 fn parse_object(&mut self) -> Option<&'a JSONValue<'a>> {
216 let mut pairs: Vec<Prop<'a>> = Vec::new();
217 if self.cur().kind() != TokenKind::r_brace {
218 loop {
219 if self.cur().kind() != TokenKind::string_literal {
220 self.error("expected a string");
221 return None;
222 }
223 let key = self.factory.get_string(self.cur().get_string_literal());
224 if self.advance().kind() != TokenKind::colon {
225 self.error("expected ':'");
226 return None;
227 }
228 self.advance();
229 let val = self.parse_value()?;
230 pairs.push((key, val));
231 if self.cur().kind() == TokenKind::comma {
232 self.advance();
233 if self.cur().kind() == TokenKind::r_brace {
234 break;
235 }
236 } else {
237 break;
238 }
239 }
240 if self.cur().kind() != TokenKind::r_brace {
241 self.error("expected '}'");
242 return None;
243 }
244 }
245 self.advance(); if let Some(dup) = self.factory.sort_props(&mut pairs) {
248 let name = String::from_utf8_lossy(self.factory.atoms().bytes(dup)).into_owned();
249 self.error(format!("key '{name}' is already present"));
250 return None;
251 }
252 self.factory.new_object_sorted(&pairs)
254 }
255}
256
257#[cfg(test)]
258mod parser_tests {
259 use super::super::*;
260 use bumpalo::Bump;
261 use hermes_atom_table::AtomTable;
262 use hermes_support::manager::SourceErrorManager;
263
264 fn parse_ok<'a>(
267 arena: &'a Bump,
268 atoms: &'a AtomTable,
269 sm: &'a mut SourceErrorManager,
270 src: &str,
271 ) -> Option<&'a JSONValue<'a>> {
272 let f = arena.alloc(JSONFactory::new(arena, atoms));
274 let id = sm.add_buffer("json", src);
275 let mut p = JSONParser::new(f, id, sm, atoms, false);
276 p.parse()
277 }
278
279 #[test]
280 fn scalars() {
281 let arena = Bump::new();
282 let atoms = AtomTable::new();
283 let mut sm = SourceErrorManager::new();
284 assert_eq!(
285 parse_ok(&arena, &atoms, &mut sm, "true").and_then(|v| v.as_boolean()),
286 Some(true)
287 );
288 assert_eq!(
289 parse_ok(&arena, &atoms, &mut sm, "false").and_then(|v| v.as_boolean()),
290 Some(false)
291 );
292 assert_eq!(
293 parse_ok(&arena, &atoms, &mut sm, "null").map(|v| v.kind()),
294 Some(JSONKind::Null)
295 );
296 assert_eq!(
297 parse_ok(&arena, &atoms, &mut sm, "42").and_then(|v| v.as_number()),
298 Some(42.0)
299 );
300 assert_eq!(
301 parse_ok(&arena, &atoms, &mut sm, "-1.5").and_then(|v| v.as_number()),
302 Some(-1.5)
303 );
304 let s = parse_ok(&arena, &atoms, &mut sm, "'hi'")
305 .unwrap()
306 .as_string()
307 .unwrap();
308 assert_eq!(atoms.bytes(s), b"hi");
309 }
310
311 fn with_parse<R>(src: &str, f: impl FnOnce(Option<&JSONValue<'_>>, &AtomTable) -> R) -> R {
314 let arena = Bump::new();
315 let atoms = AtomTable::new();
316 let factory = arena.alloc(JSONFactory::new(&arena, &atoms));
317 let mut sm = SourceErrorManager::new();
318 let id = sm.add_buffer("json", src);
319 let mut parser = JSONParser::new(factory, id, &mut sm, &atoms, false);
320 let result = parser.parse();
321 f(result, &atoms)
322 }
323
324 #[test]
325 fn arrays() {
326 with_parse("[-1.0, -1, -0]", |r, _| {
327 let v = r.unwrap().as_array().unwrap();
328 assert_eq!(v.len(), 3);
329 assert_eq!(v.at(0).as_number(), Some(-1.0));
330 assert_eq!(v.at(2).as_number(), Some(-0.0));
331 });
332 with_parse("[]", |r, _| assert!(r.unwrap().as_array().unwrap().is_empty()));
333 with_parse("[1,2,3,]", |r, _| assert!(r.is_some()));
335 with_parse("[1,2", |r, _| assert!(r.is_none()));
337 }
338
339 #[test]
340 fn lone_minus_errors() {
341 let arena = Bump::new();
343 let atoms = AtomTable::new();
344 let f = arena.alloc(JSONFactory::new(&arena, &atoms));
345 let mut sm = SourceErrorManager::new();
346 let id = sm.add_buffer("json", "-");
347 let mut p = JSONParser::new(f, id, &mut sm, &atoms, false);
348 assert!(p.parse().is_none());
349 assert_eq!(p.error_count(), 1);
350 }
351}