# `PtcRunner.Lisp.Analyze`
[🔗](https://github.com/andreasronge/ptc_runner/blob/main/lib/ptc_runner/lisp/analyze.ex#L1)

Validates and desugars RawAST into CoreAST.

The analyzer transforms the parser's output (RawAST) into a validated,
desugared intermediate form (CoreAST) that the interpreter can safely evaluate.

## Error Handling

Returns `{:ok, CoreAST.t()}` on success or `{:error, error_reason()}` on failure.

# `error_reason`

```elixir
@type error_reason() ::
  {:invalid_form, String.t()}
  | {:invalid_arity, atom(), String.t()}
  | {:invalid_cond_form, String.t()}
  | {:invalid_thread_form, atom(), String.t()}
  | {:unsupported_pattern, term()}
  | {:invalid_placeholder, atom()}
```

# `analyze`

```elixir
@spec analyze(term(), PtcRunner.Lisp.Prelude.t() | nil) ::
  {:ok, PtcRunner.Lisp.CoreAST.t()} | {:error, error_reason()}
```

Validates and desugars `raw_ast` into CoreAST.

When a compiled `prelude` (`%PtcRunner.Lisp.Prelude{}`) is supplied, the
analyzer resolves qualified prelude calls/refs (e.g. `crm/get-user`) against
the prelude's PUBLIC export table and rejects writes into protected prelude
namespaces (e.g. `(defn crm/get-user ...)`) with a protection programmer
fault. The prelude is consulted via process-local state scoped to this single
analysis pass (set on entry, cleared on exit), so the deep mutually-recursive
`do_analyze/2` clauses do not each have to thread it. Passing `nil` keeps the
pre-prelude behavior unchanged.

# `supported_forms`

```elixir
@spec supported_forms() :: [atom()]
```

Returns the canonical list of all forms handled by the analyzer.

These are forms dispatched via `dispatch_list_form/4` — special forms,
macros, predicate builders, and control flow that the analyzer intercepts
before the interpreter sees them.

## Examples

    iex> :let in PtcRunner.Lisp.Analyze.supported_forms()
    true

    iex> :filter in PtcRunner.Lisp.Analyze.supported_forms()
    false

---

*Consult [api-reference.md](api-reference.md) for complete listing*
