Skip to content

Commit d68d7dd

Browse files
committed
add pdf docs
1 parent b3c68bf commit d68d7dd

4 files changed

Lines changed: 215 additions & 70 deletions

File tree

docs/Implementation-zh.typ

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#import "@preview/modern-cug-report:0.1.3": *
2+
#show: doc => template(doc, size: 11.5pt,
3+
footer: "2026", header: "FieldMeta.jl 实现思路")
4+
5+
#set par(leading: 1em, spacing: 1em)
6+
7+
#align(center)[
8+
#text(20pt, weight: "bold")[FieldMeta.jl 实现思路]
9+
#v(0.4em)
10+
#text(11pt)[一个比 FieldMetadata.jl 更紧凑的 struct 字段元数据方案]
11+
#v(0.6em)
12+
#text(9.5pt, fill: gray)[版本 0.1.0 · 共 ~160 行]
13+
]
14+
15+
#v(1em)
16+
17+
= 1 宏展开后生成什么
18+
19+
理解整个包,最快的方式是看最终生成了什么。
20+
21+
```julia
22+
@metadata bounds nothing Any
23+
@metadata units "-" String
24+
25+
@bounds @units struct Muskingum
26+
x::Float64 | (0.01, 0.5) | "m/s"
27+
dt::Float64
28+
end
29+
```
30+
31+
等价于:
32+
33+
```julia
34+
struct Muskingum # pipe 被剥干净
35+
x::Float64
36+
dt::Float64
37+
end
38+
39+
# 每个 (类型, 字段, key) → 专属方法,直接返回常量
40+
@inline _meta(::Type{<:Muskingum}, ::Val{:x}, ::Val{:bounds}) = (0.01, 0.5)
41+
@inline _meta(::Type{<:Muskingum}, ::Val{:x}, ::Val{:units}) = "m/s"
42+
43+
# @metadata 为每个 key 生成的默认 fallback
44+
@inline _meta(::Type, ::Val, ::Val{:bounds}) = nothing
45+
@inline _meta(::Type, ::Val, ::Val{:units}) = "-"
46+
```
47+
48+
用户调用 `bounds(model, :x)` 时,内部走 `_meta(Muskingum, Val{:x}(), Val{:bounds}())`
49+
三层优先级:*专属方法 > 按 key 默认 > MethodError(未声明的 key)*。
50+
热路径全是方法派发,无 Dict 查询,完全类型稳定。
51+
52+
= 2 pipe 链与堆叠宏
53+
54+
`|` 在 Julia 里是左结合运算符:
55+
56+
```
57+
x::T | v1 | v2 | v3 ≡ ((x::T | v1) | v2) | v3
58+
```
59+
60+
最左值 `v1` 在最深的 `:|` 节点。Julia 宏从外向内展开,所以:
61+
62+
- `@bounds`(最外层)剥走 `v1`,余下 `x::T | v2 | v3` 交给下一个宏。
63+
- `@units` 剥走 `v2`,余下 `x::T | v3`
64+
- `@description` 剥走 `v3`,余下纯净的 `x::T`
65+
66+
核心实现是 `_strip_leftmost!(args, i)`(7 行),递归找到最深的 `:|` 节点,
67+
原地替换并返回被剥掉的值。
68+
69+
= 3 类型检查在何时发生
70+
71+
#table(columns: (auto, 1fr),
72+
align: (left, left),
73+
stroke: 0.5pt + gray,
74+
table.header[时机][做什么],
75+
[宏展开期], [从 `REGISTRY` 读约束 `c`,检查 key 是否已声明(未声明立即报错)],
76+
[结构体定义期], [`let v = $val; v isa c || _typeerror(...)` 执行一次],
77+
[访问期], [专属方法直接 `return $val`*零额外开销*],
78+
)
79+
80+
`REGISTRY` 只在 `@metadata` 执行时写入、宏展开时读出,运行期不接触。
81+
82+
= 4 内部函数调用链
83+
84+
`@bounds struct ... end` 展开时,调用关系如下:
85+
86+
```
87+
macro bounds(ex)
88+
_stack(ex, :bounds, src)
89+
_process(ex, src, emit_fn)
90+
1. _find_struct(ex) # 找到 :struct,穿过 @with_kw 等 macrocall
91+
2. for each field line:
92+
a. _meta_slot(block, i) # 该行有 pipe 吗?→ (args, idx, fname)
93+
b. _strip_leftmost!(args, idx) # 原地剥最左 | 值,返回 val
94+
c. _emit!(methods, T, fname, key, val)
95+
- REGISTRY[key] # 读约束 c(宏展开期,一次性)
96+
- push! 生成的方法块:
97+
let v=val; v isa c || _typeerror(...) end # 定义期执行
98+
@inline _meta(::Type{<:T}, ::Val{f}, ::Val{k}) = val
99+
3. return Expr(:block, esc(ex), methods...)
100+
```
101+
102+
步骤 2 是顺序的三步(a → b → c),不是嵌套调用。`ex` 在步骤 2 里被原地修改(pipe 已剥),步骤 3 返回时它已经是干净的 struct。
103+
104+
== 多宏堆叠时的展开顺序
105+
106+
堆叠不靠代码里的循环,而是 Julia 宏展开机制本身驱动。
107+
展开(编译期)和执行(运行期)是两个阶段:
108+
109+
*展开阶段*(外 → 内,编译期):
110+
```
111+
@bounds @units struct ... x | v1 | v2 end
112+
@bounds 展开 → block { esc(@units struct...x|v2 end), # ex 放前面
113+
@inline _meta(...bounds...) = v1 }
114+
@units 展开 → block { esc(struct...x end), # ex 放前面
115+
@inline _meta(...units...) = v2 }
116+
```
117+
118+
*执行阶段*(顺序执行,运行期):
119+
```
120+
1. struct ... x end ← struct 先定义
121+
2. @inline _meta(...units...) = v2 ← 方法引用 T,T 已存在 ✓
122+
3. @inline _meta(...bounds...) = v1
123+
```
124+
125+
`_process` 始终把 `esc(ex)` 放在 `methods` 之前返回,
126+
保证 struct 定义先于任何引用它的 `_meta` 方法。
127+
128+
= 5 调试入口
129+
130+
```julia
131+
import FieldMeta: _ispipe, _find_struct, _fieldname, _strip_leftmost!, _meta_slot
132+
133+
# 直接喂 quote 调用内部函数
134+
holder = Any[:(x::Int | (0, 1) | "m")]
135+
_strip_leftmost!(holder, 1) # => :((0, 1))
136+
137+
# 观察完整展开
138+
@macroexpand @bounds @units struct Foo; x::Int | 1 | "u"; end
139+
```
140+
141+
每个 helper 的行为在 `test/test-internals.jl` 里都有可执行示例。
Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
},
1010
{
1111
"cell_type": "code",
12-
"execution_count": 1,
12+
"execution_count": null,
1313
"metadata": {},
1414
"outputs": [],
1515
"source": [
@@ -29,7 +29,7 @@
2929
},
3030
{
3131
"cell_type": "code",
32-
"execution_count": 2,
32+
"execution_count": null,
3333
"metadata": {},
3434
"outputs": [
3535
{
@@ -57,7 +57,7 @@
5757
},
5858
{
5959
"cell_type": "code",
60-
"execution_count": 3,
60+
"execution_count": null,
6161
"metadata": {},
6262
"outputs": [
6363
{
@@ -107,7 +107,7 @@
107107
},
108108
{
109109
"cell_type": "code",
110-
"execution_count": 4,
110+
"execution_count": null,
111111
"metadata": {},
112112
"outputs": [
113113
{
@@ -148,7 +148,7 @@
148148
},
149149
{
150150
"cell_type": "code",
151-
"execution_count": 5,
151+
"execution_count": null,
152152
"metadata": {},
153153
"outputs": [
154154
{
@@ -176,7 +176,7 @@
176176
},
177177
{
178178
"cell_type": "code",
179-
"execution_count": 6,
179+
"execution_count": null,
180180
"metadata": {},
181181
"outputs": [
182182
{
@@ -207,7 +207,7 @@
207207
},
208208
{
209209
"cell_type": "code",
210-
"execution_count": 7,
210+
"execution_count": null,
211211
"metadata": {},
212212
"outputs": [
213213
{
@@ -248,7 +248,7 @@
248248
},
249249
{
250250
"cell_type": "code",
251-
"execution_count": 8,
251+
"execution_count": null,
252252
"metadata": {},
253253
"outputs": [
254254
{
@@ -277,7 +277,7 @@
277277
},
278278
{
279279
"cell_type": "code",
280-
"execution_count": 9,
280+
"execution_count": null,
281281
"metadata": {},
282282
"outputs": [
283283
{
@@ -314,7 +314,7 @@
314314
},
315315
{
316316
"cell_type": "code",
317-
"execution_count": 10,
317+
"execution_count": null,
318318
"metadata": {},
319319
"outputs": [
320320
{
@@ -404,7 +404,7 @@
404404
},
405405
{
406406
"cell_type": "code",
407-
"execution_count": 12,
407+
"execution_count": null,
408408
"metadata": {},
409409
"outputs": [
410410
{
@@ -425,7 +425,7 @@
425425
},
426426
{
427427
"cell_type": "code",
428-
"execution_count": 13,
428+
"execution_count": null,
429429
"metadata": {},
430430
"outputs": [
431431
{
@@ -466,7 +466,7 @@
466466
},
467467
{
468468
"cell_type": "code",
469-
"execution_count": 14,
469+
"execution_count": null,
470470
"metadata": {},
471471
"outputs": [
472472
{

docs/implementation.pdf

121 KB
Binary file not shown.

0 commit comments

Comments
 (0)