unluac 1.2.4

Multi-dialect Lua decompiler written in Rust.
Documentation
# Parser

> **职责**:把某个 dialect 的字节流解析成保真的 raw 模型,一次性固化后层恢复会依赖的所有协议事实。
>
> **不负责**:lowering 语义、CFG 切块、任何推断。
>
> **例子**`bytes(lua54)``parse_chunk_with_dialect(DecompileDialect::Lua54, ...)``Lua54Parser``RawChunk{ header, protos: [RawProto{...}] }`

## 入口

```text
src/parser/mod.rs
  parse_input(state, context)          -- pipeline Parse stage 入口
  parse_chunk_with_dialect(DecompileDialect, bytes, options) -- 按显式 dialect 分派,不做版本自动探测
```

## 模块布局

当前 parser 目录先按“公共入口 / 协议家族共享 / 真实 dialect”分层:

```text
src/parser/
  mod.rs           入口 + 版本分派
  raw/
    mod.rs         统一 raw 模型 re-export(后层消费这里,不直接碰 dialect 内部)
    model.rs       RawChunk / RawProto / RawInstr 等通用模型
    dialect.rs     Dialect*Extra / opcode / operand wrapper 与 accessor
    format.rs      raw instruction 紧凑格式化
  reader.rs        BinaryReader:varint / endian / 字节级读取
  strings.rs       跨 dialect 的 RawString 构造与文本解码
  options.rs       ParseOptions(ParseMode / StringEncoding / StringDecodeMode)
  error.rs         ParseError
  debug/
    mod.rs         dump_parser stage 入口与 dialect 分派
    common.rs      proto traversal / focus / RawString / literal / origin 通用展示
  family/
    puc_lua/
      header.rs           PUC-Lua chunk header 解析
      layout.rs           基于 raw header layout 的字段读取 helper
      instruction.rs      指令编解码
      proto.rs            proto 读取骨架
      sections.rs         debug section 驱动
      macros.rs           define_puc_lua_opcodes! / define_puc_lua_instruction_codec!
  dialect/
    opcodes.rs            define_opcode_enum! / define_opcode_kind_table! 宏
    lua51/ ... lua55/     各版本:mod.rs / parser.rs / raw.rs / debug.rs
    luajit/               同上
    luau/                 同上
```

## 目录重构目标

下一轮 parser 结构调整以“把真实边界显式化”为目标,而不是把所有 dialect 塞进同一套抽象:

```text
src/parser/
  mod.rs                 入口 + 显式 dialect 分派
  error.rs               ParseError
  options.rs             ParseOptions
  reader.rs              BinaryReader 与字节级读取
  strings.rs             跨 dialect 的 RawString 构造与文本解码
  raw/
    mod.rs               对外 re-export,保持后层引用入口稳定
    model.rs             RawChunk / ChunkHeader / RawProto / RawInstr 等通用模型
    dialect.rs           Dialect*Extra / opcode / operand 包装枚举与 accessor
    format.rs            raw instruction / literal / origin 的展示格式化
  family/
    puc_lua/             Lua 5.1~5.5 共享协议骨架,不是可选 dialect
  dialect/
    opcodes.rs           dialect opcode 宏
    lua51/ ... lua55/    真实 PUC-Lua dialect,逐步变成薄 parser adapter
    luajit/              LuaJIT dump 协议,保留独立 family 边界
    luau/                Luau serialized bytecode,保留独立 family 边界
  debug/
    mod.rs               dump_parser stage 入口
    common.rs            proto traversal / focus / RawString / literal / origin 通用展示
    puc_lua.rs           PUC-Lua parser debug renderer,共享 header/tree/constant/instr 框架
```

这轮重构的核心判断:PUC-Lua 5.x 可以继续收敛共享骨架;LuaJIT 与 Luau 的 chunk 协议、常量池和 proto 组织方式差异足够大,只做本目录内拆分和通用格式化复用,不强行并入 PUC-Lua 抽象。

## 迁移顺序

1. **已完成:拆分 raw 模型文件**`raw.rs` 已拆成 `raw/model.rs``raw/dialect.rs``raw/format.rs`,并在 `raw/mod.rs` 保留原有 re-export,保证 transformer 和 wasm rich output 的引用入口不变。
2. **已完成:抽出 parser debug 公共层**:proto traversal、focus plan、RawString/literal/origin 格式化已移到 `debug/common.rs`。后续如果继续压缩 Lua 5.1~5.4 的重复 renderer,再新增 `debug/puc_lua.rs`3. **已完成:补齐 Lua 5.1 instruction/string skeleton**:Lua 5.1 已复用 `family/puc_lua` 的 instruction section、layout 读取和 `strings.rs` 的 RawString 构造;helper-word 策略支持 Lua 5.1 `SETLIST` raw word 与 Lua 5.2+ `EXTRAARG` 共用“绑定后继 word”骨架。
4. **已完成:收缩空 extra**:空 payload struct 已改为 `Dialect*Extra` 的 unit variant;保留 Lua 5.4/5.5 upvalue/debug、LuaJIT、Luau 常量等真正携带协议事实的 extra。
5. **已完成:抽出跨 dialect 字符串 helper**`strings.rs` 现在由 PUC-Lua、LuaJIT、Luau 共同复用。后续如果需要进一步降低单文件长度,再把 LuaJIT 按 header/proto/constants/debug、Luau 按 string table/proto table/constants/debug/proto tree rebuild 做本目录内拆分。

## 不做的统一

- 不把 LuaJIT / Luau 套进 `family/puc_lua` 或 PUC-Lua parser skeleton。
- 不为了减少枚举数量而丢掉 dialect typed opcode / operand;后层仍应能通过 typed accessor 获得明确协议事实。
- 不在 parser 后层为前层缺失事实兜底;如果 parser 发现某个协议事实需要给 transformer 消费,应先在 raw 模型中明确建模。
- 不恢复文档里曾出现过的 `parse_chunk` 自动探测入口,除非先明确它是公开 API 需求。

## 重构验证

每个会改动业务代码的批次完成后,必须至少运行:

```bash
cargo clippy --workspace --all-targets --all-features --locked -- -D warnings
cargo unit-test --jobs 8
```

## 数据流

```text
bytes
  └─ parse_chunk_with_dialect
       └─ Lua54Parser::parse(bytes)       -- dialect/lua54/parser.rs
            ├─ BinaryReader               -- reader.rs
            ├─ family::puc_lua::read_header -- family/puc_lua/header.rs
            ├─ family::puc_lua::read_proto  -- family/puc_lua/proto.rs
            └─ RawChunk { header, main proto tree }
                  └─ RawProto { instrs, consts, upvalues, children, debug_info, extra }
```

## 应优先复用的共享设施

| 设施 | 用途 |
| --- | --- |
| `BinaryReader` | 所有字节级读取,含 `read_varint_u32_lua54` / `read_u32_le`|
| `define_puc_lua_opcodes!` | 声明 opcode enum + label table,避免手写大段 match |
| `define_puc_lua_instruction_codec!` | operand 编解码共享骨架 |
| `family/puc_lua/proto.rs` | PUC-Lua 家族 proto 读取骨架,lua52~55 不应各自复制 |
| `strings.rs` | 跨 dialect 的 `RawString` 构造与文本解码 |
| `raw/mod.rs` accessor | 后层消费协议事实的正式入口 |

## 维护规范

1. **协议事实必须在 parser/raw 收口**:来源于字节编码(而非运行语义)的事实必须在此固化。  
   - 典型:`EXTRAARG` 与前一条指令的绑定、Luau closure const 到 child proto slot 映射、Lua 5.5 字符串复用展开。  
   - 边界:`local <const>` 不是 parser 能从 chunk 读出的——只有 `local <close>` 依赖运行时语义线索。
2. **parser.rs 只负责按协议顺序读取**:opcode label 大表、operand decode 大表应放到 opcode 宏或共享设施。
3. **raw/ 只保存稳定事实**:只有后层实际消费的 typed extra 和 accessor,不保存单次读取的临时中间态。
4. **dialect debug.rs 只展示本 dialect 产物**:不做跨 dialect 判断,不重新校验 parser 已保证的版本约束。
5. **错误在 parser 边界暴露**:协议不合法优先报 `ParseError`,不拖到 transformer 再暴露。

## 向后提供的事实

`RawChunk` / `ChunkHeader` / `RawProto` / `RawInstr` / `RawConstPool` / `RawUpvalueInfo` / `RawDebugInfo` / `RawString` / 各 dialect raw extra。

## 排错指引

| 症状 | 检查点 |
| --- | --- |
| 指令数量 / 常量数量解析错误 | `family/puc_lua/sections.rs` 长度字段读取 |
| opcode 识别失败 | `dialect/opcodes.rs` 宏展开是否漏了某个 opcode |
| extra-word 绑定错位 | `parser.rs` EXTRAARG 绑定逻辑 |
| raw accessor 返回 None | `raw/dialect.rs` extra 类型是否与 dialect 版本匹配 |
| 想看 raw 结构 | `unluac --dialect lua54 --debug --target-stage parse <file>` |