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

Validates PTC-Lisp specification against implementation.

Reads `docs/ptc-lisp-specification.md`, asks
`PtcRunner.Lisp.SpecValidator.Parser` to extract `; =>` examples
from the markdown, then runs each example through
`PtcRunner.Lisp.run/2` and reports per-section pass/fail counts plus
`TODO`/`BUG` markers. Helps detect drift between the specification
and the implementation.

The markdown-parsing half lives in
`PtcRunner.Lisp.SpecValidator.Parser`. This module is the
thin orchestration façade: spec I/O + example execution + result
aggregation + negative-test handling.

## Usage

    # Validate all examples in specification
    PtcRunner.Lisp.SpecValidator.validate_spec()

    # Validate a single example
    PtcRunner.Lisp.SpecValidator.validate_example("(+ 1 2)", 3)

    # Get all examples from spec
    examples = PtcRunner.Lisp.SpecValidator.extract_examples()

# `examples_hash`

```elixir
@spec examples_hash() :: {:ok, String.t()} | {:error, String.t()}
```

Get a hash of all examples in the specification.

Used to detect changes to the specification over time.

# `extract_examples`

```elixir
@spec extract_examples() :: {:ok, map()} | {:error, String.t()}
```

Extract all examples from the specification.

Returns a map with categorized examples:
- `examples` - Testable examples as `{code, expected, section}` tuples
- `todos` - TODO markers as `{code, description, section}` tuples
- `bugs` - BUG markers as `{code, description, section}` tuples
- `skipped` - Count of illustrative examples (using `...`)

## Returns

    {:ok, %{
      examples: [{"(+ 1 2)", 3, "## Section"}, ...],
      todos: [{"(code)", "description", "## Section"}, ...],
      bugs: [],
      skipped: 2
    }}

# `extract_examples`

```elixir
@spec extract_examples(String.t()) :: map()
```

Extract examples from specification content string.

Parses the markdown content and extracts code examples with expected values,
TODO markers, BUG markers, and counts skipped illustrative examples.

Delegates to `PtcRunner.Lisp.SpecValidator.Parser.extract_examples/1`.

## Parameters

  * `content` - The specification markdown content as a string

## Returns

    %{
      examples: [{"(+ 1 2)", 3, "## Section"}, ...],
      todos: [{"(code)", "description", "## Section"}, ...],
      bugs: [],
      skipped: 2
    }

# `negative_tests`

```elixir
@spec negative_tests() :: [tuple()]
```

Get negative test cases for Section 13 (unsupported features).

Returns a list of tuples: `{feature_name, code, expected_error_type}`.
These programs should all fail with specific error types.

## Returns

    [
      {"lazy-seq", "(lazy-seq [1])", :unbound_var},
      {"eval", "(eval (+ 1 2))", :unbound_var},
      ...
    ]

# `section_hashes`

```elixir
@spec section_hashes() :: {:ok, map()} | {:error, String.t()}
```

Get hashes for each section of the specification.

Returns a map of section headers to their content hashes.
Used to detect drift in specific sections of the spec.

## Returns

    {:ok, %{
      "## 1. Overview" => "hash1",
      "## 2. Lexical Structure" => "hash2",
      ...
    }}

# `validate_example`

```elixir
@spec validate_example(String.t(), any()) :: :ok | {:error, String.t()}
```

Validate a single example: code should produce expected result.

Returns `:ok` if validation passes, `{:error, reason}` otherwise.

## Examples

    iex> PtcRunner.Lisp.SpecValidator.validate_example("(+ 1 2)", 3)
    :ok

    iex> PtcRunner.Lisp.SpecValidator.validate_example("(+ 1 2)", 4)
    {:error, "Expected 4 but got 3"}

# `validate_negative_test`

```elixir
@spec validate_negative_test(String.t(), atom()) :: :ok | {:error, String.t()}
```

Validate a negative test case (should fail with specific error).

Returns `:ok` if the code fails with the expected error type,
`{:error, reason}` otherwise.

# `validate_spec`

```elixir
@spec validate_spec() :: {:ok, map()} | {:error, String.t()}
```

Validate all examples in the PTC-Lisp specification.

Returns a summary of results with counts of passed, failed, skipped examples,
as well as TODO and BUG markers found in the spec.

## Returns

    {:ok, %{
      passed: 95,
      failed: 0,
      skipped: 2,
      todos: [{"(code)", "description", "## Section"}, ...],
      bugs: [],
      failures: [...]
    }}

---

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