1use pom::parser::*;
2
3use std::char::{decode_utf16, REPLACEMENT_CHARACTER};
4use std::collections::HashMap;
5use std::iter::FromIterator;
6use std::str::FromStr;
7
8#[derive(Debug, PartialEq)]
9pub enum JsonValue {
10 Null,
11 Bool(bool),
12 Str(String),
13 Num(f64),
14 Array(Vec<JsonValue>),
15 Object(HashMap<String, JsonValue>),
16}
17
18fn space<'a>() -> Parser<'a, char, ()> {
19 one_of(" \t\r\n").repeat(0..).discard()
20}
21
22fn number<'a>() -> Parser<'a, char, f64> {
23 let integer = one_of("123456789") - one_of("0123456789").repeat(0..) | sym('0');
24 let frac = sym('.') + one_of("0123456789").repeat(1..);
25 let exp = one_of("eE") + one_of("+-").opt() + one_of("0123456789").repeat(1..);
26 let number = sym('-').opt() + integer + frac.opt() + exp.opt();
27 number
28 .collect()
29 .map(String::from_iter)
30 .convert(|s| f64::from_str(&s))
31}
32
33fn string<'a>() -> Parser<'a, char, String> {
34 let special_char = sym('\\')
35 | sym('/')
36 | sym('"')
37 | sym('b').map(|_| '\x08')
38 | sym('f').map(|_| '\x0C')
39 | sym('n').map(|_| '\n')
40 | sym('r').map(|_| '\r')
41 | sym('t').map(|_| '\t');
42 let escape_sequence = sym('\\') * special_char;
43 let char_string = (none_of("\\\"") | escape_sequence)
44 .repeat(1..)
45 .map(String::from_iter);
46 let utf16_char = tag("\\u") * is_a(|c: char| c.is_digit(16))
47 .repeat(4)
48 .map(String::from_iter)
49 .convert(|digits| u16::from_str_radix(&digits, 16));
50 let utf16_string = utf16_char.repeat(1..).map(|chars| {
51 decode_utf16(chars)
52 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
53 .collect::<String>()
54 });
55 let string = sym('"') * (char_string | utf16_string).repeat(0..) - sym('"');
56 string.map(|strings| strings.concat())
57}
58
59fn array<'a>() -> Parser<'a, char, Vec<JsonValue>> {
60 let elems = list(call(value), sym(',') * space());
61 sym('[') * space() * elems - sym(']')
62}
63
64fn object<'a>() -> Parser<'a, char, HashMap<String, JsonValue>> {
65 let member = string() - space() - sym(':') - space() + call(value);
66 let members = list(member, sym(',') * space());
67 let obj = sym('{') * space() * members - sym('}');
68 obj.map(|members| members.into_iter().collect::<HashMap<_, _>>())
69}
70
71fn value<'a>() -> Parser<'a, char, JsonValue> {
72 (tag("null").map(|_| JsonValue::Null)
73 | tag("true").map(|_| JsonValue::Bool(true))
74 | tag("false").map(|_| JsonValue::Bool(false))
75 | number().map(|num| JsonValue::Num(num))
76 | string().map(|text| JsonValue::Str(text))
77 | array().map(|arr| JsonValue::Array(arr))
78 | object().map(|obj| JsonValue::Object(obj)))
79 - space()
80}
81
82pub fn json<'a>() -> Parser<'a, char, JsonValue> {
83 space() * value() - end()
84}
85
86#[allow(dead_code)]
87fn main() {
88 let test = r#"
89 {
90 "Image": {
91 "Width": 800,
92 "Height": 600,
93 "Title": "View from 15th Floor",
94 "Thumbnail": {
95 "Url": "http://www.example.com/image/481989943",
96 "Height": 125,
97 "Width": 100
98 },
99 "Animated" : false,
100 "IDs": [116, 943, 234, 38793]
101 },
102 "escaped characters": "\u2192\uD83D\uDE00\"\t\uD834\uDD1E"
103 }"#;
104
105 let input: Vec<char> = test.chars().collect();
106 println!("{:?}", json().parse(&input));
107}