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.
Summary
Functions
Counts unique non-core symbols and keywords in the AST.
Functions
@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