|  | @@ -0,0 +1,95 @@
 | 
	
		
			
				|  |  | +//! The shortcut command parser.
 | 
	
		
			
				|  |  | +//!
 | 
	
		
			
				|  |  | +//! This can parse predefined shortcut input, single word commands.
 | 
	
		
			
				|  |  | +//!
 | 
	
		
			
				|  |  | +//! The grammar is as follows:
 | 
	
		
			
				|  |  | +//!
 | 
	
		
			
				|  |  | +//! ```text
 | 
	
		
			
				|  |  | +//! Command: `@bot ready`, or `@bot author`.
 | 
	
		
			
				|  |  | +//! ```
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +use crate::error::Error;
 | 
	
		
			
				|  |  | +use crate::token::{Token, Tokenizer};
 | 
	
		
			
				|  |  | +use std::fmt;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#[derive(PartialEq, Eq, Debug)]
 | 
	
		
			
				|  |  | +pub enum ShortcutCommand {
 | 
	
		
			
				|  |  | +    Ready,
 | 
	
		
			
				|  |  | +    Author,
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#[derive(PartialEq, Eq, Debug)]
 | 
	
		
			
				|  |  | +pub enum ParseError {
 | 
	
		
			
				|  |  | +    ExpectedEnd,
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +impl std::error::Error for ParseError {}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +impl fmt::Display for ParseError {
 | 
	
		
			
				|  |  | +    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 | 
	
		
			
				|  |  | +        match self {
 | 
	
		
			
				|  |  | +            ParseError::ExpectedEnd => write!(f, "expected end of command"),
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +impl ShortcutCommand {
 | 
	
		
			
				|  |  | +    pub fn parse<'a>(input: &mut Tokenizer<'a>) -> Result<Option<Self>, Error<'a>> {
 | 
	
		
			
				|  |  | +        let mut toks = input.clone();
 | 
	
		
			
				|  |  | +        if let Some(Token::Word("ready")) = toks.peek_token()? {
 | 
	
		
			
				|  |  | +            toks.next_token()?;
 | 
	
		
			
				|  |  | +            if let Some(Token::Dot) | Some(Token::EndOfLine) = toks.peek_token()? {
 | 
	
		
			
				|  |  | +                toks.next_token()?;
 | 
	
		
			
				|  |  | +                *input = toks;
 | 
	
		
			
				|  |  | +                return Ok(Some(ShortcutCommand::Ready));
 | 
	
		
			
				|  |  | +            } else {
 | 
	
		
			
				|  |  | +                return Err(toks.error(ParseError::ExpectedEnd));
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        } else if let Some(Token::Word("author")) = toks.peek_token()? {
 | 
	
		
			
				|  |  | +            toks.next_token()?;
 | 
	
		
			
				|  |  | +            if let Some(Token::Dot) | Some(Token::EndOfLine) = toks.peek_token()? {
 | 
	
		
			
				|  |  | +                toks.next_token()?;
 | 
	
		
			
				|  |  | +                *input = toks;
 | 
	
		
			
				|  |  | +                return Ok(Some(ShortcutCommand::Author));
 | 
	
		
			
				|  |  | +            } else {
 | 
	
		
			
				|  |  | +                return Err(toks.error(ParseError::ExpectedEnd));
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +            return Ok(None);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#[cfg(test)]
 | 
	
		
			
				|  |  | +fn parse(input: &str) -> Result<Option<ShortcutCommand>, Error<'_>> {
 | 
	
		
			
				|  |  | +    let mut toks = Tokenizer::new(input);
 | 
	
		
			
				|  |  | +    Ok(ShortcutCommand::parse(&mut toks)?)
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#[test]
 | 
	
		
			
				|  |  | +fn test_1() {
 | 
	
		
			
				|  |  | +    assert_eq!(parse("ready."), Ok(Some(ShortcutCommand::Ready)),);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#[test]
 | 
	
		
			
				|  |  | +fn test_2() {
 | 
	
		
			
				|  |  | +    assert_eq!(parse("ready"), Ok(Some(ShortcutCommand::Ready)),);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#[test]
 | 
	
		
			
				|  |  | +fn test_3() {
 | 
	
		
			
				|  |  | +    assert_eq!(parse("author"), Ok(Some(ShortcutCommand::Author)),);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#[test]
 | 
	
		
			
				|  |  | +fn test_4() {
 | 
	
		
			
				|  |  | +    use std::error::Error;
 | 
	
		
			
				|  |  | +    assert_eq!(
 | 
	
		
			
				|  |  | +        parse("ready word")
 | 
	
		
			
				|  |  | +            .unwrap_err()
 | 
	
		
			
				|  |  | +            .source()
 | 
	
		
			
				|  |  | +            .unwrap()
 | 
	
		
			
				|  |  | +            .downcast_ref(),
 | 
	
		
			
				|  |  | +        Some(&ParseError::ExpectedEnd),
 | 
	
		
			
				|  |  | +    );
 | 
	
		
			
				|  |  | +}
 |