## Gonidium REPL Design

### Goal

Provide a lightweight CLI REPL for Gonidium that lets users iteratively type small pieces of DSL (input declarations, assignments, expressions), immediately see types and values, and experiment with the type system and optimisations without touching `.gon` files. The design must be compatible with a future TUI that reuses the same session model.

### Scope (v1)

- **CLI only**: normal terminal, no complex cursor control or panes.
- **Per-session state**:
  - Declared **inputs** and their dtypes.
  - Declared **locals** (assignments) and their dtypes / optional values.
  - Most recent diagnostics summary.
- **Per-line behaviour**:
  - Input declaration lines.
  - Assignment lines.
  - Expression lines.
- **Pipeline per line**: `parse → lower → (opt) → type check → (optional interp_eval)`.

Out of scope for v1:

- Multi-line editing, history search UI (shell readline is enough).
- Persisting sessions or attaching to `.gon` files.
- Any non-CLI UI (TUI, web, etc.).

### Session Model

Each REPL instance owns an in-memory **session**:

- **Inputs**: ordered list and map `name → DType`.
- **Locals**: map `name → { dtype: DType, value: Option<Value> }`.
- **Last diagnostics**: collected `Diag` values plus a compact printable summary.
- **Config**:
  - `opt_enabled: bool` (mirrors `--no-opt`).
  - Hooks for future custom diag / print behaviour.

Session state is only mutated by successfully processed lines; lines that fail in parse/lower do not change inputs/locals.

### Top-of-prompt Global Info

Even in CLI form, we print a small “header” block before each input prompt, anticipating a future TUI:

- **Inputs**: `inputs: x: f32, y: f64` (empty if none).
- **Locals (recent)**: e.g. `locals: t1: f64, z: f32` (can cap to N entries).
- **Last diags summary**: one short line, e.g. `last diag: L007 lower-implicit-promotion (Info)` or `last diag: none`.

A future TUI can reuse this data structure to render a persistent top/side panel.

### Line Grammar (User Input)

REPL accepts exactly three line shapes (ignoring leading/trailing whitespace and comments later if needed):

1. **Input declaration**

   - Syntax: `name: dtype`
   - Examples:
     - `x: f32`
     - `w: f64`
   - Semantics:
     - Extends the session’s **inputs set** with `name` and its `DType`.
     - If `name` already exists as an input, either:
       - v1 rule: overwrite dtype with a warning diag, or
       - alternative: reject with an error diag.
     - Does not immediately evaluate anything.

2. **Assignment**

   - Syntax: `name = <expr>`
   - Examples:
     - `t1 = x + 1`
     - `z = sigmoid(t1)`
   - Semantics:
     - Treats the RHS as a Gonidium expression in a context where current inputs and locals are visible.
     - Runs `parse → lower → (opt)` to get a `TypedDag` (or equivalent typed expression node).
     - If there are no errors, determines the dtype of the RHS and:
       - Updates `locals[name].dtype`.
       - Optionally evaluates RHS when it is **closed and evaluable** (see “Evaluation rules”).

3. **Bare expression**

   - Syntax: `<expr>`
   - Example:
     - `x * y + 1`
     - `t1 + 1`
   - Semantics:
     - Same pipeline as assignment (`parse → lower → (opt)`).
     - Does **not** bind a new name in locals.
     - Used for ad-hoc probing of expressions.

We defer multi-line definitions and control flow to normal `.gon` files; REPL is intentionally “one small statement per line”.

### Evaluation and Output Rules

Per successfully parsed & lowered line:

1. **Closed vs open expression**
   - If the final expression is **closed** over the current inputs/locals and has no remaining unknowns:
     - We attempt to run `interp_eval` using:
       - Current input values (see “Input values” below).
       - Any locals that already carry concrete `Value`s.
   - If the expression is **open** (depends on symbols without concrete values):
     - We **do not** run interpreter.

2. **Default output policy**

   - If interpreter runs and returns a concrete `Value` with `DType`:
     - Print `value@dtype` using the existing CLI formatting logic (`format_value_with_dtype` style).
   - If interpreter cannot run (open expression) but type inference succeeds:
     - Print the **simplified expression + dtype**, e.g.:
       - `x*2+1 @ f64`
     - “Simplified expression” should be what the optimisation/restoration pipeline produces for that node (mirroring what backend codegen would see).

3. **Diagnostics printing**

   - Collect diags from lower and opt phases as usual.
   - For this line:
     - Print each diag as a single-line or short multi-line message directly under the user’s input.
     - Update `last diags summary` with:
       - Highest severity code, and
       - First diagnostic’s short code and name.
   - Typical examples:
     - `info: L007 lower-implicit-promotion: promoted x: f32 and 1: f64 to f64`
     - `warning: L008 lower-float-precision-loss: literal 0.1 truncated to f32`

Errors (parse/lower) abort the line, print diagnostics, and do not mutate session state.

### Input Values for Evaluation

To actually call `interp_eval`, we need concrete `Value`s for inputs. v1 keeps this simple:

- REPL starts with **no input values bound**.
- Provide a command (future extension) to set input values, or for v1:
  - Focus primarily on expressions that are fully computable from locals and literal constants.
- The design and pipeline for using `interp_eval` are in place, even if v1 only exercises them in limited cases.

This leaves room to extend later with:

- Commands like `:set x 1.0` for binding concrete input values.
- A mode to auto-generate dummy values per dtype for quick “shape checking” runs.

### Optimisation and Type Promotion

- REPL uses the same optimisation pipeline as the CLI `run` command by default.
  - A global REPL flag `opt_enabled` controls whether to call `optimize_with_info`.
- Type promotion and precision-loss diagnostics use the existing `Diag` machinery:
  - We keep their semantics identical to batch mode (just change presentation).
  - The REPL is especially useful for interactively understanding implicit promotions.

### Error Handling

- **Parse errors**:
  - Print human-readable ariadne-style snippet, but consider a compact “one-line + caret” form for REPL.
  - Do not change inputs/locals.
- **Lower/IR errors**:
  - Show code, message, and short span snippet.
  - Do not change inputs/locals.
- **Interpreter errors**:
  - Printed as `interp error: ...` (consistent with existing CLI).
  - Do not change inputs/locals’ values for that line.

### Future Extensions (Beyond v1)

- **Value binding and commands**:
  - `:set x 1.0` / `:show` / `:clear` style meta-commands.
  - Command to toggle optimisation in-session.
- **Custom output formats**:
  - User-selectable policies: show/hide optimised expression, show raw DAG node IDs, etc.
- **TUI**:
  - Use the same session model to render:
    - Persistent top panel: inputs / locals / last diag summary.
    - Scrollable history of commands and outputs.
    - Side panel for selected expression’s optimisation trace.
