feat: connect source compilation and VM execution
Verify databases and deploy Aster VM / verify-and-deploy (push) Successful in 7m56s
Verify databases and deploy Aster VM / verify-and-deploy (push) Successful in 7m56s
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
| [Endor 阅读器](reader.md) | SourceUnit、来源/修订标签、字符串/流/文件和宿主 URI provider |
|
||||
| [源码前端](frontend.md) | 字符 PEG lexer、token PEG parser、AST、基础函数/表达式语法与诊断 |
|
||||
| [AST 模型与 ASDL](ast.md) | 统一根、声明/语句/表达式、生成器、Visitor、位置和 JSON/编辑器接口 |
|
||||
| [源码编译](compiler.md) | 名称/作用域、局部槽、字节码模板、代码装载、CLI 执行与示例 |
|
||||
| [字节码 VM](bytecode.md) | 指令编码、代码校验、局部槽、执行帧、函数创建、调用/返回与边界 |
|
||||
| [文本编码](text-encoding.md) | UTF-8、日文、外部 Shift_JIS/CP932 与宿主解码边界 |
|
||||
| [数据库特殊类](database-objects.md) | 显式连接、调用方数据模型、未来类接入与资源生命周期 |
|
||||
|
||||
+2
-2
@@ -51,7 +51,7 @@ Spanned 为有位置的节点提供 span()、source_text(&str)、location(&str)
|
||||
|
||||
生成的 Rust Visitor 有每个节点/种类的 visit_* 方法、默认 walk_* 函数,以及 enter_node/leave_node 钩子。Error 为关联类型,子节点失败时默认遍历返回错误,并配对调用已进入节点的离开钩子。可在 visit_function、visit_binding、visit_expr 等位置实现名称分析或字节码生成。
|
||||
|
||||
覆盖 visit_* 后,调用 walk_* 可继续访问子节点;覆盖方法自身的钩子管理由实现者决定,直接调用 walk_* 不会重复调用当前节点的 visit_*。这些接口只提供遍历,尚未实现名称绑定、闭包捕获分析或字节码生成。TypeScript Visitor 对应编辑器使用,回调返回 false 可跳过子树。
|
||||
覆盖 visit_* 后,调用 walk_* 可继续访问子节点;覆盖方法自身的钩子管理由实现者决定,直接调用 walk_* 不会重复调用当前节点的 visit_*。这些接口只提供遍历;独立 [Compiler](compiler.md) 实现当前模块/函数名称分析和最小字节码生成,闭包捕获分析尚未实现。TypeScript Visitor 对应编辑器使用,回调返回 false 可跳过子树。
|
||||
|
||||
## JSON 交换
|
||||
|
||||
@@ -69,6 +69,6 @@ cli parse --mode expression --json -
|
||||
cli parse --mode interactive --json -
|
||||
```
|
||||
|
||||
文件/stdin 阅读保持原有 UTF-8 和错误来源规则,stdin 到 EOF 后才解析。普通 cli parse 输出 AstRoot 的 Debug 文本,稳定交换使用带 schema 的 JSON;所有入口均不执行源码。命令在指定远端运行。
|
||||
文件/stdin 阅读保持原有 UTF-8 和错误来源规则,stdin 到 EOF 后才解析。普通 cli parse 输出 AstRoot 的 Debug 文本,稳定交换使用带 schema 的 JSON;parse 的各模式均不执行源码;run/eval 执行入口见 [编译链路](compiler.md)。命令在指定远端运行。
|
||||
|
||||
检查源码见 [frontend/tests](../../crates/frontend/tests/README.md) 和 [生成器检查](../../scripts/test_generate_ast.py),边界见 [验证](../operations/validation.md)。返回 [运行时索引](README.md)。
|
||||
|
||||
@@ -119,7 +119,7 @@ fn main() -> Result<(), endor_core::VmError> {
|
||||
}
|
||||
```
|
||||
|
||||
当前已能通过字节码读取、写入和删除共享 Cell,并创建捕获参数的 Cell。LoadClosure 与 MakeFunction 可以在外围函数运行时创建共享这些 Cell 的嵌套函数,外围帧返回后 Cell 仍由闭包保活。上面的 Python 代码说明闭包语义;独立 frontend 已能解析基础函数,但尚无源码闭包语法或 AST 到字节码生成,代码对象仍由宿主准备。
|
||||
当前已能通过字节码读取、写入和删除共享 Cell,并创建捕获参数的 Cell。LoadClosure 与 MakeFunction 可以在外围函数运行时创建共享这些 Cell 的嵌套函数,外围帧返回后 Cell 仍由闭包保活。上面的 Python 代码说明闭包语义;独立 frontend 解析基础函数,由 [Compiler](compiler.md) 生成代码对象;尚无源码闭包语法或捕获分析。
|
||||
|
||||
## 字符串与异常的准确含义
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 小型字节码 VM
|
||||
|
||||
当前提供指令与代码对象、内部执行帧、取指执行循环,语言函数已接入执行器。参考 CPython 3.14 的职责划分和栈式执行设计;源码 lexer/parser 由独立 [frontend](frontend.md) 提供,尚未接入 AST 到字节码生成;执行器不读取 Python `.pyc`,不承诺 CPython 操作码编号、ABI 或完整语言兼容性。
|
||||
当前提供指令与代码对象、内部执行帧、取指执行循环,语言函数已接入执行器。参考 CPython 3.14 的职责划分和栈式执行设计;源码 lexer/parser 由独立 [frontend](frontend.md) 提供,基础源码已由独立 [compiler](compiler.md) 接入字节码生成;执行器不读取 Python `.pyc`,不承诺 CPython 操作码编号、ABI 或完整语言兼容性。
|
||||
|
||||
Endor 是解释型语言,字节码是内部执行表示;从 AST 生成字节码属于自动执行准备,不要求使用者发布编译产物。当前没有字节码持久化缓存或跨版本装载协议;现有不可变代码对象仍可在 VM 内共享复用。平台升级与源码修订的区别见 [执行与版本模型](../architecture/execution-and-versions.md)。
|
||||
|
||||
@@ -160,7 +160,7 @@ fn main() -> Result<(), endor_core::VmError> {
|
||||
|
||||
运行错误仍返回 `VmError`。`last_traceback()` 另提供从外到内的函数名、文件、代码首行和出错指令偏移;它保存独立元数据,不保活已经清理的帧。首行是代码声明的 first_line,不是由行号表推导出的实际错误源码行。成功的新一次调用会清空旧记录。尚无语言异常对象传播、raise/try/except 或完整源码行号表。
|
||||
|
||||
暂未实现:AST 到字节码生成、关键字/可变参数、生成器/协程、迭代器专用指令、数值算术、自动方法绑定、指令特化和 JIT。
|
||||
暂未实现:源码闭包编译、关键字/可变参数、生成器/协程、迭代器专用指令、数值算术、自动方法绑定、指令特化和 JIT。
|
||||
|
||||
## 验证
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
# 最小源码编译与执行链路
|
||||
|
||||
当前已连接 reader → lexer → PEG parser → AST → 名称/作用域分析 → wordcode → 代码对象 → VM。实现位于独立 [compiler](../../crates/compiler/README.md);frontend 只负责语法,objects 拥有指令/代码数据与验证,core 解释字节码。用户无需手写指令,也不需要先补全 Python 基础类。
|
||||
|
||||
## 接口与阶段
|
||||
|
||||
| 接口 | 行为 |
|
||||
| --- | --- |
|
||||
| analyze(&AstRoot, &CompileOptions) | 返回 SymbolTable:根与函数作用域、CodeLayout、每次名称读取的位置和 Local/Global 绑定 |
|
||||
| compile_ast(&AstRoot, &SourceUnit, &CompileOptions) | 校验节点与原文范围、分析并生成 CompiledCode;不验证 AST 与原文的语义等价性 |
|
||||
| compile_source(&SourceUnit, ParseMode, &CompileOptions) | 先调用 frontend 解析,再编译;错误携带原始文件/流/URI 与修订来源及一基行列 |
|
||||
| CompiledCode::load(&mut Vm) | 将模板及子模板装载为该 VM 的代码对象,返回一个拥有根的 ObjectRef |
|
||||
|
||||
解析错误沿用 Lexical/Syntax,名称错误为 Semantic,不支持的执行特性或代码验证错误为 Compilation。编译不修改 VM 或全局字典;词法动作也不执行语言代码。模板提供 instructions/layout/name/filename/first_line/children 只读检查入口。生成时使用已有 EndorCode 验证器检查槽位、操作数和栈平衡;装载再次验证真实常量。
|
||||
|
||||
## 名称与作用域
|
||||
|
||||
首版是模块作用域和函数作用域。模块先登记全部函数名,再分析函数体,因此支持前向引用、自递归和函数作为普通值传递。函数参数占据最前面的局部槽,let 按声明顺序分配后续槽;引用优先使用函数局部,其次使用已声明全局。
|
||||
|
||||
函数内先收集全部局部名称,再按语句顺序检查初始化。后面声明的 let 会遮蔽整个函数中的同名全局,但提前读取报错;let x = x 也会报未初始化。参数、局部绑定和同一模块的函数不允许在各自作用域内重复声明;参数或局部可以遮蔽模块函数。let 当前没有赋值/重绑定语法。嵌套函数/闭包分析和块级作用域尚未实现。
|
||||
|
||||
CompileOptions.globals 显式声明宿主会提供的 globals/builtins 名称,默认空。不认识的名称在编译时报错;已声明的宿主名称仍必须在执行时存在,否则 VM 返回 NameNotFound。编译器不自动注入 print、默认基础类或标准库,也不读取这些名字的值。类型注解只保留语法,不参与名称绑定、运行时求值或类型检查。
|
||||
|
||||
## 指令与代码对象
|
||||
|
||||
| 源结构 | 生成方式 |
|
||||
| --- | --- |
|
||||
| 字符串、整数、十进制常量 | 放入常量表并 LoadConst;数字经现有 EndorNumber 解析,不转换为 f64 |
|
||||
| 数字字面量前的一个或多个负号 | 折叠符号为精确常量;不是任意表达式的一元算术 |
|
||||
| 局部读取/let | LoadFast/StoreFast;参数和局部名称在 CodeLayout 中 |
|
||||
| 全局读取 | LoadGlobal,使用该代码对象的 names 表 |
|
||||
| 函数声明 | 子代码模板 → LoadConst(code) → MakeFunction(0, 0) → StoreGlobal |
|
||||
| 普通调用 | 求值 callee → PushNull → 从左到右求值位置参数 → Call(argc) |
|
||||
| 成员读取 | 求值对象 → LoadAttr;沿用 VM 属性协议,无自动 self 绑定 |
|
||||
| return | 求值结果 → ReturnValue;无值 return 或 AST 函数末尾无 return 时生成 nil |
|
||||
|
||||
源码 parser 仍要求函数体为 let* 加一个带值 return;更通用的表达式语句和空 return 可以由 AST 调用方构造,但不能因此宣称源码语法已开放。模块初始化只发布函数并返回 nil,不自动调用 main。CLI 选择入口属于宿主行为。
|
||||
|
||||
二元算术、非字面量的一元负号和符号值 .name 目前产生明确 Compilation 诊断,不伪造运行结果。导入、类、Agent、条件/循环、关键字参数等仍未实现。函数参数个数和对象是否可调用由 VM 在运行时检查。
|
||||
|
||||
## 装载、执行与所有权
|
||||
|
||||
CompiledCode 是纯 Rust 模板,嵌套代码常量在模板内部使用占位槽,装载时替换为当前 VM 的子代码对象;模板不含跨 VM 句柄,可复用到多个 VM。父代码对象成功分配后持有子代码,装载成功或失败都会释放临时子根。返回的根代码对象由调用方 release。
|
||||
|
||||
宿主为模块提供 globals 字典,调用 vm.execute(code, globals) 发布函数,然后从字典借用函数句柄并调用 vm.call。函数共享装载后的代码,反复调用不重新编译;execute/call 的对象结果持有根,用后 release_value。函数指向 globals,globals 保存函数,因此宿主需保留命名空间期间的根,并在销毁时清空字典或释放根后显式 collect_cycles。编译器不清空宿主字典。
|
||||
|
||||
Expression 模式返回表达式值;Interactive 模式严格编译一次声明、let 或表达式。声明/绑定返回 nil,表达式返回值;宿主可以跨提交复用 globals,并在下一次 CompileOptions 中声明可见名称。CLI 当前没有 REPL、续行或自动会话管理。
|
||||
|
||||
代码对象保存来源字符串、函数名和定义起始行,现有 VM traceback 保存该位置及指令偏移;没有每条指令对应的精确源码行/列映射。现有 ExecutionLimits 帧数/指令数限制可由嵌入方继续使用;本链路不构成不可信代码沙箱。
|
||||
|
||||
## CLI 与检查
|
||||
|
||||
cli run [--entry name] <file|-> 编译模块、执行初始化、调用无参数入口(默认 main),输出返回值一行。cli eval <file|-> 编译执行一个表达式。字符串输出原始内容,数字输出无损表示,对象使用 VM str;失败仅输出 stderr 并返回非零退出码。文件和 stdin 严格 UTF-8,stdin 到 EOF 后才处理。CLI 在成功或失败后释放代码/结果并清空自己创建的命名空间。
|
||||
|
||||
可执行文件见 [示例目录](../../crates/compiler/examples/README.md),API/所有权与错误路径见 [pipeline.rs](../../crates/compiler/tests/pipeline.rs),进程入口见 [CLI 检查](../../crates/cli/tests/README.md)。这些检查由既有远端 workspace 测试覆盖;本地只做静态检查,不据此宣称实际执行通过,见 [验证约定](../operations/validation.md)。返回 [运行时索引](README.md)。
|
||||
@@ -1,6 +1,6 @@
|
||||
# 源码词法与 PEG 语法前端
|
||||
|
||||
frontend 包提供 [Endor 阅读器](reader.md)、rust-peg 生成的字符 lexer 与 token parser。宿主通过 SourceUnit 调用带来源的词法/语法入口,原有 lex、parse、parse_expression 保留;CLI 提供 parse 文件/stdin 命令;结果是 AST,尚未实现 AST 到字节码生成、类型检查、名称解析或源码执行。Core 仅依赖本地 Objects,不依赖 frontend 或 peg;Objects 保持零依赖。
|
||||
frontend 包提供 [Endor 阅读器](reader.md)、rust-peg 生成的字符 lexer 与 token parser。宿主通过 SourceUnit 调用带来源的词法/语法入口,原有 lex、parse、parse_expression 保留;CLI 提供 parse 文件/stdin 命令;结果是 AST;独立 [Compiler](compiler.md) 已接入名称/作用域分析、最小字节码生成和 CLI run/eval 执行,frontend 自身不执行代码或检查类型。Core 仅依赖本地 Objects,不依赖 frontend 或 peg;Objects 保持零依赖。
|
||||
|
||||
首版以 Endorphin-Language 设计稿的基础词法、表达式与函数章节为起点,语法可以继续修改;设计稿中的未完成部分不作为阻塞前端实现的前置条件,也不被整体视作已经实现的语言能力。这里维护当前解析契约;源码位置见 [frontend](../../crates/frontend/README.md)。
|
||||
|
||||
@@ -75,4 +75,4 @@ use、namespace、class、agent、完整类型语法、条件/循环、比较
|
||||
|
||||
`cli parse <file>` 与 `cli parse -` 成功时输出 Rust Debug 格式的 AST,失败时在 stderr 输出来源/行/列和诊断并返回非零退出码;`-` 表示从 stdin 读到 EOF,不是 REPL。阅读与来源包装规则见 [阅读器](reader.md)。可用 --mode 选择 module/expression/interactive,用 --json 输出带 schema 标识的 AstDocument;普通输出为 AstRoot Debug 文本,稳定交换格式见 [AST 模型](ast.md)。命令不执行源码、不初始化 VM、不连接数据库;具体运行与本地禁测约定见 [运行](../operations/README.md) 和 [验证](../operations/validation.md)。
|
||||
|
||||
后续需要将 AST 经名称/闭包分析转换为现有字节码,再交给 VM 解释执行。这是解释器内部的编译/执行准备步骤,不要求使用者先构建程序,见 [执行与版本模型](../architecture/execution-and-versions.md)。这条连接尚未实现;解析成功不表示表达式已有运行语义。VM 虽已支持 MakeFunction,但从源码创建函数仍需要字节码生成接入。解析器也不是不可信代码沙箱,当前没有通用输入大小或解析递归深度限额。
|
||||
当前 Compiler 将 AST 经模块/函数名称分析转换为现有字节码,再交给 VM 解释执行。这是解释器内部的编译/执行准备步骤,不要求使用者先构建程序,见 [执行与版本模型](../architecture/execution-and-versions.md)。MakeFunction 已接入源码函数编译,但解析接受的二元算术和符号值仍没有执行语义;编译器会给出明确诊断,见 [编译链路](compiler.md)。源码闭包尚未实现。解析器也不是不可信代码沙箱,当前没有通用输入大小或解析递归深度限额。
|
||||
|
||||
@@ -102,6 +102,6 @@ compare 的反向规则是 Lt 对应 Gt、Le 对应 Ge,Eq/Ne 保持不变。
|
||||
|
||||
已实现:统一对象结构、稳定地址、代际句柄、身份、显式引用计数、托管属性、原生操作覆盖、比较与哈希、原生调用、资源清理和显式循环回收。
|
||||
|
||||
尚未实现:Python type 系统、语言根类、继承和描述符、AST 到字节码生成、可变 VM 调用上下文、自动/分代/增量 GC、语言终结器/复活、完整资源限额和 VM 快照;独立 frontend 已提供阅读器、lexer/parser 与 AST,尚未接入源码执行,见 [源码前端](frontend.md);执行器已有帧数和指令数限额。数据库仅为未来特殊类提供按需连接,普通对象或宿主基础信息不自动持久化,详见 [数据库特殊类](database-objects.md)。
|
||||
尚未实现:Python type 系统、语言根类、继承和描述符、可变 VM 调用上下文、自动/分代/增量 GC、语言终结器/复活、完整资源限额和 VM 快照;独立 frontend 已提供阅读器、lexer/parser 与 AST,基础源码执行由独立 [Compiler](compiler.md) 接入,见 [源码前端](frontend.md);执行器已有帧数和指令数限额。数据库仅为未来特殊类提供按需连接,普通对象或宿主基础信息不自动持久化,详见 [数据库特殊类](database-objects.md)。
|
||||
|
||||
验证范围与执行约定见 [验证](../operations/validation.md)。
|
||||
|
||||
@@ -42,7 +42,7 @@ revision 是宿主返回的原样标签;Reader 只拒绝全空白标签,不
|
||||
|
||||
## CLI 与交互输入
|
||||
|
||||
CLI parse 文件通过 from_file → parse_source 输出 AST;`cli parse -` 通过 from_stream 读取 stdin 到 EOF,来源为 `<stdin>`。错误保留文件或流名及行列;文件读取与非法 UTF-8 错误在进入 lexer 前返回。命令仍不执行源码。
|
||||
CLI parse 文件通过 from_file → parse_source 输出 AST;`cli parse -` 通过 from_stream 读取 stdin 到 EOF,来源为 `<stdin>`。错误保留文件或流名及行列;文件读取与非法 UTF-8 错误在进入 lexer 前返回。parse 不执行源码;run/eval 使用相同阅读器后进入 [Compiler](compiler.md),支持范围见该契约。
|
||||
|
||||
stdin 入口不是 REPL,不打印提示符、不保持求值环境,也不区分“需要继续输入”和“真正语法错误”。未来 REPL 宿主先收集一次提交的输入单元,再使用 from_text 并指定会话来源;reader 不承担交互调度。包与 namespace 的成员查找和依赖解析也不由 reader 自动完成。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user