Your grammar is your AST. Formerly rust-sitter.
Most parser generators make you maintain two things: the grammar and the AST you actually want to use. Adze collapses those into one. You describe your language as Rust types, and the build tooling generates a parser that returns those types directly.
grammar as Rust types → generated parser → typed Rust AST
not:
grammar → generic tree → hand-written tree walker → hand-written AST mapper
#[adze::grammar("arithmetic")]
pub mod grammar {
#[adze::language]
#[derive(Debug, PartialEq)]
pub enum Expr {
Number(
#[adze::leaf(pattern = r"\d+", transform = |v| v.parse().unwrap())]
i32,
),
#[adze::prec_left(1)]
Add(Box<Expr>, #[adze::leaf(text = "+")] (), Box<Expr>),
#[adze::prec_left(2)]
Mul(Box<Expr>, #[adze::leaf(text = "*")] (), Box<Expr>),
}
#[adze::extra]
#[allow(dead_code)]
struct Whitespace {
#[adze::leaf(pattern = r"\s+")]
_ws: (),
}
}
let expr = grammar::parse("1 + 2 * 3")?;
// expr = Add(Number(1), (), Mul(Number(2), (), Number(3)))[dependencies]
adze = { version = "0.8", default-features = false }
[build-dependencies]
adze-tool = "0.8"
[features]
default = ["pure-rust"]
pure-rust = ["adze/pure-rust"]Add a build.rs pointing at the file that contains your #[adze::grammar] module:
use std::path::PathBuf;
fn main() {
println!("cargo::rustc-check-cfg=cfg(adze_unsafe_attrs)");
// src/lib.rs for library crates, src/main.rs for binary crates
adze_tool::build_parsers(&PathBuf::from("src/lib.rs"));
}Then call grammar::parse(input) to get Result<YourType, Vec<ParseError>>.
For the shortest path, start with Quickstart: First Parser In 10 Minutes. For the API ladder, read the Mental Model.
Adze is under active development. The core parser pipeline is working and tested. Some broader surfaces — CLI tooling, WASM, runtime2, grammar crates, golden tests, benchmarks, and Tree-sitter bridge/compatibility — are still being hardened.
Support tiers, proof commands, and CI lanes are tracked in docs/status/SUPPORT_TIERS.md.
| Tier | Meaning |
|---|---|
| Stable | Supported product contract with named required or stable-product proof |
| Stabilizing | Implemented and tested, but missing broader product proof before stable promotion |
| Experimental | Implemented, but outside the supported contract; behavior may change |
| Advisory | Useful non-blocking signal from optional CI, smoke tests, or examples |
| Surface | Tier | Proof |
|---|---|---|
| Typed extraction | Stable | just ci-supported; cargo test -p adze --features pure-rust --test typed_ast_contract typed_ast_contract_left_associative_addition -- --exact --nocapture; cargo test -p adze --features pure-rust --test typed_ast_contract typed_ast_contract_repeated_parse_is_deterministic -- --exact --nocapture |
| Pure-Rust parser | Stable | just ci-supported; cargo test -p adze-cli readme_arithmetic_quickstart_builds_and_runs -- --exact --nocapture; cargo test -p adze-cli getting_started_quickstart_builds_parses_and_reports_diagnostics -- --exact --nocapture; cargo test -p adze-cli book_quickstart_builds_parses_and_reports_diagnostics -- --exact --nocapture; cargo test -p downstream-demo -- --nocapture; cargo run -p downstream-demo --quiet; cargo test --manifest-path testing/downstream-starter/Cargo.toml; cargo run --manifest-path testing/downstream-starter/Cargo.toml --example parse |
| Operator precedence | Stable | cargo test -p adze-cli readme_arithmetic_quickstart_builds_and_runs -- --exact --nocapture; cargo test -p adze-glr-core --test ambiguity_detection_comprehensive test_precedence_resolves_add_mul -- --exact --nocapture |
| Serialization (core tables) | Stable | cargo test -p adze-glr-core --features serialization --doc; cargo test -p adze-glr-core --features serialization --test serialization_v9 sv9_complex_precedence_roundtrip -- --exact --nocapture |
| GLR conflict routing | Stabilizing | cargo test -p adze --features "pure-rust,glr,runtime-e2e" --test test_e2e_ambiguous_grammar_glr test_ambiguous_grammar_glr_parsing -- --exact --nocapture; cargo test -p adze --features "pure-rust,glr,runtime-e2e" --test test_e2e_ambiguous_grammar_glr generated_ambiguous_expr_glr_runtime_retains_multiple_complete_alternatives -- --exact --nocapture |
| Tablegen TSLanguage ABI | Stabilizing | cargo test -p adze --features "pure-rust,glr,ts-compat" --test tablegen_abi_decode_roundtrip combined_tslanguage_decode_preserves_metadata_fields_aliases_externals_and_lex_modes -- --exact --nocapture |
| Structured parse errors | Stabilizing | cargo test -p adze --features "pure-rust,glr" --test generated_parse_errors generated_typed_parser_unexpected_eof_expected_field_is_populated -- --exact --nocapture; cargo test -p adze --features pure-rust --test generated_parse_errors expected_token_sets_are_reported -- --exact --nocapture |
| AdzeDocument native API | Stabilizing | cargo test -p adze --features "pure-rust,ts-compat" --test adze_document_alpha -- --nocapture; cargo test -p adze --features pure-rust --test typed_ast_contract typed_ast_contract_parse_document_ast_matches_parse -- --exact --nocapture; cargo test --manifest-path testing/downstream-starter/Cargo.toml |
| Typed CST native view | Experimental | cargo test -p adze --features "pure-rust,ts-compat" --test typed_cst_arithmetic_spike -- --nocapture; cargo test -p adze-tablegen typed_cst_generator -- --nocapture |
| External scanners | Experimental | cargo test -p adze --features external_scanners |
| Incremental parsing | Experimental | cargo test --workspace --features incremental_glr |
| CLI | Stabilizing | cargo test -p adze-cli test_init_default_cwd_generates_buildable_project -- --exact --nocapture; cargo test -p adze-cli test_init_generates_buildable_project -- --exact --nocapture; cargo test -p adze-cli getting_started_quickstart_builds_parses_and_reports_diagnostics -- --exact --nocapture; cargo test -p adze-cli test_parse_document_projection_modes_emit_schema_envelopes -- --exact --nocapture; cargo test -p adze-cli parse_document_json_modes_emit_recovery_diagnostics -- --exact --nocapture |
adze-tool CLI |
Advisory | cargo test -p adze-tool --test cli_test test_test_command_rejects_corpus_without_parser -- --exact --nocapture |
| WASM | Advisory | cargo check --manifest-path wasm-demo/Cargo.toml --target wasm32-unknown-unknown |
| Tree-sitter interop | Advisory | ./scripts/smoke-link.sh ts-bridge |
| Tree-sitter compatibility API | Stabilizing | cargo test -p adze --features "pure-rust,glr,ts-compat" --test ts_compat_selected_tree -- --nocapture; cargo test -p adze --features "pure-rust,ts-compat,query" --test ts_compat_imported_shape_smoke -- --nocapture |
| Query compatibility subset | Stabilizing | cargo run -p adze --features query --example query_highlighting; cargo test -p adze --features query --lib query -- --nocapture; cargo test -p adze --features "pure-rust,ts-compat,query" --test query_differential -- --nocapture |
| runtime2 | Advisory | cargo test --manifest-path runtime2/Cargo.toml --features test-utils --test basic language_smoke_exposes_metadata_queries -- --exact --nocapture |
| Grammars | Advisory | cargo test -p adze-python test_python_language_exists -- --exact |
| Golden tests | Advisory | cargo test -p adze-golden-tests javascript_canary_expression_golden --features javascript-grammar -- --nocapture |
| Benchmarks | Advisory | cargo run -q -p xtask -- perf-receipt --profile product-smoke; cargo test -p adze-benchmarks --test verify_fixture_parsing verify_parse_bench_uses_real_parser_workload -- --exact --nocapture |
Rule for documentation and CI promotion: no Stable feature claim without a named proof command in docs/status/SUPPORT_TIERS.md.
Adze is a good fit if you are building a parser or DSL in Rust, you control the grammar, and you want the result as plain Rust types integrated into a normal Cargo build. It is not yet a drop-in replacement for mature parser generators, and surfaces outside the core lane should be treated as developing.
At build time, adze-tool reads your annotated Rust types, constructs a grammar IR, computes LR(1)/GLR parse tables via adze-glr-core, and emits generated Rust through adze-tablegen. At runtime, adze uses those tables to parse input and return your typed value directly — no generic tree, no secondary mapping step.
adze-macro → adze-tool → adze-ir → adze-glr-core → adze-tablegen → adze runtime → typed extraction
| Crate | Role |
|---|---|
adze |
Runtime parser, parse trees, typed extraction, errors |
adze-macro |
Grammar attributes and extraction support |
adze-tool |
Build-time parser generation |
adze-ir |
Grammar intermediate representation |
adze-glr-core |
LR/GLR automata, conflicts, ambiguity machinery |
adze-tablegen |
Parse table generation and compression |
Additional workspace areas include grammar crates, benchmarks, WASM demos, golden tests, bridge tooling, and test-support infrastructure. These are useful but not all are part of the supported core lane.
- Getting Started — build your first parser
- Architecture — how the macro, tool, and runtime fit together
- Grammar Examples — patterns for common constructs
- API Reference — generated docs on docs.rs
Contributions are welcome. See CONTRIBUTING.md for guidelines, ROADMAP.md for planned work, and the Developer Guide for internal setup.
just ci-supported # required PR gate — fmt + clippy + tests on core crates
just ci-product-stable # optional Stable README product canaries
just test # core lib tests
just clippy # lint core crates
cargo fmt --all --check
cargo t2 # tests with 2 threadsLicensed under either:
- Apache-2.0
- MIT
at your option.