# 元编程
Deft 通过 `@` 装饰器、`meta` 访问器和 `info/*` 命名空间公开自身的
元数据与反射层。它们共同覆盖内省(这个值知道自身哪些信息?)与
标注(工具应如何处理它?)。特殊形式(special form)—— 编译器保留、
会被脱糖为内部 IR 的名称 —— 也在此一并记录。
## 装饰器:`@`-标签
函数体中可以包含任意数量的 `@key value` 行。键成为元数据;
值被附加到其上。`@doc` 最为常见;任意标签也同样可用。
def greet {|name^string| @doc "Print a greeting." @since "1.2.0" @category :friendly echo "Hello, $name!" }
`@doc` 接受字符串(多个时会被连接)或结构化映射:
def create-user {|name^string email^string| @doc { :description "Create a user record." :params %{ :name "User's full name" :email "Contact email" } :returns %User } %User{ :name $name :email $email } }
### 获取元数据
`meta` 读取单个键;`info/props` 返回完整的元数据映射:
echo [meta $greet "doc"] # => "Print a greeting." echo [meta $greet "since"] # => "1.2.0" echo [info/props $greet] # => %{ :doc "Print a greeting." :since "1.2.0" :category :friendly }
### 装饰器的其他使用场景
| 标签 | 使用者 |
|---|---|
| `@doc` | 编辑器悬停提示、REPL 帮助、`info/props`、MCP 工具描述 |
| `@rpc true` | 运行时 RpcRegistry —— 将函数暴露给 `rpc` |
| `@command` | CLI 子命令注册 |
| `@private` / `@internal` | 文档工具 —— 标记为非公开 |
| `@since` / `@deprecated` | 版本追踪 |
| `@bench` | 为运行器标记基准测试 |
## `info/*` 命名空间
`info/*` 公开运行时的符号表与模块表。
| 函数 | 返回值 |
|---|---|
| `info/modules` | 已加载模块名称的列表 |
| `info/defs` | 当前命名空间中的 def |
| `info/vars` | 当前命名空间中的 var(模块局部变量) |
| `info/types` | 已注册的类型 |
| `info/protocols` | 已注册的协议 |
| `info/props` | 某个值的完整元数据映射 |
| `info/sig` | 函数签名 |
| `info/source` | def 的源代码(若可用) |
| `info/resolve` | 将名称解析到其源码 |
[info/defs] # => @{ greet create-user ... } [info/types] # => @{ User Point ... } [info/protocols] # => @{ Drawable Keyable ... } [info/sig $greet] # => function with 1 param [info/source $greet] # => source text
## 对值进行反射
[type 42] # => "number" [type "hi"] # => "string" [type %User{...}] # => "User" [type @{ 1 2 }] # => "list" [type ^{:a :b}] # => "set" [is? "number" 42] # => true [is? "User" $alice] # => true [satisfies? $p "Drawable"] # => true if $p's type impls Drawable [nil? $x] # => true if nil [empty? $xs] # => true if empty [future? $f] # => true if a Future [keyword? :foo] # => true
## 特殊形式
这些是编译器保留的名称。它们不是函数;它们会被脱糖为内部 IR,
或触发特定的编译器行为。
### 变量绑定
| 形式 | 用途 |
|---|---|
| `def name value` | 模块作用域绑定 |
| `set name value` | 局部重新绑定 |
| `set name^type value` | 带类型的重新绑定(在运行时校验) |
### 集合构造器
| 形式 | 用途 |
|---|---|
| `@{ ... }` | 列表字面量 |
| `%{ ... }` | 映射字面量 |
| `^{ ... }` | 集合字面量 |
| `%Tag{ ... }` | 标签映射字面量 |
### 控制流
| 形式 | 用途 |
|---|---|
| `if cond { ... } else { ... }` | 条件分支 |
| `match expr { pat => result ... }` | 模式分派 |
| `for x in $xs { ... }` | 集合迭代 |
| `while cond { ... }` | 条件循环 |
| `try { ... } catch e { ... }` | 错误处理 |
| `defer { ... }` | 退出时清理 |
| `return expr` | 提前返回 |
| `break` / `continue` | 循环控制 |
| `throw value` | 抛出错误 |
### 函数定义
| 形式 | 用途 |
|---|---|
| `def name { \|params\| body }` | 函数 |
| `def name { \|params\| body1 \|params\| body2 }` | 多参数个数函数 |
| `defcoro name { ... }` | 协程 |
| `deftask { body }` | 异步任务(也是函数位置形式) |
| `defworker "path.dft" ?n` | 持久化工作进程 / 池(函数位置形式;见 defworker) |
| `defmacro name { \|params\| body }` | 宏 |
| `deftype Name %{ ... }` | 记录类型 |
| `defprotocol Name %{ ... }` | 协议规范集合 |
| `defimpl Type Protocol { ... }` | 附加行为 |
| `defmethod Type name { ... }` | 添加单个方法 |
| `defsuite "name" { ... }` | 测试套件 |
| `deftest "name" { ... }` | 测试用例 |
| `defbench "name" { ... }` | 基准测试用例 |
> 以下形式出现在一些旧文档中,但在当前语言中并不存在:
> `defgen`、`defwait`、`defgroup`、`defasync`、
> `chan`、`<-`、`select`(channel 形式)、`receive`、`send`。
> 受支持的原语见并发。
### 模块系统
| 形式 | 用途 |
|---|---|
| `import "path" as alias` | 加载并设置别名 |
| `from "path" import @{ names }` | 引入特定名称 |
| `implements Interface` | 模块符合性(在加载时检查) |
| `in-ns "name"` | 切换命名空间 |
### 运算符(参数个数固定)
| 形式 | 用途 |
|---|---|
| `+ - * /` | 算术 |
| `mod` | 取模 |
| `== != < > <= >=` | 比较 |
| `and or not` | 布尔运算 |
| `& \| ^ << >>` | 位运算 |
| `..` | 范围(在模式和中缀内) |
### 内部 IR 形式
编译器会生成少量以 `__` 为前缀的 IR 节点,在阅读生成代码或宏输出时
可能会遇到:
| 形式 | 用途 |
|---|---|
| `__make-tagged-map` | 构造标签映射(由 HTML/SQL 块使用) |
| `__shell-exec` | Shell 捕获 `[|cmd]` |
| `__postfix-*` | 后缀糖 `$x(call)` |
| `__capture` | 闭包字面量 |
| `__import-file` / `__import` / `__refer` | 模块加载器钩子 |
| `__implements` | `implements` 的脱糖 |
| `__source` | 源码追踪节点 |
| `__defsuite` / `__deftest` / `__defbench` | 测试脚手架 |
你不需要直接编写这些形式;在此记录它们是为了让宏输出与错误追踪
可被解读。
## 在实践中使用元数据
### 编辑器 / 工具
文档工具会遍历 `info/defs` 并提取 `@doc` 字符串来构建 API 参考。
MCP 集成(见 MCP)使用 `@doc` 描述暴露给语言模型的工具。
### 自定义分派
为函数标注任意元数据,然后据此分派:
def handler {|req| @route "/users/:id" @method :GET # ... } # Walk all defs, find handlers by their @route metadata def routes [] for name [info/defs] { set fn [info/resolve $name] set route [meta $fn "route"] if $route { $routes << @{ $route $fn } } }
### 运行时版本管理
defn deprecated-op {|x|
@deprecated "use new-op instead"
@since "0.3.0"
# ...
}
代码检查工具可以遍历 `info/defs`,对任何调用了标记为 `@deprecated`
的函数的调用发出警告。
## 快速参考
| 形式 | 用途 |
|---|---|
| `@key value`(在 def 函数体内) | 附加元数据 |
| `[meta $fn "key"]` | 读取一条元数据 |
| `[info/props $fn]` | 读取全部元数据 |
| `[info/defs]` / `[info/types]` / `[info/protocols]` | 命名空间内容 |
| `[info/sig $fn]` / `[info/source $fn]` | 函数信息 |
| `[type x]` / `[is? "Type" x]` / `[satisfies? x "Protocol"]` | 类型反射 |