assign.rs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. //! The assignment command parser.
  2. //!
  3. //! This can parse arbitrary input, giving the user to be assigned.
  4. //!
  5. //! The grammar is as follows:
  6. //!
  7. //! ```text
  8. //! Command: `@bot claim`, `@bot release-assignment`, or `@bot assign @user`.
  9. //! ```
  10. use crate::error::Error;
  11. use crate::token::{Token, Tokenizer};
  12. use std::fmt;
  13. #[derive(PartialEq, Eq, Debug)]
  14. pub enum AssignCommand {
  15. Own,
  16. Release,
  17. User { username: String },
  18. }
  19. #[derive(PartialEq, Eq, Debug)]
  20. pub enum ParseError {
  21. ExpectedEnd,
  22. MentionUser,
  23. NoUser,
  24. }
  25. impl std::error::Error for ParseError {}
  26. impl fmt::Display for ParseError {
  27. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  28. match self {
  29. ParseError::MentionUser => write!(f, "user should start with @"),
  30. ParseError::ExpectedEnd => write!(f, "expected end of command"),
  31. ParseError::NoUser => write!(f, "specify user to assign to"),
  32. }
  33. }
  34. }
  35. impl AssignCommand {
  36. pub fn parse<'a>(input: &mut Tokenizer<'a>) -> Result<Option<Self>, Error<'a>> {
  37. let mut toks = input.clone();
  38. if let Some(Token::Word("claim")) = toks.peek_token()? {
  39. toks.next_token()?;
  40. if let Some(Token::Dot) | Some(Token::EndOfLine) = toks.peek_token()? {
  41. toks.next_token()?;
  42. *input = toks;
  43. return Ok(Some(AssignCommand::Own));
  44. } else {
  45. return Err(toks.error(ParseError::ExpectedEnd));
  46. }
  47. } else if let Some(Token::Word("assign")) = toks.peek_token()? {
  48. toks.next_token()?;
  49. if let Some(Token::Word(user)) = toks.next_token()? {
  50. if user.starts_with('@') && user.len() != 1 {
  51. Ok(Some(AssignCommand::User {
  52. username: user[1..].to_owned(),
  53. }))
  54. } else {
  55. return Err(toks.error(ParseError::MentionUser));
  56. }
  57. } else {
  58. return Err(toks.error(ParseError::NoUser));
  59. }
  60. } else if let Some(Token::Word("release-assignment")) = toks.peek_token()? {
  61. toks.next_token()?;
  62. if let Some(Token::Dot) | Some(Token::EndOfLine) = toks.peek_token()? {
  63. toks.next_token()?;
  64. *input = toks;
  65. return Ok(Some(AssignCommand::Release));
  66. } else {
  67. return Err(toks.error(ParseError::ExpectedEnd));
  68. }
  69. } else {
  70. return Ok(None);
  71. }
  72. }
  73. }
  74. #[cfg(test)]
  75. fn parse<'a>(input: &'a str) -> Result<Option<AssignCommand>, Error<'a>> {
  76. let mut toks = Tokenizer::new(input);
  77. Ok(AssignCommand::parse(&mut toks)?)
  78. }
  79. #[test]
  80. fn test_1() {
  81. assert_eq!(parse("claim."), Ok(Some(AssignCommand::Own)),);
  82. }
  83. #[test]
  84. fn test_2() {
  85. assert_eq!(parse("claim"), Ok(Some(AssignCommand::Own)),);
  86. }
  87. #[test]
  88. fn test_3() {
  89. assert_eq!(
  90. parse("assign @user"),
  91. Ok(Some(AssignCommand::User {
  92. username: "user".to_owned()
  93. })),
  94. );
  95. }
  96. #[test]
  97. fn test_4() {
  98. use std::error::Error;
  99. assert_eq!(
  100. parse("assign @")
  101. .unwrap_err()
  102. .source()
  103. .unwrap()
  104. .downcast_ref(),
  105. Some(&ParseError::MentionUser),
  106. );
  107. }