Packages
metastatic
0.8.6
0.26.0
0.25.0
0.24.1
0.24.0
0.23.0
0.22.2
0.22.1
0.22.0
0.21.3
0.21.2
0.21.1
0.21.0
0.20.3
0.20.2
0.20.1
0.20.0
0.19.0
0.18.0
0.17.0
0.16.0
0.15.1
0.15.0
0.14.2
0.14.1
0.14.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.0
0.11.0
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.2
0.9.1
0.9.0
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.1
0.7.0
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.2
0.4.1
0.4.0
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.0
0.1.3
0.1.2
0.1.1
0.1.0
Cross-language code meta-model library using unified MetaAST representation. Parse, transform, and translate code across Python, Elixir, Ruby, Erlang, Haskell, and more via a shared three-tuple AST format.
Current section
Files
Jump to
Current section
Files
lib/metastatic/analysis/purity/result.ex
defmodule Metastatic.Analysis.Purity.Result do
@moduledoc """
Result structure for purity analysis.
Contains information about whether a function/code block is pure or impure,
what side effects were detected, confidence level, and locations of impure operations.
## Fields
- `:pure?` - Boolean indicating if the code is pure (no side effects detected)
- `:effects` - List of detected effect atoms (`:io`, `:mutation`, `:random`, `:time`, `:network`, `:database`, `:exception`)
- `:confidence` - Confidence level (`:high`, `:medium`, `:low`)
- `:impure_locations` - List of `{:line, line_number, effect_type}` tuples
- `:summary` - Human-readable summary string
- `:unknown_calls` - List of function calls that couldn't be classified
## Examples
# Pure function
iex> %Metastatic.Analysis.Purity.Result{
...> pure?: true,
...> effects: [],
...> confidence: :high,
...> impure_locations: [],
...> summary: "Function is pure"
...> }
# Impure function with I/O
iex> %Metastatic.Analysis.Purity.Result{
...> pure?: false,
...> effects: [:io],
...> confidence: :high,
...> impure_locations: [{:line, 42, :io}],
...> summary: "Function is impure due to I/O operations"
...> }
# Unknown purity (unclassified function calls)
iex> %Metastatic.Analysis.Purity.Result{
...> pure?: false,
...> effects: [],
...> confidence: :low,
...> impure_locations: [],
...> summary: "Function purity unknown - contains unclassified calls",
...> unknown_calls: ["custom_function"]
...> }
"""
@enforce_keys [:pure?, :effects, :confidence]
defstruct pure?: true,
effects: [],
confidence: :high,
impure_locations: [],
summary: "",
unknown_calls: []
@type effect ::
:io | :mutation | :random | :time | :network | :database | :exception | :unknown
@type confidence :: :high | :medium | :low
@type location :: {:line, non_neg_integer(), effect()}
@type t :: %__MODULE__{
pure?: boolean(),
effects: [effect()],
confidence: confidence(),
impure_locations: [location()],
summary: String.t(),
unknown_calls: [String.t()]
}
@doc """
Creates a new pure result.
## Examples
iex> Metastatic.Analysis.Purity.Result.pure()
%Metastatic.Analysis.Purity.Result{
pure?: true,
effects: [],
confidence: :high,
impure_locations: [],
summary: "Function is pure",
unknown_calls: []
}
"""
@spec pure() :: t()
def pure do
%__MODULE__{
pure?: true,
effects: [],
confidence: :high,
impure_locations: [],
summary: "Function is pure",
unknown_calls: []
}
end
@doc """
Creates a new impure result with the given effects and locations.
## Examples
iex> Metastatic.Analysis.Purity.Result.impure([:io], [{:line, 10, :io}])
%Metastatic.Analysis.Purity.Result{
pure?: false,
effects: [:io],
confidence: :high,
impure_locations: [{:line, 10, :io}],
summary: "Function is impure due to I/O operations",
unknown_calls: []
}
"""
@spec impure([effect()], [location()]) :: t()
def impure(effects, locations) do
%__MODULE__{
pure?: false,
effects: Enum.uniq(effects),
confidence: :high,
impure_locations: locations,
summary: build_summary(effects),
unknown_calls: []
}
end
@doc """
Creates a result with unknown purity (low confidence).
## Examples
iex> Metastatic.Analysis.Purity.Result.unknown(["custom_func"])
%Metastatic.Analysis.Purity.Result{
pure?: false,
effects: [],
confidence: :low,
impure_locations: [],
summary: "Function purity unknown - contains unclassified calls: custom_func",
unknown_calls: ["custom_func"]
}
"""
@spec unknown([String.t()]) :: t()
def unknown(calls) do
%__MODULE__{
pure?: false,
effects: [],
confidence: :low,
impure_locations: [],
summary: "Function purity unknown - contains unclassified calls: #{Enum.join(calls, ", ")}",
unknown_calls: calls
}
end
@doc """
Merges multiple results, keeping impurity if any result is impure.
## Examples
iex> r1 = Metastatic.Analysis.Purity.Result.pure()
iex> r2 = Metastatic.Analysis.Purity.Result.impure([:io], [{:line, 10, :io}])
iex> result = Metastatic.Analysis.Purity.Result.merge([r1, r2])
iex> result.pure?
false
iex> result.effects
[:io]
"""
@spec merge([t()]) :: t()
def merge(results) do
pure? = Enum.all?(results, & &1.pure?)
effects = results |> Enum.flat_map(& &1.effects) |> Enum.uniq()
locations = results |> Enum.flat_map(& &1.impure_locations) |> Enum.uniq()
unknown = results |> Enum.flat_map(& &1.unknown_calls) |> Enum.uniq()
confidence =
cond do
pure? and Enum.empty?(unknown) -> :high
not Enum.empty?(unknown) -> :low
true -> :medium
end
summary =
cond do
pure? -> "Function is pure"
not Enum.empty?(effects) -> build_summary(effects)
not Enum.empty?(unknown) -> "Function purity unknown - contains unclassified calls"
true -> "Function may be impure"
end
%__MODULE__{
pure?: pure?,
effects: effects,
confidence: confidence,
impure_locations: locations,
summary: summary,
unknown_calls: unknown
}
end
# Private helpers
defp build_summary(effects) when effects == [] do
"Function is pure"
end
defp build_summary(effects) do
effect_names = Enum.map_join(effects, ", ", &effect_to_string/1)
"Function is impure due to #{effect_names}"
end
defp effect_to_string(:io), do: "I/O operations"
defp effect_to_string(:mutation), do: "mutations"
defp effect_to_string(:random), do: "random operations"
defp effect_to_string(:time), do: "time operations"
defp effect_to_string(:network), do: "network operations"
defp effect_to_string(:database), do: "database operations"
defp effect_to_string(:exception), do: "exception handling"
defp effect_to_string(:unknown), do: "unknown operations"
end