pass-lang is the pass manager a compiler runs its optimizations and transforms through. A PassManager is an ordered pipeline of passes over a unit of compilation: it runs them in registration order, can iterate to a fixpoint, and reports what changed. It is generic over the unit type — a function, a module, an intermediate representation, an AST — and owns no IR of its own. A consumer brings the unit and implements the Pass trait, which is the plugin seam capability crates register their passes into. It is a SEMA-tier crate of the -lang language-construction family.
MSRV is 1.85+ (Rust 2024 edition).
Status: stable (1.0). The public API is frozen and follows Semantic Versioning — no breaking changes before2.0. Seethe SemVer promiseandCHANGELOG.md.
[dependencies]
pass-lang = "1.0"Or from the terminal:
cargo add pass-langImplement Pass for each transform, register them in order with PassManager::add, and run the pipeline. Each pass reports whether it changed the unit, so the manager can drive the pipeline to a fixpoint and tell you what happened.
use pass_lang::{Outcome, Pass, PassError, PassManager};
// The unit is whatever a pass rewrites — here, a list of integers.
struct DropZeros;
impl Pass<Vec<i64>> for DropZeros {
fn name(&self) -> &'static str {
"drop-zeros"
}
fn run(&mut self, unit: &mut Vec<i64>) -> Result<Outcome, PassError> {
let before = unit.len();
unit.retain(|&x| x != 0);
Ok(Outcome::from_changed(unit.len() != before))
}
}
// Halve every value greater than one.
struct Halve;
impl Pass<Vec<i64>> for Halve {
fn name(&self) -> &'static str {
"halve"
}
fn run(&mut self, unit: &mut Vec<i64>) -> Result<Outcome, PassError> {
let mut changed = false;
for x in unit.iter_mut() {
if *x > 1 {
*x /= 2;
changed = true;
}
}
Ok(Outcome::from_changed(changed))
}
}
let mut pm = PassManager::new();
pm.add(DropZeros).add(Halve);
let mut unit = vec![0, 8, 0, 4];
let report = pm.run_to_fixpoint(&mut unit, 16).expect("no pass fails");
assert_eq!(unit, vec![1, 1]); // zeros dropped, 8 and 4 halved to 1
assert!(report.converged());A pass that cannot proceed returns a PassError instead of panicking; the manager stops the pipeline and names the pass that failed. The unit type is anything a pass rewrites — an IR, a function, a module, an AST, or a struct bundling an IR with the diagnostics and analysis a pass needs.
Runnable examples: examples/expr_optimizer.rs (constant folding and algebraic simplification to a fixpoint, with the error path), examples/text_normalizer.rs (the same machinery over a String), and examples/contextual_passes.rs (a unit that bundles code with a diagnostics log, so passes share context without a global).
cargo run --example expr_optimizer
cargo run --example text_normalizer
cargo run --example contextual_passes- API Reference — every public item, with examples.
- ROADMAP — the path to a frozen 1.0.
- CHANGELOG.
See dev/DIRECTIVES.md for engineering standards and the definition of done. Before a PR: cargo fmt --all, cargo clippy --all-targets --all-features -- -D warnings, and cargo test --all-features must be clean.
Licensed under either of
- Apache License, Version 2.0 — LICENSE-APACHE
- MIT License — LICENSE-MIT
at your option.