- 编程语言
- 编译器
【免费下载链接】Carp
A statically typed lisp, without a GC, for real-time applications.
Carp 是一个无 GC、静态类型、面向实时应用场景的 Lisp 方言(参见仓库根目录的 README.md 中的项目定位)。本文围绕仓库中 docs/core/README.md 这份官方指引,系统讲解 Carp 标准库 API 文档的三种使用方式:在线浏览、使用安装目录内置的本地副本、以及通过内置的generate_core_docs.carp程序一键刷新本地文档。读完本文,你将掌握carp -x脚本执行模式、Project.config文档相关配置项、save-docs/save-docs-ex文档生成命令的完整用法,并能自行产出与官方同构的标准库 API 文档站点。
一、文档获取的两种途径:在线版与本地版
Carp 标准库参考文档有两条官方获取途径:
- 在线版本:官方在线文档托管于 Carp 官方文档站点(原文档中的链接
http://carp-lang.github.io/carp-docs/core/core_index.html,为外部链接,仅作背景说明)。 - 本地版本:你的 Carp 安装目录中自带一份与在线版同源的本地副本,存放于
docs/core/目录下(即当前仓库中的 docs/core 目录)。
两者的内容完全一致,都由同一套源码生成机制产出。区别仅在于:在线版由官方维护者定期发布,本地版则随你的 Carp 安装一同分发。由于本地副本可以直接用浏览器打开(docs/core/core_index.html为入口索引页),即使处于离线环境,你依然可以完整查阅标准库 API。
二、一键刷新本地文档:运行生成程序
本地文档副本并非一成不变——当你在core/目录中修改了标准库模块(例如新增函数、更新doc字符串),或者安装的 Carp 版本与文档副本存在差异时,都可以通过官方提供的短小程序重新生成。
刷新命令如下(摘自 docs/core/README.md 原文):
carp -x ./docs/core/generate_core_docs.carp必须注意:该命令要求从 Carp 安装目录运行,而不是从./docs/core目录内部运行。这是因为生成程序内部使用相对路径"./docs/core/"作为文档输出目录(详见下文源码分析),只有以安装目录为工作目录时,这些相对路径才能正确解析。
-x是 Carp 编译器的命令行标志,表示“构建并立即运行代码,随后退出编译器”。关于该标志及-b(仅构建不运行)等更多编译器旗标的说明,参见官方手册 docs/Manual.md 中的“Compiler flags”一节;-x的常规用法在 docs/HowToRunCode.md 中也有示例($ carp some_file.carp -x)。
生成脚本做了什么
以仓库中的 docs/core/generate_core_docs.carp 为例,脚本内容如下:
; runs this from the Carp installation directory, NOT current directory! (Project.config "title" "core") (Project.config "docs-directory" "./docs/core/") (Project.config "docs-logo" "logo.png") (Project.config "docs-prelude" "Welcome to the documentation for the Carp standard library. Please select a library from the menu on the right to browse its documentation. Carp is available for download [here](https://github.com/carp-lang/carp).") (Project.config "docs-url" "https://github.com/carp-lang/carp") (load "SafeInt.carp") (load "Vector.carp") (load "Geometry.carp") (load "Statistics.carp") (load "Test.carp") (load "Bench.carp") (load "Phantom.carp") (save-docs-ex ['Array 'Bench 'Bool 'Byte 'Char 'Control 'Debug 'Derive 'Double 'Dynamic 'Float 'Function 'Geometry 'Quasiquote 'Int 'Introspect 'Unit 'IO 'Long 'Map 'Maybe 'Opaque 'Pair 'Pattern 'Quadruple 'Phantom 'Pointer 'Result 'StaticArray 'System 'Statistics 'String 'Test 'Triple 'Vector2 'Vector3 'VectorN] ["Macros.carp" "ControlMacros.carp"]) (quit)脚本的执行流程清晰分为三步:
- 配置项目与文档元信息:通过
(Project.config ...)设置标题、文档输出目录、Logo、序言(prelude)文字与站内链接等。 - 加载辅助模块:
load若干标准库模块(SafeInt、Vector、Geometry、Statistics、Test、Bench、Phantom),确保后续要生成文档的模块及其依赖都处于已加载状态。 - 生成文档:调用
save-docs-ex,第一个参数是一个模块符号数组(本次共 36 个标准库模块),第二个参数是一个字符串数组,列出要“以全局符号形式”并入文档的源文件名(这里是Macros.carp与ControlMacros.carp),最后(quit)退出。
仓库中还提供了一份同构的 SDL 文档生成脚本 docs/sdl/generate_sdl_docs.carp,用于为官方 SDL 绑定(SDL、SDLApp、IMG、GFX、Mixer、TTF)生成文档,可作为自定义文档站点的第二份参考模板。
三、文档生成的底层原理:从配置项到 HTML 渲染
要深入理解上述脚本,需要知道文档生成链路中每个环节的实现。这条链路贯穿了编译器源码中的三个文件:Project.config命令入口(src/Commands.hs)、项目配置注册表(src/ProjectConfig.hs)、以及最终的 HTML 渲染器(src/RenderDocs.hs)。
3.1Project.config:配置项的查表与设置
Project.config是 REPL / 脚本中配置当前“项目”的命令。其底层实现是commandProjectConfig(src/Commands.hs):它先以字符串键在projectKeyMap中查找对应配置项,找不到键时报CONFIG ERROR,找到但为只读时报 “is read-only”,随后调用该键对应的 setter 更新项目状态;与之对应的Project.get-config(src/Commands.hs)则调用 getter 读回配置值。
projectKeyMap位于 src/ProjectConfig.hs,其中与文档生成直接相关的键有:
| 配置键 | 含义 | 对应 getter/setter 实现 |
|---|---|---|
docs-directory | 生成的 HTML 文档输出目录 | src/ProjectConfig.hs |
docs-logo | 文档页面右上角 Logo 图片路径 | src/ProjectConfig.hs |
docs-prelude | 索引页顶部以 CommonMark 渲染的序言文字 | src/ProjectConfig.hs |
docs-url | Logo 链接到的外部 URL(如项目主页) | src/ProjectConfig.hs |
docs-generate-index | 是否生成xxx_index.html总索引页(布尔值) | src/ProjectConfig.hs |
docs-styling | 文档页面引用的 CSS 文件路径 | src/ProjectConfig.hs |
title | 项目标题,用作文档页标题与索引文件名前缀 | src/ProjectConfig.hs |
这些字段最终被存储为Project记录类型的属性,定义见 src/Project.hs;show Project实例(src/Project.hs)会把Docs directory、Docs logo、Docs prelude、Docs Project URL、Docs generate index、Docs CSS URL全部打印出来,便于调试。官方手册 docs/Manual.md 的“Configuring a project”一节同样列出这些配置项(如"docs-directory"— Where to put generated docs),与源码实现一一对应。
值得说明的是:Project.config支持远不止文档相关键位,还包括cflag、libflag、pkgconfigflag、compiler、target、output-directory、prompt、search-path、print-ast等编译与构建配置(完整列表见 src/ProjectConfig.hs)。此外core/Project.carp提供了便利宏defproject(批量设置多个配置键)以及Project.append-cflag、Project.append-libflag、Project.append-pkgflag(向已有配置追加标志)。
3.2save-docs与save-docs-ex:两条生成命令
Carp 提供两级文档生成命令:
save-docs:最简单的一层封装,定义于 core/Project.carp,接受一组未加引号的模块符号,例如(save-docs Int Float String)(官方手册 docs/Manual.md 与 docs/Libraries.md 中均有此示例)。其内部实现为:(defmacro save-docs [:rest modules] (list 'save-docs-ex (list 'quote (collect-into modules array)) []))即把模块符号收集成数组后转交给
save-docs-ex,且第二个参数(文件名数组)恒为空——因此它不处理“全局符号”的收录。save-docs-ex:完整版本,底层实现为commandSaveDocsEx(src/Commands.hs)。它接收两个数组:- 第一个参数:模块符号数组。每个符号必须在全局环境中解析为模块(
Mod),否则分别报 “I can’t generate documentation for … because it isn’t a module” 或 “I can’t find the module …”(见 src/Commands.hs)。 - 第二个参数:文件名(字符串)数组。用于把散落在这些文件中的“全局符号”(即未被模块包裹的顶层绑定)收集进一个名为
Globals in <filename>的伪模块中,一并生成文档(见 src/Commands.hs 与createFauxModule实现)。这正是generate_core_docs.carp把Macros.carp、ControlMacros.carp作为第二参数传入的原因——这两个文件中的全局宏(如defproject、save-docs本身、thread-first-internal等)也需要被文档化。
- 第一个参数:模块符号数组。每个符号必须在全局环境中解析为模块(
save-docs-ex最终调用saveDocs(src/Commands.hs),再由saveDocsForEnvs(src/RenderDocs.hs)执行实际生成。
3.3 HTML 渲染管线:saveDocsForEnvs
saveDocsForEnvs是整个生成过程的枢纽(src/RenderDocs.hs),其行为如下:
- 以
projectDocsDir为输出目录,projectTitle为标题; - 递归收集所有传入模块的子模块作为依赖(
getEnvDependencies),保证嵌套模块也被生成; - 对每个模块调用
saveDocsForEnvBinder(src/RenderDocs.hs):自动创建输出目录(createDirectoryIfMissing False dir),将每个模块渲染为独立的<模块名>.html文件; - 若
projectDocsGenerateIndex为真,则额外生成<title>_index.html总索引页,并在控制台打印Generated docs to '<dir>'。
页面的具体内容由envBinderToHtml(src/RenderDocs.hs)与binderToHtml(src/RenderDocs.hs)渲染:
- 索引页(index page):由
projectIndexPage(src/RenderDocs.hs)生成,包含 Logo 图片(docs-logo)、指向docs-url的链接、标题(title)、以 CommonMark 渲染的docs-prelude序言,以及由moduleIndex(src/RenderDocs.hs)生成的模块导航树(支持details/summary折叠分组)。 - 模块页(module page):每个 binder(函数、类型、宏等)渲染为一个带锚点的条目,包含:名称、类型签名(
beautifyType美化后的类型)、参数列表、doc元数据中的文档字符串(同样以 CommonMark 渲染)。deprecated元数据为真的绑定会附加 “deprecated” 标记及弃用说明(src/RenderDocs.hs)。 - 过滤规则:
shouldEmitDocsForBinder(src/RenderDocs.hs)只跳过hidden元数据为真的绑定,其余全部进入文档。标准库源码中有大量hidden与deprecated用法实例,例如 core/Bench.carp 的(hidden get-time-elapsed)、core/Box.carp 的(hidden heap-alloc)、core/ControlMacros.carp 的(deprecated => "deprecated in favor of->.")。这解释了为什么生成的文档中只会出现公开 API,而内部辅助函数不可见。
3.4 文档内容的来源:doc元数据
文档页面上每个条目的说明文字,来源于标准库源码中的(doc <绑定> "...")元数据形式。例如 core/Array.carp 中(doc Array "is the indexable collection data structure. ...")定义了Array模块自身的模块级文档,而(doc reduce "...")、(doc scan "...")等则为具体函数提供说明。这套元数据系统在官方手册 docs/Manual.md 的 “Metadata” 一节有完整介绍:(doc <path> "…")用于写文档、(sig <path> (Fn …))用于类型注解、(private <path>)用于隐藏。也就是说,标准库文档并非手写 HTML,而是从源码中的 doc 字符串自动生成——这也正是“刷新本地副本”这一操作的意义所在:源码注释更新后,重新运行生成脚本即可得到同步的 API 文档。
3.5 样式:carp_style.css
生成出的 HTML 页面通过docs-styling配置引用样式表。仓库的 docs/core/carp_style.css 定义了文档站点样式,包括页面字体、.logo(右浮动、150px Logo 图片)、.index模块索引列表、.args参数块(浅灰背景)、以及details summary折叠交互等。若想定制自己的文档站点外观,可仿照该文件提供自定义 CSS 并设置(Project.config "docs-styling" "你的样式.css")。
四、从 README 到自己的项目:自定义文档生成实战
理解了上述机制后,你可以完全照搬这套流程为自己的项目生成文档。综合官方指引(docs/core/README.md)、docs/Libraries.md 的 “Documentation” 一节以及 docs/Manual.md 的 “Metadata” 一节,推荐的完整做法如下:
4.1 为单个模块快速生成
在 REPL 中直接调用save-docs即可,官方示例:
> (save-docs Int Float String)该命令会把Int、Float、String三个模块的文档渲染到当前docs-directory配置指向的目录(默认见Project初始化逻辑,可通过Project.get-config查看)。
4.2 编写完整的生成脚本
参考官方模板,为你的项目创建一份生成脚本(以下为仿照 docs/core/generate_core_docs.carp 的最小示例):
; 从项目根目录运行,而非脚本所在子目录! (Project.config "title" "MyLib") (Project.config "docs-directory" "./docs/mylib/") (Project.config "docs-logo" "logo.png") (Project.config "docs-prelude" "Welcome to the MyLib documentation.") (Project.config "docs-url" "https://example.org/mylib") (load "MyLib.carp") (save-docs-ex ['MyLib 'MyLib.Helper] ; 需要文档化的模块(可含嵌套模块) ["MyLibGlobals.carp"]) ; 需要并入文档的全局符号所在文件 (quit)运行方式与官方一致:
carp -x ./docs/mylib/generate_mylib_docs.carp4.3 生成行为速查
| 需求 | 做法 |
|---|---|
| 改变输出目录 | (Project.config "docs-directory" "./docs/core/") |
| 更换 Logo | (Project.config "docs-logo" "logo.png"),配合 docs/core/carp_style.css 中的.logo img样式 |
| 自定义首页序言 | (Project.config "docs-prelude" "…(支持 CommonMark)") |
| 控制索引页开关 | (Project.config "docs-generate-index" true)(布尔值) |
| 隐藏内部函数 | 在源码中标注(hidden <绑定>),例如 core/Box.carp |
| 标记弃用 API | 在源码中标注(deprecated <绑定> "原因"),例如 core/ControlMacros.carp |
| 收录文件级全局符号 | 把文件名加入save-docs-ex第二参数,例如 docs/core/generate_core_docs.carp 中的["Macros.carp" "ControlMacros.carp"] |
五、常见问题与注意事项
- 务必从安装目录运行生成脚本:这是原文档明确强调的前提。若从
./docs/core内运行,脚本中的"./docs/core/"相对路径将无法指向预期的输出目录。 -x与-b的区别:-x会编译并执行(要求代码含main),-b仅构建可执行文件。生成文档这类“运行后即退出”的脚本,官方使用-x(docs/Manual.md “Compiler flags”一节)。save-docs-ex的两个数组缺一不可:第一个必须是模块符号数组,第二个必须是文件名(字符串)数组。传入非模块符号或找不到的模块会得到明确报错(见 src/Commands.hs 的错误信息)。hidden与deprecated控制文档可见性:被标记hidden的绑定不会出现在文档中;被标记deprecated的绑定仍会出现,但附带弃用标记与说明(src/RenderDocs.hs)。- 生成结果验证:运行脚本后控制台会输出
Generated docs to '<dir>'(src/RenderDocs.hs),随后可在输出目录找到每个模块对应的<模块名>.html与索引页<title>_index.html,直接用浏览器打开即可。
六、总结
Carp 标准库的官方文档体系是一套完全自动化、可离线自愈的流程:在线文档与安装内置的本地副本同源,均由docs/core/generate_core_docs.carp这类脚本驱动生成;脚本通过Project.config系列配置项(docs-directory、docs-logo、docs-prelude、docs-url等)定义站点形态,通过save-docs-ex选择模块并收录文件级全局符号,最终由编译器的RenderDocs模块将源码中的doc元数据渲染为带索引、折叠导航、锚点定位与弃用标记的完整 HTML 站点。理解了这条从源码注释到 HTML 文档的完整链路,你既可以在离线环境下随时查阅标准库,也能为自己的 Carp 项目一键生成同样规格的 API 文档。
- 编程语言
- 编译器
【免费下载链接】Carp
A statically typed lisp, without a GC, for real-time applications.
相关推荐
htmx 中的超媒体 API 与数据 API:为什么超媒体 API 可以拥抱变更而不必版本化
htmx 中的超媒体 API 与数据 API:为什么超媒体 API 可以拥抱变更而不必版本化 本文深入剖析 htmx 项目核心文档之一《Hypermedia A
编程语言编译器如何让Mac编程更顺手:Notepad--跨平台文本编辑器快速指南
如何让Mac编程更顺手:Notepad 跨平台文本编辑器快速指南 如果你的主力开发机是 Mac,又嫌系统自带 TextEdit 太简陋,Notepad 值得一试
桌面应用大麦自动抢票工具:三步部署Web与移动端双端的完整指南
大麦自动抢票工具:三步部署Web与移动端双端的完整指南 ticket purchase 是一个基于 Python 的大麦自动抢票工具:Web 端用 Seleni
GUI 自动化RPA
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考