Metastatic.MetaAST (Metastatic v0.33.0)

View Source

Shared, language-agnostic core for MetaAST-shaped trees.

Both Metastatic.AST (programming-language MetaAST) and Metastatic.NL.AST (natural-language MetaAST) model their trees as the same uniform 3-tuple:

{type_atom, keyword_meta, children_or_value}

This module owns the operations that are identical for both:

Metastatic.AST and Metastatic.NL.AST delegate here, so the two meta-ASTs can no longer drift apart in their shared surface. Domain-specific behaviour (conformance rules, type registries, builders, to_string/1, …) stays in the respective modules.

Traversal contract

traverse/4 visits a node's metadata values as well as its children: any metadata value that is itself a node (or a list/keyword containing one) is traversed. This keeps subterms embedded in metadata — e.g. a :coreference target or a :pattern — visible to walkers. See Metastatic.AST.traverse/4 for the precise invariant used by the programming-language side.

Summary

Types

t()

A uniform MetaAST node: {type, metadata, children_or_value}.

Functions

Returns the node's children list or leaf value.

Gets a metadata value by key, with an optional default.

Returns the node's metadata keyword list.

Returns the path from a matching node up to the root, or nil.

Post-order traversal (no accumulator).

Pre-order traversal (no accumulator).

Returns a lazy enumerable that walks the tree in depth-first pre-order.

Returns a lazy pre-order enumerable that threads an accumulator.

Puts a metadata value by key.

Depth-first traversal with pre- and post-visit callbacks.

Returns the node type atom.

Replaces a node's children/value.

Merges a keyword list of metadata updates into the node.

Updates a single metadata value with a function.

Types

t()

@type t() :: {atom(), keyword(), term()}

A uniform MetaAST node: {type, metadata, children_or_value}.

Functions

children(arg)

@spec children(t()) :: term()

Returns the node's children list or leaf value.

get_meta(arg, key, default \\ nil)

@spec get_meta(t(), atom(), term()) :: term()

Gets a metadata value by key, with an optional default.

meta(arg)

@spec meta(t()) :: keyword()

Returns the node's metadata keyword list.

path(ast, fun)

@spec path(t(), (t() -> as_boolean(term()))) :: [t()] | nil

Returns the path from a matching node up to the root, or nil.

The path starts with the matched node, followed by its parents up to the root. Mirrors Macro.path/2.

Examples

iex> ast = {:binary_op, [operator: :+],
...>   [{:variable, [], "x"}, {:literal, [subtype: :integer], 42}]}
iex> path = Metastatic.MetaAST.path(ast, fn {:literal, _, 42} -> true; _ -> false end)
iex> Enum.map(path, &Metastatic.MetaAST.type/1)
[:literal, :binary_op]

postwalk(node, fun)

@spec postwalk(t(), (t() -> t())) :: t()

Post-order traversal (no accumulator).

prewalk(node, fun)

@spec prewalk(t(), (t() -> t())) :: t()

Pre-order traversal (no accumulator).

prewalker(ast)

@spec prewalker(t()) :: Enumerable.t()

Returns a lazy enumerable that walks the tree in depth-first pre-order.

Mirrors Macro.prewalker/1: each node is yielded before its children.

prewalker(ast, acc, fun)

@spec prewalker(t(), acc, (t(), acc -> {term(), acc})) :: Enumerable.t()
when acc: term()

Returns a lazy pre-order enumerable that threads an accumulator.

Mirrors the Macro.prewalker/2 shape: the caller supplies fun.(node, acc) -> {yielded, acc} which runs for each node in pre-order and returns the value to yield together with the next accumulator.

Examples

iex> ast = {:binary_op, [operator: :+],
...>   [{:literal, [subtype: :integer], 1}, {:literal, [subtype: :integer], 2}]}
iex> ast |> Metastatic.MetaAST.prewalker(0, fn _n, acc -> {acc, acc + 1} end) |> Enum.to_list()
[0, 1, 2]

put_meta(arg, key, value)

@spec put_meta(t(), atom(), term()) :: t()

Puts a metadata value by key.

traverse(ast, acc, pre, post)

@spec traverse(t() | term(), acc, pre_fun, post_fun) :: {t() | term(), acc}
when acc: term(),
     pre_fun: (t() | term(), acc -> {t() | term(), acc}),
     post_fun: (t() | term(), acc -> {t() | term(), acc})

Depth-first traversal with pre- and post-visit callbacks.

pre runs before a node's descendants, post after. Both receive {node, acc} and must return {node, acc}. Metadata values that contain nodes are traversed too.

type(arg)

@spec type(t()) :: atom()

Returns the node type atom.

update_children(arg, new_children)

@spec update_children(t(), term()) :: t()

Replaces a node's children/value.

update_meta(arg, updates)

@spec update_meta(t(), keyword()) :: t()

Merges a keyword list of metadata updates into the node.

update_meta(arg, key, default, fun)

@spec update_meta(t(), atom(), term(), (term() -> term())) :: t()

Updates a single metadata value with a function.

The function receives the current value (or default when absent) and returns the new value.