Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
e907c33
添加可选链操作符支持 (?. ?: ?[ ?(,由 BEE_OPTCHAIN 宏启用)
sumneko Aug 13, 2026
6d439db
fix: 修正 optchain 补丁源路径(目录为 lua55/lua54,而非 55/54)
sumneko Aug 13, 2026
03cca5d
诊断完全忽略新的测试文件
sumneko Aug 13, 2026
2b799ee
feat(optchain): 新增 OP_SETTOP 指令,多值短路精确设置栈顶
sumneko Aug 13, 2026
081f0dd
跳过诊断使用完整路径
sumneko Aug 13, 2026
6edc608
fix(optchain): 用 luaK_reserveregs 分配 nil 临时寄存器
sumneko Aug 14, 2026
d4d7b5b
test(optchain): 补充带参数的可选调用测试用例
sumneko Aug 14, 2026
6adf8c6
refactor(optchain): 补丁直接写入官方源码,删除整文件复制
sumneko Aug 17, 2026
7041f7e
refactor(optchain): 改为 git diff 补丁 + 构建时 apply
sumneko Aug 19, 2026
6a42cd4
fix(optchain): source_set 用 objdeps 保证 apply_patch 先于 obj 编译
sumneko Aug 25, 2026
0a49f07
refactor(optchain): 用 luamake 依赖规则重写补丁构建,消除硬编码
sumneko Sep 2, 2026
5e85bdf
refactor(optchain): 按 review 意见简化补丁脚本与构建配置
sumneko Sep 2, 2026
61c5007
refactor(optchain): 自查清理:精确依赖、去死代码
sumneko Sep 2, 2026
70c2484
refactor(optchain): 删除补丁内冗余的 BEE_OPTCHAIN 门控
sumneko Sep 3, 2026
03f5850
增加一个test
actboy168 Sep 3, 2026
96d55a6
fix(optchain): OP_SETTOP 的 B 字段在 nresults==0 时越界写入 255
sumneko Sep 3, 2026
de81fa0
refactor(optchain): 删除 LUA_MULTRET 的空操作调用点
sumneko Sep 3, 2026
983c92b
fix(optchain): findsetreg 支持 OP_SETTOP
sumneko Sep 3, 2026
4d5365c
style(optchain): 自查清理注释与格式
sumneko Sep 3, 2026
f9affa6
git补丁通用化
actboy168 Sep 4, 2026
d9e44a3
为补丁添加文档
actboy168 Sep 4, 2026
6b01b44
增加CI测试
actboy168 Sep 4, 2026
2f2cca0
fix(optchain): ljumptab 补丁与 debug 构建的 top 断言冲突
sumneko Sep 4, 2026
13f764a
docs(optchain): README 同步补丁文件清单与配套说明
sumneko Sep 4, 2026
cf7df87
fix(optchain): lua54 补丁补充缺失的 debug 断言豁免
sumneko Sep 4, 2026
45d54e3
增加几个测试
actboy168 Sep 4, 2026
b5b06a3
fix(optchain): luaG_traceexec hook 下重置 top 破坏 open call 结果数
sumneko Sep 4, 2026
39483d4
增加lua54的测试
actboy168 Sep 4, 2026
7f75478
使用subprocess代替os.execute
actboy168 Sep 5, 2026
af4b723
简化代码
actboy168 Sep 5, 2026
c1095e7
优化代码生成
actboy168 Sep 7, 2026
54873e9
docs(optchain): README 同步 luaK_jumpifnil 代码生成
sumneko Sep 7, 2026
6df580b
fix(optchain): apply_lua_patch 参数用 @ 锚定到本工程目录
sumneko Sep 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 21 additions & 30 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,35 @@
name: test
on: push
jobs:
windows-x86:
name: windows (x86)
runs-on: windows-latest
test:
strategy:
fail-fast: false
matrix:
os:
- ubuntu-22.04
- ubuntu-24.04-arm
- windows-latest
- macos-14
- macos-15
- macos-26
- macos-15-intel
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actboy168/setup-luamake@master
- run: luamake -arch x86 -notest -sanitize
- run: luamake -notest -sanitize
- run: luamake test -v
windows-x86_64:
name: windows (x86_64)
- run: luamake -notest -sanitize -optchain
- run: luamake test -v
- run: luamake -notest -sanitize -optchain -lua 54
- run: luamake test -v
windows-x86:
name: windows (x86)
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actboy168/setup-luamake@master
- run: luamake -arch x86_64 -notest -sanitize
- run: luamake -arch x86 -notest -sanitize
- run: luamake test -v
windows-clang:
name: windows (clang)
Expand Down Expand Up @@ -48,29 +62,6 @@ jobs:
run: |
./luamake/luamake -notest
./luamake/luamake test -v
macos:
strategy:
fail-fast: false
matrix:
os: [14, 15, 26, 15-intel]
runs-on: macos-${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actboy168/setup-luamake@master
- run: luamake -notest -sanitize
- run: luamake test -v
linux:
strategy:
fail-fast: false
matrix:
os: [22.04, 24.04-arm]
runs-on: ubuntu-${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actboy168/setup-luamake@master
- run: luamake -notest -sanitize
- run: luamake lua test/glibc-version.lua
- run: luamake test -v
linux-qemu:
strategy:
fail-fast: false
Expand Down
9 changes: 7 additions & 2 deletions .luarc.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@
"code-after-break": "Warning",
"empty-block": "Warning",
"trailing-space": "Warning"
}
},
"ignoredFiles": "Disable"
},
"workspace.checkThirdParty": false
"workspace.checkThirdParty": false,
"workspace.ignoreDir": [
".vscode",
"test/test_optional_chain.lua"
]
Comment thread
Copilot marked this conversation as resolved.
}
52 changes: 52 additions & 0 deletions 3rd/lua-patch/optchain/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# 可选链(Optional Chaining)补丁

## 概述

为 Lua 添加可选链操作符支持,语法与语义对齐 ES2020 的 `?.`,包含四种形式:

- `x?.y` — 字段访问
- `x?:f()` — 方法调用
- `f?()` — 函数调用
- `t?[1]` — 索引访问

支持任意链式组合,如 `a?.b.c`、`a?.b?.c`、`obj?:get()?.x`。

## 实现方式

以 git diff 补丁形式存放在本目录(`lua54.patch` / `lua55.patch`),通过通用补丁基础设施(见 `AGENT.md` 的「自定义 Lua 补丁」)在构建期应用:`luamake -optchain` 时把官方源码整树复制到 `$builddir/patched/lua<ver>/` 并 `git apply` 本补丁。

补丁直接修改 `lparser.c` / `lvm.c` / `lopcodes.*` / `lopnames.h` / `ljumptab.h` / `ldebug.c` / `luac.c` / `lcode.c`(含 `lcode.h`),**无 `#ifdef` 门控**——门控完全在构建层:是否打补丁由注册表里的 `optchain` 开关决定,默认构建不打补丁、直接编译官方源码,行为零影响。

- **解析器(`lparser.c`)**:`?.` 在编译期展开为标准指令组合(nil 检查由 `lcode.c` 新增的 `luaK_jumpifnil` 生成:nil 常量索引可容纳时用 `EQK + JMP`,每节仅 2 条指令;索引过大时回退 `EQ` + 临时 nil 寄存器;链末非调用的短路填充用 `LOADNIL`);
- **新增指令 `OP_SETTOP`**:链末调用(`f?()`、`obj?:m()`)的短路路径使用 `CALL(k) / JMP / OP_SETTOP` 固定布局,`OP_SETTOP` 把结果寄存器填 nil 并精确设置栈顶 `L->top`,使开放指令(`OP_RETURN` / `OP_CALL` / `OP_SETLIST`)读到恰好数量的 nil;
- `OP_SETTOP` 追加在 `OP_EXTRAARG` 之后,普通代码的指令编号完全不变,补丁版编译的普通代码与标准版字节码一致;
- 新指令的配套同步:`ljumptab.h`(GCC computed-goto 跳转表,缺项会在运行时跳转 NULL)、`ldebug.c`(`findsetreg` 寄存器归属分析)、`luac.c`(`-l` 反汇编打印)、`lcode.c` / `lvm.c`(debug 构建的 top 断言对「短路生产者运行期才确定」的固定布局适配)。

## 为什么需要新增指令(及备选方案)

Lua 的 `LOADNIL` 只把寄存器填为 nil,不会调整栈顶 `L->top`,因此链末调用在多值上下文(`return f?()`、`g(f?())`、`{f?()}`)短路时,开放指令会读到栈上残留的旧值,产生「nil 数量偏多」。此前考虑过不加指令的绕过方案:短路路径改为调用一个预先准备的、返回 1 个 nil 的函数——`OP_CALL` 会按实际结果数设置 `L->top`,且在固定结果数时自动补足 nil(如 `a, b, c = nilfn()` 得 3 个 nil),可精确覆盖所有短路场景,语义上可行。但该方案:

- 依赖运行时辅助函数:需要一个全局/内部注册的「nil 函数」,既污染命名空间,又可能被用户重定义而破坏短路语义;
- 真实调用开销:每次短路都走一次完整函数调用(栈帧/参数调整),远慢于一条简单指令,短路路径也需「加载函数 + 调用」两条指令;
- 语义隐晦:依赖「辅助函数返回 1 个 nil」与「CALL 自动补 nil」的间接行为。

因此最终新增 `OP_SETTOP`:一条指令同时完成「寄存器填 nil」与「精确设置栈顶」,语义直接、零运行时依赖与调用开销,且位于 `OP_EXTRAARG` 之后不影响普通代码的指令编号。

## 语义(对齐 ES2020)

- **仅 nil 短路**:`false?.a` 仍会报错(与 JS 的 `undefined` / `null` 语义对齐);
- **短路即整链**:一旦中间某节为 nil,整条链立即得到 nil,后续 key / 实参不再求值(无副作用);
- **receiver 只求值一次**:`recv()?.a?.b` 中 `recv()` 只调用一次;
- **结果不可赋值**:`obj?.a = 1` 为语法错误;
- **支持多返回值**:链末调用保留 open call,可产生多个值;短路路径精确产生对应数量的 nil:
- `return f?()` 短路 → 恰好 1 个 nil
- `g(f?())` 短路 → 恰好 1 个参数
- `{f?()}` 短路 → 恰好 1 个 nil 元素
- `a, b, c = f?()` 短路 → 3 个 nil
- 非短路时正常返回被调用函数的全部值

## 构建与测试

- 通过 `luamake -optchain` 启用;
- 新增 `test/test_optional_chain.lua`,覆盖字段 / 索引 / 方法 / 调用(含带参)/ 链式组合 / 短路副作用 / 单次求值 / 不可赋值 / 非法语法 / 多返回值(含短路精确性)等用例;
- 测试文件在默认构建下自动跳过(`test/test.lua` 用运行时 `load` 探测 `?.` 是否可用),不影响现有测试。
Loading
Loading