语法深度解析:基于 REPL 快照测试的完整实战指南)
Roc 语言 I128 闭区间Inclusive Range语法深度解析基于 REPL 快照测试的完整实战指南【免费下载链接】rocA fast, friendly, functional language.项目地址: https://gitcode.com/GitHub_Trending/ro/roc本指南以 Roc 编译器仓库中的 REPL 快照文档 test/snapshots/repl/i128_range_to.md 为核心骨架系统讲解 Roc 语言 I128 闭区间语法..的写法、迭代行为与边界语义。你将掌握(start.I128..end.I128).iter()与Iter.fold的组合用法理解单元素区间、反向空区间的底层判定规则并透过快照测试中 token 化、解析、规范化canonicalize与类型推导各阶段输出看清区间表达式在编译器内部如何被翻译为range_inclusive_to方法调用。一、关联文档是什么REPL 快照测试的定位test/snapshots/repl/i128_range_to.md属于 Roc 编译器仓库的快照测试Snapshot Test体系。快照测试通过捕获指定 Roc 代码在编译管线各阶段token 化、解析、规范化、类型检查、REPL 求值的输出来验证编译器行为是否与预期一致。typerepl表示该快照直接驱动 REPL 求值器执行SOURCE中的表达式并把每一条命令的输出记录在OUTPUT段中。该文档的核心声明是 META 段中的descriptionI128 inclusive range syntax iterates from start to end即I128 闭区间语法会从起始值迭代到结束值包含两端。整篇快照围绕这一语义设计了三组代表性输入覆盖正向区间、单元素区间与反向区间三种情况。关于快照测试的更多运行机制可参考 test/snapshots/README.md其中说明了快照对编译管线各阶段的捕获方式以及zig build run-snapshot-tool -- file_path等命令的用法见下文第七节。二、I128 闭区间基础写法..与.iter()在 Roc 语言中闭区间inclusive range使用..运算符构造表示包含首尾两端的数值范围。关联文档中给出的三个 I128 示例均采用同一模式(-2.I128..2.I128).iter()拆解来看-2.I128与2.I128带I128类型注解的整数字面量明确将范围端点限定为 128 位有符号整数..闭区间运算符token 名称为OpDoubleDotEquals见 test/snapshots/range_inclusive.md.iter()将区间Range转换为迭代器Iter以便交给Iter.fold消费。Iter.fold是 Roc 标准库中遍历迭代器的常用折叠函数签名形如Iter.fold(iter, initial, closure)把初始值[]空 List与迭代产生的每个元素一起交给闭包|acc, item| acc.append(item)将元素逐个追加进列表最终返回完整列表。因此整个表达式Iter.fold(iter, [], |acc, item| acc.append(item))的求值结果就是把该区间迭代出的全部元素收集为一个 List——这正是观察区间迭代行为的直接手段。三、三个核心用例逐行解读正向、单元素与反向空区间关联文档 i128_range_to.md 的 SOURCE 与 OUTPUT 完整如下» Iter.fold((-2.I128..2.I128).iter(), [], |acc, item| acc.append(item)) » Iter.fold((0.I128..0.I128).iter(), [], |acc, item| acc.append(item)) » Iter.fold((3.I128..1.I128).iter(), [], |acc, item| acc.append(item))对应输出[-2, -1, 0, 1, 2] --- [0] --- []三条用例分别验证了闭区间的三种典型情况3.1 正向区间-2..2起始值-2小于结束值2迭代器按1 步进从-2走到2端点2被包含得到[-2, -1, 0, 1, 2]共 5 个元素。这正是inclusive range iterates from start to end的直接体现。3.2 单元素区间0..0起始值与结束值相等时区间恰好包含唯一元素0输出[0]。闭区间语义下相等端点不会被误判为空这与排他区间..见第五节形成鲜明对比。3.3 反向区间3..1起始值3大于结束值1属于降序descending区间。快照输出为[]说明 Roc 的 I128 区间迭代不支持反向迭代——当start end时闭区间直接产生空迭代序列而不会倒序输出[3, 2, 1]。值得注意的是这一行为并非 I128 独有。仓库中所有数值类型的*_range_to.md快照如 i32_range_to.md、u128_range_to.md都遵循同样的规则反向区间一律得到空列表。四、降级边界Empty/Trivial Range的统一判定闭区间何时为空综合关联文档与同目录快照可以归纳出两条判定规则反向区间为空start end→[]如3.I128..1.I128单元素区间非空start end→ 恰含一个元素如0.I128..0.I128输出[0]。U128 快照 u128_range_to.md 给出了同样的三条用例» Iter.fold((1.U128..5.U128).iter(), [], |acc, item| acc.append(item)) » Iter.fold((0.U128..0.U128).iter(), [], |acc, item| acc.append(item)) » Iter.fold((5.U128..3.U128).iter(), [], |acc, item| acc.append(item))输出分别为[1, 2, 3, 4, 5]、[0]、[]——正向完整、单元素保留、反向为空与 I128 行为完全一致。这提示闭区间的空区间判定逻辑是跨数值类型统一的I128 快照验证的其实是这套通用语义在有符号 128 位整数上的具体表现。五、闭区间..与排他区间..的行为对比Roc 提供两种区间运算符语义差异仅在于是否包含结束端点运算符名称token端点语义示例I128结果..闭区间inclusiveOpDoubleDotEquals含 start 与 end(-2.I128..2.I128)[-2, -1, 0, 1, 2]..排他区间exclusiveOpDoubleDotLessThan含 start、不含 end(-2.I128..2.I128)[-2, -1, 0, 1]对比同目录的 i128_range_until.md» Iter.fold((-2.I128..2.I128).iter(), [], |acc, item| acc.append(item)) » Iter.fold((1.I128..1.I128).iter(), [], |acc, item| acc.append(item)) » Iter.fold((3.I128..1.I128).iter(), [], |acc, item| acc.append(item))输出[-2, -1, 0, 1] --- [] --- []两个关键差异点同一区间-2..2比-2..2少一个元素不含21.I128..1.I128输出[]——排他区间在 start end 时为空而闭区间0..0输出[0]。因此单元素区间是闭区间独有的行为。浮点类型同样适用这两套语义。例如 dec_range_to.md 中0.5.Dec..2.5输出[0.5, 1.5, 2.5]步进 1.0、含 2.5而 dec_range_until.md 中0.5..3.5输出[0.5, 1.5, 2.5]不含 3.51.25.Dec..1.25输出[1.25]。F32/F64 快照f32_range_to.md、f64_range_to.md也验证了相同模式。六、I128 的数值边界快照为什么选 I128 作为测试目标I128 是 Roc 支持的最大整数类型之一选择它作为区间测试目标并非偶然。同目录快照 repl_i128_large_values.md 验证了 I128/U128 能表示超出 64 位的极值» 170141183460469231731687303715884105727.I128 → 170141183460469231731687303715884105727 » -170141183460469231731687303715884105728.I128 → -170141183460469231731687303715884105728 » 340282366920938463463374607431768211455.U128 → 340282366920938463463374607431768211455I128 的取值范围为-170141183460469231731687303715884105728170141183460469231731687303715884105727-2^1272^127 - 1上界170141183460469231731687303715884105727是 I128 的最大值下界-170141183460469231731687303715884105728是最小值。因此i128_range_to.md验证的是区间迭代逻辑在完整 128 位宽度下依然正确端点比较、1 步进、空区间判定等操作不会因数值宽度或符号位而出现偏差。U128 的最大值340282366920938463463374607431768211455则覆盖了无符号场景的上界。七、从源码看实现..在编译管线中如何被处理快照测试的价值在于它把编译各阶段的中间表示都钉在文档里。参考 range_inclusive.md以r 1..5为例可以完整还原..的编译路径1. Token 化——..被识别为OpDoubleDotEquals区别于排他区间的OpDoubleDotLessThanLowerIdent,OpAssign,Int,OpDoubleDotEquals,Int,EndOfFile,2. 解析Parse——..作为二元运算符e-binop处理左右操作数分别为区间两端(s-decl (p-ident (raw r)) (e-binop (op ..) (e-int (raw 1)) (e-int (raw 5))))3. 规范化Canonicalize——区间表达式被翻译为对range_inclusive_to方法的分发调用dispatch call(e-dispatch-call (method range_inclusive_to) (constraint-fn-var 223) (receiver (e-num (value 1))) (args (e-num (value 5))))对比排他区间 range_exclusive.md1..5规范化后调用的是range_exclusive_to。也就是说..与..在编译后期被分别路由到两个不同的底层方法这解释了第五节中端点包含差异的来源。4. 类型推导——1..5的类型被推断为Range(Dec)(patt (type Range(Dec)))) (expr (type Range(Dec))))这里可见 Roc 的类型默认策略不带类型注解的整数字面量在区间表达式中默认落为Dec。而关联文档中显式书写.I128注解正是为了把区间端点钉死在 I128 上从而精确测试 I128 的迭代语义。7.1 快照测试的实际运行方式依据 test/snapshots/README.md可以手动重放本快照# 生成全部快照 zig build run-snapshot-tool # 仅更新/重跑指定快照 zig build run-snapshot-tool -- test/snapshots/repl/i128_range_to.md # 调试 REPL 求值过程打印解释器 trace zig build run-snapshot-tool -- test/snapshots/repl/i128_range_to.md --trace-eval其中--trace-eval仅适用于typerepl快照且一次只能处理单个文件debug 构建默认开启 tracerelease 构建需通过-Dtrace-evaltrue启用。快照的PROBLEMS段为NIL表示这三条表达式在编译与求值过程中没有产生任何诊断报告——即它们是合法的、被完整支持的语法。八、闭区间在for循环中的典型用法区间不仅是Iter的数据源也直接驱动for循环。快照 range_for_loop.md 展示了闭区间的循环写法该快照同时演示了var可变绑定须以$开头的新约定total : U64 total { var $sum_ 0 for i in 1..5 { $sum_ $sum_ i } $sum_ }其规范化结果range_for_loop.md显示for i in 1..5中的区间同样被翻译为range_inclusive_to方法调用。由于闭区间包含结束端点1..5会迭代1, 2, 3, 4, 5累加和为15若改用1..5则只迭代到4。在设计循环边界时这一差异直接影响循环次数是实际编码中最容易踩中的细节。九、常见错误裸..不是合法的区间运算符Roc 要求区间运算符必须二选一..排他或..闭。若写成裸1..5编译器会报错。快照 range_bare_double_dot_error.md 记录了完整的诊断信息I was parsing an expression, and .. is not a range operator. Use .. for an exclusive range or .. for an inclusive range. For example: 1..10 1..10token 阶段..被单独识别为DoubleDot而非OpDoubleDotEquals/OpDoubleDotLessThan解析阶段产生e-malformed类型退化为Error。因此在 Roc 中书写区间时永远不要省略或。十、总结I128 闭区间的完整行为画像综合关联文档与仓库证据Roc 语言(start.I128..end.I128)的迭代行为可归纳为一张速查表条件行为示例结果start end按 1 步进包含两端-2..2[-2, -1, 0, 1, 2]start end恰含一个元素0..0[0]start end空迭代不支持反向3..1[]三条规则与同目录下 I8I128、U8U128、Dec、F32、F64 的所有range_to快照行为一致属于 Roc 区间语义的通用约定而i128_range_to.md的价值在于把这一约定在128 位有符号整数全量程含-2^127与2^127-1极值上做了验证。实现证据可继续查看test/snapshots/repl/i128_range_to.md本文核心文档test/snapshots/repl/i128_range_until.mdI128 排他区间对照test/snapshots/repl/u128_range_to.mdU128 闭区间test/snapshots/range_inclusive.md..编译管线全阶段test/snapshots/range_exclusive.md..编译管线全阶段test/snapshots/range_for_loop.mdfor i in 1..5循环test/snapshots/repl/repl_i128_large_values.mdI128/U128 极值test/snapshots/README.md快照测试机制与命令【免费下载链接】rocA fast, friendly, functional language.项目地址: https://gitcode.com/GitHub_Trending/ro/roc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考