Skip to content

jamesgober/pass-lang

Repository files navigation

Rust logo
pass-lang
PASS MANAGER

Crates.io Downloads docs.rs CI MSRV

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 before 2.0. See the SemVer promise and CHANGELOG.md.


Installation

[dependencies]
pass-lang = "1.0"

Or from the terminal:

cargo add pass-lang

Usage

Implement 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

Documentation



Contributing

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.


License

Licensed under either of

at your option.

COPYRIGHT © 2026 James Gober .

About

Optimization/transform pass manager with a plugin seam.

Topics

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

0 stars

Watchers

1 watching

Forks

Sponsor this project

Packages

 
 
 

Contributors

Languages