Search documentation of Metastatic

# Metastatic.Document (Metastatic v0.2.0)

View Source

A MetaAST Document wraps an M2 AST with metadata and language information.

This structure represents the result of abstraction (M1 → M2) and serves as input for reification (M2 → M1).

## Fields

- `ast` - The M2 MetaAST representation
- `metadata` - Language-specific information preserved from M1
- `language` - Source language (:python, :javascript, :elixir, etc.)
- `original_source` - Optional: original source code (for debugging/comparison)

## Metadata

Metadata contains M1-specific information that cannot be represented at M2 level:

- Formatting preferences (indentation, spacing)
- Comments and documentation
- Type annotations (TypeScript, Python type hints)
- Language-specific hints (async models, iterator styles, etc.)

This enables high-fidelity M2 → M1 round-trips while maintaining semantic equivalence.

## Examples

    # After abstraction from Python
    %Metastatic.Document{
      language: :python,
      ast: {:binary_op, :arithmetic, :+, {:variable, "x"}, {:literal, :integer, 5}},
      metadata: %{
        native_lang: :python,
        type_hints: %{"x" => "int"},
        formatting: %{indent: 4}
      },
      original_source: "x + 5"
    }

# Summary

## Types

t()

A Document containing M2 AST with associated metadata.

## Functions

equivalent?(document1, document2)

Check if two documents have semantically equivalent ASTs.

language(document)

Get the language of a document.

new(ast, language, metadata \\ %{}, original_source \\ nil)

Create a new MetaAST document.

update_ast(doc, new_ast)

Update the AST in a document while preserving metadata and language.

update_metadata(doc, new_metadata)

Update document metadata (merges with existing metadata).

valid?(document)

Validate that a document's AST conforms to M2 meta-model.

variables(document)

Extract all variables referenced in the document's AST.

# Types

# t()

    @type t() :: %Metastatic.Document{
      ast: Metastatic.AST.meta_ast(),
      language: atom(),
      metadata: map(),
      original_source: String.t() | nil
    }

A Document containing M2 AST with associated metadata.

# Functions

# equivalent?(document1, document2)

    @spec equivalent?(t(), t()) :: boolean()

Check if two documents have semantically equivalent ASTs.

This compares the M2 AST structures, ignoring metadata and original source.

## Examples

    iex> doc1 = Metastatic.Document.new({:literal, :integer, 42}, :python)
    iex> doc2 = Metastatic.Document.new({:literal, :integer, 42}, :javascript)
    iex> Metastatic.Document.equivalent?(doc1, doc2)
    true

    iex> doc1 = Metastatic.Document.new({:literal, :integer, 42}, :python)
    iex> doc2 = Metastatic.Document.new({:literal, :string, "42"}, :python)
    iex> Metastatic.Document.equivalent?(doc1, doc2)
    false

# language(document)

    @spec language(t()) :: atom()

Get the language of a document.

## Examples

    iex> doc = Metastatic.Document.new({:literal, :integer, 42}, :python)
    iex> Metastatic.Document.language(doc)
    :python

# new(ast, language, metadata \\ %{}, original_source \\ nil)

    @spec new(Metastatic.AST.meta_ast(), atom(), map(), String.t() | nil) :: t()

Create a new MetaAST document.

## Examples

    iex> ast = {:literal, :integer, 42}
    iex> Metastatic.Document.new(ast, :python)
    %Metastatic.Document{
      ast: {:literal, :integer, 42},
      language: :python,
      metadata: %{},
      original_source: nil
    }

    iex> ast = {:variable, "x"}
    iex> metadata = %{type_hint: "str"}
    iex> Metastatic.Document.new(ast, :python, metadata, "x")
    %Metastatic.Document{
      ast: {:variable, "x"},
      language: :python,
      metadata: %{type_hint: "str"},
      original_source: "x"
    }

# update_ast(doc, new_ast)

    @spec update_ast(t(), Metastatic.AST.meta_ast()) :: t()

Update the AST in a document while preserving metadata and language.

Useful for transformations that operate on the M2 level.

## Examples

    iex> doc = Metastatic.Document.new({:literal, :integer, 42}, :python)
    iex> new_ast = {:literal, :integer, 100}
    iex> updated = Metastatic.Document.update_ast(doc, new_ast)
    iex> updated.ast
    {:literal, :integer, 100}
    iex> updated.language
    :python

# update_metadata(doc, new_metadata)

    @spec update_metadata(t(), map()) :: t()

Update document metadata (merges with existing metadata).

## Examples

    iex> doc = Metastatic.Document.new({:variable, "x"}, :python, %{type: "int"})
    iex> updated = Metastatic.Document.update_metadata(doc, %{mutable: false})
    iex> updated.metadata
    %{type: "int", mutable: false}

# valid?(document)

    @spec valid?(t()) :: boolean()

Validate that a document's AST conforms to M2 meta-model.

## Examples

    iex> doc = Metastatic.Document.new({:literal, :integer, 42}, :python)
    iex> Metastatic.Document.valid?(doc)
    true

    iex> doc = %Metastatic.Document{
    ...>   ast: {:invalid_node, "data"},
    ...>   language: :python,
    ...>   metadata: %{}
    ...> }
    iex> Metastatic.Document.valid?(doc)
    false

# variables(document)

    @spec variables(t()) :: MapSet.t(String.t())

Extract all variables referenced in the document's AST.

Delegates to `Metastatic.AST.variables/1`.

## Examples

    iex> ast = {:binary_op, :arithmetic, :+, {:variable, "x"}, {:variable, "y"}}
    iex> doc = Metastatic.Document.new(ast, :python)
    iex> Metastatic.Document.variables(doc)
    MapSet.new(["x", "y"])