laps
Lexer and parser collections.
With laps
, you can build parsers by just defining ASTs and deriving Parse
trait for them.
Usage
Add laps
to your project by running cargo add
:
cargo add laps
Example
Implement a lexer for S-expression:
use laps::prelude::*;
#[token_kind]
enum TokenKind {
/// Atom.
Atom(String),
/// Parentheses.
Paren(char),
/// End-of-file.
Eof,
}
type Token = laps::token::Token<TokenKind>;
struct Lexer<T>(laps::reader::Reader<T>);
impl<T: std::io::Read> Tokenizer for Lexer<T> {
type Token = Token;
fn next_token(&mut self) -> laps::span::Result<Self::Token> {
// skip spaces
self.0.skip_until(|c| !c.is_whitespace())?;
// check the current character
Ok(match self.0.peek()? {
// parentheses
Some(c) if c == '(' || c == ')' => Token::new(c, self.0.next_span()?.clone()),
// atom
Some(_) => {
let (atom, span) = self
.0
.collect_with_span_until(|c| c.is_whitespace() || c == '(' || c == ')')?;
Token::new(atom, span)
}
// end-of-file
None => Token::new(TokenKind::Eof, self.0.next_span()?.clone()),
})
}
}
And the parser and ASTs (or actually CSTs):
token_ast! {
macro Token(mod = crate, Kind = TokenKind) {
[atom] => (TokenKind::Atom(_), "atom"),
[lpr] => (TokenKind::Paren('('), _),
[rpr] => (TokenKind::Paren(')'), _),
[eof] => (TokenKind::Eof, _),
}
}
#[derive(Parse)]
#[token(Token)]
enum Statement {
Elem(Elem),
End(Token![eof]),
}
#[derive(Parse)]
#[token(Token)]
struct SExp(Token![lpr], Vec<Elem>, Token![rpr]);
#[derive(Parse)]
#[token(Token)]
enum Elem {
Atom(Token![atom]),
SExp(SExp),
}
The above implementation is very close in form to the corresponding EBNF representation of the S-expression:
Statement ::= Elem | EOF;
SExp ::= "(" {Elem} ")";
Elem ::= ATOM | SExp;
More Examples
See the examples
directory, which contains the following examples:
sexp
: a S-expression parser.calc
: a simple expression calculator.json
: a simple JSON parser.clike
: interpreter for a C-like programming language.
Changelog
See CHANGELOG.md.
License
Copyright (C) 2022-2023 MaxXing. Licensed under either of Apache 2.0 or MIT at your option.