storm_config/path/
parser.rs1use crate::path::Expression;
2use nom::{
3 branch::alt,
4 bytes::complete::{is_a, tag},
5 character::complete::{char, digit1, space0},
6 combinator::{map, map_res, opt, recognize},
7 error::ErrorKind,
8 sequence::{delimited, pair, preceded},
9 Err, IResult,
10};
11use std::str::FromStr;
12
13fn raw_ident(i: &str) -> IResult<&str, String> {
14 map(
15 is_a(
16 "abcdefghijklmnopqrstuvwxyz \
17 ABCDEFGHIJKLMNOPQRSTUVWXYZ \
18 0123456789 \
19 _-",
20 ),
21 ToString::to_string,
22 )(i)
23}
24
25fn integer(i: &str) -> IResult<&str, isize> {
26 map_res(delimited(space0, recognize(pair(opt(tag("-")), digit1)), space0), FromStr::from_str)(i)
27}
28
29fn ident(i: &str) -> IResult<&str, Expression> {
30 map(raw_ident, Expression::Identifier)(i)
31}
32
33fn postfix<'a>(expr: Expression) -> impl FnMut(&'a str) -> IResult<&'a str, Expression> {
34 let e2 = expr.clone();
35 let child =
36 map(preceded(tag("."), raw_ident), move |id| Expression::Child(Box::new(expr.clone()), id));
37
38 let subscript = map(delimited(char('['), integer, char(']')), move |num| {
39 Expression::Subscript(Box::new(e2.clone()), num)
40 });
41
42 alt((child, subscript))
43}
44
45pub fn from_str(input: &str) -> Result<Expression, ErrorKind> {
46 match ident(input) {
47 Ok((mut rem, mut expr)) => {
48 while !rem.is_empty() {
49 match postfix(expr)(rem) {
50 Ok((rem_, expr_)) => {
51 rem = rem_;
52 expr = expr_;
53 }
54
55 result => {
57 return result.map(|(_, o)| o).map_err(to_error_kind);
58 }
59 }
60 }
61
62 Ok(expr)
63 }
64
65 result => result.map(|(_, o)| o).map_err(to_error_kind),
67 }
68}
69
70pub fn to_error_kind(e: Err<nom::error::Error<&str>>) -> ErrorKind {
71 match e {
72 Err::Incomplete(_) => ErrorKind::Complete,
73 Err::Failure(e) | Err::Error(e) => e.code,
74 }
75}
76
77#[cfg(test)]
78mod test {
79 use super::Expression::*;
80 use super::*;
81
82 #[test]
83 fn test_id() {
84 let parsed: Expression = from_str("abcd").unwrap();
85 assert_eq!(parsed, Identifier("abcd".into()));
86 }
87
88 #[test]
89 fn test_id_dash() {
90 let parsed: Expression = from_str("abcd-efgh").unwrap();
91 assert_eq!(parsed, Identifier("abcd-efgh".into()));
92 }
93
94 #[test]
95 fn test_child() {
96 let parsed: Expression = from_str("abcd.efgh").unwrap();
97 let expected = Child(Box::new(Identifier("abcd".into())), "efgh".into());
98
99 assert_eq!(parsed, expected);
100
101 let parsed: Expression = from_str("abcd.efgh.ijkl").unwrap();
102 let expected =
103 Child(Box::new(Child(Box::new(Identifier("abcd".into())), "efgh".into())), "ijkl".into());
104
105 assert_eq!(parsed, expected);
106 }
107
108 #[test]
109 fn test_subscript() {
110 let parsed: Expression = from_str("abcd[12]").unwrap();
111 let expected = Subscript(Box::new(Identifier("abcd".into())), 12);
112
113 assert_eq!(parsed, expected);
114 }
115
116 #[test]
117 fn test_subscript_neg() {
118 let parsed: Expression = from_str("abcd[-1]").unwrap();
119 let expected = Subscript(Box::new(Identifier("abcd".into())), -1);
120
121 assert_eq!(parsed, expected);
122 }
123}