| Crates.io | parsey-derive |
| lib.rs | parsey-derive |
| version | 0.1.0 |
| created_at | 2024-12-09 10:16:24.738642+00 |
| updated_at | 2024-12-09 10:16:24.738642+00 |
| description | A simple parser-generator framework. |
| homepage | |
| repository | https://github.com/swolfenden9/parsey |
| max_upload_size | |
| id | 1477193 |
| size | 6,492 |
parsey is a lightweight, no_std framework for creating custom parsers and abstract syntax trees (ASTs).
It provides two key traits: Parser and Ast, which together form the foundation
for building parsers and representing the structure of parsed data.
Ast trait.no_std: Ideal for embedded or constrained environments.Parser TraitDefine a struct that will serve as your parser. This struct must implement the Parser trait,
which processes tokens and produces an AST.
use parsey::{Ast, Parser, PeekableParser};
#[derive(Debug, PartialEq)]
pub enum MyToken {
Zero,
One,
}
#[derive(Debug, PartialEq)]
pub struct MyError;
pub struct MyParser {
tokens: Vec<MyToken>,
}
impl MyParser {
pub fn new(mut tokens: Vec<MyToken>) -> Self {
tokens.reverse();
Self { tokens }
}
}
impl Parser<MyToken, MyError> for MyParser {
type Root = Root;
fn expect(
peekable_parser: &mut PeekableParser<Self, MyToken, MyError>,
token: MyToken,
) -> Result<(), MyError> {
if peekable_parser.peek() == Some(&token) {
peekable_parser.next();
Ok(())
} else {
Err(MyError)
}
}
}
impl Iterator for MyParser {
type Item = MyToken;
fn next(&mut self) -> Option<Self::Item> {
self.tokens.pop()
}
}
Create the structure for your AST by implementing the Ast trait for each node.
The root node must match the type defined in Parser::Root.
#[derive(Debug, PartialEq)]
pub struct Root(Vec<TwoBit>);
#[derive(Debug, PartialEq)]
pub enum TwoBit {
ZeroZero,
ZeroOne,
OneZero,
OneOne,
}
impl Ast<MyToken, MyError> for Root {
fn parse<P>(parser: &mut PeekableParser<P, MyToken, MyError>) -> Result<Self, MyError>
where
P: Parser<MyToken, MyError>,
{
let mut two_bits = vec![];
while parser.peek().is_some() {
two_bits.push(TwoBit::parse(parser)?);
}
Ok(Self(two_bits))
}
}
impl parsey::Ast<MyToken, MyError> for TwoBit {
fn parse<P>(parser: &mut PeekableParser<P, MyToken, MyError>) -> Result<Self, MyError>
where
P: parsey::Parser<MyToken, MyError>,
{
match parser.next() {
Some(MyToken::Zero) => match parser.next() {
Some(MyToken::Zero) => Ok(TwoBit::ZeroZero),
Some(MyToken::One) => Ok(TwoBit::ZeroOne),
_ => Err(MyError),
},
Some(MyToken::One) => match parser.next() {
Some(MyToken::Zero) => Ok(TwoBit::OneZero),
Some(MyToken::One) => Ok(TwoBit::OneOne),
_ => Err(MyError),
},
_ => Err(MyError),
}
}
}
Use your parser to parse a sequence of tokens into an AST.
fn main() {
use MyToken::{One, Zero};
use TwoBit::{OneOne, OneZero, ZeroOne, ZeroZero};
let tokens = vec![Zero, Zero, Zero, One, One, Zero, One, One];
let parser = MyParser::new(tokens);
let ast = parser.parse().unwrap();
assert_eq!(ast, Root(vec![ZeroZero, ZeroOne, OneZero, OneOne]));
}