Code 管线
Code 模块(.notc)用函数扩展内容。本文描述单个模块如何从源码编译成可复用的 CodeModule,以及检查会话如何把函数体 Expr 变成具体实例的 TypedExpr。类型系统与求值规则见 Code 函数系统,模块间的 import 与名称解析见 本地模块,两种语言的交互与整体数据流见 文档管线。
数据流
以是否依赖环境为界分成两段。装配之前:源码 → Code CST → CodeModule,不读取任何定义,产物与实例无关、可复用。会话之内:按具体实例把函数体检查为 TypedExpr;内容节点把内嵌的 IR₁ 交给共享 Markup 后端,收回 Item 森林。
阶段对象 | 表示 | 已确定的信息 |
|---|---|---|
Code CST | 无损 Module 语法树 | import / fn 声明结构、签名语法与恢复节点;内容字面量是不透明 token |
内容语法树 | ParsedContent side list | 字面量范围、Inline / Block flavor、前端语法树与语法诊断 |
函数体 Expr(Code IR) | CodeProgram.bodies | 名称引用、调用与字面量结构;内容位置是内嵌 IR₁ 的 |
TypedExpr | InstanceRecord.body | 具体类型、编译期已知值、已检查调用与已完成的 Item 内容 |
Parse:声明语法与字面量定界
模块顶层只有两类声明:import 与 fn。CST 无损——空白与注释作为 trivia 保留,源码可完整恢复;语法错误就近诊断,恢复以声明为界:破损声明进入 Error 节点,下一个 fn / import 从不被吞掉。AST 视图(Module、FunctionDecl、ImportDecl、ImportMember 等)是 CST 上的薄访问器,值与类型在此仍是语法:默认值保存字面量 token,类型引用保存路径节点,转换与校验留给 Lower。
内容字面量外包给所选前端。遇到 [ 时,ContentParser.parse_content(source, open) 用前端自己的 token 流做括号配平——raw 块、字符串等不透明区域整块跳过——决定字面量边界与 flavor,并就地解析出前端语法树。Code 词法器随后从字面量结束处继续,字面量在 CST 里只有 [、ContentText、] 三个 token;语法树与诊断按源码范围放进 side list,等 Lower 回查。
片段入口让文档前端复用同一份 Code 语法:parse_call_prefix、parse_annotation_prefix、parse_import_prefix、parse_content_literal 分别解析 # 调用头、@ 注解、#import 行与独立字面量前缀。它们只产 CST 与诊断,不做语义。
Lower:CST → CodeModule
Lower 把一份模块拆成三个去向:
imports:保存模块别名、成员选择与重命名或通配选择,校验路径字面量与保留名称;模块别名默认取文件 stem。宿主加载目标后由 Context 展开公开绑定,统一诊断缺失成员、导入之间及与本模块函数的名称冲突。
签名:类型引用与默认值在此转换为 FunctionDef,汇入 DefinitionModule;签名与导入声明的错误使模块编译整体失败;依赖公开表相关错误使宿主环境装配失败。
函数体:机械映射为 Expr——成员访问、调用、If / Match、数据字面量与块;调用的 children 字面量整体作为一个
Expr::Content进入 children,flavor 取自 Parse 结果,函数体内的错误收进 CodeBody 诊断。
内容字面量在这一步才 Lower:按 span 回查内容语法树,经 ContentLowering 转成 Markup IR₁ 嵌入 Expr::Content。名称解析、类型检查与结构定稿都不在这里发生——函数体保留源码里的名字,直到实例检查。
实例检查:Expr → TypedExpr
检查以 ResolvedInstance(DefId + 编译期实参值)为单位、按需进行;FunctionInstance 是输入边界的具名选择器。Checker 会话持有只读 Context、当前 ModuleId、局部绑定与实例缓存 CheckedProgram,名称拥有关系随 Sources 保留。见 定义身份。规则如下:
名称解析:局部绑定遮蔽优先,随后是当前文件的函数与静态绑定,未绑定的裸名回落内置 prelude;限定路径只遍历公开绑定;
notist与self是保留命名空间。非调用位置的模块成员访问报module members must be called。常量折叠与折枝:沿途记录编译期已知值;编译期已知的 If / Match 直接折枝,未选中分支不做名称与类型检查。
实例建立:先登记实例签名,再在定义模块的作用域中检查函数体;递归调用引用已登记实例。普通参数与 children 作为输入绑定;嵌套深度上限 32,实例总数上限 4096。
内容检查:将
Expr::Content的 IR₁ 与词法绑定交给共享内容后端,返回的 Item 森林嵌入ExprKind::Content。
产物按实例进 CheckedProgram:一个函数可对应多个实例、多棵 TypedExpr 树,CodeModule 的 Expr 保持可复用。文档分析把 CheckedProgram 保存在 Analysis 中;独立 Code 检查(check_module、check)以编译期参数均有默认值的函数为种子,其余实例在调用处触发,CodeAnalysis 只导出声明、诊断与来源源码。
诊断与恢复
阶段 | 诊断与恢复 |
|---|---|
Parse | 语法错误就近诊断并继续;恢复以声明为界;类型嵌套超过 128 层报错 |
Lower | 数据字面量、默认值与 imports 的语义错误;函数体错误收进 CodeBody,签名与 imports 错误使模块编译失败 |
模块加载 | 展开显式 / 通配成员选择,检查缺失成员、保留名称、统一名称冲突与循环依赖;加载失败不返回正式环境 |
实例检查 | 名称、实参、类型与内容契约错误;诊断随 InstanceRecord 保存,单个实例失败不影响其他实例与独立内容 |
求值 | 步数与内容节点数各 100k(步数预算在每个内容边界重置)、调用深度 32;失败在内容边界恢复 |
求值
Evaluate 执行内容表达式,生成独立输出树。replace 扩展选择同签名执行目标;原生实现生成内容元素,Code 实现返回内容森林。失败在内容边界恢复为 Error,原语义树保留。完整契约见 Code 函数系统。