Packages
metastatic
0.3.3
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/supplemental/validator.ex
defmodule Metastatic.Supplemental.Validator do
@moduledoc """
Validates supplemental module availability and compatibility.
Analyzes MetaAST documents to detect required supplemental modules
and checks if they are registered and compatible.
"""
alias Metastatic.Document
alias Metastatic.Supplemental.Registry
@doc """
Analyzes a document to detect required supplementals for target language.
Returns analysis result with required and available supplementals.
## Examples
iex> Validator.analyze(document, :python)
{:ok, %{required: [:actor_call], available: [:actor_call], missing: []}}
iex> Validator.analyze(document_with_actors, :python)
{:error, %{required: [:actor_call], available: [], missing: [:actor_call]}}
"""
@spec analyze(Document.t(), atom()) ::
{:ok, map()} | {:error, map()}
def analyze(%Document{} = document, target_language) do
required = detect_required_constructs(document.ast)
available = Registry.available_constructs(target_language)
missing = required -- available
result = %{
required: required,
available: available,
missing: missing
}
if Enum.empty?(missing) do
{:ok, result}
else
{:error, result}
end
end
@doc """
Checks if all required supplementals are available for a language.
## Examples
iex> Validator.compatible?(document, :python)
true
"""
@spec compatible?(Document.t(), atom()) :: boolean()
def compatible?(%Document{} = document, target_language) do
case analyze(document, target_language) do
{:ok, _} -> true
{:error, _} -> false
end
end
@doc """
Lists all supplemental-requiring constructs in a MetaAST.
## Examples
iex> Validator.detect_required_constructs(meta_ast)
[:actor_call, :spawn_actor]
"""
@spec detect_required_constructs(term()) :: [atom()]
def detect_required_constructs(meta_ast) do
walk_ast(meta_ast, MapSet.new())
|> MapSet.to_list()
|> Enum.sort()
end
# Private Functions
defp walk_ast({construct, _} = node, acc) when is_atom(construct) do
# Add construct if it might need supplemental support
# (not a core M2.1 type)
acc =
if supplemental_construct?(construct) do
MapSet.put(acc, construct)
else
acc
end
# Walk children
node
|> Tuple.to_list()
|> Enum.reduce(acc, &walk_ast/2)
end
defp walk_ast({construct, _, _} = node, acc) when is_atom(construct) do
acc =
if supplemental_construct?(construct) do
MapSet.put(acc, construct)
else
acc
end
node
|> Tuple.to_list()
|> Enum.reduce(acc, &walk_ast/2)
end
defp walk_ast({construct, _, _, _} = node, acc) when is_atom(construct) do
acc =
if supplemental_construct?(construct) do
MapSet.put(acc, construct)
else
acc
end
node
|> Tuple.to_list()
|> Enum.reduce(acc, &walk_ast/2)
end
defp walk_ast(list, acc) when is_list(list) do
Enum.reduce(list, acc, &walk_ast/2)
end
defp walk_ast(_, acc), do: acc
# Core M2.1 constructs that don't need supplementals
@core_constructs [
:literal,
:variable,
:binary_op,
:unary_op,
:function_call,
:conditional,
:block,
:early_return,
:assignment,
:inline_match,
:tuple
]
# Extended M2.2 constructs that don't need supplementals
@extended_constructs [
:loop,
:lambda,
:collection_op,
:pattern_match,
:exception_handling,
:async_operation
]
# Native M2.3 - always language-specific, not supplemental
@native_constructs [:language_specific]
defp supplemental_construct?(construct) do
construct not in @core_constructs and
construct not in @extended_constructs and
construct not in @native_constructs
end
end