Schooner.Library.Loader (schooner v1.2.0)

Copy Markdown View Source

Compiles (define-library ...) declarations into %Schooner.Library{} registry entries.

Supported declaration heads

  • (import spec ...) — pull bindings from already-registered libraries, with any of the r7rs import modifiers: only, except, prefix and rename.
  • (begin form ...) — body forms evaluated in the library's private env.
  • (export name ...) — names visible to importers. Each entry is a bare symbol or (rename internal external). Names not bound by the body or imports raise at compile time.
  • (cond-expand clause ...) — selects a list of declarations based on the feature requirement clauses. Supported requirement forms: feature-id (a symbol), (library NAME), (and ...), (or ...), (not ...), and an else clause.
  • (include "path" ...) — read each named file as a sequence of body forms and splice them into the library's (begin …). Paths resolve relative to the file containing the include form.
  • (include-library-declarations "path" ...) — read each named file as a sequence of declarations and process them in place. Paths resolve relative to the including file, so nested includes thread the directory of the innermost file.

When a base directory is known (from load_file/2 or the :base_dir option), include paths, relative or absolute, that resolve outside it are rejected. Nested includes retain this root even when their resolution directory changes. Without a base directory, both relative and absolute include paths are an error.

Diagnostics

Errors raised by the loader quote the file path and line:column of the offending source datum where the reader can supply one. Libraries loaded from disk record their origin in the :source field as {:file, path, {line, column}}. The topological pre-pass over include-library-declarations runs without per-path positions, so a malformed path datum found during that pass is reported without a line number; once the pass succeeds, the main walker re-reads the same files with positions and quotes any subsequent error precisely.

Libraries always record source locations. Script-level errors raised while expanding or evaluating a library body, or later by a procedure the library defines, carry the Schooner.Location of the form in the file it was read from: the library's own file, or the included file. Pass debug: true to load_file/3 or load_string/3 to also locate errors raised while applying procedures inside the library's code (see "Source locations" in Schooner).

Summary

Types

Path-resolution context threaded through declaration processing.

Functions

Compile a single (define-library ...) datum against registry. Returns a %Schooner.Library{} ready for Library.register/2.

Read a file containing one or more (define-library ...) forms and register every library it defines into registry. Libraries are compiled in topological order so each library's dependencies are already present when its body is evaluated. Returns the augmented registry.

Compile and register every define-library form in source.

Types

ctx()

@type ctx() :: %{
  optional(:debug) => boolean(),
  base_dir: binary() | nil,
  root_dir: binary() | nil,
  path: binary() | nil
}

Path-resolution context threaded through declaration processing.

Functions

compile(datum, registry, ctx \\ default_ctx())

Compile a single (define-library ...) datum against registry. Returns a %Schooner.Library{} ready for Library.register/2.

ctx carries the directory used to resolve relative include paths and the path threaded into diagnostics. When called with a raw datum (no positioned tree from the reader), error messages render without line/column information.

load_file(path, registry \\ Library.standard(), opts \\ [])

Read a file containing one or more (define-library ...) forms and register every library it defines into registry. Libraries are compiled in topological order so each library's dependencies are already present when its body is evaluated. Returns the augmented registry.

Raises ArgumentError on cycles in the local-to-the-file dependency graph. Cycles that mix file-local libraries with already-registered libraries cannot occur because the registry is append-only.

load_string(source, registry \\ Library.standard(), opts \\ [])

Compile and register every define-library form in source.

Options:

  • :base_dir — directory used to resolve relative (include …) and (include-library-declarations …) paths and confine all include paths. Defaults to nil, which rejects both relative and absolute includes.
  • :path — file path threaded into diagnostics and error locations. Defaults to nil (anonymous source).
  • :debug — when true, locate errors raised while applying procedures inside the libraries' code. Defaults to false.