# Backend Simplification & Numba Backend — Design

## Goals

- Simplify the `backend` module so that the core library focuses on IR, optimisation and interpretation.
- Remove built-in Python/Rust codegen entry points (`emit_python`, `emit_rust`) and the `--codegen` CLI switch.
- Provide a small, explicit trait-based backend interface that users can implement to build their own backends.
- Ship a single, opinionated default backend that emits inline Numba-decorated Python kernels, mainly as a working example.

## Public API Shape

- Define a backend trait directly in `backend`:

  ```rust
  pub trait Backend {
      type Output;

      fn emit_kernel(&self, dag: &TypedDag, fn_name: &str) -> Self::Output;
  }
  ```

  - The name `Backend` is intentionally short and is always used in the context of the `backend` module (`backend::Backend`), which makes it clear that it is the trait representing “a backend”.
  - Concrete implementations will always carry a more specific suffix (for example `NumbaBackend`), so that bare `Backend` only ever refers to the trait.

- Re-exports from `lib.rs`:
  - Keep: interpreter exports (`InterpError`, `Value`, `interp_eval`).
  - New: re-export `backend::Backend` and the default Numba backend type.

## Default Numba Backend

- New module `src/backend/numba.rs`:

  ```rust
  pub struct NumbaBackend;

  impl Backend for NumbaBackend {
      type Output = String;

      fn emit_kernel(&self, dag: &TypedDag, fn_name: &str) -> String {
          // emit Python + Numba source code for a single kernel function
      }
  }
  ```

- Codegen strategy:
  - Reuse the current `python_gen` traversal logic:
    - Discover the subset of nodes that are needed to compute the outputs.
    - Assign each node to a temporary `t{idx}` variable.
    - Emit a single function that computes all needed temporaries and returns either a single value or a tuple of output temporaries.
  - Differences from the current Python backend:
    - Header: emit `import numba` in addition to `import math`.
    - Decorator: emit `@numba.njit` immediately before the `def` line.
    - Clean up small issues called out in the review:
      - For `Node::Param`, don’t silently fall back to `"arg"` — instead rely on the param list and treat missing entries as internal bugs (e.g. via `expect`).
      - For `Node::Call`, don’t use `unwrap_or(0)` for the first argument; instead, require that calls have at least one argument and fail loudly if not.
  - Output is a `String` containing valid Python source that users can `exec` or write to disk.

## Module Layout Changes

- `src/backend/mod.rs`:
  - Before:

    ```rust
    pub mod interp;
    pub mod python_gen;
    pub mod rust_gen;
    ```

  - After:

    ```rust
    pub mod interp;
    pub mod numba;

    use crate::ir::TypedDag;

    pub trait Backend {
        type Output;

        fn emit_kernel(&self, dag: &TypedDag, fn_name: &str) -> Self::Output;
    }
    ```

- Remove the now-unused modules:
  - Delete `src/backend/python_gen.rs`.
  - Delete `src/backend/rust_gen.rs`.

## CLI Behaviour

- `src/bin/gonidium.rs`:
  - Remove the `--codegen` option entirely and the associated `codegen: Option<String>` field on `Run`.
  - The `run` subcommand now has a single behaviour:
    - Parse → lower → optionally optimise → interpret with `interp_eval`.
  - Adjust help text and error messages so that they no longer mention codegen, Python or Rust backends.

## Tests and Documentation

- Update tests:
  - Remove tests that refer directly to `emit_python` / `emit_rust`.
  - Add tests that exercise the Numba backend:
    - Basic end-to-end codegen sanity (generated source contains `@numba.njit` and a `def kernel(...):`).
    - Special float constants still map to `float('inf')`, `float('-inf')`, `float('nan')`.
  - Keep existing optimisation-vs-interpretation tests as-is (they don’t depend on codegen).

- Update docs:
  - `README.md`: update the “pipeline” section to describe:
    - `lower` → `optimize` → user-defined `Backend` implementation (optional) or `interp_eval`.
  - `docs/config.md`: adjust the “后端” section to reference the `Backend` trait and the default Numba backend instead of `emit_python` / `emit_rust`.
