Registry entries for r7rs libraries.
A %Schooner.Library{} is the result of compiling a library — a
frozen exports map plus the dependency list and provenance metadata
the importer and the diagnostics need. It is not a representation of
the library's source: the original datums and the expanded body AST
are dropped after the body has run and the exports have been
materialised. Closures that escape via :exports carry their own
body AST inside {:closure, params, body, env, name}; macros survive
as transformers.
Names are canonical lists of segments where each segment is either a
binary (Scheme-symbol form) or a non-negative integer. The reader
will produce datum-form names like [{:sym, "scheme"}, {:sym, "base"}]
once import and define-library land; this module accepts only
the canonicalised form so the registry key is ==-comparable.
Registries and persistent storage
A registry is a plain map of name => %Schooner.Library{}.
register/2 and lookup/2 are pure and operate on a map the caller
owns. The standard library registry is built once at OTP
application start and stashed under the persistent term key
{Schooner.Library, :standard}. standard/0 reads it without
copying, so spawned evaluator processes pay no cost to access it.
Summary
Functions
Convert a Scheme datum form of a library name (e.g. (scheme base)
read as a cons-cell list of {:sym, _} segments) into the canonical
registry-key form (["scheme", "base"]). Symbol segments become
binaries; non-negative integer segments pass through.
Look up name or raise Schooner.Library.NotFoundError if absent.
Look up name in registry. Returns {:ok, library} or :error.
Build a library entry. :name is required; other fields default
empty (exports: %{}, imports: [], source: :native,
features: []).
Persist registry as the standard registry. Triggers a global
literal-area GC if the key is being updated rather than created;
callers expect to use this only at OTP application start.
Insert library into registry. Raises ArgumentError if a library
with the same canonical name is already present — registries are
append-only.
Render name in (scheme base) form for diagnostics. The empty
list (an anonymous host library) renders as
"(anonymous host library)" — there is no Scheme syntax that can
produce that name, so a literal () rendering would be misleading.
Read the standard registry from persistent term storage. Returns
%{} when the key is unset, which lets the standard-library
bootstrapper build the first registry on top of an empty default.
Topologically sort registry by :imports. Returns the names in an
order where every import precedes the library that imports it. Edges
pointing at libraries not present in registry are silently
skipped — import resolution surfaces those at use site.
Types
Functions
@spec canonicalise_name(Schooner.Value.t()) :: name()
Convert a Scheme datum form of a library name (e.g. (scheme base)
read as a cons-cell list of {:sym, _} segments) into the canonical
registry-key form (["scheme", "base"]). Symbol segments become
binaries; non-negative integer segments pass through.
Look up name or raise Schooner.Library.NotFoundError if absent.
Look up name in registry. Returns {:ok, library} or :error.
Build a library entry. :name is required; other fields default
empty (exports: %{}, imports: [], source: :native,
features: []).
@spec persist!(registry()) :: :ok
Persist registry as the standard registry. Triggers a global
literal-area GC if the key is being updated rather than created;
callers expect to use this only at OTP application start.
Insert library into registry. Raises ArgumentError if a library
with the same canonical name is already present — registries are
append-only.
Render name in (scheme base) form for diagnostics. The empty
list (an anonymous host library) renders as
"(anonymous host library)" — there is no Scheme syntax that can
produce that name, so a literal () rendering would be misleading.
@spec standard() :: registry()
Read the standard registry from persistent term storage. Returns
%{} when the key is unset, which lets the standard-library
bootstrapper build the first registry on top of an empty default.
Topologically sort registry by :imports. Returns the names in an
order where every import precedes the library that imports it. Edges
pointing at libraries not present in registry are silently
skipped — import resolution surfaces those at use site.
Returns {:error, {:cycle, names}} when registry contains an
import cycle. names lists the cycle entry-to-cycle-back order so
(a) imports (b), (b) imports (a) reports [a, b, a].