mx-sanebot: port the parsing over to a more formal implementation

This commit is contained in:
Colin 2023-04-29 07:31:16 +00:00
parent b0c68308b7
commit 7c1961eba8
2 changed files with 36 additions and 13 deletions

View File

@ -3,7 +3,7 @@ use std::fmt;
use std::process; use std::process;
use std::str; use std::str;
use super::parsing; use super::parsing::{self, Parser};
mod tt { mod tt {
@ -12,6 +12,7 @@ mod tt {
Lit, Lit,
Then, Then,
}; };
use crate::ilit;
// grammar: // grammar:
// REQUEST = <!> (HELP | BT | BT-ADD) // REQUEST = <!> (HELP | BT | BT-ADD)
@ -26,15 +27,15 @@ mod tt {
pub(super) type Bang = Lit<{ '!' as u8 }>; pub(super) type Bang = Lit<{ '!' as u8 }>;
pub(super) type Help = Then< pub(super) type Help = Then<
Lit<{ 'H' as u8 }>, Then< ilit!('H'), Then<
Lit<{ 'E' as u8 }>, Then< ilit!('E'), Then<
Lit<{ 'L' as u8 }>, ilit!('L'),
Lit<{ 'P' as u8 }>, ilit!('P'),
>>>; >>>;
pub(super) type Bt = Then< pub(super) type Bt = Then<
Lit<{ 'B' as u8 }>, ilit!('B'),
Lit<{ 'T' as u8 }>, ilit!('T'),
>; >;
} }
@ -51,11 +52,9 @@ impl MessageHandler {
} }
fn parse_msg(&self, msg: &str) -> Result<Request, ()> { fn parse_msg(&self, msg: &str) -> Result<Request, ()> {
let msg = msg.trim(); match msg.as_bytes().parse_all::<tt::Request>() {
match msg { Ok(req) => Ok(req.into()),
"!help" => Ok(Request::Help), Err(_) => Err(()),
"!bt" => Ok(Request::Bt),
_ => Err(())
} }
} }
} }

View File

@ -15,7 +15,12 @@ pub enum Either<A, B> {
} }
// case-insensitive u8 character. // case-insensitive u8 character.
// type ILit<const BYTE: u8> = Either<Lit<{ BYTE.to_ascii_lowercase() }>, Lit<{ BYTE.to_ascii_uppercase() }>>; #[macro_export]
macro_rules! ilit {
($BYTE:literal) => {
Either<Lit<{ ($BYTE as u8).to_ascii_lowercase() }>, Lit<{ ($BYTE as u8).to_ascii_uppercase() }>>
}
}
pub type PResult<P, C> = std::result::Result<(C, P), P>; pub type PResult<P, C> = std::result::Result<(C, P), P>;
@ -37,6 +42,25 @@ pub trait Parser: Sized {
} }
} }
impl<'a> Parser for &'a [u8] {
fn expect_byte(self, b: Option<u8>) -> PResult<Self, ()> {
match (b, self.split_first()) {
// expected the correct character
(Some(exp), Some((first, rest))) if *first == exp => Ok( ((), rest) ),
// expected EOF, got EOF
(None, None) => Ok( ((), self)),
_ => Err(self),
}
}
fn expect<C: Parse>(self) -> PResult<Self, C> {
match C::consume(self.clone()) {
Ok(res) => Ok(res),
// rewind the parser should we fail
Err(_p) => Err(self),
}
}
}
pub trait Parse: Sized { pub trait Parse: Sized {
fn consume<P: Parser>(p: P) -> PResult<P, Self>; fn consume<P: Parser>(p: P) -> PResult<P, Self>;
} }