Packages
metastatic
0.6.1
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/adapters/ruby/from_meta.ex
defmodule Metastatic.Adapters.Ruby.FromMeta do
@moduledoc """
Transform MetaAST (M2) back to Ruby AST (M1).
This module implements the reification function ρ_Ruby that converts
meta-level representations back to Ruby-specific AST structures.
## Coverage
M2.1 Core Layer: Fully supported
M2.2 Extended Layer: Partial support (loops, basic iterators)
M2.3 Native Layer: Direct passthrough (preserves original AST)
"""
@doc """
Transform MetaAST back to Ruby AST.
Returns `{:ok, ruby_ast}` on success or `{:error, reason}` on failure.
"""
@spec transform(term(), map()) :: {:ok, term()} | {:error, String.t()}
# M2.1 Core Layer - Literals
def transform({:literal, :integer, value}, _metadata) do
{:ok, %{"type" => "int", "children" => [value]}}
end
def transform({:literal, :float, value}, _metadata) do
{:ok, %{"type" => "float", "children" => [value]}}
end
def transform({:literal, :string, value}, _metadata) do
{:ok, %{"type" => "str", "children" => [value]}}
end
def transform({:literal, :symbol, value}, _metadata) do
{:ok, %{"type" => "sym", "children" => [value]}}
end
def transform({:literal, :boolean, true}, _metadata) do
{:ok, %{"type" => "true", "children" => []}}
end
def transform({:literal, :boolean, false}, _metadata) do
{:ok, %{"type" => "false", "children" => []}}
end
def transform({:literal, :null, nil}, _metadata) do
{:ok, %{"type" => "nil", "children" => []}}
end
def transform({:literal, :collection, elements}, %{collection_type: :array}) do
with {:ok, elements_ast} <- transform_list(elements) do
{:ok, %{"type" => "array", "children" => elements_ast}}
end
end
def transform({:literal, :constant, name}, _metadata) do
{:ok, %{"type" => "const", "children" => [nil, name]}}
end
# M2.1 Core Layer - Variables
def transform({:variable, name}, %{scope: :local}) do
{:ok, %{"type" => "lvar", "children" => [name]}}
end
def transform({:variable, name}, %{scope: :instance}) do
{:ok, %{"type" => "ivar", "children" => [name]}}
end
def transform({:variable, name}, %{scope: :class}) do
{:ok, %{"type" => "cvar", "children" => [name]}}
end
def transform({:variable, name}, %{scope: :global}) do
{:ok, %{"type" => "gvar", "children" => [name]}}
end
def transform({:variable, name}, _metadata) do
# Default to local variable
{:ok, %{"type" => "lvar", "children" => [name]}}
end
# M2.1 Core Layer - Binary Operations
def transform({:binary_op, :arithmetic, op, left, right}, _metadata) do
with {:ok, left_ast} <- transform(left, %{}),
{:ok, right_ast} <- transform(right, %{}) do
{:ok, %{"type" => "send", "children" => [left_ast, op, right_ast]}}
end
end
def transform({:binary_op, :comparison, op, left, right}, _metadata) do
with {:ok, left_ast} <- transform(left, %{}),
{:ok, right_ast} <- transform(right, %{}) do
{:ok, %{"type" => "send", "children" => [left_ast, op, right_ast]}}
end
end
def transform({:binary_op, :boolean, :and, left, right}, _metadata) do
with {:ok, left_ast} <- transform(left, %{}),
{:ok, right_ast} <- transform(right, %{}) do
{:ok, %{"type" => "and", "children" => [left_ast, right_ast]}}
end
end
def transform({:binary_op, :boolean, :or, left, right}, _metadata) do
with {:ok, left_ast} <- transform(left, %{}),
{:ok, right_ast} <- transform(right, %{}) do
{:ok, %{"type" => "or", "children" => [left_ast, right_ast]}}
end
end
# M2.1 Core Layer - Unary Operations
def transform({:unary_op, :arithmetic, op, operand}, _metadata) do
with {:ok, operand_ast} <- transform(operand, %{}) do
{:ok, %{"type" => "send", "children" => [operand_ast, op, nil]}}
end
end
def transform({:unary_op, :boolean, :not, operand}, _metadata) do
with {:ok, operand_ast} <- transform(operand, %{}) do
{:ok, %{"type" => "send", "children" => [operand_ast, :!, nil]}}
end
end
# M2.1 Core Layer - Function Calls
def transform({:function_call, name, args}, %{call_type: :local}) do
with {:ok, args_ast} <- transform_list(args) do
{:ok, %{"type" => "send", "children" => [nil, String.to_atom(name) | args_ast]}}
end
end
def transform({:function_call, name, args}, _metadata) do
# Default to local call
with {:ok, args_ast} <- transform_list(args) do
{:ok, %{"type" => "send", "children" => [nil, String.to_atom(name) | args_ast]}}
end
end
# M2.1 Core Layer - Conditionals
def transform({:conditional, condition, then_branch, else_branch}, _metadata) do
with {:ok, cond_ast} <- transform(condition, %{}),
{:ok, then_ast} <- transform_or_nil(then_branch),
{:ok, else_ast} <- transform_or_nil(else_branch) do
{:ok, %{"type" => "if", "children" => [cond_ast, then_ast, else_ast]}}
end
end
# M2.1 Core Layer - Assignment
def transform({:assignment, {:variable, name}, value}, %{scope: :local}) do
with {:ok, value_ast} <- transform(value, %{}) do
{:ok, %{"type" => "lvasgn", "children" => [name, value_ast]}}
end
end
def transform({:assignment, {:variable, name}, value}, %{scope: :instance}) do
with {:ok, value_ast} <- transform(value, %{}) do
{:ok, %{"type" => "ivasgn", "children" => [name, value_ast]}}
end
end
def transform({:assignment, {:variable, name}, value}, _metadata) do
# Default to local
with {:ok, value_ast} <- transform(value, %{}) do
{:ok, %{"type" => "lvasgn", "children" => [name, value_ast]}}
end
end
# M2.1 Core Layer - Blocks
def transform({:block, statements}, _metadata) do
with {:ok, statements_ast} <- transform_list(statements) do
{:ok, %{"type" => "begin", "children" => statements_ast}}
end
end
# M2.2 Extended Layer - Loops (basic support)
def transform({:loop, :while, condition, body}, _metadata) do
with {:ok, cond_ast} <- transform(condition, %{}),
{:ok, body_ast} <- transform_or_nil(body) do
{:ok, %{"type" => "while", "children" => [cond_ast, body_ast]}}
end
end
# M2.3 Native Layer - Passthrough
def transform({:language_specific, :ruby, original_ast, _construct_type}, _metadata) do
{:ok, original_ast}
end
# Nil passthrough
def transform(nil, _metadata), do: {:ok, nil}
# Catch-all
def transform(unsupported, _metadata) do
{:error, "Unsupported MetaAST construct for Ruby reification: #{inspect(unsupported)}"}
end
# Helper Functions
defp transform_list(items) when is_list(items) do
items
|> Enum.reduce_while({:ok, []}, fn item, {:ok, acc} ->
case transform(item, %{}) do
{:ok, ast} -> {:cont, {:ok, [ast | acc]}}
{:error, _} = err -> {:halt, err}
end
end)
|> case do
{:ok, items_ast} -> {:ok, Enum.reverse(items_ast)}
error -> error
end
end
defp transform_or_nil(nil), do: {:ok, nil}
defp transform_or_nil(value), do: transform(value, %{})
end