Metastatic.Analysis.Purity
(Metastatic v0.10.4)
View Source
Function purity analysis at the MetaAST level.
Analyzes code to determine if it's pure (no side effects) or impure (has side effects like I/O, mutations, random operations, etc.).
Works across all supported languages by operating on the unified MetaAST representation.
Purity Definition
A pure function:
- Always returns the same output for the same input (deterministic)
- Has no side effects (no I/O, no mutations, no global state access)
- Doesn't depend on external state
An impure function has one or more of:
- I/O operations (print, file access, network, database)
- Mutations (modifying variables, especially in loops)
- Non-deterministic operations (random, time/date)
- Exception handling (raising/catching exceptions)
Usage
alias Metastatic.{Document, Analysis.Purity}
# Analyze a document
ast = {:binary_op, :arithmetic, :+, {:variable, "x"}, {:literal, :integer, 5}}
doc = Document.new(ast, :elixir)
{:ok, result} = Purity.analyze(doc)
result.pure? # => true
result.effects # => []
result.confidence # => :high
result.summary # => "Function is pure"Examples
# Pure arithmetic
iex> ast = {:binary_op, [category: :arithmetic, operator: :+], [{:literal, [subtype: :integer], 1}, {:literal, [subtype: :integer], 2}]}
iex> doc = Metastatic.Document.new(ast, :python)
iex> {:ok, result} = Metastatic.Analysis.Purity.analyze(doc)
iex> result.pure?
true
# Impure I/O
iex> ast = {:function_call, [name: "print"], [{:literal, [subtype: :string], "hello"}]}
iex> doc = Metastatic.Document.new(ast, :python)
iex> {:ok, result} = Metastatic.Analysis.Purity.analyze(doc)
iex> result.pure?
false
iex> result.effects
[:io]
Summary
Functions
@spec analyze(Metastatic.language(), term(), keyword()) :: {:ok, map()} | {:error, term()}
Analyzes a document for purity.
Accepts either:
- A
Metastatic.Documentstruct - A
{language, native_ast}tuple
Returns {:ok, result} where result is a Metastatic.Analysis.Purity.Result struct.
Examples
# Using Document
iex> ast = {:literal, [subtype: :integer], 42}
iex> doc = Metastatic.Document.new(ast, :elixir)
iex> {:ok, result} = Metastatic.Analysis.Purity.analyze(doc)
iex> result.pure?
true
# Using {language, native_ast} tuple
iex> python_ast = %{"_type" => "Constant", "value" => 42}
iex> {:ok, result} = Metastatic.Analysis.Purity.analyze(:python, python_ast)
iex> result.pure?
true
@spec analyze!(Metastatic.language(), term(), keyword()) :: map()
Analyzes a document for purity.
Accepts either:
- A
Metastatic.Documentstruct - A
{language, native_ast}tuple
Returns {:ok, result} where result is a Metastatic.Analysis.Purity.Result struct.
Examples
# Using Document
iex> ast = {:literal, [subtype: :integer], 42}
iex> doc = Metastatic.Document.new(ast, :elixir)
iex> {:ok, result} = Metastatic.Analysis.Purity.analyze(doc)
iex> result.pure?
true
# Using {language, native_ast} tuple
iex> python_ast = %{"_type" => "Constant", "value" => 42}
iex> {:ok, result} = Metastatic.Analysis.Purity.analyze(:python, python_ast)
iex> result.pure?
trueUnlike not-banged version, this one either returns a result or raises