一段脚本:从 JSON 一路到机器码
← 目录
作者: 一了 <
[email protected]
> 日期: 2026-09-01 一句话总结: 同一段脚本,从 JSON/FD 数据一路延伸到运行时编译的 C 与内联汇编,无需离开这门语言。
多数脚本语言都逼你选一条路:要么留在高层图省事,要么在循环吃紧时降到 C。而 Fun 把整条能力阶梯**收敛进同一个运行时、同一段脚本**。 ## 能力阶梯 ``` 高层 JSON / FD 数据,list / set / tree 集合 原生调用 `dll.getapi(name, 'signature')` (紧凑 FFI) 运行时 C `ccompile(code, ...)` (内置 Tiny C 编译器) JIT `NewJit(...)` (C 或汇编,自动选择) 机器码 `Assembly(code, ...).Load()` (内联汇编) ``` ## 一段脚本可以触及全部五层 这条阶梯的**顶端和底端可以在同一个文件里相遇**,并且互相调用。下面这段对 `1..n` 求和,一次走运行时编译的 C,一次走内联汇编,两次都把结果交还给 Fun 函数: ```fun use 'lib-jit.fun'; fun cb(a, b) # 由 JIT 编译代码回调的 Fun 函数 result = a * 2^32 + b; end fun; # 汇编路径(32 位 x86) var asm = `#!asm i:i mov ecx, dword ptr [esp+04] @sum1ton push eax push edx mov eax, <test> call eax `; var jit = NewJit(asm, names: [test: cb.@toCallback(nil, 'ii:i', true)]); ?. jit.Run(100000); # C 路径(用内置 TCC 在运行时编译) var c = `#!C ii:i int sum(int n, int (*test)(int, int)) { long long s = 0; for (int i = 1; i <= n; i++) s += i; test((int)(s >> 32), (int)(s & 0xFFFFFFFF)); return 1; } `; jit = NewJit(c); ?. jit.call(100000, cb.@toCallback(nil, 'ii:C', true)); ``` 没有独立工具链,没有链接器,也不需要胶水代码。解释器现场编译 C,或直接生成机器码,而原生这一侧又能直通回脚本。 ## 为什么重要 - **不再「撞上 FFI 的墙」。** 性能关键部分不会逼你跳出这门语言。 - **一个二进制。** 解释器、解析器、TCC、汇编装载器,整个运行时以一个可嵌入的 `fun.dll` / `fun.exe` 交付。 - **刻意保持精简。** 一个你可以读完、想透、随手嵌入的小型树遍历解释器。 一句话:**数据与代码同等是一等公民,而一段脚本无需离开这门语言,就能一路探到机器。**