Type System
本文定义 Markup/Code 双 Mode 下现行的类型与求值模型。精确语法见 vault::grammar,内置 Function 签名见 vault::functions。当前实现已经具备 mode-aware syntax tree、Function signature、argument binding 与 Document 静态检查;尚未完成的 typed IR 和 Value-returning Function 边界见“当前迁移边界”。
核心判断
Notist Document 是一个隐式 Markup expression。整篇文档具有静态类型 Content,求值结果也是 Content:
source Document
-> parse Markup and embedded Code
-> resolve names and check expression types
-> evaluate Code expressions
-> concatenate Markup fragments and embedded outputs
-> Content形式化地写:
Γ ⊢ document : Content
Γ ⊢ document ⇓ content其中 Annotation 是独立的 source span metadata,不参与上述类型判断和求值关系。
Markup 与 Code 的类型边界
Document 默认处于 Markup。Markup 中的普通文字和宿主语法直接产生 Content:
Text : Content
Wiki Reference : Content
Inline/Fenced Raw : Content
Embedded Expression : Content
Markup sequence : Content# 在 Markup 中开始一个 EmbeddedExpression,并切换到 Code。CodeExpression 先按自己的类型求值,再通过 Content insertion 规则进入外层 Markup。
Markup: Before #expr after
│
└─ CodeExpression# 不是运行时 unary operator,也不改变 expression 自身的类型。它是语法 mode switch 和插值边界。
Content Literal
Code mode 中的 [...] 是 Content literal。方括号内部切回 Markup,因此可以包含 Text、Reference、Raw、Function Call 和嵌套 EmbeddedExpression。
#[Plain Content]
#[Outer #[inner]@inner Content]
#quote[Body with [[vault::grammar]] and #raw(text="code").]类型规则:
Γ ⊢ markup : Content
──────────────────────
Γ ⊢ [markup] : Content在普通 Markup 中,裸 [abc] 是包含方括号的文字,不是 Content literal。只有进入 Code 后,[...] 才具有 literal 含义:
[abc] // Markup text containing brackets
#[abc] // embedded Content literal未来变量系统可以直接复用相同规则:
#let x = [stored Content]
#xlet 本身不属于当前阶段,但不需要为它重新设计 Content literal。
Content 插入规则
EmbeddedExpression 的结果必须能够进入外层 Content。本阶段定义三个允许的结果:
Content -> 原样插入
String -> 转换为一个 Text Element
None -> 空 Content形式化规则:
Γ ⊢ e : Content
────────────────
Γ ⊢ #e : Content
Γ ⊢ e : String
─────────────────────────
Γ ⊢ #e : Content(Text(e))
Γ ⊢ e : None
────────────────────
Γ ⊢ #e : Content()Bool、Int、Float 和其他未来 Value 不自动 stringify;直接插入时产生 type diagnostic。需要显示时应显式转换为 String。这样避免 Agent 和 renderer 依赖隐式格式化规则。
#"text" // String -> Text Content
#[content] // Content -> Content
#none // empty Content
#42 // type error in Markup positionStatic Type
本阶段静态类型集合为:
Type
├─ None
├─ Bool
├─ Int
├─ Float
├─ String
├─ Content
└─ Optional<T>Type 描述 CodeExpression、Function parameter 和 Function result 可以产生或接受的值。显示名称使用 None、Bool、Int、Float、String、Content;Optional<T> 显示为 T?。
None 与 Optional
None 是 literal none 的类型。T? 接受 none 或 T,不是独立运行时容器:
String? accepts None
String? accepts String
String? rejects Int可选类型不等于具有 default。是否允许省略由 Function signature 的 default 决定:
lang: String? = noneString? 允许显式传入 none,= none 允许完全省略 lang。
数值兼容
Int 和 Float 是不同类型。Binding 允许 Int 实参用于 Float parameter,但不允许 Float 用于 Int parameter:
Float accepts Float
Float accepts Int
Int accepts Int
Int rejects Float兼容绑定必须明确定义运行时行为。目标实现应在绑定时把 Int widening 为 Value::Float,或者为 Function API 暴露统一的 checked numeric accessor;不能让 signature 声明 Float、实际却在无约定的情况下传入 Int variant。
Runtime Value
CodeExpression 求值产生 Value:
Value
├─ None
├─ Bool(bool)
├─ Int(i64)
├─ Float(f64)
├─ String(String)
└─ Content(Content)Optional 没有对应 Value variant;运行时使用 Value::None 或具体 Value。
Content 是有顺序的语义 Element sequence,不是 String,也不是待重新解析的源码。Content literal 内的 Markup 在产生 Value::Content 前已经完成递归 parse、analysis 和 evaluation。
String 与 Markup Text
String literal 只存在于 Code mode:
"abc" // Markup Text,保留 quote
#"abc" // Code String,插入时转成 Text("abc")四种 String literal 都具有同一个 String 类型与 Value::String:
Form | Escape style | Type |
|---|---|---|
| Escaped | String |
triple quote 后立即换行 | Escaped | String |
| Raw | String |
| Raw | String |
Inline/Multiline 与 Escaped/Raw 是 literal provenance,不是不同类型。Binder 可以保留:
完整 literal range。
payload range。
Inline/Multiline form。
Escaped/Raw style。
这些信息不改变 String 类型,但 raw 等 native Function 可以读取。默认值和未来计算产生的 String 不保证具有 literal provenance。
Function Signature
Function signature 包含:
有顺序的 parameters。
parameter name、Type 和可选 default。
trailing Content parameter binding。
result Type。
部分内置 Function:
heading(level: Int = 1, body: Content) -> Content
raw(text: String, lang: String? = none) -> Content
quote(attribution: Content? = none, body: Content) -> Content
callout(kind: String = "note", title: Content? = none, body: Content) -> Content
details(summary: Content? = none, open: Bool = false, body: Content) -> ContentFunction Call 是 CodeExpression。普通 arguments 在 Code mode 中解析;紧随调用的 [...] 是普通 Content literal,并作为 trailing argument 参与 signature binding:
#heading(level=2)[Title]
#quote[Quoted Content]等价的类型视图:
heading(level=2, body=[Title])
quote(attribution=none, body=[Quoted Content])Parser 不根据 Function name 或 signature 改变 [...] 的语法。Analysis 负责确认 trailing Content 能绑定到哪个 parameter。
Function Result
Function result Type 必须是真实契约,而不能只用于 Hover 显示:
arguments satisfy signature
Function::call(arguments) -> value
value.type satisfies signature.result当前 native Function 都产生 Content。在 Markup 中嵌入 Call 时,其结果还必须满足 Content insertion 规则。
foo() -> Content // 可直接 #foo()
bar() -> String // 可直接 #bar(),转成 Text
count() -> Int // #count() 是 Content-position type error如果第一阶段继续使用只返回 FunctionOutput/Content 的 trait,则 Registry 必须强制 result == Content;等一般 Value-returning Function 实现后,再把 runtime API 扩展为返回 Value。
Argument Binding
参数按以下规则绑定:
Positional argument 按 parameter 顺序绑定。
Named argument 按名称绑定。
第一个 named argument 后不能再出现 positional argument。
Trailing Content literal 绑定到 signature 指定的 Content parameter。
同一个 parameter 不能由 positional、named 或 trailing argument 重复提供。
未提供的 parameter 使用 default;无 default 则产生 missing argument diagnostic。
所有 Value 必须满足 parameter Type。
Default 本身必须在 Function 注册时满足 parameter Type。
Binding 在 Function 执行前报告:
unknown argument。
positional after named。
too many positional arguments。
duplicate argument。
missing required argument。
type mismatch。
Function 不接受 trailing Content。
非法 signature/default/result。
任何 binding diagnostic 都会阻止 Function 执行。Parser 遇到缺失或非法 CodeExpression 时必须先产生 syntax diagnostic,不能静默丢弃 argument 后让 default 掩盖错误。
Document 的类型与求值
Markup sequence 的组合规则是 Content concatenation:
Γ ⊢ a : Content Γ ⊢ b : Content
──────────────────────────────────
Γ ⊢ concat(a, b) : ContentDocument 可以建模为隐式 Content expression:
Document
└─ Concat
├─ Text Content
├─ Reference Content
├─ Embedded Code output converted to Content
├─ Raw Content
└─ Text Content目标管线:
Source
-> mode-aware Syntax Tree
-> name resolution
-> Function signature resolution
-> static type checking
-> Typed Document : Content
-> evaluation
-> Content
-> structuring
-> StructuredDocument静态 analysis 不执行 Function runtime。LSP diagnostics 应使用 resolved signatures 和 typed tree;只有 preview/build 等 evaluation 路径执行 native、user 或 plugin Function。
错误恢复与 Partial Content
Syntax、name resolution 或 type diagnostic 不应让整篇文档不可分析。实现可以保留 Error/Unknown typed node,并在 evaluation 或 preview 中产生可恢复的 UnresolvedCall。
但恢复必须显式:
非法 expression 不能静默消失。
错误 argument 不能偷偷回退到 default。
Function result Type 不匹配不能当作 Content 插入。
notist check、LSP 和 build 必须共享同一套静态 diagnostics。
Evaluation 可以同时返回 partial Content 和 diagnostics,但成功状态由 diagnostics 决定,不得因为存在 partial Content 就报告检查成功。
Annotation 不属于类型与求值
@... 是 EmbeddedExpression source scope 上的独立 metadata。它不属于:
Type。
Value。
Content。
Function argument。
Function result。
类型推断或 Function execution。
#[Content]@concept,#important
#quote[Content]@citation,source="book"Analysis 可以建立 Annotation index,供 Agent query、LSP 和 renderer source-range projection 使用。忽略 Annotation 后,typed tree 与 evaluation Content 必须保持不变:
type_of(erase_annotations(document)) == type_of(document)
eval(erase_annotations(document)) == eval(document)Annotation 的 delimiter nesting 属于 syntax well-formedness,而不是类型兼容规则。
当前迁移边界
当前代码已实现:
Markup/Code mode-aware syntax tree 与一般 EmbeddedExpression。
literal Expression、Type、Value、Optional。
Function signature 与 argument binding。
trailing Content lowering。
built-in Function 返回 Content。
String/None 到 Content 的统一插入检查。
Annotation 从 evaluator 完全移出:经 syntax 层
Parse::annotations()暴露,不再进入Evaluation或StructuredDocument。注册时 signature 校验:default 满足参数类型、
result == Content、trailing Content 参数已声明。Document 的静态
Contenttype checking:notist-analysis 的 check pass 做名称解析、argument binding 检查和 Markup 插入检查,不执行 Function runtime;notist check与 LSP 共享这套静态诊断。
但尚未完成目标模型中的:
一般 Value-returning Function 及其 result runtime validation(当前 Registry 强制
result == Content)。跨 Module 的 Function name resolution(静态检查目前只解析 built-in 签名)。
analysis 侧统一的 Annotation index(目前由 syntax 层按需提供)。
迁移已按"先建立 mode-aware syntax tree 和显式错误恢复,再将 binder 扩展为 Typed Document analysis"完成第一阶段;不应继续在 flat syntax vectors 上增加新的 Code feature。
非本阶段类型系统
以下能力不属于当前双 Mode 规范:
let、变量和 lexical scope。一般 unary/binary Expression。
Array、Dict、record、union 和用户定义类型。
Function Type、Function Value 和 User Function。
控制流与完整类型推断。
跨 Module value import。
Annotation 作为 Value 或 Content metadata。
以后扩展这些能力时,应保持两个边界稳定:CodeExpression 在插入 Markup 前具有可检查的 Type;Document 最终仍静态检查并求值为 Content。