Metastatic.CLI.Formatter (Metastatic v0.33.0)

View Source

Output formatting utilities for Metastatic CLI.

Supports three output formats, all rendered from a single canonical intermediate representation produced by to_map/1:

  • :tree (default) -- human-readable, indented tree
  • :json -- machine-readable JSON
  • :plain -- compact single-line text

Why a single intermediate

Historically each format had its own pattern-match ladder over MetaAST nodes, so adding or changing a node type meant editing three functions in lockstep. to_map/1 now normalises every node into one shape:

%{type: atom, meta: keyword, children: [map] | value, label: String.t()}
  • type -- the MetaAST node type atom
  • meta -- the node's metadata keyword list
  • children -- normalised child maps (or the raw leaf value)
  • label -- a format-independent short description used by the tree
              and plain renderers (e.g. `"binary_op (arithmetic: +)"`)

Tree, JSON and plain renderers then only need to walk this one shape, never to re-interpret MetaAST again.

Summary

Types

Canonical intermediate node consumed by every renderer.

Functions

Format a MetaAST node for display.

Format a Document for display.

Normalise a MetaAST node into the canonical node_map shape.

Types

format()

@type format() :: :tree | :json | :plain

meta_ast()

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

node_map()

@type node_map() :: %{
  type: atom(),
  meta: keyword(),
  children: [node_map()] | term(),
  label: String.t()
}

Canonical intermediate node consumed by every renderer.

Functions

format(ast, atom)

@spec format(meta_ast(), format()) :: String.t()

Format a MetaAST node for display.

Uses 3-tuple format: {type, meta, children_or_value}

Examples

iex> format({:literal, [subtype: :integer], 42}, :plain)
"literal(integer, 42)"

iex> format({:binary_op, [category: :arithmetic, operator: :+], [{:variable, [], "x"}, {:literal, [subtype: :integer], 5}]}, :tree)
"binary_op (arithmetic: +)\n  variable: x\n  literal (integer): 5"

format_document(doc, format)

@spec format_document(Metastatic.Document.t(), format()) :: String.t()

Format a Document for display.

Includes metadata about language, validation status, etc.

to_map(other)

@spec to_map(meta_ast() | term()) :: node_map()

Normalise a MetaAST node into the canonical node_map shape.

Every renderer consumes this, so node-type knowledge lives in exactly one place. Leaf nodes keep their raw value in children; composite nodes carry a list of normalised child maps.

Examples

iex> m = Metastatic.CLI.Formatter.to_map({:literal, [subtype: :integer], 42})
iex> {m.type, m.label}
{:literal, "literal (integer)"}