11 releases
new 0.0.11 | Apr 23, 2024 |
---|---|
0.0.10 | Apr 16, 2024 |
0.0.9 | Mar 15, 2024 |
0.0.4 | Feb 24, 2024 |
#1 in #simplest
1,137 downloads per month
10KB
178 lines
The Simplest Parser Library (TSPL)
TSPL is the The Simplest Parser Library that works in Rust.
Concept
In pure functional languages like Haskell, a Parser can be represented as a function:
Parser<A> ::= String -> Reply<A, Error>
This allows us to implement a Monad instance for Parser<A>
, letting us use the do-notation
to
create simple and elegant parsers for our own types. Sadly, Rust doesn't have an equivalent. Yet,
we can easily emulate it by:
-
Using structs and
impl
to manage the cursor state internally. -
Returning a
Result
, which allows us to use Rust's?
to emulate monadic blocks.
This library merely exposes some functions to implement parsers that way, and nothing else.
Example
As an example, let's create a λ-Term parser using TSPL.
- Implement the type you want to create a parser for.
enum Term {
Lam { name: String, body: Box<Term> },
App { func: Box<Term>, argm: Box<Term> },
Var { name: String },
}
- Define your grammar. We'll use the following:
<term> ::= <lam> | <app> | <var>
<lam> ::= "λ" <name> " " <term>
<app> ::= "(" <term> " " <term> ")"
<var> ::= alphanumeric_string
- Create a new Parser with the
new_parser()!
macro.
TSPL::new_parser!(TermParser);
- Create an
impl TermParser
, with your grammar:
impl<'i> TermParser<'i> {
fn parse(&mut self) -> Result<Term, String> {
self.skip_trivia();
match self.peek_one() {
Some('λ') => {
self.consume("λ")?;
let name = self.parse_name()?;
let body = Box::new(self.parse()?);
Ok(Term::Lam { name, body })
}
Some('(') => {
self.consume("(")?;
let func = Box::new(self.parse()?);
let argm = Box::new(self.parse()?);
self.consume(")")?;
Ok(Term::App { func, argm })
}
_ => {
let name = self.parse_name()?;
Ok(Term::Var { name })
}
}
}
}
- Use your parser!
fn main() {
let mut parser = TermParser::new("λx(λy(x y) λz z)");
match parser.parse() {
Ok(term) => println!("{:?}", term),
Err(err) => eprintln!("{}", err),
}
}
The complete example is available in ./examples/lambda_term.rs. Run it with:
cargo run --example lambda_term
Credit
This design is based on T6's new parser for HVM-Core, and is much cleaner than the old HOPA approach.
Dependencies
~16KB