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