libconfig_rs/
parser.rs

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}