Skip to content

Commit 026e922

Browse files
committed
Add initial parsing for merge and hold commands
1 parent dfe4f7a commit 026e922

File tree

1 file changed

+95
-9
lines changed

1 file changed

+95
-9
lines changed

parser/src/command/decision.rs

Lines changed: 95 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
//! Command: `@bot merge`, `@bot hold`, `@bot restart`, `@bot dissent`, `@bot stabilize` or `@bot close`.
99
//! ```
1010
11+
use std::fmt;
12+
1113
use crate::error::Error;
1214
use crate::token::{Token, Tokenizer};
1315
use postgres_types::{FromSql, ToSql};
@@ -23,20 +25,49 @@ pub struct DecisionCommand {
2325

2426
impl DecisionCommand {
2527
pub fn parse<'a>(input: &mut Tokenizer<'a>) -> Result<Option<Self>, Error<'a>> {
26-
if let Some(Token::Word("merge")) = input.peek_token()? {
27-
Ok(Some(Self {
28-
resolution: Resolution::Merge,
29-
reversibility: Reversibility::Reversible,
30-
}))
31-
} else {
32-
Ok(None)
28+
let mut toks = input.clone();
29+
30+
match toks.peek_token()? {
31+
Some(Token::Word("merge")) => {
32+
command_or_error(input, &mut toks, Self {
33+
resolution: Resolution::Merge,
34+
reversibility: Reversibility::Reversible,
35+
})
36+
}
37+
Some(Token::Word("hold")) => {
38+
command_or_error(input, &mut toks, Self {
39+
resolution: Resolution::Hold,
40+
reversibility: Reversibility::Reversible,
41+
})
42+
}
43+
_ => Ok(None),
3344
}
3445
}
3546
}
3647

37-
#[derive(Debug, Eq, PartialEq)]
48+
fn command_or_error<'a>(input: &mut Tokenizer<'a>, toks: &mut Tokenizer<'a>, command: DecisionCommand) -> Result<Option<DecisionCommand>, Error<'a>> {
49+
toks.next_token()?;
50+
if let Some(Token::Dot) | Some(Token::EndOfLine) = toks.peek_token()? {
51+
*input = toks.clone();
52+
Ok(Some(command))
53+
} else {
54+
Err(toks.error(ParseError::ExpectedEnd))
55+
}
56+
}
57+
58+
#[derive(PartialEq, Eq, Debug)]
3859
pub enum ParseError {
39-
InvalidFirstCommand,
60+
ExpectedEnd,
61+
}
62+
63+
impl std::error::Error for ParseError {}
64+
65+
impl fmt::Display for ParseError {
66+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
67+
match self {
68+
ParseError::ExpectedEnd => write!(f, "expected end of command"),
69+
}
70+
}
4071
}
4172

4273
#[derive(Serialize, Deserialize, Debug, Clone, ToSql, FromSql, Eq, PartialEq)]
@@ -56,3 +87,58 @@ pub enum Resolution {
5687
#[postgres(name = "hold")]
5788
Hold,
5889
}
90+
#[cfg(test)]
91+
mod tests {
92+
use super::*;
93+
94+
fn parse<'a>(input: &'a str) -> Result<Option<DecisionCommand>, Error<'a>> {
95+
let mut toks = Tokenizer::new(input);
96+
Ok(DecisionCommand::parse(&mut toks)?)
97+
}
98+
99+
#[test]
100+
fn test_correct_merge() {
101+
assert_eq!(
102+
parse("merge"),
103+
Ok(Some(DecisionCommand {
104+
resolution: Resolution::Merge,
105+
reversibility: Reversibility::Reversible
106+
})),
107+
);
108+
}
109+
110+
#[test]
111+
fn test_correct_merge_final_dot() {
112+
assert_eq!(
113+
parse("merge."),
114+
Ok(Some(DecisionCommand {
115+
resolution: Resolution::Merge,
116+
reversibility: Reversibility::Reversible
117+
})),
118+
);
119+
}
120+
121+
#[test]
122+
fn test_correct_hold() {
123+
assert_eq!(
124+
parse("hold"),
125+
Ok(Some(DecisionCommand {
126+
resolution: Resolution::Hold,
127+
reversibility: Reversibility::Reversible
128+
})),
129+
);
130+
}
131+
132+
#[test]
133+
fn test_expected_end() {
134+
use std::error::Error;
135+
assert_eq!(
136+
parse("hold my beer")
137+
.unwrap_err()
138+
.source()
139+
.unwrap()
140+
.downcast_ref(),
141+
Some(&ParseError::ExpectedEnd),
142+
);
143+
}
144+
}

0 commit comments

Comments
 (0)