Packages
Secure BEAM sandbox runtime for LLM code mode and MCP aggregation. Run concurrent LLM/tool clients safely while agents orchestrate approved tools, call upstream MCP/OpenAPI servers, and transform data.
Current section
Files
Jump to
Current section
Files
lib/mix/tasks/ptc.gen_docs.ex
defmodule Mix.Tasks.Ptc.GenDocs do
@shortdoc "Generate function reference and audit docs from registry"
@moduledoc """
Generates documentation from `priv/functions.exs`:
1. `docs/function-reference.md` — all implemented functions grouped by section
2. `docs/clojure-core-audit.md` — clojure.core coverage audit
3. `docs/clojure-string-audit.md` — clojure.string coverage audit
4. `docs/clojure-set-audit.md` — clojure.set coverage audit
5. `docs/java-math-audit.md` — java.lang.Math coverage audit
## Usage
mix ptc.gen_docs
"""
use Mix.Task
alias PtcRunner.Lisp.Registry
@function_ref_path "docs/function-reference.md"
@audits [
%{
path: "docs/clojure-core-audit.md",
title: "Clojure Core Audit for PTC-Lisp",
description: "Comparison of `clojure.core` vars against PTC-Lisp builtins.",
fetch: &Registry.clojure_core_audit/0
},
%{
path: "docs/clojure-string-audit.md",
title: "Clojure String Audit for PTC-Lisp",
description: "Comparison of `clojure.string` vars against PTC-Lisp builtins.",
fetch: &Registry.clojure_string_audit/0
},
%{
path: "docs/clojure-set-audit.md",
title: "Clojure Set Audit for PTC-Lisp",
description: "Comparison of `clojure.set` vars against PTC-Lisp builtins.",
fetch: &Registry.clojure_set_audit/0
},
%{
path: "docs/java-math-audit.md",
title: "Java Math Audit for PTC-Lisp",
description: "Comparison of `java.lang.Math` methods against PTC-Lisp builtins.",
fetch: &Registry.java_math_audit/0
}
]
@interop_path "docs/java-interop.md"
@impl Mix.Task
def run(_args) do
Mix.Task.run("app.start")
generate_function_reference()
Enum.each(@audits, &generate_audit/1)
generate_java_interop()
end
defp generate_function_reference do
entries = Registry.implemented()
sections =
entries
|> Enum.group_by(& &1.section)
|> Enum.sort_by(fn {section, _} -> section_order(section) end)
audit_links =
@audits
|> Enum.map_join(" | ", fn %{path: path, title: title} ->
name = title |> String.replace(" for PTC-Lisp", "") |> String.replace(" Audit", "")
"[#{name}](#{Path.basename(path)})"
end)
content = """
<!-- Auto-generated — do not edit by hand -->
# PTC-Lisp Function Reference
> **Warning:** This file is auto-generated by `mix ptc.gen_docs` from `priv/functions.exs`.
> Manual edits will be overwritten. Edit `priv/functions.exs` instead.
#{length(entries)} functions and special forms.
See also: [PTC-Lisp Specification](ptc-lisp-specification.md) | #{audit_links}
## Table of Contents
#{toc(sections)}
#{Enum.map_join(sections, "\n\n", &render_section/1)}
"""
File.write!(@function_ref_path, content)
Mix.shell().info("Generated #{@function_ref_path} (#{length(entries)} entries)")
end
defp toc(sections) do
Enum.map_join(sections, "\n", fn {section, entries} ->
anchor =
section |> String.downcase() |> String.replace(~r/[^a-z0-9]+/, "-") |> String.trim("-")
"- [#{section}](##{anchor}) (#{length(entries)})"
end)
end
defp section_order("Definitions & Bindings"), do: 0
defp section_order("Conditionals"), do: 1
defp section_order("Threading Macros"), do: 2
defp section_order("Control Flow"), do: 3
defp section_order("Iteration"), do: 4
defp section_order("Core"), do: 5
defp section_order("Predicate Builders"), do: 6
defp section_order("Functional Tools"), do: 7
defp section_order("Agent Control"), do: 8
defp section_order("String Functions"), do: 9
defp section_order("Set Operations"), do: 10
defp section_order("Regex Functions"), do: 11
defp section_order("Math Functions"), do: 12
defp section_order("Interop"), do: 13
defp section_order(_), do: 99
defp render_section({section, entries}) do
rows =
entries
|> Enum.sort_by(& &1.name)
|> Enum.map_join("\n", fn entry ->
sigs = Enum.join(entry.signatures, ", ")
ext = if entry.ptc_extension?, do: " *", else: ""
"| `#{entry.name}`#{ext} | `#{sigs}` | #{entry.description} |"
end)
examples =
entries
|> Enum.flat_map(fn entry ->
Enum.map(entry.examples, fn {code, result} -> {entry.name, code, result} end)
end)
example_block =
if examples == [] do
""
else
examples_text =
Enum.map_join(examples, "\n", fn {_name, code, result} ->
"#{code}\n;; => #{result}"
end)
"\n```clojure\n#{examples_text}\n```"
end
"""
## #{section}
| Function | Signature | Description |
|----------|-----------|-------------|
#{rows}
#{example_block}
"""
end
defp generate_audit(%{path: path, title: title, description: description, fetch: fetch}) do
entries = fetch.()
counts = Enum.frequencies_by(entries, & &1.status)
rows =
entries
|> Enum.sort_by(& &1.name)
|> Enum.map_join("\n", fn entry ->
icon = status_icon(entry.status)
"| `#{entry.name}` | #{icon} #{entry.status} | #{entry.description} | #{entry.notes} |"
end)
see_also =
@audits
|> Enum.reject(&(&1.path == path))
|> Enum.map_join(" | ", fn %{path: p, title: t} ->
name = t |> String.replace(" for PTC-Lisp", "")
"[#{name}](#{Path.basename(p)})"
end)
content = """
<!-- Auto-generated — do not edit by hand -->
# #{title}
> **Warning:** This file is auto-generated by `mix ptc.gen_docs` from `priv/functions.exs`.
> Manual edits will be overwritten. Edit `priv/functions.exs` instead.
#{description}
See also: [Function Reference](function-reference.md) | #{see_also}
## Summary
| Status | Count |
|--------|-------|
| Supported | #{counts[:supported] || 0} |
| Candidate | #{counts[:candidate] || 0} |
| Not Relevant | #{counts[:not_relevant] || 0} |
| Not Classified | #{counts[:not_classified] || 0} |
| **Total** | **#{length(entries)}** |
## Details
| Var | Status | Description | Notes |
|-----|--------|-------------|-------|
#{rows}
"""
File.write!(path, content)
Mix.shell().info("Generated #{path} (#{length(entries)} entries)")
end
defp generate_java_interop do
entries = Registry.java_interop()
by_class =
entries
|> Enum.group_by(& &1.class)
|> Enum.sort_by(fn {class, _} -> class end)
sections =
Enum.map_join(by_class, "\n\n", fn {class, items} ->
rows =
items
|> Enum.sort_by(& &1.name)
|> Enum.map_join("\n", fn entry ->
sigs = Enum.join(entry.signatures, ", ")
kind = entry.kind |> to_string() |> String.capitalize()
notes = if entry.notes != "", do: entry.notes, else: ""
"| `#{entry.name}` | #{kind} | `#{sigs}` | #{entry.description} | #{notes} |"
end)
"""
### #{class}
| Name | Kind | Signature | Description | Notes |
|------|------|-----------|-------------|-------|
#{rows}
"""
end)
content = """
<!-- Auto-generated — do not edit by hand -->
# Java Interop Reference for PTC-Lisp
> **Warning:** This file is auto-generated by `mix ptc.gen_docs` from `priv/functions.exs`.
> Manual edits will be overwritten. Edit `priv/functions.exs` instead.
PTC-Lisp emulates a subset of Java interop for LLM compatibility. These are **not** real JVM calls — they are BEAM-native implementations that mirror the Java API surface LLMs are trained on.
#{length(entries)} interop entries across #{length(by_class)} classes.
See also: [Function Reference](function-reference.md) | [PTC-Lisp Specification](ptc-lisp-specification.md)
#{sections}
"""
File.write!(@interop_path, content)
Mix.shell().info("Generated #{@interop_path} (#{length(entries)} entries)")
end
defp status_icon(:supported), do: "✅"
defp status_icon(:candidate), do: "🔲"
defp status_icon(:not_relevant), do: "❌"
defp status_icon(_), do: "❓"
end