PtcRunner.Lisp.CoreToSource (PtcRunner v0.14.0)

Copy Markdown View Source

Convert Core AST (the analyzed/desugared representation) back to PTC-Lisp source strings.

This is distinct from PtcRunner.Lisp.Formatter which handles raw parser AST. CoreToSource works with the intermediate representation produced by the analyzer and stored inside closures.

Use Cases

  • Serializing capture-free closures for archive persistence
  • Novelty comparison between memory designs
  • Debugging Core AST output

Summary

Functions

Export an entire memory namespace as PTC-Lisp source.

Convert a Core AST node to a PTC-Lisp source string.

Serialize a closure tuple to PTC-Lisp source string.

Serialize all closures in a memory namespace to source strings.

Types

export_error()

@type export_error() ::
  {:non_exportable_java_value, list(), atom()}
  | {:non_exportable_source_name, list(), atom(), term()}
  | {:non_exportable_source_value, list(), term()}
  | {:non_exportable_source_collision, list(), :identifier | :map | :set}
  | {:non_exportable_binding_collision, String.t()}
  | {:non_exportable_closure_capture, list(), [String.t()]}
  | {:non_exportable_dependency_cycle, [String.t()]}
  | {:non_exportable_closure_metadata, list(), [atom()]}
  | {:non_exportable_namespace, module()}

Functions

export_namespace(memory)

@spec export_namespace(map()) :: {:ok, String.t()} | {:error, export_error()}

Export an entire memory namespace as PTC-Lisp source.

Serializes all entries — closures become (def name (fn [...] ...)), non-closure values become (def name value). Multiple top-level forms are emitted without a do wrapper (the parser handles them natively).

Examples

iex> memory = %{"x" => 5, "f" => {:closure, [{:var, "n"}], {:call, {:var, :+}, [{:var, "n"}, 1]}, %{}, [], %{}}}
iex> {:ok, source} = PtcRunner.Lisp.CoreToSource.export_namespace(memory)
iex> source =~ "def x"
true
iex> source =~ "def f"
true

format(value)

@spec format(term()) :: String.t()

Convert a Core AST node to a PTC-Lisp source string.

Examples

iex> PtcRunner.Lisp.CoreToSource.format({:var, :x})
"x"

iex> PtcRunner.Lisp.CoreToSource.format({:string, "hello"})
~S("hello")

iex> PtcRunner.Lisp.CoreToSource.format({:call, {:var, :+}, [1, 2]})
"(+ 1 2)"

serialize_closure(closure)

@spec serialize_closure(term()) :: {:ok, String.t()} | {:error, export_error()}

Serialize a closure tuple to PTC-Lisp source string.

Rejects closures that reference captured lexical state. Named closures retain their self binding, and attached-prelude exports serialize as their public reference so hydration restores isolation and contracts. Docstrings are rejected because a function expression has no source position for them; export_namespace/1 preserves them on the surrounding def. Unreferenced diagnostic environment, history, and metadata fields are not emitted.

Examples

iex> closure = {:closure, [{:var, "x"}], {:call, {:var, :+}, [{:var, "x"}, 1]}, %{}, [], %{}}
iex> PtcRunner.Lisp.CoreToSource.serialize_closure(closure)
{:ok, "(fn [x] (+ x 1))"}

serialize_namespace(memory)

@spec serialize_namespace(map()) :: {:ok, map()} | {:error, export_error()}

Serialize all closures in a memory namespace to source strings.

Returns a map of {name => source_string} for each closure value in memory. Non-closure values are skipped.

Examples

iex> memory = %{"f" => {:closure, [{:var, "x"}], {:var, "x"}, %{}, [], %{}}, "count" => 5}
iex> PtcRunner.Lisp.CoreToSource.serialize_namespace(memory)
{:ok, %{"f" => "(fn [x] x)"}}