这是一个用 C# 从零重新实现 Lua 5.5 的学习型项目。
核心目标:
- 用清晰、可测试、可阅读的 C# 代码,完整实现 Lua 5.5 的运行时
- 最终能接受并运行官方 Lua 5.5 编译器能接受的 Lua 源码
- 整个过程按小步推进,每一步先写文档、再写代码和测试
工具链: .NET 10 / net10.0
- Lua 5.5 手册:https://www.lua.org/manual/5.5/
- Lua 5.5 变更说明:https://www.lua.org/manual/5.5/readme.html
- 官方测试集:https://www.lua.org/tests/
- 官方源码索引:https://www.lua.org/source/5.5/
- 本地参考源码:
references/lua-5.5.0/
src/Lua.Runtime 运行时值、栈、调用帧、闭包、表、状态对象
src/Lua.Bytecode 二进制块读取、指令元数据、反汇编
src/Lua.Syntax 词法分析、语法分析、AST
src/Lua.Compiler AST 到字节码的编译
src/Lua.StandardLib 基础库、table、string、math、coroutine 等
src/Lua.Cli REPL、脚本执行、诊断输出
test/Lua.*.Tests 单元测试、夹具测试、兼容性测试
不需要第一天就把所有项目建好,但新代码应该朝这个方向组织。
把目标版本锁定为 Lua 5.5,搭好项目基础。
- 明确对齐 Lua 5.5.0
- 确定模块边界和测试策略
- 本地保留官方源码作为参考
定义 Lua 运行时的核心类型。
LuaValue:统一表示 nil / 布尔 / 整数 / 浮点 / 字符串 / 表 / 函数 / 线程 / userdataLuaStack:值栈CallFrame:调用帧LuaState:整体运行时状态
正确读取 Lua 5.5 二进制块,并输出结构化结果。
- chunk 头部解析
- 指令格式和 85 个 opcode 元数据表
- 可读的反汇编输出
让真实 Lua 5.5 字节码跑起来。
- 取指、解码、执行循环
- 算术运算、比较、跳转、表构造、循环
- 85 个 opcode 全部实现基础路径
让 Lua 函数调用真正工作。
- 闭包与共享上值捕获
_ENV全局环境- 可变参数(VARARG / GETVARG / vararg table)
__close与 to-be-closed 变量
补上 Lua 最核心的数据结构。
__index/__newindex表访问元方法__add/__sub/__mul等二元算术元方法__len/__concat/__eq/__lt/__le__unm/__bnot/__call- userdata 的全套元方法
让真实脚本开始具备可运行性。
已实现:
setmetatable/getmetatable(含 protected metatable)rawget/rawset/rawlen/rawequalnext/pairs/ipairscollectgarbage(最小版本)load/loadfile/dofile(先覆盖二进制 chunk 路径)- 最小
package/require type/assert/selecttonumber/tostring(含__tostring/__name)pcall/xpcall/errorprint/warn- 最小
string表(upper/lower/len) - 字符串元表
__index - 字符串算术元方法
待补充:
这一阶段计划范围已经完成。
说明:
- 文本 chunk 的
load/loadfile路径依赖后续 Step 11-13 的源码编译链路 - 完整 package 系统、C module 与
loadlib仍然留在 Step 14 collectgarbage的更完整模式参数留待后续扩展
补上最常用的两个标准库。
已实现:
table.concat/table.insert/table.remove/table.movetable.sorttable.pack/table.unpack- 基础函数:
abs/ceil/floor/max/min/sqrt/log/exp - 三角函数:
sin/cos/tan/asin/acos/atan - 转换:
deg/rad/fmod/modf/tointeger/type - 常量:
pi/huge/maxinteger/mininteger - 位相关:
ult utf8.offset/utf8.codepoint/utf8.char/utf8.len/utf8.codes
待补充:
table.createmath.random/math.randomseedmath.frexp/math.ldexp
说明:
utf8.charpattern这一轮已经预置常量,实际消费路径要等 Step 09 的字符串模式匹配一起展开
string 库函数数量多,模式匹配引擎是独立的复杂子系统。
基础函数:
string.byte/string.char/string.lenstring.lower/string.upper/string.reverse/string.repstring.sub/string.format
模式匹配引擎:
string.find/string.match/string.gmatch/string.gsub- 字符类(
%a%d%w%s%p等) - 锚点(
^$) - 捕获(
()与位置捕获) - 平衡匹配(
%b())
二进制打包:
string.pack/string.packsize/string.unpack
需要改造 VM 调用栈以支持挂起和恢复。
coroutine.create/coroutine.resume/coroutine.yieldcoroutine.wrap/coroutine.status/coroutine.isyieldablecoroutine.close(Lua 5.4+ 新增,与__close配合)coroutine.running
支持直接输入 Lua 源码。
- 分词器:保留字、标识符、数字字面量、字符串字面量(短字符串和长字符串)
- 注释处理(短注释和长注释)
- token 流与源码位置追踪
- Lua 5.5 新增保留字:
global
- 表达式解析(优先级攀爬)
- 语句解析(赋值、if/elseif/else、while、repeat、for、do、return、break、goto/labels)
- 函数定义与方法定义
- 表构造器
global声明(Lua 5.5 新增)- 带源码位置的语法错误报告
- 作用域解析与局部变量分配
- 上值解析与闭包生成
- 寄存器分配
- 常量折叠
- 表达式降级与语句降级
- 跳转修补与控制流编译
- 常量表和原型生成
补上与宿主系统交互的库。
io 库:
io.open/io.close/io.read/io.write/io.linesio.input/io.output/io.flush/io.type- 文件句柄方法
os 库:
os.clock/os.date/os.time/os.difftimeos.execute/os.getenv/os.remove/os.rename
package 系统:
require()完整语义package.path/package.cpath/package.loadedpackage.searchpath/package.loadlib- 搜索器链与模块缓存
debug 库:
debug.getinfo/debug.getlocal/debug.setlocaldebug.getupvalue/debug.setupvaluedebug.traceback/debug.sethook/debug.gethookdebug.upvalueid/debug.upvaluejoindebug.getuservalue/debug.setuservalue
string.dump():将函数序列化为二进制 chunk(与 Step 3 对称)- 交互式 REPL(读取-求值-打印循环)
- 脚本执行入口(
lua script.lua) - 命令行参数处理
从"能跑演示"推进到"能跑真实 Lua 程序"。
- 接入官方测试集
- 补语言边角行为:
- 弱表(
__mode = "k"/"v"/"kv") __gc终结器- 多 userdata 关联值
- 错误层级(error level)与完整 traceback
- 弱表(
- 量化与官方 Lua 5.5 的差距
- 性能基线测量
以下特性是 5.5 相对于 5.4 新增或变更的,需要在对应步骤中特别关注:
| 特性 | 涉及步骤 | 说明 |
|---|---|---|
global 关键字 |
11, 12 | 新增保留字,用于声明全局变量 |
| 字符串算术元方法 | 7 | 字符串自动注册 __add / __sub 等元方法 |
| 分代式 GC 增强 | 16 | collectgarbage 的 generational/incremental 模式参数 |
| to-be-closed 完善 | 5 | __close 语义与 coroutine.close 配合 |
| 泛型 for 迭代协议变更 | 4 | 闭合值的处理方式调整 |
- 先正确再性能 — 不为了快而牺牲清晰
- 小步推进 — 每步一个纵向切片,不做大重写
- 文档先行 — 每步先写文档,再写代码和测试
- 语义对齐 — 以 Lua 5.5 手册和官方源码为准
每个实现步骤必须在 docs/ 下新增一份文档,至少包含:
- 背景和官方参考
- 本步骤范围
- 数据模型或模块设计
- 实现清单
- 完成标准
- 明确延期的内容