reefer 0.3.0

Optimizing proc-macro for geometric algebra
Documentation
> ⚠️ **Heads up:** The remaining chapters dive into the compiler internals that power Reefer. If you’re here for day-to-day algebra usage, you can safely skip what's ahead or come back later when you’re ready for the gory details.

# Optimization Pipeline

Reefer behaves like a tiny compiler that runs entirely during macro expansion. The input is the Rust module annotated with `#[reefer::algebra]` plus any later calls to the generated `expr!` macro; the output is more Rust code that Rustc can type-check and inline. This chapter walks through the pipeline end to end so you can reason about where behaviours or diagnostics originate.

## Stage 1 - Attribute parsing (front end)

- **Responsibilities:** Decode the attribute payload and gather `basis!` / `shape!` invocations.
- **Key modules:** `src/spec.rs`, `src/algebra.rs`.
- **Inputs & outputs:** The procedural macro receives a module annotated with `#[reefer::algebra(scalar, p, q)]`. It lowers the arguments into `AlgebraAttr`, then aggregates basis and shape declarations into an `AlgebraSpec`.
- **Failure surface:** Any syntactic issue (unknown argument, missing module body, malformed `basis!`) is surfaced immediately via `syn::Error` tied to the offending span.

At the end of this stage we have a structured description of the algebra, no code has been emitted yet, but the spec contains everything downstream passes need.

## Stage 2 - Module elaboration

- **Responsibilities:** Turn the declarative spec into concrete Rust items.
- **Key modules:** `src/algebra.rs` (`build_algebra`), `src/spec.rs` (`ShapeItem`).
- **What happens:**
    - Every `basis!` block is recorded and removed from the expanded module.
    - Each `shape!` block desugars into a public struct with scalar fields, constructors, and basic trait impls.
    - The module receives an `expr!` helper backed by `reefer::build_expr!` so user crates can author symbolic closures.

If anything goes wrong here, such as the module being empty, the macro emits a compile-time error and stops.

## Stage 3 - Alias rewrite

- **Responsibilities:** Normalise user-friendly aliases (`e12`, `rotorA`) to canonical basis masks.
- **Key modules:** `src/build_expr/rewrite.rs`, `src/optimizer.rs` (`Optimizer::alias_mapping`).
- **Inputs & outputs:** When a user invokes `ga::expr!(...)`, the macro captures the closure and builds a `BuildExpr` record. Alias mapping produces a deterministic table from strings to basis masks; the rewrite pass walks the syntax tree, replacing identifiers so the rest of the pipeline only sees canonical names.
- **Failure surface:** Rewriting is designed to be total. If an identifier cannot be mapped, the optimiser records a diagnostic that materialises as a compile-time error attached to the original token.

This stage keeps the symbolic IR free from any naming quirks and enables deterministic simplifications.

## Stage 4 - IR construction

- **Responsibilities:** Interpret the rewritten closure into a Clifford-aware intermediate representation.
- **Key modules:** `src/optimizer/parser.rs`, `src/clifford/multivector.rs`, `src/clifford/mod.rs`.
- **Inputs & outputs:** The parser walks the `syn::Expr` tree, calling algebraic helpers to produce a `SymbolMultivector` (backed by `SynField` coefficients). Each node records the blade mask and the coefficient expression, preserving structure like wedges, inner products, involutions, and exponentials.
- **Failure surface:** If the expression uses unsupported syntax (for example a method call the parser does not recognise), `analysis_error` is set on `BuildExpr`. Expansion continues with a fallback closure so compilation succeeds, but later optimisation steps are skipped.

Think of this stage as turning syntax into a typed, algebra-specific IR; much like translating Rust HIR into MIR.

## Stage 5 - Optimisation passes

- **Responsibilities:** Simplify the multivector and prepare literals.
- **Key modules:** `src/build_expr.rs` (`BuildExpr::optimise`, `constant_shape_literal`), `src/clifford/multivector.rs` (algebraic helpers).
- **Pass highlights:**
    - **Zero pruning:** Any blade whose coefficient evaluates to zero is dropped immediately, keeping the representation sparse.
    - **Term merging:** Like-grade blades with compatible masks are merged via `accumulate_term`, reducing redundant arithmetic.

Feature flags (`backend_cas`, `backend_egg`) control which scalar backend drives simplification. The default CAS stack works quite well. Egg is an alternative that is being explored but is not yet functional and thus is behind a feature flag.

## Stage 6 - Backend emission

- **Responsibilities:** Convert the final IR back into Rust tokens.
- **Key modules:** `src/build_expr.rs` (`BuildExpr::into_stream`), `src/algebra.rs` (module generation).
- **What happens:**
    - Successful constant folding swaps the closure body for a literal shape struct value.
    - The closure is rehydrated into tokens using `quote!`, referencing the generated shape/basis types.
    - The resulting `TokenStream` is emitted to Rustc, which then performs its normal type checking and optimisation pipeline.

## Cross-cutting behaviours

- **Diagnostics:** Every stage propagates `syn::Error` or human-friendly messages. Front-end issues halt expansion; middle-end failures record context on `BuildExpr` so users receive actionable compiler notes. There are still some `todo!()`s sprinkled in (eg `div` still needs implemented) but every other path should not panic.
- **Testing hooks:** Unit tests in `src/algebra.rs` validate attribute handling, `optimizer::parser::tests` cover IR construction, and integration suites in `tests/smoke.rs` exercise the complete pipeline.
- **Extensibility:** New passes should slot naturally into Stage 5. They operate in place on `SymbolMultivector`.

Understanding these stages makes it easier to diagnose compile-time errors and to extend Reefer with new algebraic tricks. When you add a feature, ask which stage owns the logic, wire a couple tests into the matching module, and verify that the emitted tokens still type-check under both backends.