1use std::fmt::Write;
9
10use num_bigint::BigInt;
11
12use crate::error::{DogeError, DogeResult};
13use crate::ordered_map::OrderedMap;
14use crate::stdlib::serialize::{escape_str, too_deep, unsupported, MAX_DEPTH};
15use crate::stdlib::str_arg;
16use crate::value::Value;
17
18pub fn json_parse(text: &Value) -> DogeResult {
21 let text = str_arg("json", "parse", text)?;
22 let mut p = Parser {
23 chars: text.chars().collect(),
24 pos: 0,
25 };
26 p.skip_ws();
27 let value = p.value(0)?;
28 p.skip_ws();
29 if p.pos != p.chars.len() {
30 return Err(p.error("expected end of input"));
31 }
32 Ok(value)
33}
34
35pub fn json_emit(value: &Value) -> DogeResult {
39 let mut out = String::new();
40 emit(value, &mut out, 0)?;
41 Ok(Value::str(out))
42}
43
44fn emit(value: &Value, out: &mut String, depth: usize) -> Result<(), DogeError> {
45 if depth >= MAX_DEPTH {
46 return Err(too_deep("json", "emit"));
47 }
48 match value {
49 Value::None => out.push_str("null"),
50 Value::Bool(b) => out.push_str(if *b { "true" } else { "false" }),
51 Value::Int(n) => {
52 let _ = write!(out, "{n}");
53 }
54 Value::Decimal(d) => {
58 let _ = write!(out, "{d}");
59 }
60 Value::Float(x) => {
61 if !x.is_finite() {
62 return Err(DogeError::value_error(
63 "json.emit cannot serialize a Float that is not finite",
64 ));
65 }
66 if x.fract() == 0.0 {
69 let _ = write!(out, "{x:.1}");
70 } else {
71 let _ = write!(out, "{x}");
72 }
73 }
74 Value::Str(s) => escape_str(s, out, |o, cp| {
75 let _ = write!(o, "\\u{cp:04x}");
76 }),
77 Value::List(items) => {
78 out.push('[');
79 for (i, item) in items.borrow().iter().enumerate() {
80 if i > 0 {
81 out.push(',');
82 }
83 emit(item, out, depth + 1)?;
84 }
85 out.push(']');
86 }
87 Value::Dict(entries) => {
88 out.push('{');
89 for (i, (key, val)) in entries.borrow().iter().enumerate() {
90 if i > 0 {
91 out.push(',');
92 }
93 escape_str(key, out, |o, cp| {
94 let _ = write!(o, "\\u{cp:04x}");
95 });
96 out.push(':');
97 emit(val, out, depth + 1)?;
98 }
99 out.push('}');
100 }
101 other => return Err(unsupported("json", other)),
102 }
103 Ok(())
104}
105
106struct Parser {
107 chars: Vec<char>,
108 pos: usize,
109}
110
111impl Parser {
112 fn error(&self, what: &str) -> DogeError {
113 DogeError::value_error(format!(
114 "json.parse: much invalid. {what} at offset {}",
115 self.pos
116 ))
117 }
118
119 fn peek(&self) -> Option<char> {
120 self.chars.get(self.pos).copied()
121 }
122
123 fn skip_ws(&mut self) {
124 while matches!(self.peek(), Some(' ' | '\t' | '\n' | '\r')) {
125 self.pos += 1;
126 }
127 }
128
129 fn value(&mut self, depth: usize) -> DogeResult {
130 if depth >= MAX_DEPTH {
131 return Err(too_deep("json", "parse"));
132 }
133 match self.peek() {
134 Some('{') => self.object(depth),
135 Some('[') => self.array(depth),
136 Some('"') => Ok(Value::str(self.string()?)),
137 Some('t') => self.keyword("true", Value::Bool(true)),
138 Some('f') => self.keyword("false", Value::Bool(false)),
139 Some('n') => self.keyword("null", Value::None),
140 Some(c) if c == '-' || c.is_ascii_digit() => self.number(),
141 Some(_) => Err(self.error("unexpected character")),
142 None => Err(self.error("unexpected end of input")),
143 }
144 }
145
146 fn keyword(&mut self, word: &str, value: Value) -> DogeResult {
147 for expected in word.chars() {
148 if self.peek() != Some(expected) {
149 return Err(self.error("unexpected character"));
150 }
151 self.pos += 1;
152 }
153 Ok(value)
154 }
155
156 fn object(&mut self, depth: usize) -> DogeResult {
157 self.pos += 1; let mut map = OrderedMap::new();
159 self.skip_ws();
160 if self.peek() == Some('}') {
161 self.pos += 1;
162 return Ok(Value::dict(map));
163 }
164 loop {
165 self.skip_ws();
166 if self.peek() != Some('"') {
167 return Err(self.error("expected a string key"));
168 }
169 let key = self.string()?;
170 self.skip_ws();
171 if self.peek() != Some(':') {
172 return Err(self.error("expected ':'"));
173 }
174 self.pos += 1;
175 self.skip_ws();
176 let val = self.value(depth + 1)?;
177 map.insert(key, val);
178 self.skip_ws();
179 match self.peek() {
180 Some(',') => self.pos += 1,
181 Some('}') => {
182 self.pos += 1;
183 return Ok(Value::dict(map));
184 }
185 _ => return Err(self.error("expected ',' or '}'")),
186 }
187 }
188 }
189
190 fn array(&mut self, depth: usize) -> DogeResult {
191 self.pos += 1; let mut items = Vec::new();
193 self.skip_ws();
194 if self.peek() == Some(']') {
195 self.pos += 1;
196 return Ok(Value::list(items));
197 }
198 loop {
199 self.skip_ws();
200 items.push(self.value(depth + 1)?);
201 self.skip_ws();
202 match self.peek() {
203 Some(',') => self.pos += 1,
204 Some(']') => {
205 self.pos += 1;
206 return Ok(Value::list(items));
207 }
208 _ => return Err(self.error("expected ',' or ']'")),
209 }
210 }
211 }
212
213 fn string(&mut self) -> DogeResult<String> {
214 self.pos += 1; let mut s = String::new();
216 loop {
217 match self.peek() {
218 None => return Err(self.error("unterminated string")),
219 Some('"') => {
220 self.pos += 1;
221 return Ok(s);
222 }
223 Some('\\') => {
224 self.pos += 1;
225 self.escape(&mut s)?;
226 }
227 Some(c) if (c as u32) < 0x20 => {
228 return Err(self.error("control character in a string"))
229 }
230 Some(c) => {
231 s.push(c);
232 self.pos += 1;
233 }
234 }
235 }
236 }
237
238 fn escape(&mut self, s: &mut String) -> DogeResult<()> {
239 match self.peek() {
240 Some('"') => s.push('"'),
241 Some('\\') => s.push('\\'),
242 Some('/') => s.push('/'),
243 Some('b') => s.push('\u{08}'),
244 Some('f') => s.push('\u{0c}'),
245 Some('n') => s.push('\n'),
246 Some('r') => s.push('\r'),
247 Some('t') => s.push('\t'),
248 Some('u') => {
249 self.pos += 1;
250 return self.unicode_escape(s);
251 }
252 _ => return Err(self.error("invalid escape")),
253 }
254 self.pos += 1;
255 Ok(())
256 }
257
258 fn unicode_escape(&mut self, s: &mut String) -> DogeResult<()> {
262 let hi = self.hex4()?;
263 let cp = if (0xd800..=0xdbff).contains(&hi) {
264 if self.peek() != Some('\\') {
265 return Err(self.error("lone surrogate in a \\u escape"));
266 }
267 self.pos += 1;
268 if self.peek() != Some('u') {
269 return Err(self.error("lone surrogate in a \\u escape"));
270 }
271 self.pos += 1;
272 let lo = self.hex4()?;
273 if !(0xdc00..=0xdfff).contains(&lo) {
274 return Err(self.error("invalid low surrogate in a \\u escape"));
275 }
276 0x10000 + ((hi - 0xd800) << 10) + (lo - 0xdc00)
277 } else if (0xdc00..=0xdfff).contains(&hi) {
278 return Err(self.error("lone surrogate in a \\u escape"));
279 } else {
280 hi
281 };
282 match char::from_u32(cp) {
283 Some(c) => {
284 s.push(c);
285 Ok(())
286 }
287 None => Err(self.error("invalid code point in a \\u escape")),
288 }
289 }
290
291 fn hex4(&mut self) -> DogeResult<u32> {
292 let mut value = 0u32;
293 for _ in 0..4 {
294 match self.peek().and_then(|c| c.to_digit(16)) {
295 Some(d) => {
296 value = value * 16 + d;
297 self.pos += 1;
298 }
299 None => return Err(self.error("expected four hex digits after \\u")),
300 }
301 }
302 Ok(value)
303 }
304
305 fn number(&mut self) -> DogeResult {
308 let start = self.pos;
309 if self.peek() == Some('-') {
310 self.pos += 1;
311 }
312 self.digits()?;
313 let mut is_float = false;
314 if self.peek() == Some('.') {
315 is_float = true;
316 self.pos += 1;
317 self.digits()?;
318 }
319 if matches!(self.peek(), Some('e' | 'E')) {
320 is_float = true;
321 self.pos += 1;
322 if matches!(self.peek(), Some('+' | '-')) {
323 self.pos += 1;
324 }
325 self.digits()?;
326 }
327 let literal: String = self.chars[start..self.pos].iter().collect();
328 if !is_float {
329 if let Ok(n) = literal.parse::<BigInt>() {
330 return Ok(Value::Int(n));
331 }
332 }
333 match literal.parse::<f64>() {
334 Ok(x) => Ok(Value::Float(x)),
335 Err(_) => Err(self.error("invalid number")),
336 }
337 }
338
339 fn digits(&mut self) -> DogeResult<()> {
340 if !matches!(self.peek(), Some(c) if c.is_ascii_digit()) {
341 return Err(self.error("expected a digit"));
342 }
343 while matches!(self.peek(), Some(c) if c.is_ascii_digit()) {
344 self.pos += 1;
345 }
346 Ok(())
347 }
348}
349
350#[cfg(test)]
351mod tests {
352 use super::*;
353 use crate::error::ErrorKind;
354 use crate::ops::values_equal;
355
356 fn parse(text: &str) -> DogeResult {
357 json_parse(&Value::str(text))
358 }
359
360 fn emit_str(v: &Value) -> String {
361 match json_emit(v).unwrap() {
362 Value::Str(s) => s.to_string(),
363 other => panic!("expected a Str, got {other:?}"),
364 }
365 }
366
367 #[test]
368 fn scalars_parse_to_the_right_types() {
369 assert!(matches!(parse("null").unwrap(), Value::None));
370 assert!(matches!(parse("true").unwrap(), Value::Bool(true)));
371 assert!(matches!(parse("false").unwrap(), Value::Bool(false)));
372 assert!(values_equal(&parse(" 42 ").unwrap(), &Value::int(42)));
373 assert!(values_equal(&parse("-7").unwrap(), &Value::int(-7)));
374 assert!(matches!(parse("\"wow\"").unwrap(), Value::Str(s) if &*s == "wow"));
375 }
376
377 #[test]
378 fn a_fraction_or_exponent_is_a_float_but_a_bare_integer_is_an_int() {
379 assert!(matches!(parse("3.5").unwrap(), Value::Float(x) if x == 3.5));
380 assert!(matches!(parse("3.0").unwrap(), Value::Float(x) if x == 3.0));
381 assert!(matches!(parse("1e2").unwrap(), Value::Float(x) if x == 100.0));
382 assert!(values_equal(&parse("100").unwrap(), &Value::int(100)));
383 }
384
385 #[test]
386 fn an_integer_past_i64_parses_exactly() {
387 let big = "9223372036854775808";
390 assert_eq!(parse(big).unwrap().to_string(), big);
391 }
392
393 #[test]
394 fn nested_structure_round_trips_through_emit() {
395 let src = "{\"name\":\"kabosu\",\"tags\":[\"doge\",\"shibe\"],\"age\":7,\"good\":true,\"note\":null}";
396 let value = parse(src).unwrap();
397 assert_eq!(emit_str(&value), src);
398 }
399
400 #[test]
401 fn a_surrogate_pair_decodes_to_one_astral_character() {
402 assert!(matches!(parse("\"\\ud83d\\udc15\"").unwrap(), Value::Str(s) if &*s == "🐕"));
404 }
405
406 #[test]
407 fn a_duplicate_key_keeps_the_last_value() {
408 assert_eq!(emit_str(&parse("{\"a\":1,\"a\":2}").unwrap()), "{\"a\":2}");
409 }
410
411 #[test]
412 fn emit_escapes_quotes_and_control_characters() {
413 assert_eq!(
414 emit_str(&Value::str("a\"b\n\t\u{01}")),
415 "\"a\\\"b\\n\\t\\u0001\""
416 );
417 }
418
419 #[test]
420 fn trailing_garbage_is_a_catchable_value_error() {
421 assert_eq!(parse("[1, 2] wow").unwrap_err().kind, ErrorKind::ValueError);
422 }
423
424 #[test]
425 fn deep_nesting_is_a_catchable_error_not_a_stack_overflow() {
426 let deep = "[".repeat(MAX_DEPTH + 5);
427 assert_eq!(parse(&deep).unwrap_err().kind, ErrorKind::ValueError);
428 }
429
430 #[test]
431 fn a_non_finite_float_cannot_be_emitted() {
432 assert_eq!(
433 json_emit(&Value::Float(f64::NAN)).unwrap_err().kind,
434 ErrorKind::ValueError
435 );
436 }
437
438 #[test]
439 fn an_unsupported_type_is_a_catchable_type_error() {
440 let f = Value::function(0, "greet", vec![]);
441 assert_eq!(json_emit(&f).unwrap_err().kind, ErrorKind::TypeError);
442 }
443
444 #[test]
445 fn a_non_str_argument_to_parse_is_a_type_error() {
446 assert_eq!(
447 json_parse(&Value::int(1)).unwrap_err().kind,
448 ErrorKind::TypeError
449 );
450 }
451}