PtcRunner.Lisp.Introspection (PtcRunner v0.14.0)

Copy Markdown View Source

Read-only introspection over the callable PTC-Lisp surface.

Backs the dir, apropos, doc, export-meta, and source builtins. dir, export-meta, and source describe the attached prelude. apropos and doc additionally expose fixed built-ins and the bounded Java surface from PtcRunner.Lisp.Registry. The same answers are produced in the REPL, in workflow and mission source, and inside a prelude export reading another prelude's documentation — there is no REPL-only path.

Ref arguments accept a string or a {:symbol_ref, name} runtime value (from a quoted symbol, or from the analyzer's bare-symbol rewrite on these forms). meta is intentionally not included: in Clojure it is an ordinary function over values, not a discovery form. source resolves only against the attached prelude's compile-time source_index — there is no registry fallthrough.

Attached prelude visibility

Only public export records (%PtcRunner.Lisp.Prelude.Export{}), which cover both :prompt and :discoverable visibility. Private defn- helpers have no export record and are unreachable by qualified call, so they are absent from dir/apropos/doc/export-meta. source is the exception: it can reveal a private helper that is transitively reachable from a visible public export, via Prelude.source_index (not form_graph callables).

Namespaces are derived from the visible export set rather than from Prelude.namespaces/1, so a namespace holding only private helpers does not appear in namespaces/2.

Visibility filter

Callers pass a predicate over export records rather than any runtime context, keeping this module pure. PtcRunner.Lisp.Eval.Apply builds it from the evaluation context so that what a program can discover matches what it can call: PtcRunner.Lisp.Eval.Context.prelude_ref_visible?/2 supplies the strict_transitive_calls half, and the run's prelude_export_mask supplies the discovery half. A narrowed session grant needs no filter here — it hands the run a prelude whose exports list is already the narrow set.

How the reported effect is bounded

Export.effect joins an export's own declaration with those of the prelude helpers it calls, but not with the effects of the capabilities it reaches. The authoritative value is the mission-resolved effect PtcRunner.Kernel.MissionInventory publishes, which adds that last join: a wrapper declaring :read over a capability installed as :write resolves to :write. Producing it needs the mission's capability set, which this layer does not have.

Reporting the raw declaration would therefore let a program read :read for an operation the inventory calls :write — the direction that invites repeating an irreversible call. Omitting the effect is no better: the inventory covers only Prelude.prompt_exports/1, so a :discoverable export is callable with no effect stated anywhere.

So the reported effect is deliberately weakened rather than dropped. An export that reaches no capability is reported as declared. An export that does reach one is reported as :write if anything in its chain declares :write, and :unknown otherwise. It can still fall short of a :write the inventory resolves, but it never calls something :read that touches a capability, so no answer here presents an unresolved effect as safe.

Misses

An exact attached export occupies its ref before its visibility filter is applied. A hidden attached ref therefore cannot fall through to registry documentation for the same spelling. Otherwise doc falls back to the registry, and apropos merges visible attached refs with canonical registry names. An unknown or malformed ref is a miss, not a failure.

Summary

Functions

Sorted visible export refs and canonical registry names matching query.

Sorted visible export refs declared by namespace.

Structured metadata for one visible export, or nil on a miss.

Validates arguments and answers one introspection call.

Sorted namespace names holding at least one visible export.

The introspection operations bound as {:special, op} builtins.

Rendered human-readable documentation for one visible attached export or fixed registry entry.

Rendered defining form for one attached prelude ref, or a miss notice.

Types

operation()

@type operation() :: :dir | :apropos | :doc | :export_meta | :source

visible()

@type visible() :: (PtcRunner.Lisp.Prelude.Export.t() -> boolean())

Functions

apropos(prelude, query, visible)

@spec apropos(PtcRunner.Lisp.Prelude.t() | nil, String.t(), visible()) :: [String.t()]

Sorted visible export refs and canonical registry names matching query.

Matching is a case-insensitive literal substring. Attached exports search their ref and docstring; registry entries search their name, signatures, description, notes, divergences, and section. A blank query matches nothing rather than everything — an empty search is not a request for the whole surface.

dir(prelude, namespace, visible)

@spec dir(PtcRunner.Lisp.Prelude.t() | nil, String.t(), visible()) :: [String.t()]

Sorted visible export refs declared by namespace.

export_meta(prelude, ref, visible)

@spec export_meta(PtcRunner.Lisp.Prelude.t() | nil, String.t(), visible()) ::
  map() | nil

Structured metadata for one visible export, or nil on a miss.

Reports the calling contract: identity, arity, parameter names, call form, docstring, visibility, effect, and any declared signature or type. The effect is bounded as described in the module documentation. Capability wiring (tool_refs, requires) and compiler internals (min_arity, parsed_signature, parsed_type) stay out.

invoke(op, args, context)

@spec invoke(operation(), [term()], PtcRunner.Lisp.Eval.Context.t()) ::
  {:ok, term()} | {:print, String.t()} | {:error, term()}

Validates arguments and answers one introspection call.

Every call path — direct application and higher-order dispatch — routes through here, so argument faults and answers cannot differ between them. doc answers {:print, text} because its text belongs on the print channel rather than in the result.

namespaces(prelude, visible)

@spec namespaces(PtcRunner.Lisp.Prelude.t() | nil, visible()) :: [String.t()]

Sorted namespace names holding at least one visible export.

operations()

@spec operations() :: [operation()]

The introspection operations bound as {:special, op} builtins.

render_doc(prelude, ref, visible)

@spec render_doc(PtcRunner.Lisp.Prelude.t() | nil, String.t(), visible()) ::
  String.t()

Rendered human-readable documentation for one visible attached export or fixed registry entry.

Callers print this rather than returning it, so documentation text is charged to the print budget instead of the result channel. An attached ref occupies its exact spelling before visibility is applied and therefore cannot fall through to registry documentation when hidden.

render_source(prelude, ref, visible)

@spec render_source(PtcRunner.Lisp.Prelude.t() | nil, String.t(), visible()) ::
  String.t()

Rendered defining form for one attached prelude ref, or a miss notice.

Resolves only against Prelude.source_index — public exports and private helpers transitively reachable from a visible public export. There is no registry or filesystem fallthrough. Visibility matches the other discovery forms: a masked or unauthorized public ref is a miss, and a private helper is visible only when at least one public export that reaches it is visible. Callers print this rather than returning it.