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
@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
@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
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)"
@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))"}
@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)"}}