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

Counts unique user-defined symbols and keywords in a parsed Lisp AST.

Used to enforce the `max_symbols` limit, preventing atom table exhaustion
from malicious programs that create many unique symbols/keywords.

Core language symbols (special forms like `if`, `let`, `fn`) are excluded
from the count since they're predefined and don't contribute to atom exhaustion.

# `count`

```elixir
@spec count(term()) :: non_neg_integer()
```

Counts unique non-core symbols and keywords in the AST.

Returns the count of unique user-defined atoms that would be created
when parsing/evaluating the program.

## Examples

    iex> {:ok, ast} = PtcRunner.Lisp.Parser.parse("{:a 1 :b 2}")
    iex> PtcRunner.Lisp.SymbolCounter.count(ast)
    2

    iex> {:ok, ast} = PtcRunner.Lisp.Parser.parse("{:a 1 :a 2}")
    iex> PtcRunner.Lisp.SymbolCounter.count(ast)
    1

    iex> {:ok, ast} = PtcRunner.Lisp.Parser.parse("(if true 1 2)")
    iex> PtcRunner.Lisp.SymbolCounter.count(ast)
    0

---

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