# Introspection
The introspection family is how a running Deft program describes itself
and its runtime. `deft/` round-trips values as source literals, parses
arbitrary source into form trees, and highlights source text; `info/`
queries the registry for modules, definitions, types, protocols,
metadata, signatures, and source;
`capture/` intercepts `echo` output for tests and tooling; and
`capabilities` reports what the binary was compiled with. All are native
stdlib, available without an import.
## Functions
| Function | Purpose |
|---|---|
| `deft/stringify $value` | Serialize any value to a parseable Deft-literal string |
| `deft/parse "source"` | Parse a literal string back to a value; data-only, no evaluation |
| `deft/parse-forms "source"` | Parse arbitrary source into `%Sexpr{}` form trees; no evaluation |
| `deft/syntax-highlight $source` | Tokenize Deft source into `%__HtmlSafe{:value "<html>"}` |
| `info/modules` | Loaded namespace names |
| `info/defs ?ns` | Defs in the current namespace, or in a named namespace |
| `info/vars` | Vars visible in the current scope |
| `info/types` | User-defined type names |
| `info/protocols` | Registered protocol names |
| `info/props value` | Metadata map for a value, namespace, or type |
| `info/sig value` | Formatted signature string for a function |
| `info/source value` | Source file and namespace for a symbol |
| `info/resolve name` | Resolve a name through the namespace chain; value or `nil` |
| `capture/start` | Install (or clear) the echo capture buffer; idempotent |
| `capture/flush` | Drain the buffer and uninstall it; list of captured lines |
| `capture/clear` | Discard the buffer without reading it |
| `capture/with $thunk` | Scoped capture around a 0-arity callable |
| `capabilities` | Compiled-in feature map for portability checks |
Notes:
- Literal round-trip. `deft/stringify` handles nil, booleans,
numbers, strings, keywords, vectors, maps, tagged maps, and sets;
`deft/parse` reads the result back. Parsing is data-only — function
calls, infix expressions, variables, and statement keywords are
rejected, which makes it safe to run on untrusted input. Bare
identifiers are read as keywords, and a source with no literal value
yields `nil`.
- Form parsing. Unlike `deft/parse`, `deft/parse-forms` runs the
full parser over any source and returns `%{ :forms @{%Sexpr{} ...}`
:errors @{...} }`. Each form carries `:tag`, `:line`/`:col`, and a`
payload (`:value`, `:items`, or `:pairs`); malformed source recovers
with diagnostics in `:errors` rather than throwing. Use it for tooling
that inspects code — importers, graph builders, linters.
- Syntax highlighting. `deft/syntax-highlight` returns an
HTML-escaped `%__HtmlSafe{ :value "..." }` where each token with a
known type is wrapped in a Tailwind-classed `<span>` (keywords
`text-cyan-400`, strings and keywords `text-green-400`, numbers
`text-amber-400`, and so on). Lex failures fall back to plain escaped
text, so the result always renders as source.
- Registry queries. `info/modules`, `info/types`, and
`info/protocols` return keyword lists; `info/defs` takes an optional
namespace name and otherwise lists the current one; `info/vars` lists
what is visible in scope. `info/props` returns a metadata map (doc
text, declared return type, and other `@` tags), `info/sig` a
formatted `name(args) -> type | doc` string, and `info/source` the
source file and namespace — native functions report `%{ :ns core }`.
`info/resolve` walks the namespace chain and returns the bound value
or `nil`.
- Output capture. `capture/start` redirects subsequent
`echo`/`println` calls into a buffer; `capture/flush` returns one entry
per call and uninstalls the buffer, and `capture/clear` drops it
without reading. `capture/with` scopes the same behaviour around a
zero-arity callable and returns `%{ :result $r :output $lines }`; it is
safe to nest, restoring the previous buffer on exit. The test framework
builds on these verbs.
- Capabilities. The map reports `:pixels` (raster output really
rasterizes), `:svg`, `:textures`, `:ffi`, and `:backend` (`:ansi` in
the scripting binary and lean text build, `:gl` in the full TUI
build). Branch on these instead of relying on silent no-ops in builds
that lack a feature.
## Examples
# Literal round-trip [deft/stringify %Point{ :x 1 :y 2 }] # => "%Point{:y 2 :x 1}" [deft/parse "%{:a 1 :b @{1 2 3}}"] # => %{ :a 1 :b @{1 2 3} } # Parse arbitrary source into positioned form trees (no evaluation) set p [deft/parse-forms "set x [len \$xs]"] [first $p~forms] # => %Sexpr{ :tag :list :line 1 :col 1 ... } [get [first $p~errors] :message] # diagnostics, not exceptions # Inspect the registry [info/modules] # => @{ :core :user } [info/defs "core"] # defs exported from :core [info/types] # user-defined type names [info/protocols] # registered protocol names [info/sig "str"] # => "str(...) -> string | ..." [info/props "str"] # => metadata map (doc, returns, ...) [info/source "str"] # => %{ :ns core } [info/resolve "map"] # => <native-fn> # Highlight a snippet the way the docs renderer does [get [deft/syntax-highlight "set x 42"] :value] # => "<span class=\"text-cyan-400\">set</span> x <span ...>42</span>" # Assert on printed output without touching stdout [capture/with { echo "hi" }] # => %{ :output @{ "hi" } :result nil } # Discover what this binary actually exposes [capabilities] # => %{ :textures false :svg false :ffi false :backend :ansi :pixels false } [info/defs] # defs in the current namespace
## See Also
- Utility — `eval`, `pretty`, and the rest of the grab-bag
- Testing — `capture/*` inside `deftest`
- Debug Server — inspecting a live runtime