Metastatic (Metastatic v0.10.4)

View Source

Metastatic - Cross-language code analysis via unified MetaAST.

Main API

The primary entry points for working with Metastatic:

  • quote/2 - Convert source code to MetaAST
  • unquote/2 - Convert MetaAST back to source code

Examples

# Parse Python code to MetaAST
iex> {:ok, {:binary_op, meta, _}} = Metastatic.quote("x + 5", :python)
iex> Keyword.get(meta, :category) == :arithmetic and Keyword.get(meta, :operator) == :+
true

# Convert MetaAST back to Python source
iex> ast = {:binary_op, [category: :arithmetic, operator: :+], [{:variable, [], "x"}, {:literal, [subtype: :integer], 5}]}
iex> Metastatic.unquote(ast, :python)
{:ok, "x + 5"}

# Round-trip demonstration
iex> {:ok, my_ast} = Metastatic.quote("x + 5", :python)
iex> {:ok, source} = Metastatic.unquote(my_ast, :python)
iex> source
"x + 5"

Cross-Language Translation

Since MetaAST is language-independent, you can parse in one language and generate in another:

# Parse from Python, generate Elixir code (same MetaAST!)
iex> {:ok, py_ast} = Metastatic.quote("x + 5", :python)
iex> {:ok, _source} = Metastatic.unquote(py_ast, :elixir)
iex> true
true

Summary

Functions

Convert source code to MetaAST.

Convert MetaAST to source code.

Types

language()

@type language() :: :elixir | :erlang | :ruby | :haskell | :python

meta_ast()

@type meta_ast() :: Metastatic.AST.meta_ast()

Functions

quote(code, language)

@spec quote(String.t(), language()) :: {:ok, meta_ast()} | {:error, term()}

Convert source code to MetaAST.

Performs Source → M1 → M2 transformation, returning just the MetaAST without the Document wrapper.

Parameters

  • code - Source code string
  • language - Language atom (:python, :elixir, :ruby, :erlang, :haskell)

Returns

  • {:ok, meta_ast} - Successfully parsed and abstracted to M2
  • {:error, reason} - Parsing or abstraction failed

Examples

iex> {:ok, {:binary_op, meta, _}} = Metastatic.quote("x + 5", :python)
iex> Keyword.get(meta, :category) == :arithmetic and Keyword.get(meta, :operator) == :+
true

iex> {:ok, {:binary_op, meta, _}} = Metastatic.quote("x + 5", :elixir)
iex> Keyword.get(meta, :category) == :arithmetic and Keyword.get(meta, :operator) == :+
true

iex> {:ok, {:list, _, items}} = Metastatic.quote("[1, 2, 3]", :python)
iex> length(items) == 3
true

unquote(ast, language)

@spec unquote(meta_ast(), language()) :: {:ok, String.t()} | {:error, term()}

Convert MetaAST to source code.

Performs M2 → M1 → Source transformation, generating source code in the specified target language.

Parameters

  • ast - MetaAST structure (M2 level)
  • language - Target language atom (:python, :elixir, :ruby, :erlang, :haskell)

Returns

  • {:ok, source} - Successfully generated source code
  • {:error, reason} - Generation failed

Examples

iex> ast = {:binary_op, [category: :arithmetic, operator: :+], [{:variable, [], "x"}, {:literal, [subtype: :integer], 5}]}
iex> Metastatic.unquote(ast, :python)
{:ok, "x + 5"}

iex> ast = {:binary_op, [category: :arithmetic, operator: :+], [{:variable, [], "x"}, {:literal, [subtype: :integer], 5}]}
iex> Metastatic.unquote(ast, :elixir)
{:ok, "x + 5"}

iex> ast = {:literal, [subtype: :integer], 42}
iex> Metastatic.unquote(ast, :python)
{:ok, "42"}

iex> ast = {:list, [], [{:literal, [subtype: :integer], 1}, {:literal, [subtype: :integer], 2}]}
iex> Metastatic.unquote(ast, :python)
{:ok, "[1, 2]"}

Cross-Language Translation

Since MetaAST is language-independent, you can parse from one language and generate in another:

iex> {:ok, ast} = Metastatic.quote("x + 5", :python)
iex> {:ok, source} = Metastatic.unquote(ast, :elixir)
iex> source
"x + 5"

iex> {:ok, ast} = Metastatic.quote("42", :ruby)
iex> {:ok, source} = Metastatic.unquote(ast, :python)
iex> source
"42"