)
META —— 快照的元信息描述、类型【免费下载链接】rocA fast, friendly, functional language.项目地址: https://gitcode.com/GitHub_Trending/ro/rocSOURCE —— 被测的 Roc 源码EXPECTED —— 预期的评估结果PROBLEMS —— 编译器产生的诊断报告NIL 表示无任何报告TOKENS —— 词法分析阶段的 Token 序列PARSE —— 语法分析阶段的 ASTS-表达式FORMATTED —— 格式化器的输出CANONICALIZE —— 规范化阶段的 CIRTYPES —— 类型推断结果这一节节之间首尾相接恰好构成一条完整的编译流水线下面逐段精读。 ## SOURCE 与 META被测代码与快照身份 expr_int.md 的 META 段声明了快照的基本身份 ini descriptionA primitive typesnippet其中typesnippet表示这是一份普通ordinary快照与reporting/目录下专门固定诊断渲染输出的快照相区分。按 test/snapshots/README.md 的说明普通快照的PROBLEMS段捕获的是诊断的语义每个reporting.Report的规范 S-表达式序列化不含任何渲染层细节无框线字符、ANSI 转义、换行折行回答的问题是编译器是否产生了正确的诊断。NIL表示编译未产生任何报告。而 SOURCE 段只有一行 Roc 代码foo 42这是一个顶层值声明top-level declaration把整数字面量42绑定到标识符foo。别看它简单它完整走过了编译器全部核心阶段是观察编译流水线最干净、最不易被干扰的示波器探头。对应地EXPECTED与PROBLEMS均为NIL表示这段代码语义正确、无任何诊断输出。TOKENS词法分析把源码切成 Token 流LowerIdent,OpAssign,Int, EndOfFile,词法分析tokenization把字符流切分成标记流。foo 42被切成 4 个 TokenLowerIdent—— 小写开头的标识符fooOpAssign—— 赋值运算符Int—— 整数字面量42EndOfFile—— 文件结束符。Token 标签的权威定义位于 src/parse/tokenize.zig 的Token.Tag枚举在// primitives注释下可以看到Float、Int等基本字面量标签同时还定义了若干畸形数字标签MalformedNumberBadSuffix、MalformedNumberUnicodeSuffix、MalformedNumberNoDigits、MalformedNumberNoExponentDigits——这些标签会保留接近 Int/Float的词法身份供解析器继续处理同时把错误前向转发给 AST 层体现了词法层尽量宽容、错误后置的设计思路。Int的判定还伴随一些边界处理src/parse/tokenize.zig 的单元测试给出了生动例证1..2被切成Int, DoubleDot, Int3...4被切成Int, TripleDot, Int1..5、1..5也都能正确区分整数字面量与范围运算符说明词法器能精确处理数字后紧跟点号这类歧义场景。PARSE语法分析生成 AST(file (type-mod) (statements (s-decl (p-ident (raw foo)) (e-int (raw 42)))))语法分析把 Token 流组装成抽象语法树AST同样以 S-表达式序列化。这棵树的层次非常清晰file是顶层节点包含一个空的type-mod类型模块和statements语句列表语句列表里只有一个s-decl声明语句它由p-ident模式标识符foo保留原始拼写raw foo和e-int整数表达式raw 值为42组成。值得注意的是解析阶段把整数和浮点分开建模对照同目录下的 test/snapshots/primitive/expr_float.mdfoo 12.34的解析结果是e-frac分数/浮点表达式而整数走的是e-int。在 src/parse/AST.zig 中可以看到解析器向 AST 树写入e-int节点的代码raw字段保留的是源码中的原始字面量文本进制、下划线、类型后缀等细节在规范化阶段才会被解释。FORMATTED格式化器确认代码已符合规范风格NO CHANGEFORMATTED段输出NO CHANGE表示格式化器对foo 42的处理结果与源码完全一致没有任何需要改写的地方。这是快照测试的巧妙之处它顺带把格式化器也纳入了回归保护网——一旦格式化器的规则变化导致这段代码被改写快照就会报差异提醒维护者确认这是有意变更还是回归。CANONICALIZE规范化到 CIR整数字面量变成e-num(can-ir (d-let (p-assign (ident foo)) (e-num (value 42))))规范化canonicalization阶段把 AST 降级为更接近语义层的规范中间表示Canonical IRCIR。这里可以观察到几个显著变化file变成了can-irs-decl变成了d-letlet 绑定定义模式p-ident变成了p-assign并且不再保留raw原始文本只保留干净的ident foo整数表达式e-int变成了e-num值为42。e-num是 CIR 中表示具有确定数值的数字字面量的统一节点其定义位于 src/canonicalize/Expression.zig它由一个value: CIR.IntValue和一个kind: CIR.NumKind组成注释里明确写出了它覆盖的范围——十进制、十六进制0xFF、八进制0o755、二进制0b1010以及带类型后缀的42u8、42f32等写法。也就是说无论源码里写的是哪种进制、有没有后缀规范化后统一收敛为e-num这为后续类型推断与代码生成提供了统一的语义接口。作为对照浮点字面量在规范化阶段会走另一条路expr_float.md的 CANONICALIZE 输出是e-dec-small带有numerator 1234与denominator-power-of-ten 2两个字段即把12.34精确表示成分数形式 1234/10²避免二进制浮点误差。e-dec-small的序列化逻辑可以在 src/canonicalize/Expression.zig 中找到它同时输出分子、10 的幂次分母以及由二者相除得到的展示用value。这也是 Roc 语言十进制字面量默认用高精度 Dec 表示这一设计在编译器内部的落点。TYPES类型推断把42定为Dec(inferred-types (defs (patt (type Dec))) (expressions (expr (type Dec))))最后一个阶段是类型推断。inferred-types下分defs与expressions两个视图defs中的patt说明定义左侧的模式foo类型为Decexpressions中的expr说明右侧表达式字面量42类型也是Dec。这里蕴含了 Roc 的一个重要设计决策无后缀整数字面量默认推断为Decdecimal十进制高精度类型而不是机器整数类型。Dec在 Roc 中是自动导入的内置类型见 src/types/import_mapping.zig 中 Auto-imported builtin types (e.g., Bool, Str, Dec, U64, etc.) 与 Builtin.Num.Dec → Dec 的映射逻辑类型展示层src/types/TypeWriter.zig也负责把完整的Builtin.Num.Dec缩写为Dec呈现给用户。若需要显式的机器类型可以写42u8、42i64、42f64等带后缀的字面量这些后缀在词法与规范化阶段e-num的NumKind就已准备好被识别。至此一条完整的编译流水线在快照中闭合foo 42从一行源码依次变为 4 个 Token、一棵 4 层深的 AST、一行无需改动的格式化结果、一组d-let/e-num的 CIR 节点最终被推断为Dec类型的绑定。兄弟快照primitive 系列与更广的语法对照expr_int.md位于 test/snapshots/primitive 目录该目录只收录 6 份最小原语快照expr_float.md、expr_int.md、expr_string.md、expr_tag.md、stmt_import.md、stmt_type_decl.md。它们共同构成原语层字面量、字符串、标签、导入、类型声明的编译行为基线是理解编译器对最小语法元素处理方式的入口。把这几份对照起来读特别有收获快照文件源码示例解析节点规范化节点推断类型expr_int.mdfoo 42e-inte-numDecexpr_float.mdfoo 12.34e-frace-dec-small分子10 的幂Decexpr_string.mdname luc、hello ${name}e-string含插值片段e-string/e-interpolationStr例如 expr_string.md 展示了字符串插值hello ${name}在解析期被拆成e-string-part、e-ident等片段规范化后进一步生成#interp_0临时变量、e-interpolation与e-lookup-local的完整插值实现——这解释了字符串插值本质上是对局部变量的闭包式引用这一实现事实。实操如何生成、更新与运行快照快照并非手工维护而是由专门的快照工具生成与校验。结合 test/snapshots/README.md 的说明常用命令如下# 生成/重跑全部快照 zig build run-snapshot-tool # 只处理指定快照文件 zig build run-snapshot-tool -- test/snapshots/primitive/expr_int.md # 把 EXPECTED 段更新为当前实际输出用于认可行为变更 zig build run-snapshot-tool -- test/snapshots/primitive/expr_int.md --update-expected # REPL 类快照开启解释器跟踪调试 zig build run-snapshot-tool -- repl_snapshot.md --trace-eval【免费下载链接】rocA fast, friendly, functional language.项目地址: https://gitcode.com/GitHub_Trending/ro/roc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考