diff --git a/src/parse.rs b/src/parse.rs index 55fdea6..f0f8ca1 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -1,6 +1,8 @@ +mod helpers; mod names; mod terms; +pub(crate) use helpers::word_boundary; pub use names::{function_name, predicate_name, variable_name}; pub use terms::{integer, special_integer}; diff --git a/src/parse/helpers.rs b/src/parse/helpers.rs new file mode 100644 index 0000000..bff2b96 --- /dev/null +++ b/src/parse/helpers.rs @@ -0,0 +1,77 @@ +use nom:: +{ + IResult, + branch::alt, + bytes::complete::take_while_m_n, + combinator::{map, peek, rest_len, verify}, +}; + +fn is_character_word_boundary(c: char) -> bool +{ + if c.is_whitespace() + { + return true; + } + + match c + { + '(' + | ')' + | ',' + | '+' + | '-' + | '*' + | '/' + | '%' + => true, + _ => false, + } +} + +pub(crate) fn word_boundary(i: &str) -> IResult<&str, ()> +{ + peek + ( + alt + (( + // Accept word boundary characters + map + ( + take_while_m_n(1, 1, is_character_word_boundary), + |_| (), + ), + // Accept end of file + map + ( + verify + ( + rest_len, + |rest_length| *rest_length == 0usize, + ), + |_| (), + ), + )) + )(i) +} + +#[cfg(test)] +mod tests +{ + use crate::parse::*; + + #[test] + fn detect_word_boundaries() + { + assert_eq!(word_boundary(" rest"), Ok((" rest", ()))); + assert_eq!(word_boundary("(rest"), Ok(("(rest", ()))); + assert_eq!(word_boundary(")rest"), Ok((")rest", ()))); + assert_eq!(word_boundary(",rest"), Ok((",rest", ()))); + assert_eq!(word_boundary("+rest"), Ok(("+rest", ()))); + assert_eq!(word_boundary("-rest"), Ok(("-rest", ()))); + assert_eq!(word_boundary("*rest"), Ok(("*rest", ()))); + assert_eq!(word_boundary("/rest"), Ok(("/rest", ()))); + assert_eq!(word_boundary("%rest"), Ok(("%rest", ()))); + assert!(word_boundary("0").is_err()); + assert!(word_boundary("rest").is_err()); + } +} diff --git a/src/parse/terms.rs b/src/parse/terms.rs index a0e1ddd..2fa2b36 100644 --- a/src/parse/terms.rs +++ b/src/parse/terms.rs @@ -5,9 +5,11 @@ use nom:: bytes::complete::tag, character::complete::digit1, combinator::{map, map_res, opt, recognize}, - sequence::pair, + sequence::{pair, terminated}, }; +use super::word_boundary; + pub fn integer(i: &str) -> IResult<&str, crate::Term> { map @@ -16,17 +18,21 @@ pub fn integer(i: &str) -> IResult<&str, crate::Term> ( recognize ( - pair + terminated ( - opt + pair ( - alt - (( - tag("-"), - tag("+"), - )) + opt + ( + alt + (( + tag("-"), + tag("+"), + )) + ), + digit1, ), - digit1, + word_boundary, ) ), std::str::FromStr::from_str, @@ -39,7 +45,11 @@ fn infimum(i: &str) -> IResult<&str, crate::Term> { map ( - tag("#inf"), + terminated + ( + tag("#inf"), + word_boundary, + ), |_| crate::Term::infimum(), )(i) } @@ -48,7 +58,11 @@ fn supremum(i: &str) -> IResult<&str, crate::Term> { map ( - tag("#sup"), + terminated + ( + tag("#sup"), + word_boundary, + ), |_| crate::Term::supremum(), )(i) } @@ -148,8 +162,19 @@ mod tests { assert_eq!(integer("0"), Ok(("", crate::Term::integer(0)))); assert_eq!(integer("10000"), Ok(("", crate::Term::integer(10000)))); + assert_eq!(integer("+10000"), Ok(("", crate::Term::integer(10000)))); assert_eq!(integer("-10000"), Ok(("", crate::Term::integer(-10000)))); - assert_eq!(integer("1.5"), Ok((".5", crate::Term::integer(1)))); + assert_eq!(integer("0 42"), Ok((" 42", crate::Term::integer(0)))); + assert_eq!(integer("10000 42"), Ok((" 42", crate::Term::integer(10000)))); + assert_eq!(integer("+10000 42"), Ok((" 42", crate::Term::integer(10000)))); + assert_eq!(integer("-10000 42"), Ok((" 42", crate::Term::integer(-10000)))); + assert_eq!(integer("10000("), Ok(("(", crate::Term::integer(10000)))); + assert_eq!(integer("+10000("), Ok(("(", crate::Term::integer(10000)))); + assert_eq!(integer("-10000("), Ok(("(", crate::Term::integer(-10000)))); + assert!(integer("10000a").is_err()); + assert!(integer("+10000a").is_err()); + assert!(integer("-10000a").is_err()); + assert!(integer("1.5").is_err()); assert!(integer("a").is_err()); assert!(integer("-").is_err()); assert!(integer(" ").is_err()); @@ -160,6 +185,14 @@ mod tests { assert_eq!(special_integer("#inf"), Ok(("", crate::Term::infimum()))); assert_eq!(special_integer("#sup"), Ok(("", crate::Term::supremum()))); + assert_eq!(special_integer("#inf #sup"), Ok((" #sup", crate::Term::infimum()))); + assert_eq!(special_integer("#sup #inf"), Ok((" #inf", crate::Term::supremum()))); + assert_eq!(special_integer("#inf("), Ok(("(", crate::Term::infimum()))); + assert_eq!(special_integer("#sup("), Ok(("(", crate::Term::supremum()))); + assert!(special_integer("#inf0").is_err()); + assert!(special_integer("#sup0").is_err()); + assert!(special_integer("#infimum").is_err()); + assert!(special_integer("#supremum").is_err()); assert!(special_integer("inf").is_err()); assert!(special_integer("sup").is_err()); assert!(special_integer("0").is_err());