Roc 注释与文档注释实战指南从#单行注释到##文档注释的完整规则【免费下载链接】rocA fast, friendly, functional language.项目地址: https://gitcode.com/GitHub_Trending/ro/roc本篇围绕 Roc 语言参考文档中的注释章节展开讲清两类注释的精确语法规则普通单行注释#开头、无多行语法与文档注释##开头、必须紧跟赋值语句。结合仓库中分词器、LSP 与文档生成工具的源码实现你将掌握如何写出既不影响程序行为、又能被 LSP 悬停提示和roc docs文档流水线正确采集的注释。单行注释#之后直到行尾都是注释Roc 的注释一律以#字符开始并一直延伸到该行末尾。语言只支持单行注释和文档注释两种形式没有专门的多行注释语法。以下示例直接来自语言参考文档# This comment takes up a whole line. # So does this one. # There is no dedicated multi-line comment syntax. x 5 # end-of-line comment需要特别注意的设计约定Roc 编译器从不从注释中推导任何语义。修改注释在不改变代码排版的前提下永远不应影响程序运行行为唯一例外是堆栈跟踪中报告的源码位置信息。这意味着注释是纯粹的阅读辅助不能作为任何注释掉的逻辑开关来依赖。分词器层面注释如何被丢弃从源码结构看这一不产生语义的保证在分词阶段就落实了。src/parse/tokenize.zig中处理#的分支逻辑非常简单遇到#后直接跳过该字符然后持续消耗位置直到遇到\n或\r为止期间不生成任何 token见 tokenize.zig} else if (b #) { self.pos 1 while (self.pos self.buf.len and self.buf[self.pos] ! \n and self.buf[self.pos] ! \r) { self.pos 1 } }这也解释了为什么注释里的内容可以随意书写——包括在文档注释中嵌入代码块##前缀行内可以出现任意反引号代码它们对分词器而言都只是被跳过的普通字节。Shebang#!注释部分 shell 会在可执行文本文件开头查找#!shebang例如#!/usr/bin/env rocRoc 编译器对 shebang 没有任何特殊支持。由于#开启的是一个普通注释上面的示例在 Roc 编译器看来就是一行普通注释而 shell 则可能将其解释为 shebang。两者的解释恰好互不冲突因此可以把.roc文件写成带 shebang 的可执行文件。文档注释Doc Comments为赋值附带说明文档注释用于给一个赋值assignment附加文档说明它使用专门的注释语法规则如下逐条来自语言参考文档 comments-and-docs.md文档注释的每一行都必须以## 开头——即行首两个#后跟一个空格连续的、以## 开头的行共同构成同一条文档注释文档注释最后一行## 之后的下一行必须是一条赋值语句assignment statement如果一行或多行以## 开头、但下一行行首没有紧跟赋值语句那么这些行全部不被视为文档注释而是被当成普通注释处理。典型示例原文档给出的完整例子## Returns the given number unmodified if its even, ## and negated if its odd. ## ## roc ## expect negate_if_odd(1) -1 ## expect negate_if_odd(2) 2 ## negate_if_odd |num| if num.is_odd() { num.negate() } else { num }注意文档注释内部可以包含空行标记单独的##以及用##前缀逐行书写的 roc 代码块——LSP 与文档工具会把这些前缀剥离后还原为普通 Markdown。##与###的边界为什么###不算文档注释一个容易踩坑的细节是行首三个####。仓库把文档注释行的判定规则集中封装在 doc_comment.zig 中并明确区分了两种谓词isDocCommentLine严格判定要求以##开头且第三个字符不是####被排除视为 section-header 注释startsWithHashHash宽松判定只要求前两个字符是##不排除###stripPrefix剥离行首的##以及其后至多一个空格得到文档正文内容。/// Returns true if trimmed is a doc comment line: starts with ## but not ###. pub fn isDocCommentLine(trimmed: []const u8) bool { if (trimmed.len 2) return false; if (trimmed[0] ! # or trimmed[1] ! #) return false; // Make sure its not ### (section header) if (trimmed.len 3 and trimmed[2] #) return false; return true }文件内自带的单元测试覆盖了关键边界doc_comment.zig## doc、##、##doc都是合法文档注释行# comment、### header不是stripPrefix(## doc)返回 doc只剥掉一个空格保留内容前原有缩进语义。实操建议把###当作注释里的小节标题来使用而不要指望它进入文档注释流水线——不同消费者对它的处理并不一致有的算、有的不算这是 doc_comment.zig 模块文档注释中明确说明的现状。编译器与工具链如何消费文档注释理解了语法规则后值得看看仓库中各消费方如何把这些##行变成可用的文档数据。LSP按需从源码文本反向提取由于分词器会剥离所有注释注释内容不会进入语法树因此 LSP 需要按需在保留的源码文本上反向查找。doc_comments.zig 中的extractDocCommentBefore从定义所在行开始向上逐行扫描其行为细节很能说明工具链对文档注释语法的实际实现遇到空行允许继续向上扫描文档注释与定义之间可以有空白行间隔遇到##行提取该行内容剥离前缀并继续向上收集连续文档行遇到普通注释单个#或###小节头立即停止搜索遇到类型标注行如add : I64, I64 - I64跳过并继续向上——从而支持文档注释 → 类型标注 → 赋值这种三段式写法遇到其他非注释内容停止搜索。提取结果是多行内容以换行符连接的字符串供悬停提示等场景展示。文档生成流水线src/docsroc docs文档生成能力的实现位于src/docs目录从源码结构看是一条清晰的流水线extract.zig 提供extractDocComment针对定义按字节偏移定位其所在行边界并向上收集##行与extractModuleDocComment文件开头的模块级文档注释把源码中的文档注释转成结构化数据DocModel.zig 定义文档模型模块、定义、文档文本等render_html.zig 与 render_markdown.zig 分别把文档模型渲染为 HTML 或 Markdown 输出。语言参考文档中## Generating Docs with roc docs一节目前仍是 TODO 占位因此本文不展开具体命令行参数但上述模块的存在说明文档注释而非普通注释正是该流水线的数据来源——这也是文档注释必须紧跟赋值这条语法约束存在的原因只有与某个定义绑定在一起的##行才有明确的挂载目标。常见陷阱与核对清单综合原文档规则与源码实现书写文档注释时建议逐条核对行首严格为##两井号空格前导缩进或 Tab 会使该行不再是行首##判定失败##块之后下一行行首必须是赋值语句中间如果插入了非类型标注的普通代码整块##会降级为普通注释LSP 悬停与文档生成都取不到不要用###期望进入文档###是被严格判定排除的小节头遇到它提取过程会停止##之间可以有内容缩进语义stripPrefix只剥掉##后一个可选空格内容自身的前导空格会被保留书写嵌套列表/代码块时需注意对齐注释零语义不要依赖注释内容改变程序行为含 shebang 行唯一例外是堆栈跟踪中的源码位置类型标注的位置把类型标注放在文档注释与赋值定义之间是被 LSP 提取逻辑明确支持的可以放心使用这种三段式写法。小结Roc 的注释体系非常克制#到行尾的普通注释被分词器整体丢弃不产生任何语义##文档注释则通过必须紧跟赋值语句的约束与具体定义绑定成为 LSP 悬停提示src/lsp/doc_comments.zig和文档生成流水线src/docs/extract.zig的数据来源。判定与剥离规则统一收敛在 src/base/doc_comment.zig 中并有单元测试覆盖##/###/空行/类型标注等边界行为都以该模块和 LSP 提取器中的实现为准。掌握行首两井号空格、下一行是赋值这两条核心规则就能写出被工具链正确采集的文档注释。【免费下载链接】rocA fast, friendly, functional language.项目地址: https://gitcode.com/GitHub_Trending/ro/roc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
