trait Parser<'a> {
type Input;
type Output;
type Error;
fn parse(&self, input: &mut 'a Self::Input) -> Result<ParsedValue<'a>, Self::Error>;
}
enum ParsedValue<'a> {
NoMatch(&mut 'a Self::Input),
Match(Option<&mut 'a Self::Input>, Output<'a>),
}
input and output should be able to be mutable reference, so parser can also decode inline
based on this, implement several operators:
- split with separator
- sequence (steps that are concatenated, one result passed into the next, much like fold) could be a macro to allow arbritary number of steps, generating a struct Self::input = Child1::Input, Self::Output = ChildN::Output, Child2::Input must be Child1::Output types are forced to be compatible
- delimited ("..."..." yielding everything inside quotes)
- ignore (e.g. swallows literal \0, " " before and after child parser)
- trim, trim_left, trim_right (ignore before and after child)
- map (for post processing an output value)
- a | b | c (yielding an enum for example)
these are all composed using monomorphism
the url decoding scheme by delimiting/padding a string with 0 bytes:
name: not(or(literal(&), literal(=))) value: not(literal(=)) encoded_pair: sequence!(map(name, url_decode_and_move_1), literal(=), map(value, url_decode_and_move_1)) decoded_pair: sequence!(trim_right(delimited(\0), \0), literal(=), trim_right(delimited(\0), \0)) pair: or(decoded_pair, encoded_pair) //first decoded pairs: split(pair, &)
TODO:
- check nom, does this or similar, allows mut references and decoding inline?
- if we do implement this, write benchmark to measure diff with manual url decode code
struct Map<'a, F, P> {
child: P,
map: F
}
impl<'a, C, P> Parser<'a> for Map<'a, C, P>
where
P: Parser<'a>,
F: Fn(P::Output<'a>) -> Self::Output<'a>
{
fn parse(&self, input: &mut Self::Input) -> ParseResult<'a> {
let m = match self.child.parse()? {
Match(r, o) => Match(r, (self.map)(o)),
m => m,
}
Ok(m)
}
}