1use crate::data::{Data, NULL};
15use crate::gc::GcState;
16use crate::gc::Heap;
17use crate::rt::EnumType;
18use crate::rt::Struct;
19use crate::vm::map_insert;
20use crate::vm::{MapPool, ObjectPool, RegisterFile, StringPool};
21
22const MAX_NESTING_DEPTH: u32 = 128;
27
28struct JsonParser<'a> {
29 bytes: &'a [u8],
30 pos: usize,
31 depth: u32,
32}
33
34impl JsonParser<'_> {
35 fn skip_ws(&mut self) {
36 while self.pos < self.bytes.len() {
37 match self.bytes[self.pos] {
38 b' ' | b'\t' | b'\n' | b'\r' => self.pos += 1,
39 _ => break,
40 }
41 }
42 }
43
44 fn peek(&self) -> Option<u8> {
45 self.bytes.get(self.pos).copied()
46 }
47
48 fn parse_value(&mut self, heap: &mut Heap<'_>) -> Result<Data, &'static str> {
52 self.skip_ws();
53 match self.peek() {
54 Some(open @ (b'{' | b'[')) => {
55 self.depth += 1;
56 if self.depth > MAX_NESTING_DEPTH {
57 return Err("nesting too deep");
58 }
59 self.pos += 1;
60 Ok(if open == b'{' {
61 heap.map()
62 } else {
63 heap.array()
64 })
65 }
66 Some(b'"') => {
67 let s = self.parse_string()?;
68 Ok(heap.string(&s))
69 }
70 Some(b't') | Some(b'f') => self.parse_bool(),
71 Some(b'n') => self.parse_null(),
72 Some(c) if c == b'-' || c.is_ascii_digit() => self.parse_number(),
73 Some(_) => Err("unexpected character"),
74 None => Err("unexpected end of input"),
75 }
76 }
77
78 fn fill(&mut self, heap: &mut Heap<'_>, d: Data) -> Result<(), &'static str> {
81 if d.is_array() {
82 self.fill_array(heap, d.as_array())?;
83 } else if d.is_map() {
84 self.fill_object(heap, d.as_map())?;
85 } else {
86 return Ok(());
87 }
88 self.depth -= 1;
89 Ok(())
90 }
91
92 fn fill_object(&mut self, heap: &mut Heap<'_>, id: usize) -> Result<(), &'static str> {
93 self.skip_ws();
94 if self.peek() == Some(b'}') {
95 self.pos += 1;
96 return Ok(());
97 }
98 loop {
99 self.skip_ws();
100 if self.peek() != Some(b'"') {
101 return Err("object key must be a string");
102 }
103 let key = self.parse_string()?;
104 let key = heap.string(&key);
105 self.skip_ws();
106 if self.peek() != Some(b':') {
107 return Err("expected ':' after object key");
108 }
109 self.pos += 1;
110 map_insert(&mut heap.maps[id], key, NULL, heap.strings);
114 let val = self.parse_value(heap)?;
115 map_insert(&mut heap.maps[id], key, val, heap.strings);
116 self.fill(heap, val)?;
117 self.skip_ws();
118 match self.peek() {
119 Some(b',') => self.pos += 1,
120 Some(b'}') => {
121 self.pos += 1;
122 return Ok(());
123 }
124 _ => return Err("expected ',' or '}' in object"),
125 }
126 }
127 }
128
129 fn fill_array(&mut self, heap: &mut Heap<'_>, id: usize) -> Result<(), &'static str> {
130 self.skip_ws();
131 if self.peek() == Some(b']') {
132 self.pos += 1;
133 return Ok(());
134 }
135 loop {
136 let val = self.parse_value(heap)?;
137 heap.objs[id].push(val);
138 self.fill(heap, val)?;
139 self.skip_ws();
140 match self.peek() {
141 Some(b',') => self.pos += 1,
142 Some(b']') => {
143 self.pos += 1;
144 return Ok(());
145 }
146 _ => return Err("expected ',' or ']' in array"),
147 }
148 }
149 }
150
151 fn parse_string(&mut self) -> Result<String, &'static str> {
152 self.pos += 1; let mut out = String::new();
154 loop {
155 let Some(c) = self.peek() else {
156 return Err("unterminated string");
157 };
158 self.pos += 1;
159 match c {
160 b'"' => return Ok(out),
161 b'\\' => {
162 let Some(esc) = self.peek() else {
163 return Err("unterminated escape");
164 };
165 self.pos += 1;
166 match esc {
167 b'"' => out.push('"'),
168 b'\\' => out.push('\\'),
169 b'/' => out.push('/'),
170 b'b' => out.push('\u{0008}'),
171 b'f' => out.push('\u{000C}'),
172 b'n' => out.push('\n'),
173 b'r' => out.push('\r'),
174 b't' => out.push('\t'),
175 b'u' => {
176 let cp = self.parse_hex4()?;
177 if (0xD800..=0xDBFF).contains(&cp) {
178 if self.peek() != Some(b'\\') {
180 return Err("unpaired surrogate");
181 }
182 self.pos += 1;
183 if self.peek() != Some(b'u') {
184 return Err("unpaired surrogate");
185 }
186 self.pos += 1;
187 let low = self.parse_hex4()?;
188 if !(0xDC00..=0xDFFF).contains(&low) {
189 return Err("invalid low surrogate");
190 }
191 let c = 0x10000 + ((cp - 0xD800) << 10) + (low - 0xDC00);
192 match char::from_u32(c) {
193 Some(ch) => out.push(ch),
194 None => return Err("invalid unicode escape"),
195 }
196 } else {
197 match char::from_u32(cp) {
198 Some(ch) => out.push(ch),
199 None => return Err("invalid unicode escape"),
200 }
201 }
202 }
203 _ => return Err("invalid escape"),
204 }
205 }
206 c if c.is_ascii() => out.push(c as char),
207 c => {
210 let start = self.pos - 1;
211 let len = if c >= 0xF0 {
212 4
213 } else if c >= 0xE0 {
214 3
215 } else {
216 2
217 };
218 let end = (start + len).min(self.bytes.len());
219 match std::str::from_utf8(&self.bytes[start..end]) {
220 Ok(ch) => out.push_str(ch),
221 Err(_) => return Err("invalid utf-8"),
222 }
223 self.pos = end;
224 }
225 }
226 }
227 }
228
229 fn parse_hex4(&mut self) -> Result<u32, &'static str> {
230 if self.pos + 4 > self.bytes.len() {
231 return Err("truncated unicode escape");
232 }
233 let mut v: u32 = 0;
234 for _ in 0..4 {
235 let d = self.bytes[self.pos];
236 self.pos += 1;
237 let n = match d {
238 b'0'..=b'9' => (d - b'0') as u32,
239 b'a'..=b'f' => (d - b'a' + 10) as u32,
240 b'A'..=b'F' => (d - b'A' + 10) as u32,
241 _ => return Err("invalid hex digit"),
242 };
243 v = (v << 4) | n;
244 }
245 Ok(v)
246 }
247
248 fn parse_bool(&mut self) -> Result<Data, &'static str> {
249 if self.bytes[self.pos..].starts_with(b"true") {
250 self.pos += 4;
251 Ok(Data::bool(true))
252 } else if self.bytes[self.pos..].starts_with(b"false") {
253 self.pos += 5;
254 Ok(Data::bool(false))
255 } else {
256 Err("invalid literal")
257 }
258 }
259
260 fn parse_null(&mut self) -> Result<Data, &'static str> {
261 if self.bytes[self.pos..].starts_with(b"null") {
262 self.pos += 4;
263 Ok(NULL)
264 } else {
265 Err("invalid literal")
266 }
267 }
268
269 fn parse_number(&mut self) -> Result<Data, &'static str> {
270 let start = self.pos;
271 let mut is_float = false;
272 if self.peek() == Some(b'-') {
273 self.pos += 1;
274 }
275 while let Some(c) = self.peek() {
276 match c {
277 b'0'..=b'9' => self.pos += 1,
278 b'.' | b'e' | b'E' | b'+' | b'-' => {
279 is_float = true;
280 self.pos += 1;
281 }
282 _ => break,
283 }
284 }
285 let text = match std::str::from_utf8(&self.bytes[start..self.pos]) {
286 Ok(t) => t,
287 Err(_) => return Err("invalid number"),
288 };
289 if !is_float && let Ok(n) = text.parse::<i64>() {
290 return Ok(Data::int(n));
291 }
292 match text.parse::<f64>() {
293 Ok(f) => Ok(Data::float(f)),
294 Err(_) => Err("invalid number"),
295 }
296 }
297}
298
299pub fn json_parse(
307 input: &str,
308 obj_pool: &mut ObjectPool,
309 map_pool: &mut MapPool,
310 str_pool: &mut StringPool,
311 registers: &RegisterFile,
312 recursion_stack: &mut RegisterFile,
313 gc: &mut GcState,
314) -> Result<Data, &'static str> {
315 let mut heap = Heap {
316 objs: obj_pool,
317 maps: map_pool,
318 strings: str_pool,
319 gc,
320 registers,
321 recursion_stack,
322 };
323 let mut p = JsonParser {
324 bytes: input.as_bytes(),
325 pos: 0,
326 depth: 0,
327 };
328 let v = p.parse_value(&mut heap)?;
329 heap.recursion_stack.0.push(v);
330 let filled = p.fill(&mut heap, v);
331 heap.recursion_stack.0.pop();
332 filled?;
333 p.skip_ws();
334 if p.pos != p.bytes.len() {
335 return Err("trailing characters after value");
336 }
337 Ok(v)
338}
339
340fn escape_into(s: &str, out: &mut String) {
341 out.push('"');
342 for c in s.chars() {
343 match c {
344 '"' => out.push_str("\\\""),
345 '\\' => out.push_str("\\\\"),
346 '\n' => out.push_str("\\n"),
347 '\r' => out.push_str("\\r"),
348 '\t' => out.push_str("\\t"),
349 '\u{0008}' => out.push_str("\\b"),
350 '\u{000C}' => out.push_str("\\f"),
351 c if (c as u32) < 0x20 => {
352 out.push_str(&format!("\\u{:04x}", c as u32));
353 }
354 c => out.push(c),
355 }
356 }
357 out.push('"');
358}
359
360fn write_json(
361 d: Data,
362 out: &mut String,
363 obj_pool: &ObjectPool,
364 map_pool: &MapPool,
365 str_pool: &StringPool,
366 structs: &[Struct],
367 enums: &[EnumType],
368) {
369 if d.is_int() {
370 out.push_str(&d.as_int().to_string());
371 } else if d.is_float() {
372 let f = d.as_float();
373 if f.is_finite() {
374 out.push_str(&format!("{f:?}"));
377 } else {
378 out.push_str("null");
379 }
380 } else if d.is_bool() {
381 out.push_str(if d.as_bool() { "true" } else { "false" });
382 } else if d.is_null() {
383 out.push_str("null");
384 } else if d.is_string() {
385 escape_into(d.as_str(str_pool), out);
386 } else if d.is_array() {
387 out.push('[');
388 for (i, e) in obj_pool[d.as_array()].iter().enumerate() {
389 if i != 0 {
390 out.push(',');
391 }
392 write_json(*e, out, obj_pool, map_pool, str_pool, structs, enums);
393 }
394 out.push(']');
395 } else if d.is_map() {
396 out.push('{');
397 for (i, (k, v)) in map_pool[d.as_map()].iter().enumerate() {
398 if i != 0 {
399 out.push(',');
400 }
401 if k.is_string() {
404 escape_into(k.as_str(str_pool), out);
405 } else {
406 let key = k.format(obj_pool, str_pool, map_pool, structs, enums, true);
407 escape_into(&key, out);
408 }
409 out.push(':');
410 write_json(*v, out, obj_pool, map_pool, str_pool, structs, enums);
411 }
412 out.push('}');
413 } else {
414 let s = d.format(obj_pool, str_pool, map_pool, structs, enums, true);
416 escape_into(&s, out);
417 }
418}
419
420pub fn json_stringify(
422 d: Data,
423 obj_pool: &ObjectPool,
424 map_pool: &MapPool,
425 str_pool: &StringPool,
426 structs: &[Struct],
427 enums: &[EnumType],
428) -> String {
429 let mut out = String::new();
430 write_json(d, &mut out, obj_pool, map_pool, str_pool, structs, enums);
431 out
432}
433
434#[cfg(test)]
435mod json_tests {
436 use super::MAX_NESTING_DEPTH;
437 use crate::data::Data;
438 use crate::gc::GcState;
439 use crate::vm::{MapPool, ObjectPool, Pool, RegisterFile, StringPool};
440
441 fn pools() -> (ObjectPool, MapPool, StringPool) {
442 (Pool(Vec::new()), Pool(Vec::new()), StringPool::default())
443 }
444
445 fn json_parse(
447 input: &str,
448 objs: &mut ObjectPool,
449 maps: &mut MapPool,
450 strings: &mut StringPool,
451 ) -> Result<Data, &'static str> {
452 super::json_parse(
453 input,
454 objs,
455 maps,
456 strings,
457 &RegisterFile(Vec::new()),
458 &mut RegisterFile(Vec::new()),
459 &mut GcState::default(),
460 )
461 }
462
463 #[test]
464 fn malformed_input_is_rejected() {
465 for bad in [
466 "nope",
467 "[1,",
468 "{oops",
469 "",
470 "{\"a\":}",
471 "[1] extra",
472 "\"open",
473 ] {
474 let (mut obj, mut map, mut strings) = pools();
475 assert!(
476 json_parse(bad, &mut obj, &mut map, &mut strings).is_err(),
477 "{bad:?} must not parse"
478 );
479 }
480 }
481
482 #[test]
485 fn nesting_past_the_limit_raises_instead_of_overflowing() {
486 let (mut obj, mut map, mut strings) = pools();
487 assert_eq!(
488 json_parse(&"[".repeat(200_000), &mut obj, &mut map, &mut strings),
489 Err("nesting too deep")
490 );
491
492 let (mut obj, mut map, mut strings) = pools();
493 assert_eq!(
494 json_parse(&"{\"a\":".repeat(200_000), &mut obj, &mut map, &mut strings),
495 Err("nesting too deep")
496 );
497 }
498
499 #[test]
500 fn nesting_up_to_the_limit_parses() {
501 let depth = MAX_NESTING_DEPTH as usize;
502 let doc = format!("{}{}", "[".repeat(depth), "]".repeat(depth));
503 let (mut obj, mut map, mut strings) = pools();
504 assert!(json_parse(&doc, &mut obj, &mut map, &mut strings).is_ok());
505 }
506
507 #[test]
511 fn object_keys_are_found_by_their_text() {
512 let (mut obj, mut map, mut strings) = pools();
513 let parsed = json_parse(
514 "{\"n\": 7, \"long_key_name\": 42}",
515 &mut obj,
516 &mut map,
517 &mut strings,
518 )
519 .expect("valid object parses");
520 assert!(parsed.is_map());
521
522 let short = Data::p_str("n", &mut strings);
523 let long = Data::p_str("long_key_name", &mut strings);
524 strings.push(String::from("long_key_name"));
525 let other_slot = Data::large_str_id((strings.len() - 1) as u64);
526 let entries = &map[parsed.as_map()];
527 let get = |key: Data| {
528 entries
529 .get(&crate::vm::KeyByText {
530 key,
531 strings: &strings,
532 })
533 .copied()
534 .map(Data::as_int)
535 };
536 assert_eq!(get(short), Some(7));
537 assert_eq!(get(long), Some(42));
538 assert_eq!(get(other_slot), Some(42));
539 }
540
541 #[test]
544 fn raw_non_ascii_characters_parse_as_themselves() {
545 for text in ["\u{e9}", "a\u{e9}b", "\u{4e2d}\u{6587} and \u{1f600} here"] {
546 let (mut obj, mut map, mut strings) = pools();
547 let doc = format!("\"{text}\"");
548 let parsed =
549 json_parse(&doc, &mut obj, &mut map, &mut strings).expect("valid string parses");
550 assert_eq!(parsed, Data::p_str(text, &mut strings), "{text:?}");
551 }
552 }
553
554 #[test]
557 fn equal_strings_share_a_pool_slot() {
558 let (mut obj, mut map, mut strings) = pools();
559 let parsed = json_parse(
560 "[\"a_long_repeated_value\", \"a_long_repeated_value\"]",
561 &mut obj,
562 &mut map,
563 &mut strings,
564 )
565 .expect("valid array parses");
566 let items = &obj[parsed.as_array()];
567 assert_eq!(items[0], items[1]);
568 }
569
570 #[test]
576 fn a_collection_mid_parse_keeps_the_partial_value() {
577 let entries: Vec<String> = (0..3000)
578 .map(|i| {
579 format!(
580 "{{\"id\":{i},\"name\":\"an entry named after {i}\",\"tags\":[{i},\"tag {i} of many\"]}}"
581 )
582 })
583 .collect();
584 let doc = format!("[{}]", entries.join(","));
585 let (mut objs, mut maps, mut strings) = pools();
586 let registers = RegisterFile(Vec::new());
587 let mut stack = RegisterFile(Vec::new());
588 let mut gc = GcState::default();
589 let mut parse = |objs: &mut ObjectPool, maps: &mut MapPool, strings: &mut StringPool| {
590 super::json_parse(&doc, objs, maps, strings, ®isters, &mut stack, &mut gc)
591 .expect("the document parses")
592 };
593 parse(&mut objs, &mut maps, &mut strings);
594 let parsed = parse(&mut objs, &mut maps, &mut strings);
595 assert!(gc.cycles() > 0, "the parses never started a collection");
596 assert!(stack.0.is_empty(), "the parse left its root behind");
597 let text = super::json_stringify(parsed, &objs, &maps, &strings, &[], &[]);
598 assert!(
599 text == doc,
600 "the parsed value reads back as a different document"
601 );
602 }
603}