Fun 代码质量分析报告 - 元宝

4 阅读9分钟
作者: 一了 <1liao3@funlang.org>
日期: 2026-10-20

一句话总结: 腾讯元宝的第三方代码质量分析:综合 7.1/10,约 1.29 万行手写内核、62 个自托管模块,附五类结构性债务与改进清单。基于 2026-10-20 快照,数字会随代码演进。
  

Fun 代码质量分析报告 - 元宝

分析对象:github.com/funlang/fun · main 分支 · v9.x(CHANGELOG 已至 9.4.5,2026-10-20) 分析方式:拉取完整源码(499 文件)后静态阅读 + 脚本化度量,非 README 转述。所有行号/数据以仓库实际内容为准。 分析快照:2026-10-20。仓库每日合入,文中行号、文件数与统计只代表这一天的 main。


编者按:本文是腾讯元宝以第三方视角完成的独立、中立分析,不代表 Fun 项目官方立场。本站只做了标题、标点与少量事实口径的编辑,评分、判断与改进建议保留原文,仅订正计数口径并弱化两处过强表述。站内另有一篇《Fun语言源码深度分析报告 - 元宝》,偏架构与能力面;本篇偏代码质量评分、模块体检与风险清单,两篇可以对照着看。

原文的度量基于 2026-10-20 的 main 快照,而代码库每天都在演进,所以具体数字会随提交漂移。上架前复核了一次:标准库顶层 .fun 文件仍是 89 个(不含 fun/lib/tools 下的 6 个),逻辑模块仍是 62 个;顶层测试脚本 64 → 65,黄金快照仍是 95 个,内核 raise / try 仍是 38 / 53,有顶层 var 的文件仍是 54 个。结论的方向没有变,引用具体行号或计数时请以引用当日的 HEAD 为准。

一句话结论

这是一个「极小内核 + 极宽能力面」的成熟工程:手写 Pascal 内核仅约 1.29 万行代码(不含 lex/yacc 生成表),却完整覆盖词法/语法分析、对象与闭包、正则、FFI、运行时 C 编译、JIT 与内联汇编;标准库 62 个逻辑模块(9,897 行)全部用 Fun 自身编写。

代码风格高度统一、注释记录的是「为什么」而不是「做了什么」、几乎零重复代码,这是二十余年单一作者演进的典型优点。

代价同样清晰:错误处理偏薄(全内核仅 38 处 raise)、引用计数无环检测、标准库全局状态泛滥、平台变体近乎双份实现、安全沙箱(-safe)尚未落地。

它不是「不规范」,而是「单人维护规模下的极致压缩」;一旦要交给多人协作或长期多平台演进,几处结构性债务必须优先偿还。

综合质量分手写内核代码行(Pascal)标准库代码行(Fun)自托管标准库模块
7.1 / 1012.9k9.9k62

一、整体评分卡

维度评分判定依据
架构与设计一致性8.5分层干净(core / parse / lib / regex / utils / prj),树遍历 + Variant 值模型一条主线贯穿到底;CAssignFast 等热点有显式快路径设计并写明取舍。
风格一致性与可读性8.0注释 99.9% 为英文、换行 100% CRLF、无硬编码绝对路径、命名(C* 类 / _* 内建)自洽;函数切分普遍很细:parse.pas 最长仅 78 行,core.pas 最长 93 行,连 385 行的 _ParseJson 主函数体也只有 19 行。扣分项是 {$I} 嵌在函数体内导致的工具链失明。
健壮性与错误处理6.01.6 万行内核只有 38 处 raise、53 处 try,大量失败路径是 exit / 返回 nil 的静默降级;异常类型直接复用 SysUtils.Exception,无层级。
测试与工程化6.55 平台 CI + 95 个黄金快照是加分项;但测试多为快照比对而非断言式单测,仅 33/89 个文件有覆盖,无覆盖率度量。
可维护性与演进7.5CHANGELOG 细到日粒度、CONTRIBUTING 中英双份、授权分层清晰;负担来自平台变体双实现与密集条件编译。
安全性4.5作者自撰 SAFETY 清单逐分支标注危险能力,态度诚实;但 NAT/MEM 类拦截(getapi/@toCallback/TCC/汇编)全部开放,-safe 未实现。
依赖治理7.0vendored 第三方(KOL ≈ 6.96 万行、PCRE)明确隔离在 src/3rd、src/regex/pcre;缺失时构建降级而非失败,规则写进 CI 与文档。

评分口径:以「同等规模单人/小团队系统语言实现」为基准,非以 Linux 内核级工程要求衡量。


二、规模与构成:先把数字摆正

层次文件行数代码行注释率职责与质量观察
src/core/6,0284,63713%值模型(CValue=Variant)、CList/CHash(Trie)、节点树、对象与闭包、流程控制、IO。注释率最低但代码密度最高。
src/parse/8,0995,21931%其中 6,057 行是 lex/yacc 生成表(ytab/ltab/yact/yacc/lact/ycon),手写仅约 2,042 行:parse.pas + 语义动作 + BNF 定义。
src/lib/5,2593,89916%内建运行时:libase(字符串/JSON/时间/系统)、libset(集合)、libfd(FD 读写)、lffi(libffi 后端)、winapi/winole、UI。
src/regex/2,7151,94020%PCRE 移植(vendored)+ 一层 regex.pas 封装成语言值类型。PCRE 缺失时构建降级。
src/utils/68746426%打包/解包(FunPack)与工具函数。
src/prj/53933030%唯一入口 funcmd.dpr:编译 → 执行两步,注释解释线程模型取舍。
fun/lib/12,9369,89714.6%89 个 .fun 文件 = 62 个逻辑模块(含平台变体)。
fun/test/3,957——64 个测试脚本 + 95 个 expected 黄金快照。

汇总:src/ 自写(排除 src/3rd)总行 23,327,代码行 16,489,注释率 21.9%;vendored 第三方约 69.6k 行(KOL 为主)。

口径提醒:README 与白皮书提到的「1.5 万行 / 61 模块」是逻辑代码口径(剔除生成表与 vendored)。实际仓库里 src/3rd/KOL.pas 一个文件就有 62,633 行,占了全仓库代码量的 80% 以上,但属于 GUI 相关的 vendored 依赖,评估内核质量时应整体剔除,否则会严重误判。


三、内核 Pascal 分析

3.1 做得好的地方(值得学习)

  • 注释写「为什么」,不写「做了什么」。 funcmd.dpr 对 cthreads 的说明:「每次分配加锁会让运行慢约 20%,所以做成 opt-in」;core.pas 对 CAssignFast 的说明:「首次运行解析槽位类型并缓存,后续直接读写」;fun.pas 解释为什么指针宽度别名集中在一处定义。这类注释在单人项目里极其罕见,说明作者有意识地对抗「代码自解释」的错觉。

  • 几乎零重复代码。 对全部 Pascal 源文件做 5 行以上连续重复块检测,只命中 2 组、冗余约 10 行(还是 destructor Destroy; override; 这类声明)。对比之下标准库有 83 组重复,内核的重构纪律明显更严。

  • 平台差异被刻意收敛到类型层。 fun.pas 用 int/uint/intptr/uintptr/real 一套别名屏蔽 Delphi 与 FPC、32 位与 64 位差异,并专门注释「不用 PtrInt/NativeInt,避免各单元各写一套」;base.pas 为 64 位指针读取单独提供 PtrOfVal,避免 fun.int(val^) 截断地址。这是有 64 位移植实战痕迹的代码。

  • 数据结构选择有依据。 变量表用 CHash(Trie + 顺序 List),兼顾按名查找与插入顺序;CList 带 autoDel 语义;引用计数用 lockInc/lockDec 原子操作实现 IInterface,为跨线程回调留出余地。

  • 风格零漂移。 全部 38 个 Pascal 文件 100% CRLF;注释中仅 5 行含中文(0.1%);无一处硬编码盘符或绝对路径;构建产物被 .gitignore 完整覆盖。

  • 热路径有显式优化且被注释固化。 CAssignFast、calc-fastpath(测试里有对应用例)说明作者做过性能剖析并留下了回归保护。

3.2 明确的问题(按严重度)

口径说明:两处函数长度度量的更正

第一处:度量脚本起初按「相邻两个 function/procedure 头的行距」估算长度,曾据此称 io.pas 存在 395 行的读取函数,该结论错误。脚本对 class function 形式的函数头匹配失败,又把嵌套过程 DoRead(L321) 当成边界,加上条件编译({$IfDef})造成的 begin/end 不配对,最终把 DoRead(L321) 到 LoadLib(L716) 的 395 行行距误报成了函数体长度。改用「顶层函数头 → 下一个顶格 end;」并人工核验后,io.pas 实际最长函数是 CIO.Find 135 行、CIO.Load 129 行。

第二处:据此把 libase.pas 的 _ParseJson(385 行,内嵌 libfd.inc 后展开约 694 行)定性为「巨型函数」,这个定性同样不准确。它的主函数体只有 19 行(L1643–1661,一个 if fd then ParseFD else ParseJSON 派发器),385 行里绝大部分是 8 个嵌套子过程与两个平级扫描器。该模块是「宽容 JSON → JSON 兼容 → FD → strict」逐层长出来的(CHANGELOG L446 加深度限制、L491 加 RFC 8259 分隔文法可佐证),且生长伴随了全仓唯一一组断言式测试(89 个 strict 用例)。

本节及 §3.3、§五、§六 的数据与定性均已按修正后的口径更新。

级别问题证据与影响
高错误处理不成体系EBase = SysUtils.Exception,没有任何自定义异常层级(无 EFunParse / EFunRuntime / EFunFFI)。全内核 raise 38 次、try 53 次,摊到 1.6 万行约每 420 行一次异常抛出;core.pas 里有 9 处裸 exit、11 处 result := nil。后果:脚本层错误往往是「静默拿到 nil」而非报错,定位成本高;FFI/JIT 这类高风险路径的失败同样缺少结构化信息。
高引用计数无环检测CBase._Release 归零即 Destroy,无 mark-sweep 兜底、无弱引用。class 是闭包的语法糖,对象与父环境天然容易成环。后果:长生命周期脚本(服务、常驻 Agent)一旦成环就会持续泄漏,作者自己在考察报告里也承认「必须显式打破循环」。
中_ParseJson:{$I} 嵌在函数体内函数体本身只有 19 行(L1643–1661,纯粹的 if fd then ParseFD else ParseJSON 派发器),真正的两个扫描器 ParseJSON(263 行)与 ParseFD(309 行)是它的嵌套子过程,整个 385 行其实是「派发器 + 8 个辅助子过程 + 2 个平级扫描器」。
真正的问题是 ParseFD 通过 L1641 的 {$I 'libfd.inc'} 嵌进函数体内部:libfd.inc 不是一个独立编译单元,IDE、静态分析、函数列表都看不到它,也不能被单独引用或测试。后果:导航与工具链失明,且两个扫描器共享父函数的局部变量(Root/Level/Stack),无法独立演化。
中扫描器内部的 goto 状态机ParseJSON(263 行)用 label _STR, _NUM, _KEY + goto 做扫描跳转(_STR: L1442、_NUM: L1529、_KEY: L1561),是字符串/数字/裸键三类 token 的公共出口。评价:这是解析器里常见且高效的写法,但 263 行 + goto 让它难以分段验证,目前只能靠 §五 提到的 89 个 strict 用例兜底。
中条件编译密度过高libase.pas 114 处、utils.pas 91 处、calc.inc 84 处、io.pas 78 处 {$IfDef}。后果:同一文件的「有效代码」在不同平台完全不同,静态审查与重构工具基本失效,也意味着未被 CI 覆盖的平台(WinCE、32 位 Windows)实际处于腐烂风险中。
中goto 与手工控制流全内核 52 处 goto:生成代码 yacc.inc 20 处可忽略,但 calc.inc(10)、base.pas(4)、libase.pas(3)、ie.pas(3)是手写代码里的跳转,多半是性能考量下的早退路径。
低Variant 值模型的性能天花板CValue = System.Variant 让值与 Pascal 生态零成本互操作(这是设计目标),但每次运算都要判类型标签,无法类型特化。仓库自带基准显示简单算术在 78–143 ns/次量级,与内联汇编路径相差数百倍。这是已声明的取舍,不是缺陷,但集成方必须知情。
低技术债标记偏少全仓库仅 16 处 TODO、6 处 XXX。以这个体量和能力面而言,说明大量「已知但不处理」的点没有落档。

3.3 分模块体检表

文件行数函数数最长函数评价
core/core.pas2,12528693良 节点树与对象系统主心骨,类划分细、函数短(最长 CIdx.find 93 行),边界检查(字符串/索引越界 raise)近期补齐。
core/base.pas1,345143171中 值模型 + 容器 + 类型转换全家桶,varComp 171 行且带 4 处 goto,是全局热点。
parse/parse.pas1,17214978良 手写解析器 + 表达式解析,最长函数仅 78 行(CParser.ParseFileName),函数切分是全仓最细的;语法定义在 bnf/fun.ebnf 与 yacc.y 双份维护,改语法需同步。
lib/libase.pas1,83367385
(主函数体 19)中 _ParseJson 385 行但主函数体仅 19 行(派发器),内含 8 个子过程 + ParseJSON(263) / ParseFD(309,经 {$I} 嵌入) 两个扫描器;ParseFD 自身又有 11 个子过程、主函数体 86 行。结构合理,问题在 {$I} 嵌在函数体内;114 处条件编译亦为全仓最高。
core/io.pas76338135中 最长 CIO.Find 135 行(嵌套拆分合理)、CIO.Load 129 行;规模其实健康,问题集中在 CIO.Load 混合了编码探测/转换/分块读三件事。
regex/pcre/*.pas2,223230170vendored PCRE 移植层,不计入自研质量(最长 ComputeReplacement 170 行);历史版本移植、无独立安全更新通道。
lib/lffi.pas50926120良 libffi 后端,7 处 raise 且错误文案具体(含库名/符号名),是本仓错误处理做得最好的模块之一。
utils/utils.pas68741104中 打包/解包,91 处条件编译。

四、标准库 .fun 分析(62 个自托管模块)

4.1 结构:62 个逻辑模块,89 个文件

89 个 .fun 文件合并平台变体后是 62 个逻辑模块,其中:

  • 7 个是纯文档占位模块(0 行代码):lib-string、lib-type、lib-winapi、lib-winole、lib-file、lib-match、lib-dyns,它们用 # 注释块列出内核内建函数清单。这是「文档即模块」的写法,可读性尚可,但会让「模块数」这个指标虚高(README 的 61 与此接近)。
  • 多个 -lnx.fun 是薄转发壳(8–9 行,正文只有一条 use),符合 CONTRIBUTING 声明的分层约定:<name>.fun(Windows) / -unx.fun(Unix) / -base.fun(共享)。
  • 14 个模块存在平台变体,但只有 winsock 真正做了 lib-winsock-base.fun(427 行)共享抽象;ado / crypt / xml / cmdline / jsonrpc 等仍是两套独立实现。
分组代表模块(代码行)观察
底层能力lib-asm-a64(501)、lib-asm(143)、lib-tcc(49)、lib-jit(9)AArch64 汇编后端是最新的重头(642 行、分支密度 44.4%,全仓最高);lib-jit 仅 14 行做路由,委托干净。
数据格式lib-json(16)、lib-fd(106)、lib-bnf(104)、lib-yaml(218)、lib-xml(132)JSON 只有 16 行,因为解析/序列化已下沉为内核内建(@toJson/getJson),库层只剩薄封装;FD 的 BNF 自举(fd.bnf.fd 描述 FD 自身)设计上很漂亮,实现只有 114 行。
网络lib-winsock-unx(480)、lib-winsock-base(427)、http-server(397)、lib-ajax(369)http-server 是 532 行的完整框架(路由/中间件/静态文件/日志),是库里最像「应用」的模块。
ORM / 数据库lib-orm(478)、lib-ado-unx(380)、lib-ado(195)注释率仅 5–6%,是全文注释最稀薄的角落,也是逻辑最复杂的部分,风险集中。
系统 / UIlib-os(394)、lib-ui-base(142)、lib-registry(93)lib-os.fun 含 62 个模块级 var(全仓最高)。
基础lib-utils(150)、lib-set(139)、lib-zlib(137)、lib-math(27)lib-utils 被 9 个模块依赖,是事实上的基石,但注释率仅 1%。

4.2 优点

  • 平台变体的头部文档质量极高。 lib-ado-unx.fun 开头 10 行就讲清「Windows 版是 COM 形状的 ADODB,无法在 Unix 复用,因此 Unix 后端改用 SQLite 但对外保持同一 ADO 类与契约」。这类「为什么要有两份」的说明,是跨平台代码里最值钱的信息。

  • 依赖图浅而清晰。 37 个模块参与依赖,最高入度:lib-host(10)、lib-utils(9)、lib-os(7)、lib-regex(6);未发现跨模块循环依赖(检测到的自引用是变体的幂等 use 守卫)。

  • 能力下沉边界合理。 字符串、正则、类型、文件这些高频操作下沉到内核,库层只留 API 形状,避免了脚本层反复低效实现。

4.3 问题

级别问题证据与影响
高模块级全局状态泛滥89 个 .fun 文件中 54 个存在顶层 var(按 62 个逻辑模块算,覆盖 42 个):lib-os.fun 62 个、lib-ado-unx.fun 46 个、lib-ado-schema.fun 44 个、lib-crypt.fun 33 个、lib-winsock-unx.fun 40 个。连 lib-fd.fun 的解析器都把 root/stak 挂在模块全局上。后果:模块不是可重入的,同一进程内无法安全地并发解析两个 FD 文档,也无法持有两个独立实例;多模块同名 var 存在互相踩踏风险。
高平台变体近乎双份实现行级相似度:lib-ado 0.07、lib-crypt 0.10、lib-winsock 0.11、lib-xml 0.07、lib-ajax 0.07、lib-os 0.05(仅 lib-ado-schema 0.78、lib-jsonrpc 0.70 较高)。83 组、约 415 行重复块主要集中在 ADO 常量表等处被原样复制两遍。后果:修一个 bug 要改两处,且两处无人交叉验证,这是多平台维护中最典型的腐烂源。
中注释密度两极分化整体 14.6%,但分布极不均匀:lib-regex 74%、lib-json 52%(多为 API 说明块)vs lib-orm 6%、lib-ado-schema 1%、lib-utils 1%、lib-cstruct 4%。最复杂的代码恰是最少注释的代码。
中热点模块复杂度集中分支密度(每 100 行的分支/循环数):lib-asm-a64 44.4、lib-tree 44.0、lib-cwinapi 39.1、lib-cstruct 38.1、lib-utils 37.4、lib-orm 31.3;全库平均 18.5。这些模块既缺注释又缺测试。
中测试覆盖不均衡只有 33/89 个文件(约 37%)有对应测试脚本;lib-orm、lib-yaml、lib-cstruct、lib-async、lib-ui*、lib-md5、lib-bind 等复杂度不低的模块无测试。测试多为 -lnx 侧(受 CI 平台限制),Windows 侧几乎无自动化。
低占位模块造成指标失真7 个 0 代码模块让「61 个模块」的说法在技术评估时偏乐观;建议 README 区分「模块 / 文档清单」。

五、工程化、测试与安全

做得好的

  • CI 矩阵实在:5 个平台(Linux x64/arm64、macOS x64/arm64、Windows x64)全为 gate,并明确写了 windows-arm64 因 FPC 3.2.2 无 win64/aarch64 目标而禁用及其原因,把「做不到」写进 CI 注释,是成熟做法。

  • 宿主感知的回归体系:regression-skip-<platform>.txt + expected/<platform>/ 快照覆盖机制,让「平台不支持」与「平台输出不同」分开处理;缺失能力(PCRE、ffi.dll)时探测后降级为 SKIP 而非失败。

  • 文档双语、授权分层:README/CHANGELOG/CONTRIBUTING/SAFETY 均有中英两份;LICENSE(MIT)+ LICENSE.custom + LICENSE.dll 三层。

  • CHANGELOG 细到日:9.0 → 9.4.5,最近条目日期 2026-10-20,说明仓库处于高频迭代而非归档状态。

  • 安全态度诚实:SAFETY.zh.md 按分支(而非按函数)逐个标注 move/movs/toNum/fromByte/eval/compile 的能力类别(NAT/MEM/FSW/SRC/ENV),并直接写明哪些已落地、哪些未实现。

  • 有一处真正的断言式测试(全仓唯一): JSON/FD 这一块没有沿用黄金快照,而是写了 strict-valid.fun(63 个用例)与 strict-probe.fun(26 个用例),用 try/except 包住 getJson(json: 2),逐条打印 PASS/FAIL 并区分「该接受却拒绝」与「该拒绝却接受」两种失败方向。覆盖率也细致到分隔文法层面:尾随逗号、前导/重复逗号、缺逗号、缺/重复冒号、;/= 分隔、单引号与反引号字符串、@ 日期字面量、十六进制数字、非字符串键、括号错配、顶层尾随值,以及「数字保持宽容(.5/03/1. 仍接受)」这类刻意保留的行为也被固化为用例。

    这正是「功能长大 = 测试长大」的实证:CHANGELOG 里 MaxNestDepth=512(L446)与 RFC 8259 分隔文法(L491)两条新增,都对应这批用例的扩充。建议把这个模式推广到其余模块,它比快照比对更能定位语义回归。

短板

  • 测试多为黄金快照,不是断言。95 个 expected/*.txt 是整段输出比对,失败时只能看到 diff,无法定位语义;没有单测框架、没有覆盖率统计、没有属性测试/模糊测试。
  • 测试/产品代码比约 0.17(3,957 行测试 vs 约 22,750 行产品代码),对解释器这类「分支即语义」的软件偏低。
  • 安全边界未落成机制。SAFETY 文档自述:越界检查(MEM 的分支/参数部分)已于 2026-09-14 落地,但 -safe 开关、s.move(numDest)、toNum(ptr:-1)、getapi/@toCallback/COM 拦截尚未实现。当前默认构建下,任何 Fun 脚本都可以执行任意机器码。
  • vendored 依赖无更新通道。KOL(≈6.96 万行)与 PCRE 移植是静态快照,无 submodule / 版本清单 / CVE 跟踪;KOL 已属历史 Pascal 生态组件。
  • 贡献门槛实际很高。CONTRIBUTING 要求改动解析器时同步 fun.ebnf + yacc.y + lex.l,并需本地准备 Delphi/FPC 工具链与第三方库(PCRE、TCC),新贡献者上手成本高。

六、风险清单与改进建议(按优先级)

优先级动作预估工作量收益
P0建立异常层级 EFunError → EParseError / ERuntimeError / EFFIError,并给错误附 file:line 上下文(ErrPos 已有雏形)2–3 周把「静默 nil」变成可定位错误,直接改善可调试性与嵌入场景的可信度。
P0实现 -safe 能力开关(NAT/MEM/FSW 三类),把 SAFETY 文档变成可执行策略3–4 周文档已经把分支列全了,实现成本低而收益大:这是嵌入第三方应用与 AI Agent 场景的准入条件。
P0为标准库引入实例作用域:把模块级 var 收敛进工厂函数返回的对象4–6 周消除 54 个文件(42 个逻辑模块)的全局状态,使库可重入、可并发、可嵌套使用;是库层最大的结构性债务。
P1把 {$I 'libfd.inc'} 从 _ParseJson 函数体内部提出来:让 libfd.inc 成为独立单元,两个扫描器通过显式参数而非共享父函数局部变量协作1–2 周注意:这不是「拆分巨型函数」。主函数体只有 19 行,结构本身是合理的。 收益是让 IDE / 静态分析能看到 ParseFD(现在它对工具链完全隐形),并让两个扫描器可独立引用与演化。风险低,因为已有 89 个 strict 用例兜底。
P1把 strict-valid.fun / strict-probe.fun 的断言式测试模式推广到 lib-orm / lib-yaml / lib-cstruct 等无测试的高复杂度模块2–3 周这是全仓唯一一处 PASS/FAIL 断言(其余 95 个是整段输出快照);照抄这个模板的边际成本很低,收益是失败时能直接定位语义而非看 diff。
P1把 io.pas 的 CIO.Load(129 行)中 BOM 探测 / 代码页转换 / 分块读拆成独立函数,并补编码往返测试1–2 周编码处理是跨平台 bug 重灾区,拆开后可单独测试,且能覆盖当前 CI 无法验证的 Windows 路径。
P1平台变体抽共享层:按 lib-winsock-base 的先例,为 ado / crypt / xml / cmdline / orm 抽出 -base,常量表只留一份3–5 周消除约 415 行重复,把「改两处」变成「改一处」。
P1为 lib-orm / lib-yaml / lib-cstruct / lib-async / lib-ui 等无测试的高复杂度模块补回归用例;引入覆盖率统计3–4 周把测试覆盖从 37% 提到 70%+,并让 CI 差异可被量化。
P1引用计数补环检测(周期标记扫描或引入弱引用类型)2–4 周让 Fun 能胜任常驻服务;否则长跑场景必须靠人工破环。
P2为 vendored 第三方建立版本清单与更新流程(KOL / PCRE / TCC)1 周安全合规与长期可维护性。
P2README 区分「模块」与「文档清单模块」,并把 vendored 代码量从总代码量中单列<1 周避免外界(含 AI 摘要)误读规模与自研比例。
P2降低条件编译密度:把 libase.pas(114 处)等按平台拆成 -win/-unix 实现单元 + 薄适配层4–6 周让静态分析工具生效,减少未覆盖平台的腐烂。

七、给不同角色的建议

考虑嵌入 fun.dll

先做三件事:

  1. 确认目标平台在 CI 5 矩阵内;
  2. 明确脚本来源可信:当前无 -safe,脚本等价于本机任意代码执行;
  3. 用长跑脚本压测内存,验证引用计数泄漏在你的场景下是否可控。

想学习这门实现

推荐阅读顺序:

src/core/fun.pas(类型别名与平台抽象)→ src/core/base.pas(值模型与容器)→ src/core/core.pas(节点树与对象)→ src/parse/bnf/fun.ebnf(语法)→ fun/lib/lib-fd.fun(自举解析器)。

注释里大量「为什么」,是本仓最值钱的部分。

想贡献代码

最容易被接受且价值最高的三类改动:

  1. 补标准库回归测试(尤其 Windows 侧与 ORM/YAML);
  2. 把 {$I 'libfd.inc'} 提为独立单元;
  3. 为平台变体抽 -base 共享层。

注意 CRLF + 英文注释 + SPDX 头,改语法需同步三份语法文件。


分析说明 分析方式:拉取 main 分支完整源码(499 文件)后,结合脚本化度量(行数/注释率/函数长度/分支密度/重复块/依赖图/条件编译密度/换行与编码一致性/goto 与异常统计)与关键文件精读。 所有数字均由仓库实际内容计算得出,未采用 README 或第三方文章的口径;vendored 第三方(src/3rd、src/regex/pcre)与 lex/yacc 生成表已在内核指标中单独剔除或标注。 函数长度采用「顶层函数头 → 下一个顶格 end;」口径并人工核验边界;条件编译导致的 begin/end 不配对会使自动配对失效,故未采用纯字符配对法。 本报告为静态分析结论,不含运行时验证(未编译执行),性能与安全影响的最终判断需结合目标平台的实测。