1use crate::{ArrayType, Value};
2use indexmap::IndexMap;
3use nom::{
4 branch::alt,
5 bytes::complete::{tag, take_while},
6 character::{
7 complete::{alpha1, char, one_of},
8 streaming::alphanumeric1,
9 },
10 combinator::{cut, map, map_res, opt, recognize, value},
11 error::{context, ContextError, FromExternalError, ParseError},
12 multi::{many0_count, many1, separated_list0},
13 number::complete::double,
14 sequence::{delimited, pair, preceded, separated_pair, terminated},
15 IResult,
16};
17mod string;
18
19fn sp<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
20 let chars = " \t\r\n";
21 take_while(move |c| chars.contains(c))(i)
22}
23
24fn boolean<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, bool, E> {
25 alt((value(true, tag("true")), value(false, tag("false"))))(input)
26}
27
28fn number<'a, E: ParseError<&'a str> + FromExternalError<&'a str, std::num::ParseIntError>>(
29 i: &'a str,
30) -> IResult<&'a str, i64, E> {
31 terminated(
32 alt((
33 map_res(
34 recognize(many1(one_of("0123456789.eE"))),
35 |digit_str: &str| digit_str.parse::<i64>(),
36 ),
37 map_res(
38 preceded(tag("-"), recognize(many1(one_of("0123456789.eE")))),
39 |digit_str: &str| digit_str.parse::<i64>().map(|v| -v),
40 ),
41 )),
42 opt(tag("L")),
43 )(i)
44}
45
46fn key<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
47 i: &'a str,
48) -> IResult<&'a str, &'a str, E> {
49 context(
50 "ident",
51 recognize(pair(
52 alt((alpha1, tag("_"))),
53 many0_count(alt((alphanumeric1, tag("_")))),
54 )),
55 )(i)
56}
57
58fn string<
59 'a,
60 E: ParseError<&'a str>
61 + ContextError<&'a str>
62 + FromExternalError<&'a str, std::num::ParseIntError>,
63>(
64 i: &'a str,
65) -> IResult<&'a str, String, E> {
66 context("string", string::parse)(i)
67}
68
69fn array<
70 'a,
71 E: ParseError<&'a str>
72 + ContextError<&'a str>
73 + FromExternalError<&'a str, std::num::ParseIntError>,
74>(
75 i: &'a str,
76) -> IResult<&'a str, Vec<Value>, E> {
77 context(
78 "array",
79 preceded(
80 char('['),
81 cut(terminated(
82 separated_list0(preceded(sp, char(',')), libconfig_value),
83 preceded(sp, char(']')),
84 )),
85 ),
86 )(i)
87}
88
89fn list<
90 'a,
91 E: ParseError<&'a str>
92 + ContextError<&'a str>
93 + FromExternalError<&'a str, std::num::ParseIntError>,
94>(
95 i: &'a str,
96) -> IResult<&'a str, Vec<Value>, E> {
97 context(
98 "list",
99 preceded(
100 char('('),
101 cut(terminated(
102 separated_list0(preceded(sp, char(',')), libconfig_value),
103 preceded(sp, char(')')),
104 )),
105 ),
106 )(i)
107}
108
109fn key_value<
110 'a,
111 E: ParseError<&'a str>
112 + ContextError<&'a str>
113 + FromExternalError<&'a str, std::num::ParseIntError>,
114>(
115 i: &'a str,
116) -> IResult<&'a str, (&'a str, Value), E> {
117 terminated(
118 separated_pair(
119 preceded(sp, key),
120 cut(preceded(sp, char(':'))),
121 libconfig_value,
122 ),
123 tag(";"),
124 )(i)
125}
126
127fn hash<
128 'a,
129 E: ParseError<&'a str>
130 + ContextError<&'a str>
131 + FromExternalError<&'a str, std::num::ParseIntError>,
132>(
133 i: &'a str,
134) -> IResult<&'a str, IndexMap<String, Value>, E> {
135 context(
136 "map",
137 preceded(
138 char('{'),
139 cut(terminated(
140 map(separated_list0(sp, key_value), |tuple_vec| {
141 tuple_vec
142 .into_iter()
143 .map(|(k, v)| (String::from(k), v))
144 .collect()
145 }),
146 preceded(sp, char('}')),
147 )),
148 ),
149 )(i)
150}
151
152fn libconfig_value<
153 'a,
154 E: ParseError<&'a str>
155 + ContextError<&'a str>
156 + FromExternalError<&'a str, std::num::ParseIntError>,
157>(
158 i: &'a str,
159) -> IResult<&'a str, Value, E> {
160 preceded(
161 sp,
162 alt((
163 map(hash, Value::Object),
164 map(array, |v| Value::Array(v, ArrayType::Array)),
165 map(list, |v| Value::Array(v, ArrayType::List)),
166 map(string, Value::String),
167 map(boolean, Value::Bool),
168 map(number, Value::Int),
169 map(double, Value::Float),
170 )),
171 )(i)
172}
173
174pub fn root<
175 'a,
176 E: ParseError<&'a str>
177 + ContextError<&'a str>
178 + FromExternalError<&'a str, std::num::ParseIntError>,
179>(
180 i: &'a str,
181) -> IResult<&'a str, Value, E> {
182 delimited(sp, map(key_value, |(_, v)| v), opt(sp))(i)
183}