首页
/ Carbon 语言规范框架的诞生:解读 p000140 提案与 `docs/spec` 目录的落地实践

Carbon 语言规范框架的诞生:解读 p000140 提案与 `docs/spec` 目录的落地实践

2026-09-09 19:45:09作者:殷蕙予

导读

本文以 Carbon Language 仓库中的提案 p000140-create-initial-rough-framework-for-specification 为核心,系统讲解 Carbon 语言正式规范(specification)的组织框架:它为何要把规范拆分为"语言"与"库"两个部分、按什么原则划分文件、采用哪些写作约定,以及这套框架如何在当前仓库的 docs/spec 目录中一步步落地并充实。读完本文,你将理解 Carbon 规范文档的目录语义、每份文件的定位、段落编号等写作规范,以及规范中的"翻译流水线"与 toolchain 编译器实现之间的对应关系。


一、背景:为什么需要一个规范框架

1.1 问题:规范无从下笔,先要有"骨架"

在 Carbon 语言设计早期,大量语言细节仍在讨论和决策之中。此时撰写完整规范既不现实也无必要,但若完全没有载体,后续一旦有结论就无法有序沉淀。因此提案的 Problem 一节非常直白:

我们需要为规范准备一个粗略的布局(rough layout),以便在细节被确定后可以开始往里面填充内容。

换句话说,这份提案解决的不是"规范写什么",而是"规范放在哪、按什么结构组织"——先搭好架子,再等待内容。

1.2 长远承诺:规范要支撑独立实现

这个"架子"并非临时草稿。仓库中的规范首页 docs/spec/README.md 明确写道:Carbon 承诺拥有一份详细到足以允许独立实现该语言的正式规范;虽然计划提供参考实现,但规范本身是确保语言行为被充分理解、前后自洽的重要工具。这正是 p000140 提案的深层动机——框架的最终目标是一份可让第三方独立实现的语言定义文档。


二、提案核心:语言与库的二分结构

2.1 总体方案

提案提出的方案可以归纳为三条原则:

  1. 规范拆分为 language(语言)与 library(库)两个顶层部分——前者描述语言本身的语法与语义,后者描述随语言分发的标准库。
  2. 在语言部分,按"功能大领域"(broad area of functionality)一文件一主题——每个文件覆盖一个功能领域,方便独立维护与交叉引用。
  3. 文件划分依据语言设计的预期分层(intended layering of the language design)——即按编译器前端处理源码的自然阶段来切分,这为后来与工具链实现对齐埋下了伏笔。

2.2 提案中的初始目录结构

提案原文给出了 spec/ 目录的顶层结构建议(截至该 PR 时):

spec/
├── README.md          # 规范总览(Introduction to the specification)
├── lang/              # 语言规范
│   ├── README.md      # 语言规范概述与基础(overview and basics)
│   ├── execution.md   # 执行语义(Execution semantics)
│   ├── lex.md         # 词法分析(Lexical analysis)
│   ├── libs.md        # 库与包(Libraries and packages)
│   ├── names.md       # 名称与名称绑定/查找(Names and name binding / lookup)
│   ├── parsing.md     # 语法分析(Parsing)
│   └── semantics.md   # 语义分析(Semantic analysis)
└── lib/
    └── README.md      # 库规范概述与基础

提案同时强调:这只是起点,随着规范被逐步填充,结构应当持续调整与生长;当时列出的文件大多为空或近乎空的占位符(placeholder)。

2.3 现状:结构被完整采纳

对照当前仓库 docs/spec,可以看到这套结构被一字不差地落地了:

这个"提案提出的结构 = 仓库实际结构"的一致性,本身就是提案在 Carbon 决策流程中落地的最直观证据。


三、写作约定(Conventions):让规范可引用、可检索

提案 Details / Conventions 一节为规范文档制定了三条写作约定,它们是这份规范在排版层面区别于普通技术文档的关键:

  1. 段落编号:规范中的所有段落(paragraph)都编号,以便于被精确引用(例如"见第 3 节第 2 段")。这种编号机制让评审、实现与测试都能锚定到唯一文本位置。
  2. 术语斜体:被定义的术语(defined terms)以 斜体 引入,读者可以据此区分"首次定义的术语"与"一般用法"。
  3. 超链接贯通:规范各节之间大量使用超链接互相引用,形成一张可导航的语义网。

这三条约定在当前规范中已经生效,例如:

提示:docs/spec/README.md 中写有"Linkage rules for foreign entities"等 TODO 标记,说明框架已就位,具体规则仍在补充中——这正是提案预期的"结构先行、内容跟进"演进方式。


四、备选方案:为什么坚持用 Markdown

提案还记录了被否决的备选方案——用其他语言维护规范(如支持自定义排版、文法表示、定义链接能力更强的文档语言)。

备选方案的优势:另一种文档语言可能对自定义排版、文法表示、链接到定义等提供更好支持。

否决的理由(即 Markdown 的劣势对比):

  • 引入其他文档语言会增加文档体系的复杂度与不一致性
  • 很难找到一种无需大量定制就能契合规范需求的现成文档语言
  • 从更复杂的文档语言再转换回来,通常比从 Markdown 转换更复杂。

结论:由于 Markdown 文档相对简单,日后无论是手工还是借助 Sphinx 之类的工具将其转换为其他格式,成本都预期保持在较低水平。因此"先 Markdown、必要时再迁移"是一个低成本、高灵活性的决策。当前仓库 docs/spec 下全部规范文件均为 .md,正是这一决策的延续。


五、从骨架到血肉:规范框架中已填充的核心内容

提案之后,规范文件陆续获得了实质性内容。以目前信息密度最高的 docs/spec/lang/README.md 为例,可以看到框架如何被内容填满:

5.1 程序结构(Program structure)

  • 一个 program 是若干**链接单元(linkage unit)**的集合;
  • Carbon linkage unit 是源文件经翻译的产物,foreign linkage unit 则由其他语言翻译流程产生;
  • source file 是 Unicode 码点序列,通常以 UTF-8 编码、.carbon 扩展名存储于磁盘。

5.2 一致性(Conformance)

  • 不含任何违反规范中 "shall" 约束的程序是 valid(有效),否则 invalid(无效);
  • conforming(符合规范的)实现必须:接受所有有效程序、对要求诊断的无效程序给出诊断、且所有被接受程序的执行语义与规范一致。

5.3 翻译流水线(Translation)——与编译器实现的对应

规范为"源文件翻译为 Carbon 链接单元"定义了如下顺序流程,这正是框架"按语言设计分层划分文件"的体现:

步骤 规范章节 对应实现路径(当前仓库)
词法分析:码点序列分解为词法元素 lex.md toolchain/lex
丢弃空白与注释,得到 token 序列 lex.md toolchain/lex
token 解析为抽象语法树 parsing.md toolchain/parse
非限定名称绑定到声明 names.md toolchain/check
定位并加载每个被导入库的翻译形式 libs.md 包/导入处理相关代码
语义分析:确定类型、语义检查、常量求值、模板实例化 semantics.md toolchain/checktoolchain/sem_ir

规范还注明:语义分析之后实现可选用类似模板实例化的过程对泛型做单态化(monomorphize);链接单元包含源文件中所有外部实体或从外部实体可达的实体,可含未单态化的泛型但从不含模板。

从实现侧看,toolchain/driver/compile_driver.cppCompilationUnit 持有 SemIR::CheckIRIdSemIR::File,并有"将 SemIR 降低为 LLVM IR(lower)"的职责注释;toolchain/driver/compile_options.cpp 提供 --dump-sem-ir 等选项用于输出语义分析结果,toolchain/driver/testdata/fail_dump_phase_conflict.carbon 中还可见"compile phase is limited to parse"之类的阶段控制测试。可以说,规范中的分层翻译模型与 toolchain 的 lex → parse → check(SemIR) → lower(LLVM IR) 流水线高度吻合——这就是"按预期分层划分文件"在实现侧的投影。

5.4 链接(Linkage)

  • 两个声明若处于同一库、同一作用域且声明同名,则声明同一实体(规范中为外来实体规则、文件局部实体能力留有 TODO);
  • 同一实体的所有声明必须使用相同类型;
  • 程序中每个从链接单元可达的实体都须由某个链接单元定义;
  • 一个实体在程序中不得有多个定义。

5.5 词法与名称的细化

  • docs/spec/lang/lex.md:源文件码点序列被划分为连续的 lexical elements;每一步都取能由剩余码点前缀构成的最长有效词法元素(最长匹配原则),即使这会导致后续元素无法形成;规范中词法元素清单仍为 TODO。
  • docs/spec/lang/names.mdname 是标识符,两个名称相同当且仅当码点序列相同(归一化问题留作 TODO);scope 分为源文件顶层、模式作用域、块作用域、类型定义四类;声明名字的构造在最内层包围作用域内绑定名称;非限定名称查找即"绑定该名称的最内层作用域中的实体"。

这些内容直接呼应了提案中"随着细节被确定后填充"的规划,也验证了框架在真实演进中的可用性。


六、给规范读者的使用建议

如果你希望跟踪或引用 Carbon 的规范,可以从以下路径切入:

  1. 从总入口 docs/spec/README.md 开始,了解规范的承诺与当前状态;
  2. 语言规范以 docs/spec/lang/README.md 为枢纽,按"程序结构 → 一致性 → 翻译 → 链接"的顺序阅读,再进入 lex.mdparsing.mdnames.mdsemantics.mdexecution.mdlibs.md 各专题;
  3. 库规范暂为空壳(docs/spec/lib/README.md 仅含 TODO),说明该部分尚待设计沉淀;
  4. 规范中凡以编号列出的段落均可作为精确引用锚点,文中 斜体 术语为定义处。

结语

p000140 是一份典型的"过程性"提案:它没有定义任何语言语法,却定义了承载语法的容器。通过"语言/库"二分、按功能领域分层分文件、Markdown 维护与三项写作约定,它为 Carbon 建立了一套可持续生长、可精确引用、与编译器实现分层天然对齐的规范骨架。今天你在 docs/spec 中看到的每一个编号段落、每一条交叉链接,都可以追溯到这份早期提案所奠定的结构决策。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
docsdocs
暂无描述
Markdown
899
5.83 K
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.76 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.35 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
925
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.84 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
533
601
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
395
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.04 K
525