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