Handmade parsers and combinators for your string extraction needs
This is an introduction by example. For a first-principles introduction to parser combinators see here.
A parser is a function that takes some input in, extracts some information and returns the result of this extraction. In order to make any progress, the result contains the leftover input after consuming some part of it, or in the case of error returns some value indicating failure.
```rust use ruminant::str::; use ruminant::;
// A parser that can recognize the string --
fn double_dash(input: &[u8]) -> ParseResult<&str> {
// literal
is a function that takes a string and returns a parser that
// recognizes when that string is at the start of the input.
let (first, rest) = literal("-")(input)?;
// Notice how we use the leftover from parsing the first dash as the input
// to parse the second
let (second, rest) = literal("-")(rest)?;
Ok(("--", rest))
}
fn main() { if let Ok((dashes, rest)) = double_dash(b"--option=value") { // parse the rest } } ```
A combinator takes one or more parsers as input and returns a different parser. They are useful for uhh...combining multiple parsers together or even changing what parsers do.
```rust use ruminant::{str::, combinator::}; use ruminant::*;
fn double_dash(input: &[u8]) -> ParseResult
// We also want to recognize "short" options (e.g. -v)
fn single_dash(input: &[u8]) -> ParseResult
fn main() { // We can use a combinator to try to match either a double or single dash let dashes = choiceof(parsers![doubledash, single_dash]); if let Ok((item, rest)) = dashes(b"--option=value") { // parse the rest } }
```
With only these two ideas the parsing world becomes your oyster.
```rust use ruminant::{str::, combinator::}; use ruminant::*;
pub struct Color { pub red: u8, pub green: u8, pub blue: u8, }
fn hexdigit(input: &[u8]) -> ParseResult<&str> { choiceof(parsers![ digit, literals(vec!["a", "b", "c", "d", "e", "f"]), literals(vec!["A", "B", "C", "D", "E", "F"]), ])(input) }
fn hexprimary(input: &[u8]) -> ParseResult
let value = u8::from_str_radix(&hex, 16).unwrap();
Ok((value, rest))
}
fn hexcolor(input: &[u8]) -> ParseResult
Ok((Color { red, green, blue }, rest))
}
fn main() { asserteq!(hexcolor(b"#2F14DF").unwrap().0, Color { red: 47, green: 20, blue: 223, }); } ```