用 C# 从零实现 Lua 5.5 的学习项目。
这个项目的目标不是做最快的 Lua 实现,而是用最清楚的方式把 Lua 5.5 的运行机制拆开给你看——每一步先写文档说清楚要做什么、为什么做,再写代码和测试把它钉住。
简单说:用 C# 重写 Lua 5.5 的完整运行时。
它能做什么?
- 读取 Lua 5.5 编译出的字节码文件(
.luac) - 执行字节码,跑出和官方 Lua 一样结果
- 支持表、闭包、元方法、标准库函数等核心语言特性
最终目标是:能接受并运行官方 Lua 5.5 编译器能接受的 Lua 源码。
# 运行全部测试
dotnet test lua-net.sln
# 启动交互式 REPL
dotnet run --project src/Lua.Cli
# 执行 Lua 脚本
dotnet run --project src/Lua.Cli -- script.lua arg1 arg2
# 查看解决方案结构
dotnet sln lua-net.sln list工具链基线:.NET 10 / net10.0
整个项目按 路线图 分 16 步推进,每一步先写文档,再写代码和测试:
| 阶段 | 主题 | 状态 |
|---|---|---|
| 第 1 步 | 基础基线与规范对齐 | 已完成 |
| 第 2 步 | 运行时值模型 | 已完成 |
| 第 3 步 | 字节码加载与反汇编 | 已完成 |
| 第 4 步 | VM 骨架与指令执行 | 已完成 |
| 第 5 步 | 调用、闭包、上值、可变参数 | 已完成 |
| 第 6 步 | 表与元表 | 已完成 |
| 第 7 步 | 基础库核心函数 | 已完成 |
| 第 8 步 | table / math / utf8 基础库 |
已完成 |
| 第 9 步 | string 库与模式匹配 | 已完成 |
| 第 10 步 | coroutine 库 | 已完成 |
| 第 11 步 | 词法分析 | 已完成 |
| 第 12 步 | 语法分析与 AST | 已完成 |
| 第 13 步 | 编译器(AST → 字节码) | 已完成 |
| 第 14 步 | io / os / package / debug 库 | 已完成 |
| 第 15 步 | 字节码序列化与 REPL | 已完成 |
| 第 16 步 | 兼容性收口 | 进行中 |
当前 310 个测试全部通过。Step 1–15 已全部完成,正在进行 Step 16(兼容性收口)。
当前官方 Lua 5.5.0 compatibility 已正式转绿 6 个脚本:bwcoercion.lua、bitwise.lua、locals.lua、gengc.lua、gc.lua、attrib.lua。下一步可以继续扩展更多官方脚本接入,例如 api.lua。
src/
├── Lua.Runtime/ 运行时值系统与执行基础设施
│ ├── Values/ LuaValue, LuaValueKind, LuaValueHelper
│ ├── Objects/ LuaTable, LuaClosure, LuaUserData, IMetatableOwner
│ └── Execution/ LuaState, LuaStack, CallFrame, LuaUpvalue
├── Lua.Bytecode/ Lua 5.5 字节码格式与反汇编
│ ├── Chunks/ LuaChunk, LuaPrototype, LuaChunkReader
│ ├── Instructions/ LuaOpcode(85), LuaInstruction, 指令格式与布局
│ └── Disassembly/ LuaDisassembler, LuaLineInfoResolver
├── Lua.Syntax/ 词法分析、语法分析与 AST 前端
│ ├── Lexing/ LuaLexer, LuaToken, LuaSourceRange
│ ├── Ast/ 语法树节点(chunk/block/statement/expression)
│ └── Parsing/ LuaParser
├── Lua.Compiler/ AST 到 LuaPrototype 的源码编译器
│ ├── LuaCompiler.cs 作用域解析、寄存器分配、语句/表达式降级
│ └── LuaCompilerException.cs 源码编译错误
├── Lua.VM/ 虚拟机执行引擎(按职责拆分为 partial class)
│ ├── LuaVirtualMachine.cs 核心执行循环与公共 API
│ ├── LuaVirtualMachine.Arithmetic.cs 算术、位运算、拼接、长度
│ ├── LuaVirtualMachine.Comparison.cs 相等性、有序比较、条件跳转
│ ├── LuaVirtualMachine.TableAccess.cs 表读写与 __index/__newindex 链
│ ├── LuaVirtualMachine.Metamethods.cs 元方法解析与分发
│ ├── LuaVirtualMachine.ControlFlow.cs 循环、vararg、泛型 for、跳转
│ ├── LuaVirtualMachine.Helpers.cs 寄存器、上值、常量、资源清理
│ └── Closures/ LuaBytecodeClosureBody
├── Lua.Cli/ REPL、脚本执行入口与命令行参数处理
└── Lua.Core/ 共享二进制 chunk 工具(早期遗留)
test/
├── Lua.Compatibility.Tests/ 官方 Lua 5.5.0 脚本兼容性测试(6 个)
├── Lua.Cli.Tests/ CLI / REPL / 脚本入口测试(5 个)
├── Lua.Runtime.Tests/ 运行时单元测试(93 个)
├── Lua.Bytecode.Tests/ 字节码解析测试(15 个)
├── Lua.Syntax.Tests/ 词法分析与语法分析测试
├── Lua.Compiler.Tests/ 编译器与文本 chunk 集成测试(46 个)
├── Lua.VM.Tests/ VM 集成测试(111 个,使用真实 Lua 5.5 chunk fixture)
└── Lua.Core.Test/ Lua.Core 测试
docs/ 阶段规划和设计文档(57 份)
references/lua-5.5.0/ 官方 Lua 5.5.0 源码参考
| 编号 | 文档 | 主题 |
|---|---|---|
| 001 | roadmap | 总路线图与 16 步阶段计划 |
| 002 | foundation | 基础基线(目标版本、模块边界、测试策略) |
| 003 | source-reference | 官方源码参考策略 |
| 编号 | 文档 | 主题 |
|---|---|---|
| 004 | runtime-model | 运行时模型设计(LuaValue, LuaStack, LuaState 等) |
| 编号 | 文档 | 主题 |
|---|---|---|
| 005 | bytecode-loader | 字节码格式、指令解码、反汇编 |
| 编号 | 文档 | 主题 |
|---|---|---|
| 006 | vm-skeleton | VM 核心执行循环与全部已支持指令 |
| 007 | table-access | 最小表构造与原始表访问 |
| 015 | load-opcodes | LOADF / LOADKX / LFALSESKIP |
| 016 | setlist | SETLIST 与数组批量写入 |
| 018 | loops | 数值 for、泛型 for、while |
| 019 | repeat-global-checks | repeat/until 与 global 声明检查 |
| 编号 | 文档 | 主题 |
|---|---|---|
| 008 | self-call | SELF 指令与 : 方法调用 |
| 009 | global-environment | _ENV 与全局变量读写 |
| 010 | upvalue-cells | 共享上值 cell 与闭包捕获 |
| 011 | close | CLOSE 与块作用域上值关闭 |
| 012 | tbc | TBC 的 nil/false 快速路径 |
| 013 | close-metamethod | __close 生命周期 |
| 014 | close-errors | __close 错误传播 |
| 017 | vararg-open-results | VARARG 与开放结果协议 |
| 020 | vararg-table | 具名 vararg 参数与 vararg table |
| 编号 | 文档 | 主题 |
|---|---|---|
| 021 | binary-metamethods | __add / __sub 等二元算术与位运算元方法 |
| 022 | length-concat-compare | __len / __concat / __eq / __lt / __le |
| 023 | unary-call | __unm / __bnot / __call |
| 024 | table-metamethods | __index / __newindex 表访问元方法 |
| 025 | userdata-metamethods | userdata 的全套元方法 |
| 编号 | 文档 | 主题 |
|---|---|---|
| 026 | base-metatable-raw | getmetatable / rawget / rawset / rawlen / rawequal |
| 027 | base-core | type / assert / select / pcall |
| 028 | xpcall | xpcall 与 message handler |
| 029 | number-string-conversion | tonumber / tostring |
| 030 | table-iteration-functions | next / pairs / ipairs |
| 031 | print-warn-functions | print / warn |
| 032 | string-metamethods | 最小 string 表、字符串元表与字符串算术 |
| 033 | load-dofile-functions | load / loadfile / dofile 的二进制 chunk 路径 |
| 034 | collectgarbage-require-functions | collectgarbage 与最小 require / package |
| 编号 | 文档 | 主题 |
|---|---|---|
| 035 | table-math-utf8-libraries | table / math / utf8 基础库 |
| 编号 | 文档 | 主题 |
|---|---|---|
| 036 | string-library-patterns | 完整 string 库、Lua 模式匹配与二进制 pack/unpack |
| 编号 | 文档 | 主题 |
|---|---|---|
| 037 | coroutine-library | coroutine 库、显式调用栈与挂起恢复 |
| 编号 | 文档 | 主题 |
|---|---|---|
| 038 | lexical-analysis | Lua.Syntax、token 流、字符串/注释/数字字面量扫描 |
| 编号 | 文档 | 主题 |
|---|---|---|
| 039 | syntax-analysis-ast | AST 节点、LuaParser、表达式/语句解析与语法错误 |
| 编号 | 文档 | 主题 |
|---|---|---|
| 040 | compiler-first-cut | Lua.Compiler、作用域/上值解析、文本 chunk 执行链路 |
| 编号 | 文档 | 主题 |
|---|---|---|
| 041 | package-system | package.config / searchpath / loadlib / C searcher |
| 编号 | 文档 | 主题 |
|---|---|---|
| 042 | bytecode-dump | LuaChunkWriter、string.dump、debug info strip 与二进制 roundtrip |
| 043 | cli-repl | Lua.Cli、REPL、脚本执行入口、arg 注入与参数解析 |
| 编号 | 文档 | 主题 |
|---|---|---|
| 044 | userdata-uservalues | LuaUserData 多槽位 user value、debug.getuservalue / setuservalue |
| 045 | official-test-suite | 官方 Lua 5.5.0 测试集接入、compatibility harness 与当前缺口量化 |
| 046 | vararg-functions | vararg 函数定义、... 多返回编译与 {...} 表构造展开 |
| 047 | for-loops-bitwise | 源码 for 编译、逻辑右移修正、bitwise.lua 转绿与下一缺口推进 |
| 048 | local-variable-attributes | 局部变量 <const> / <close>、作用域 CLOSE 与 locals.lua 缺口推进 |
| 049 | locals-close-runtime | goto / label、__close / error / traceback 语义修正与 locals.lua 当前 hook 缺口 |
| 050 | return-hooks | debug.sethook / gethook、return hook 触发顺序与 locals.lua 当前 coroutine close/yield 缺口 |
| 051 | coroutine-close-continuations | coroutine close continuation、return / CLOSE suspend-resume 与当前 protected-call 恢复缺口 |
| 052 | yieldable-protected-calls | yieldable pcall / xpcall、error-unwind __close continuation 与 locals.lua 转绿 |
| 053 | gc-api-modes | collectgarbage mode / param API、gengc.lua 缺口推进到 weak tables |
| 054 | weak-tables | 弱表 __mode 语义、live register 清理、gengc.lua 转绿与 gc.lua ephemeron 缺口 |
| 055 | gc-finalizers-ephemerons | __gc 终结器、自动 GC、ephemeron 固定点传播与 gc.lua 当前 count 缺口 |
| 056 | gc-count-official-gc | collectgarbage("count") Lua 侧估算、GC 不可重入返回语义与 gc.lua 转绿 |
| 057 | attrib-compatibility | attrib.lua compatibility 收口、工作目录/无 BOM IO、主 chunk vararg 与 large integer/float 边界修正 |
- 先明确阶段目标
- 先在
docs/里写阶段文档 - 再写最小可用实现
- 用测试把当前阶段钉住
- 再进入下一步
官方资料使用顺序:Lua 5.5 手册 → 官方源码 → 落实到 C# 代码和测试