1use nom::{
2 branch::alt,
3 bytes::complete::{escaped, tag, take_while, take_till1, take_while_m_n},
4 character::complete::char,
5 combinator::{cut, map, opt, value, peek},
6 error::{context, ContextError, ParseError, VerboseError, convert_error},
7 multi::separated_list0,
8 number::complete::double,
9 sequence::{delimited, preceded, separated_pair, terminated},
10 IResult,
11};
12use std::str;
13
14#[derive(Debug, PartialEq)]
15pub enum JsonValue {
16 Str(String),
17 Boolean(bool),
18 Num(f64),
19 Array(Vec<JsonValue>),
20 Object(Vec<(String, JsonValue)>),
21}
22
23fn sp<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
24 let chars = " \t\r\n";
25
26 take_while(move |c| chars.contains(c))(i)
27}
28
29fn parse_str<'a, E: ParseError<&'a str> + ContextError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
30 escaped(normal, '\\', escapable)(i)
31}
32
33fn escapable<'a, E: ParseError<&'a str> + ContextError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
34 context(
35 "escaped",
36 alt((
37 tag("\""),
38 tag("\\"),
39 tag("/"),
40 tag("b"),
41 tag("f"),
42 tag("n"),
43 tag("r"),
44 tag("t"),
45 parse_hex,
46 )),
47 )(i)
48}
49
50
51fn parse_hex<'a, E: ParseError<&'a str> + ContextError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
52 context(
53 "hex string",
54 preceded(
55 peek(tag("u")),
56 take_while_m_n(5, 5, |c: char| c.is_ascii_hexdigit() || c == 'u'),
57 ),
58 )(i)
59}
60
61fn normal<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
62 take_till1(|c: char| c == '\\' || c == '"' || c.is_ascii_control())(i)
63}
64
65fn boolean<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, bool, E> {
66 alt(
67 (
68 value(true, tag("true")),
69 value(false, tag("false")),
70 )
71 )(input)
72}
73
74fn string<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
75 i: &'a str,
76) -> IResult<&'a str, &'a str, E> {
77 context(
78 "string",
79 alt((tag("\"\""), delimited(tag("\""), parse_str,tag("\"")))),
80 )(i)
81}
82
83fn array<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
84 i: &'a str,
85) -> IResult<&'a str, Vec<JsonValue>, E> {
86 context(
87 "array",
88 preceded(
89 char('['),
90 cut(terminated(
91 separated_list0(preceded(sp, char(',')), json_value),
92 preceded(sp, char(']')),
93 )),
94 ),
95 )(i)
96}
97
98fn key_value<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
99 i: &'a str,
100) -> IResult<&'a str, (&'a str, JsonValue), E> {
101 separated_pair(
102 preceded(sp, string),
103 cut(preceded(sp, char(':'))),
104 json_value,
105 )(i)
106}
107
108fn hash<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
109 i: &'a str,
110) -> IResult<&'a str, Vec<(String, JsonValue)>, E> {
111 context(
112 "map",
113 preceded(
114 char('{'),
115 cut(terminated(
116 map(
117 separated_list0(preceded(sp, char(',')), key_value),
118 |tuple_vec| {
119 tuple_vec
120 .into_iter()
121 .map(|(k, v)| (String::from(k), v))
122 .collect()
123 },
124 ),
125 preceded(sp, char('}')),
126 )),
127 ),
128 )(i)
129}
130
131fn json_value<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
133 i: &'a str,
134) -> IResult<&'a str, JsonValue, E> {
135 preceded(
136 sp,
137 alt((
138 map(hash, JsonValue::Object),
139 map(array, JsonValue::Array),
140 map(string, |s| JsonValue::Str(String::from(s))),
141 map(double, JsonValue::Num),
142 map(boolean, JsonValue::Boolean),
143 )),
144 )(i)
145}
146
147fn root(
149 i: &str,
150) -> IResult<&str, JsonValue, VerboseError<&str>> {
151 delimited(
152 sp,
153 alt((map(hash, JsonValue::Object), map(array, JsonValue::Array))),
154 opt(sp),
155 )(i)
156}
157
158pub fn parse_root(i: &str) -> Result<JsonValue, Box<dyn std::error::Error + 'static>> {
160 match root(i) {
161 Ok((_, json_value)) => {
162 Ok(json_value)
163 },
164 Err(nom::Err::Error(e)) => {
165 Err(convert_error(i, e).into())
166 },
167 Err(nom::Err::Failure(e)) => {
168 Err(convert_error(i, e).into())
169 },
170 Err(nom::Err::Incomplete(_)) => {
171 Err("incomplete json".into())
172 }
173 }
174}