pestle

Crates.iopestle
lib.rspestle
version
sourcesrc
created_at2024-12-14 11:36:48.48017
updated_at2025-01-07 01:44:42.654471
descriptiontyped AST facade for the pest parser
homepage
repositoryhttps://github.com/a6f/pestle
max_upload_size
id1483085
Cargo.toml error:TOML parse error at line 17, column 1 | 17 | autolib = false | ^^^^^^^ unknown field `autolib`, expected one of `name`, `version`, `edition`, `authors`, `description`, `readme`, `license`, `repository`, `homepage`, `documentation`, `build`, `resolver`, `links`, `default-run`, `default_dash_run`, `rust-version`, `rust_dash_version`, `rust_version`, `license-file`, `license_dash_file`, `license_file`, `licenseFile`, `license_capital_file`, `forced-target`, `forced_dash_target`, `autobins`, `autotests`, `autoexamples`, `autobenches`, `publish`, `metadata`, `keywords`, `categories`, `exclude`, `include`
size0
Ambrose Feinstein (a6f)

documentation

README

pestle: typed AST facade for the pest parser

A code generator which produces ergonomic Rust structs and enums from a pest grammar. These types are meant for examining a parsed AST—not modifying it or constructing a new one.

The grammar must obey one restriction: the choice operator (|) may appear only in rules which use no other operators (these become Rust enums), and all choices must be named rules (these become the variant names).

Atomic rules become tuple structs containing only a Span.

Other rules become ordinary structs with fields named according to the types of their children. All children of the same type are accumulated into one field; depending on cardinality, this may be a value, an Option, or a Vec. Each child type appears in parse order, but if there are multiple types, relative ordering is lost. (Many rules will be unambiguous, but consider e.g. { A* ~ B ~ A* }. The original order could be deduced from spans, however.)

All children are stored as references; this allows representing recursive or mutually recursive rules. Since Span already infects all the types with a lifetime parameter (representing the input string), the child references are given the same lifetime, and an allocator is required during construction.

The generated types, in addition to their public fields, have a span() accessor, and a static function build() which can construct them from a Pair and an allocator.

Example

#[derive(pest_derive::Parser, pestle::TypedRules)]
#[grammar = "src/expr.pest"]
#[typed_mod = "ast"]
pub struct Parser;

pub fn parse<'i>(source: &'i str, arena: &'i Bump) -> &'i ast::Expr<i'> {
    let pair = Parser::parse(Rule::Expr, source).unwrap().next().unwrap();
    ast::Expr::build(pair, arena)
}
Why

Written out of frustration after examining all the alternatives, implementing a complete system atop pest_typed_derive, and discovering it adds quadratic overhead to parsing.

Commit count: 12

cargo fmt