Skip to content

Instantly share code, notes, and snippets.

@cfcosta
Created April 15, 2019 20:11
Show Gist options
  • Save cfcosta/6f326edafd3bda30f9d816f0e54a716e to your computer and use it in GitHub Desktop.
Save cfcosta/6f326edafd3bda30f9d816f0e54a716e to your computer and use it in GitHub Desktop.
use nom::is_alphabetic;
use std::str;
#[derive(Debug, PartialEq, Eq)]
pub enum Keyword {
Unknown,
Help,
Echo,
}
#[derive(Debug, PartialEq, Eq)]
pub enum Command {
Unknown,
Help,
Echo(String),
}
fn to_keyword(s: &[u8]) -> Keyword {
if compare_no_case(&s, b"help") {
return Keyword::Help;
} else if compare_no_case(&s, b"echo") {
return Keyword::Echo;
}
Keyword::Unknown
}
fn is_argument_char(i: u8) -> bool {
!b"\r\n".contains(&i)
}
pub fn to_command(keyword: Keyword, argument: &[u8]) -> Command {
match keyword {
Keyword::Unknown => Command::Unknown,
Keyword::Help => Command::Help,
Keyword::Echo => Command::Echo(str::from_utf8(argument).unwrap().into()),
}
}
fn is_token_char(i: u8) -> bool {
is_alphabetic(i) || b"_-".contains(&i)
}
pub fn compare_no_case(left: &[u8], right: &[u8]) -> bool {
if left.len() != right.len() {
return false;
}
left.iter().zip(right).all(|(a, b)| match (*a, *b) {
(0...64, 0...64) | (91...96, 91...96) | (123...255, 123...255) => a == b,
(65...90, 65...90) | (97...122, 97...122) | (65...90, 97...122) | (97...122, 65...90) => {
*a | 0b00_10_00_00 == *b | 0b00_10_00_00
}
_ => false,
})
}
named!(eoc, alt!(tag!("\n") | tag!("\r\n")));
named!(space, alt!(tag!(" ") | tag!("\t")));
named!(keyword<&[u8], Keyword>, map!(take_while!(is_token_char), to_keyword));
named!(argument, take_while!(is_argument_char));
named!(command<&[u8], Command>,
do_parse!(
tag!("!") >>
keyword: keyword >>
opt!(space) >>
argument: argument >>
eoc >>
(to_command(keyword, argument))
)
);
pub fn parse(input: &str) -> Result<Command, nom::Err<&[u8]>> {
let result = command(input.as_bytes())?;
Ok(result.1)
}
#[cfg(test)]
mod tests {
use crate::parser::*;
#[test]
fn parse_command_with_crlf() {
assert_eq!(parse("!help\r\n"), Ok(Command::Help));
}
#[test]
fn parse_command_with_lf() {
assert_eq!(parse("!help\n"), Ok(Command::Help));
}
#[test]
fn parse_unknown_command() {
assert_eq!(parse("!omg\n"), Ok(Command::Unknown));
}
#[test]
fn parse_command_with_argument() {
assert_eq!(parse("!echo omg\n"), Ok(Command::Echo("omg".into())));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment