Metastatic.Semantic.Enricher (Metastatic v0.10.4)

View Source

AST enricher for semantic metadata injection.

This module provides functions to enrich MetaAST nodes with semantic operation metadata (op_kind). It is designed to be called during adapter transformations (in to_meta) to eagerly annotate function calls with their semantic meaning.

Usage

Single Node Enrichment

alias Metastatic.Semantic.Enricher

# Enrich a single function_call node
enriched = Enricher.enrich(node, :elixir)

Full Tree Enrichment

# Enrich all nodes in an AST tree
enriched_ast = Enricher.enrich_tree(ast, :python)

Integration with Adapters

The enricher should be called at the end of the to_meta transformation:

def transform(native_ast) do
  with {:ok, meta_ast, metadata} <- do_transform(native_ast) do
    enriched = Enricher.enrich_tree(meta_ast, :python)
    {:ok, enriched, metadata}
  end
end

Enrichment Strategy

Enrichment is eager - all applicable nodes are enriched in a single pass. This ensures semantic information is available immediately for analyzers.

Only :function_call nodes are currently enriched. The enricher:

  1. Extracts the function name from metadata
  2. Matches against registered patterns for the source language
  3. If matched, adds op_kind to the node's metadata
  4. Extracts target entity from arguments when possible

Summary

Types

Language identifier for pattern matching

Functions

Enriches a single MetaAST node with semantic metadata.

Enriches an entire AST tree with semantic metadata.

Checks if a node has been enriched with semantic metadata.

Gets the op_kind from a node, if present.

Types

language()

Language identifier for pattern matching

Functions

enrich(node, language)

Enriches a single MetaAST node with semantic metadata.

If the node is a :function_call and matches a known pattern for the given language, adds op_kind metadata. Otherwise returns the node unchanged.

Parameters

  • node - The MetaAST node to enrich
  • language - The source language for pattern matching

Examples

iex> node = {:function_call, [name: "Repo.get"], [{:variable, [], "User"}, {:literal, [subtype: :integer], 1}]}
iex> enriched = Enricher.enrich(node, :elixir)
iex> Keyword.get(elem(enriched, 1), :op_kind)
[domain: :db, operation: :retrieve, target: "User", async: false, framework: :ecto]

enrich_tree(ast, language)

Enriches an entire AST tree with semantic metadata.

Traverses the AST and enriches all applicable nodes. This is the recommended way to enrich AST during adapter transformations.

Parameters

  • ast - The root MetaAST node
  • language - The source language for pattern matching

Examples

iex> ast = {:block, [], [
...>   {:function_call, [name: "Repo.get"], [{:variable, [], "User"}, {:literal, [subtype: :integer], 1}]},
...>   {:function_call, [name: "Repo.all"], [{:variable, [], "Post"}]}
...> ]}
iex> enriched = Enricher.enrich_tree(ast, :elixir)
iex> {:block, [], [call1, call2]} = enriched
iex> Keyword.get(elem(call1, 1), :op_kind) |> Keyword.get(:operation)
:retrieve
iex> Keyword.get(elem(call2, 1), :op_kind) |> Keyword.get(:operation)
:retrieve_all

enriched?(arg1)

@spec enriched?(Metastatic.AST.meta_ast()) :: boolean()

Checks if a node has been enriched with semantic metadata.

Examples

iex> node = {:function_call, [name: "Repo.get", op_kind: [domain: :db, operation: :retrieve]], []}
iex> Enricher.enriched?(node)
true

iex> node = {:function_call, [name: "unknown"], []}
iex> Enricher.enriched?(node)
false

get_op_kind(arg1)

@spec get_op_kind(Metastatic.AST.meta_ast()) :: Metastatic.Semantic.OpKind.t() | nil

Gets the op_kind from a node, if present.

Examples

iex> node = {:function_call, [name: "Repo.get", op_kind: [domain: :db, operation: :retrieve]], []}
iex> Enricher.get_op_kind(node)
[domain: :db, operation: :retrieve]

iex> node = {:function_call, [name: "unknown"], []}
iex> Enricher.get_op_kind(node)
nil