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

View File

@ -15,7 +15,12 @@ pub enum Either<A, B> {
}
// 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>;
@ -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 {
fn consume<P: Parser>(p: P) -> PResult<P, Self>;
}