mx-sanebot: port the parsing over to a more formal implementation
This commit is contained in:
parent
b0c68308b7
commit
7c1961eba8
|
@ -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(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user