use nom::*; use std::str::{FromStr, from_utf8}; use super::Expression; named!(ident_, map!( map_res!(is_a!( "abcdefghijklmnopqrstuvwxyz \ ABCDEFGHIJKLMNOPQRSTUVWXYZ \ 0123456789 \ _-" ), from_utf8), |s: &str| { s.to_string() } ) ); named!(integer , map_res!( map_res!( ws!(digit), from_utf8 ), FromStr::from_str ) ); named!(ident, map!(ident_, Expression::Identifier)); #[allow(cyclomatic_complexity)] fn postfix(expr: Expression) -> Box IResult<&[u8], Expression>> { 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: &str) -> Result { match ident(input.as_bytes()) { IResult::Done(mut rem, mut expr) => { while !rem.is_empty() { match postfix(expr)(rem) { IResult::Done(rem_, expr_) => { rem = rem_; expr = expr_; } // Forward Incomplete and Error result => { return result.to_result(); } } } Ok(expr) } // Forward Incomplete and Error result => result.to_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); } }