# 自省
自省系列是运行中的 Deft 程序描述自身及其运行时的方式。`deft/` 在值与源码字面量之间往返转换、把任意源码解析为形式树,并对源码文本做高亮;`info/` 查询注册表中的模块、定义、类型、协议、元数据、签名和源码;`capture/` 为测试和工具拦截 `echo` 输出;`capabilities` 报告二进制在编译时内置了哪些能力。它们都是原生标准库,无需导入即可使用。
## 函数
| 函数 | 用途 |
|---|---|
| `deft/stringify $value` | 将任意值序列化为可解析的 Deft 字面量字符串 |
| `deft/parse "source"` | 把字面量字符串解析回值;仅处理数据,不求值 |
| `deft/parse-forms "source"` | 把任意源码解析为 `%Sexpr{}` 形式树;不求值 |
| `deft/syntax-highlight $source` | 将 Deft 源码分词为 `%__HtmlSafe{:value "<html>"}` |
| `info/modules` | 已加载的命名空间名称 |
| `info/defs ?ns` | 当前命名空间或指定命名空间中的定义 |
| `info/vars` | 当前作用域中可见的变量 |
| `info/types` | 用户定义的类型名称 |
| `info/protocols` | 已注册的协议名称 |
| `info/props value` | 值、命名空间或类型的元数据映射 |
| `info/sig value` | 函数的格式化签名字符串 |
| `info/source value` | 符号的源文件与命名空间 |
| `info/resolve name` | 沿命名空间链解析名称;返回值或 `nil` |
| `capture/start` | 安装(或清除)echo 捕获缓冲区;幂等 |
| `capture/flush` | 排空并卸载缓冲区;返回捕获行的列表 |
| `capture/clear` | 丢弃缓冲区而不读取 |
| `capture/with $thunk` | 围绕 0 元可调用对象的作用域捕获 |
| `capabilities` | 编译时内置的能力映射,用于可移植性检查 |
说明:
- 字面量往返。 `deft/stringify` 处理 nil、布尔值、数字、字符串、关键字、向量、映射、带标签的映射和集合;`deft/parse` 把结果读回来。解析仅处理数据 —— 函数调用、中缀表达式、变量和语句关键字都会被拒绝,因此可以安全地用于不受信任的输入。裸标识符会被读作关键字,没有任何字面量值的源码则得到 `nil`。
- 形式解析。 与 `deft/parse` 不同,`deft/parse-forms` 对任意源码运行完整的解析器,并返回 `%{ :forms @{%Sexpr{} ...} :errors @{...} }`。每个形式都带有 `:tag`、`:line`/`:col` 以及一个负载(`:value`、`:items` 或 `:pairs`);畸形源码会在 `:errors` 中给出诊断信息后恢复,而不是抛出异常。用它来构建检查代码的工具 —— 导入器、图构建器、linter。
- 语法高亮。 `deft/syntax-highlight` 返回经过 HTML 转义的 `%__HtmlSafe{ :value "..." }`,其中每个具有已知类型的词元都被包裹在带 Tailwind 类的 `<span>` 中(关键字为 `text-cyan-400`,字符串和关键字为 `text-green-400`,数字为 `text-amber-400`,等等)。词法分析失败时回退为纯转义文本,因此结果总能作为源码渲染。
- 注册表查询。 `info/modules`、`info/types` 和 `info/protocols` 返回关键字列表;`info/defs` 接受一个可选的命名空间名称,否则列出当前命名空间;`info/vars` 列出作用域中可见的内容。`info/props` 返回元数据映射(文档文本、声明的返回类型以及其他 `@` 标签),`info/sig` 返回格式化的 `name(args) -> type | doc` 字符串,`info/source` 返回源文件和命名空间 —— 原生函数报告 `%{ :ns core }`。`info/resolve` 沿命名空间链查找并返回绑定的值或 `nil`。
- 输出捕获。 `capture/start` 把随后的 `echo`/`println` 调用重定向到缓冲区;`capture/flush` 为每次调用返回一个条目并卸载缓冲区,`capture/clear` 则在不读取的情况下丢弃它。`capture/with` 将相同行为限定在零元可调用对象的作用域内,并返回 `%{ :result $r :output $lines }`;它可以安全嵌套,退出时恢复之前的缓冲区。测试框架就建立在这些动词之上。
- 能力。 该映射报告 `:pixels`(栅格输出确实会栅格化)、`:svg`、`:textures`、`:ffi` 和 `:backend`(脚本二进制和精简文本构建中为 `:ansi`,完整 TUI 构建中为 `:gl`)。请根据这些字段分支,而不要依赖缺少某特性的构建中的静默空操作。
## 示例
# 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