1use std::convert::TryFrom;
2
3use nom::{
4 branch::alt,
5 bytes::complete::{escaped, is_not, tag},
6 character::complete::{char, digit1, multispace0, one_of},
7 combinator::{map, not, opt, recognize},
8 multi::separated_list,
9 number::complete::double,
10 re_find,
11 sequence::{delimited, preceded, terminated, tuple},
12 IResult,
13};
14
15use super::Value;
16use crate::value::Arg;
17use crate::value::Arg::Kwarg;
18
19pub fn parse_bool(input: &str) -> IResult<&str, Value> {
20 alt((
21 map(tag("True"), |_| Value::Bool(true)),
22 map(tag("False"), |_| Value::Bool(false)),
23 ))(input)
24}
25
26pub fn parse_str(input: &str) -> IResult<&str, Value> {
27 let single_quoted_str_escape = r#"\'abfnNrtuUvx01234567"#;
42 let double_quoted_str_escape = r#"\"abfnNrtuUvx01234567"#;
43
44 let single_quoted = recognize(delimited(
45 char('\''),
46 escaped(is_not(r#"'\"#), '\\', one_of(single_quoted_str_escape)),
47 char('\''),
48 ));
49 let double_quoted = recognize(delimited(
50 char('"'),
51 escaped(is_not(r#""\"#), '\\', one_of(double_quoted_str_escape)),
52 char('"'),
53 ));
54 map(alt((single_quoted, double_quoted)), Value::Str)(input)
55}
56
57pub fn parse_int(input: &str) -> IResult<&str, Value> {
58 map(
59 tuple((opt(tag("-")), terminated(digit1, not(tag("."))))),
60 |(sign, s): (Option<&str>, &str)| {
61 let sign = if sign.is_some() { -1 } else { 1 };
62 let i = s
63 .parse::<i64>()
64 .expect("sequence of digits can parse to int");
65 Value::Int(sign * i)
66 },
67 )(input)
68}
69
70pub fn parse_float(input: &str) -> IResult<&str, Value> {
71 map(double, Value::Float)(input)
72}
73
74fn parse_seq<'a>(
75 open: char,
76 f: impl Fn(Vec<Value<'a>>) -> Value<'a>,
77 close: char,
78) -> impl Fn(&'a str) -> IResult<&'a str, Value<'a>> {
79 move |input: &'a str| -> IResult<&'a str, Value> {
80 map(
81 delimited(
82 char(open),
83 separated_list(comma_space, parse_value),
84 char(close),
85 ),
86 &f,
87 )(input)
88 }
89}
90
91pub fn parse_list(input: &str) -> IResult<&str, Value> {
92 parse_seq('[', Value::List, ']')(input)
93}
94
95pub fn parse_tuple(input: &str) -> IResult<&str, Value> {
96 parse_seq('(', Value::Tuple, ')')(input)
97}
98
99pub fn parse_set(input: &str) -> IResult<&str, Value> {
100 parse_seq('{', Value::Set, '}')(input)
101}
102
103fn colon_space(input: &str) -> IResult<&str, ()> {
104 map(preceded(char(':'), multispace0), |_| ())(input)
105}
106
107fn parse_dict_key_value(input: &str) -> IResult<&str, (Value, Value)> {
108 tuple((parse_value, preceded(colon_space, parse_value)))(input)
109}
110
111fn comma_space(input: &str) -> IResult<&str, ()> {
112 map(preceded(char(','), multispace0), |_| ())(input)
113}
114
115pub fn parse_dict(input: &str) -> IResult<&str, Value> {
116 map(
117 delimited(
118 char('{'),
119 separated_list(comma_space, parse_dict_key_value),
120 char('}'),
121 ),
122 Value::Dict,
123 )(input)
124}
125
126fn identifier(input: &str) -> IResult<&str, &str> {
127 re_find!(
128 input,
129 r"^([a-zA-Z_][a-zA-Z0-9_]*)(\.[a-zA-Z_][a-zA-Z0-9_]*)*"
130 )
131}
132
133pub fn parse_symbol(input: &str) -> IResult<&str, Value> {
134 map(identifier, Value::Symbol)(input)
135}
136
137fn parse_arg(input: &str) -> IResult<&str, Arg> {
138 alt((
139 map(
140 tuple((identifier, preceded(char('='), parse_value))),
141 |(ident, value)| Kwarg(ident, value),
142 ),
143 map(parse_value, Arg::Arg),
144 ))(input)
145}
146
147pub fn parse_constructor(input: &str) -> IResult<&str, Value> {
148 map(
149 tuple((
150 identifier,
151 delimited(char('('), separated_list(comma_space, parse_arg), char(')')),
152 )),
153 |(name, kwargs)| Value::Constructor(name, kwargs),
154 )(input)
155}
156
157pub fn parse_value(input: &str) -> IResult<&str, Value> {
158 alt((
159 parse_int,
160 parse_float, parse_bool,
162 parse_str,
163 parse_list,
164 parse_tuple,
165 parse_dict,
166 parse_set, parse_constructor,
168 parse_symbol,
169 ))(input)
170}
171
172impl<'a> TryFrom<&'a str> for Value<'a> {
173 type Error = nom::Err<(&'a str, nom::error::ErrorKind)>;
174
175 fn try_from(input: &'a str) -> Result<Self, Self::Error> {
176 match parse_value(input) {
177 Ok((_rest, value)) => Ok(value),
178 Err(err) => Err(err),
179 }
180 }
181}