Skip to content

Instantly share code, notes, and snippets.

@bwindels
Created April 27, 2021 15:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bwindels/8701e8018bbfe3fb6cc160039c140d77 to your computer and use it in GitHub Desktop.
Save bwindels/8701e8018bbfe3fb6cc160039c140d77 to your computer and use it in GitHub Desktop.
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)
   }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment