SHARE
TWEET

Untitled

a guest Apr 26th, 2019 75 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. use nom::is_alphabetic;
  2. use std::str;
  3.  
  4. #[derive(Debug, PartialEq, Eq)]
  5. pub enum Keyword {
  6.     Unknown,
  7.     Help,
  8.     Echo,
  9. }
  10.  
  11. #[derive(Debug, PartialEq, Eq)]
  12. pub enum Command {
  13.     Unknown,
  14.     Help,
  15.     Echo(String),
  16. }
  17.  
  18. fn to_keyword(s: &[u8]) -> Keyword {
  19.     if compare_no_case(&s, b"help") {
  20.         return Keyword::Help;
  21.     } else if compare_no_case(&s, b"echo") {
  22.         return Keyword::Echo;
  23.     }
  24.  
  25.     Keyword::Unknown
  26. }
  27.  
  28. fn is_argument_char(i: u8) -> bool {
  29.     !b"\r\n".contains(&i)
  30. }
  31.  
  32. pub fn to_command(keyword: Keyword, argument: &[u8]) -> Command {
  33.     match keyword {
  34.         Keyword::Unknown => Command::Unknown,
  35.         Keyword::Help => Command::Help,
  36.         Keyword::Echo => Command::Echo(str::from_utf8(argument).unwrap().into()),
  37.     }
  38. }
  39.  
  40. fn is_token_char(i: u8) -> bool {
  41.     is_alphabetic(i) || b"_-".contains(&i)
  42. }
  43.  
  44. pub fn compare_no_case(left: &[u8], right: &[u8]) -> bool {
  45.     if left.len() != right.len() {
  46.         return false;
  47.     }
  48.  
  49.     left.iter().zip(right).all(|(a, b)| match (*a, *b) {
  50.         (0...64, 0...64) | (91...96, 91...96) | (123...255, 123...255) => a == b,
  51.         (65...90, 65...90) | (97...122, 97...122) | (65...90, 97...122) | (97...122, 65...90) => {
  52.             *a | 0b00_10_00_00 == *b | 0b00_10_00_00
  53.         }
  54.         _ => false,
  55.     })
  56. }
  57.  
  58. named!(eoc, alt!(tag!("\n") | tag!("\r\n")));
  59. named!(space, alt!(tag!(" ") | tag!("\t")));
  60. named!(keyword<&[u8], Keyword>, map!(take_while!(is_token_char), to_keyword));
  61. named!(argument, take_while!(is_argument_char));
  62.  
  63. named!(command<&[u8], Command>,
  64.        do_parse!(
  65.            tag!("!") >>
  66.            keyword: keyword >>
  67.            opt!(space) >>
  68.            argument: argument >>
  69.            eoc >>
  70.            (to_command(keyword, argument))
  71.        )
  72. );
  73.  
  74. pub fn parse(input: &str) -> Result<Command, nom::Err<&[u8]>> {
  75.     let result = command(input.as_bytes())?;
  76.     Ok(result.1)
  77. }
  78.  
  79. #[cfg(test)]
  80. mod tests {
  81.     use crate::parser::*;
  82.  
  83.     #[test]
  84.     fn parse_command_with_crlf() {
  85.         assert_eq!(parse("!help\r\n"), Ok(Command::Help));
  86.     }
  87.  
  88.     #[test]
  89.     fn parse_command_with_lf() {
  90.         assert_eq!(parse("!help\n"), Ok(Command::Help));
  91.     }
  92.  
  93.     #[test]
  94.     fn parse_unknown_command() {
  95.         assert_eq!(parse("!omg\n"), Ok(Command::Unknown));
  96.     }
  97.  
  98.     #[test]
  99.     fn parse_command_with_argument() {
  100.         assert_eq!(parse("!echo omg\n"), Ok(Command::Echo("omg".into())));
  101.     }
  102. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top