summaryrefslogtreecommitdiffstats
path: root/lib/src/path/parser.rs
diff options
context:
space:
mode:
Diffstat (limited to 'lib/src/path/parser.rs')
-rw-r--r--lib/src/path/parser.rs120
1 files changed, 120 insertions, 0 deletions
diff --git a/lib/src/path/parser.rs b/lib/src/path/parser.rs
new file mode 100644
index 0000000..ad7ab91
--- /dev/null
+++ b/lib/src/path/parser.rs
@@ -0,0 +1,120 @@
+use nom::*;
+use std::str::{FromStr, from_utf8};
+use super::Expression;
+
+named!(ident_<String>,
+ map!(
+ map_res!(is_a!(
+ "abcdefghijklmnopqrstuvwxyz \
+ ABCDEFGHIJKLMNOPQRSTUVWXYZ \
+ 0123456789 \
+ _-"
+ ), from_utf8),
+ |s: &str| {
+ s.to_string()
+ }
+ )
+);
+
+named!(integer <i32>,
+ map_res!(
+ map_res!(
+ ws!(digit),
+ from_utf8
+ ),
+ FromStr::from_str
+ )
+);
+
+named!(ident<Expression>, map!(ident_, Expression::Identifier));
+
+fn postfix(expr: Expression) -> Box<Fn(&[u8]) -> IResult<&[u8], Expression>> {
+ return Box::new(move |i: &[u8]| {
+ alt!(i,
+ do_parse!(
+ tag!(".") >>
+ id: ident_ >>
+ (Expression::Child(Box::new(expr.clone()), id))
+ ) |
+ delimited!(
+ char!('['),
+ do_parse!(
+ negative: opt!(tag!("-")) >>
+ num: integer >>
+ (Expression::Subscript(
+ Box::new(expr.clone()),
+ num * (if negative.is_none() { 1 } else { -1 })
+ ))
+ ),
+ char!(']')
+ )
+ )
+ });
+}
+
+pub fn from_str(input: &[u8]) -> IResult<&[u8], Expression> {
+ match ident(input) {
+ IResult::Done(mut rem, mut expr) => {
+ while rem.len() > 0 {
+ match postfix(expr)(rem) {
+ IResult::Done(rem_, expr_) => {
+ rem = rem_;
+ expr = expr_;
+ }
+
+ // Forward Incomplete and Error
+ result @ _ => {
+ return result;
+ }
+ }
+ }
+
+ IResult::Done(&[], expr)
+ }
+
+ // Forward Incomplete and Error
+ result @ _ => result,
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use super::Expression::*;
+
+ #[test]
+ fn test_id() {
+ let parsed: Expression = from_str("abcd").unwrap();
+ assert_eq!(parsed, Identifier("abcd".into()));
+ }
+
+ #[test]
+ fn test_id_dash() {
+ let parsed: Expression = from_str("abcd-efgh").unwrap();
+ assert_eq!(parsed, Identifier("abcd-efgh".into()));
+ }
+
+ #[test]
+ fn test_child() {
+ let parsed: Expression = from_str("abcd.efgh").unwrap();
+ let expected = Child(Box::new(Identifier("abcd".into())), "efgh".into());
+
+ assert_eq!(parsed, expected);
+ }
+
+ #[test]
+ fn test_subscript() {
+ let parsed: Expression = from_str("abcd[12]").unwrap();
+ let expected = Subscript(Box::new(Identifier("abcd".into())), 12);
+
+ assert_eq!(parsed, expected);
+ }
+
+ #[test]
+ fn test_subscript_neg() {
+ let parsed: Expression = from_str("abcd[-1]").unwrap();
+ let expected = Subscript(Box::new(Identifier("abcd".into())), -1);
+
+ assert_eq!(parsed, expected);
+ }
+}