1use std::str::FromStr;
2
3use nom::branch::alt;
4use nom::character::complete::{char as cchar, digit0, digit1};
5use nom::combinator::{map, map_res, opt, recognize};
6use nom::multi::separated_list0;
7use nom::sequence::{delimited, pair, separated_pair, tuple};
8use nom::IResult;
9
10use crate::basic::{Identifier, IdentifierRef, ListSeparator, Literal, LiteralRef, Separator};
11use crate::Parser;
12
13#[derive(Debug, Clone, PartialEq)]
15pub enum ConstValueRef<'a> {
16 Identifier(IdentifierRef<'a>),
17 Literal(LiteralRef<'a>),
18 Double(DoubleConstant),
19 Int(IntConstant),
20 List(ConstListRef<'a>),
21 Map(ConstMapRef<'a>),
22}
23
24impl<'a> Parser<'a> for ConstValueRef<'a> {
25 fn parse(input: &'a str) -> IResult<&'a str, Self> {
26 alt((
27 map(IdentifierRef::parse, ConstValueRef::Identifier),
28 map(LiteralRef::parse, ConstValueRef::Literal),
29 map(DoubleConstant::parse2, ConstValueRef::Double),
30 map(IntConstant::parse, ConstValueRef::Int),
31 map(ConstListRef::parse, ConstValueRef::List),
32 map(ConstMapRef::parse, ConstValueRef::Map),
33 ))(input)
34 }
35}
36
37#[derive(Debug, Clone, PartialEq)]
38pub enum ConstValue {
39 Identifier(Identifier),
40 Literal(Literal),
41 Double(DoubleConstant),
42 Int(IntConstant),
43 List(ConstList),
44 Map(ConstMap),
45}
46
47impl<'a> From<ConstValueRef<'a>> for ConstValue {
48 fn from(r: ConstValueRef<'a>) -> Self {
49 match r {
50 ConstValueRef::Identifier(i) => Self::Identifier(i.into()),
51 ConstValueRef::Literal(i) => Self::Literal(i.into()),
52 ConstValueRef::Double(i) => Self::Double(i),
53 ConstValueRef::Int(i) => Self::Int(i),
54 ConstValueRef::List(i) => Self::List(i.into()),
55 ConstValueRef::Map(i) => Self::Map(i.into()),
56 }
57 }
58}
59
60impl<'a> Parser<'a> for ConstValue {
61 fn parse(input: &'a str) -> IResult<&'a str, Self> {
62 ConstValueRef::parse(input).map(|(remains, parsed)| (remains, parsed.into()))
63 }
64}
65
66#[derive(derive_newtype::NewType, Hash, Eq, PartialEq, Debug, Copy, Clone)]
68pub struct IntConstant(i64);
69
70impl<'a> Parser<'a> for IntConstant {
71 fn parse(input: &'a str) -> IResult<&'a str, Self> {
72 map_res(
73 recognize(tuple((opt(alt((cchar('-'), cchar('+')))), digit1))),
74 |d_str| -> Result<Self, std::num::ParseIntError> {
75 let d = FromStr::from_str(d_str)?;
76 Ok(Self(d))
77 },
78 )(input)
79 }
80}
81
82#[derive(derive_newtype::NewType, Debug, Copy, Clone)]
84pub struct DoubleConstant(f64);
85
86impl<'a> Parser<'a> for DoubleConstant {
87 fn parse(input: &'a str) -> IResult<&'a str, Self> {
88 map_res(
89 recognize(tuple((
90 opt(alt((cchar('-'), cchar('+')))),
91 digit0,
92 opt(pair(cchar('.'), digit1)),
93 opt(pair(alt((cchar('E'), cchar('e'))), IntConstant::parse)),
94 ))),
95 |d_str| -> Result<Self, std::num::ParseFloatError> {
96 let d = FromStr::from_str(d_str)?;
97 Ok(Self(d))
98 },
99 )(input)
100 }
101}
102impl DoubleConstant {
104 fn parse2(input: &str) -> IResult<&str, Self> {
105 map_res(
106 recognize(tuple((
107 opt(alt((cchar('-'), cchar('+')))),
108 digit0,
109 opt(pair(cchar('.'), digit1)),
110 opt(pair(alt((cchar('E'), cchar('e'))), IntConstant::parse)),
111 ))),
112 |d_str| -> Result<Self, std::num::ParseFloatError> {
113 if !d_str.contains('.') && !d_str.contains('e') && !d_str.contains('E') {
114 return Err(f64::from_str("").unwrap_err());
115 }
116 let d = FromStr::from_str(d_str)?;
117 Ok(Self(d))
118 },
119 )(input)
120 }
121}
122
123impl PartialEq for DoubleConstant {
124 fn eq(&self, other: &Self) -> bool {
125 float_cmp::approx_eq!(f64, self.0, other.0)
126 }
127}
128
129#[derive(derive_newtype::NewType, PartialEq, Debug, Clone)]
131pub struct ConstListRef<'a>(Vec<ConstValueRef<'a>>);
132
133impl<'a> Parser<'a> for ConstListRef<'a> {
134 fn parse(input: &'a str) -> IResult<&'a str, Self> {
135 map(
136 delimited(
137 pair(cchar('['), opt(Separator::parse)),
138 separated_list0(parse_list_separator, ConstValueRef::parse),
139 pair(opt(Separator::parse), cchar(']')),
140 ),
141 Self,
142 )(input)
143 }
144}
145
146#[derive(derive_newtype::NewType, PartialEq, Debug, Clone)]
147pub struct ConstList(Vec<ConstValue>);
148
149impl<'a> From<ConstListRef<'a>> for ConstList {
150 fn from(r: ConstListRef<'a>) -> Self {
151 Self(r.0.into_iter().map(Into::into).collect())
152 }
153}
154
155impl<'a> Parser<'a> for ConstList {
156 fn parse(input: &'a str) -> IResult<&'a str, Self> {
157 ConstListRef::parse(input).map(|(remains, parsed)| (remains, parsed.into()))
158 }
159}
160
161#[derive(derive_newtype::NewType, PartialEq, Debug, Clone)]
163pub struct ConstMapRef<'a>(Vec<(ConstValueRef<'a>, ConstValueRef<'a>)>);
164
165impl<'a> Parser<'a> for ConstMapRef<'a> {
166 fn parse(input: &'a str) -> IResult<&'a str, Self> {
167 map(
168 delimited(
169 pair(cchar('{'), opt(Separator::parse)),
170 separated_list0(
171 parse_list_separator,
172 separated_pair(
173 ConstValueRef::parse,
174 delimited(opt(Separator::parse), cchar(':'), opt(Separator::parse)),
175 ConstValueRef::parse,
176 ),
177 ),
178 pair(opt(Separator::parse), cchar('}')),
179 ),
180 Self,
181 )(input)
182 }
183}
184
185#[derive(derive_newtype::NewType, PartialEq, Debug, Clone)]
186pub struct ConstMap(Vec<(ConstValue, ConstValue)>);
187
188impl<'a> From<ConstMapRef<'a>> for ConstMap {
189 fn from(r: ConstMapRef<'a>) -> Self {
190 Self(r.0.into_iter().map(|(a, b)| (a.into(), b.into())).collect())
191 }
192}
193
194impl<'a> Parser<'a> for ConstMap {
195 fn parse(input: &'a str) -> IResult<&'a str, Self> {
196 ConstMapRef::parse(input).map(|(remains, parsed)| (remains, parsed.into()))
197 }
198}
199
200pub fn parse_list_separator(input: &str) -> IResult<&str, ()> {
202 alt((
203 map(
204 tuple((
205 Separator::parse,
206 opt(ListSeparator::parse),
207 opt(Separator::parse),
208 )),
209 |_| (),
210 ),
211 map(tuple((ListSeparator::parse, opt(Separator::parse))), |_| ()),
212 ))(input)
213}
214
215#[cfg(test)]
216mod test {
217 use crate::utils::*;
218
219 use super::*;
220
221 #[test]
222 fn test_int_constant() {
223 assert_list_eq_with_f(
224 vec!["123", "+123", "-123"],
225 vec![123, 123, -123],
226 IntConstant::parse,
227 IntConstant,
228 );
229 assert_list_err_with_f(
230 vec![
231 "-+123",
232 "+-123",
233 "+",
234 "-",
235 "10000000000000000000000000000000000000000000000",
236 ],
237 IntConstant::parse,
238 );
239 }
240
241 #[test]
242 fn test_double_constant() {
243 assert_list_eq_with_f(
244 vec![
245 "123.0",
246 ".5",
247 "-.5",
248 "+123.2333333e10",
249 "+123.2333333E100",
250 "+123.1.THE.FOLLOWING",
251 "1.1",
252 ],
253 vec![
254 123.0,
255 0.5,
256 -0.5,
257 123.2333333e10,
258 123.2333333E100,
259 123.1,
260 1.1,
261 ],
262 DoubleConstant::parse,
263 DoubleConstant,
264 );
265 assert_list_err_with_f(vec!["+-123.THE.FOLLOWING"], DoubleConstant::parse);
266 }
267
268 #[test]
269 fn test_const_list() {
270 assert_list_eq_with_f(
271 vec![
272 "[ 1, 3 ; 5 6/**/7 , ihciah 1.1]",
273 "[6/**/7 ihciah 1.1 A ]",
274 "[]",
275 ],
276 vec![
277 vec![
278 ConstValueRef::Int(IntConstant(1)),
279 ConstValueRef::Int(IntConstant(3)),
280 ConstValueRef::Int(IntConstant(5)),
281 ConstValueRef::Int(IntConstant(6)),
282 ConstValueRef::Int(IntConstant(7)),
283 ConstValueRef::Identifier(IdentifierRef::from("ihciah")),
284 ConstValueRef::Double(DoubleConstant(1.1)),
285 ],
286 vec![
287 ConstValueRef::Int(IntConstant(6)),
288 ConstValueRef::Int(IntConstant(7)),
289 ConstValueRef::Identifier(IdentifierRef::from("ihciah")),
290 ConstValueRef::Double(DoubleConstant(1.1)),
291 ConstValueRef::Identifier(IdentifierRef::from("A")),
292 ],
293 vec![],
294 ],
295 ConstListRef::parse,
296 ConstListRef,
297 );
298 assert_list_err_with_f(vec!["[1,2,3A]"], ConstListRef::parse);
299 }
300
301 #[test]
302 fn test_const_map() {
303 assert_list_eq_with_f(
304 vec!["{1:2, 3:4}", "{}"],
305 vec![
306 vec![
307 (
308 ConstValueRef::Int(IntConstant(1)),
309 ConstValueRef::Int(IntConstant(2)),
310 ),
311 (
312 ConstValueRef::Int(IntConstant(3)),
313 ConstValueRef::Int(IntConstant(4)),
314 ),
315 ],
316 vec![],
317 ],
318 ConstMapRef::parse,
319 ConstMapRef,
320 );
321 assert_list_err_with_f(vec!["{1:34:5}"], ConstMapRef::parse);
322 }
323}