Skip to main content

lua_assembler/program/
mod.rs

1use serde::{Deserialize, Serialize};
2use std::fmt::Debug;
3
4#[derive(Clone, Debug, PartialEq, Eq, Copy)]
5pub enum LuaVersion {
6    Unknown,
7    Lua51,
8    Lua52,
9    Lua53,
10    Lua54,
11    LuaJIT,
12    Luau,
13}
14
15impl LuaVersion {
16    pub fn to_byte(&self) -> u8 {
17        match self {
18            LuaVersion::Lua51 => 0x51,
19            LuaVersion::Lua52 => 0x52,
20            LuaVersion::Lua53 => 0x53,
21            LuaVersion::Lua54 => 0x54,
22            _ => 0x00, // Default or unknown version
23        }
24    }
25
26    pub fn from_byte(byte: u8) -> Self {
27        match byte {
28            0x51 => LuaVersion::Lua51,
29            0x52 => LuaVersion::Lua52,
30            0x53 => LuaVersion::Lua53,
31            0x54 => LuaVersion::Lua54,
32            _ => LuaVersion::Unknown,
33        }
34    }
35}
36
37#[derive(Clone, PartialEq, Eq, Copy)]
38pub struct LuacHeader {
39    pub magic: [u8; 4], // "\x1bLua"
40    pub version: LuaVersion,
41    pub format_version: u8,     // LUAC_FORMAT, usually 0
42    pub endianness: u8,         // 0x01 for little-endian, 0x00 for big-endian
43    pub int_size: u8,           // sizeof(int)
44    pub size_t_size: u8,        // sizeof(size_t)
45    pub instruction_size: u8,   // sizeof(Instruction)
46    pub lua_number_size: u8,    // sizeof(lua_Number)
47    pub integral_flag: u8,      // 0x00 if lua_Number is float, 0x01 if integral
48    pub flags: u8,              // 新增字段
49    pub timestamp: Option<u32>, // 新增字段
50    pub size: Option<u32>,      // 新增字段
51    pub hash: Option<[u8; 8]>,  // 新增字段
52}
53
54impl Debug for LuacHeader {
55    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56        f.debug_struct("LuacHeader")
57            .field("version", &self.version)
58            .field("magic", &format!("0x{:08X}", u32::from_le_bytes(self.magic)))
59            .field("flags", &format!("0x{:02X}", self.flags))
60            .field("timestamp", &self.timestamp)
61            .field("size", &self.size)
62            .field("hash", &self.hash.as_ref().map(|h| format!("{:02X?}", h)))
63            .finish()
64    }
65}
66
67impl LuacHeader {
68    pub fn to_bytes(&self) -> Vec<u8> {
69        let mut bytes = Vec::new();
70        bytes.extend_from_slice(&self.magic);
71        bytes.push(self.version.to_byte());
72        bytes.push(self.format_version);
73        bytes.push(self.endianness);
74        bytes.push(self.int_size);
75        bytes.push(self.size_t_size);
76        bytes.push(self.instruction_size);
77        bytes.push(self.lua_number_size);
78        bytes.push(self.integral_flag);
79        bytes.push(self.flags);
80
81        if self.flags & 0x01 != 0 {
82            // SOURCE_HASH_MODE
83            if let Some(hash_val) = self.hash {
84                bytes.extend_from_slice(&hash_val);
85            }
86            else {
87                // This should not happen if flags indicate hash mode
88                // For now, let's just write 8 zero bytes as a fallback
89                bytes.extend_from_slice(&[0; 8]);
90            }
91        }
92        else {
93            // Timestamp and size mode
94            if let Some(timestamp_val) = self.timestamp {
95                bytes.extend_from_slice(&timestamp_val.to_le_bytes());
96            }
97            else {
98                // This should not happen if flags indicate timestamp mode
99                bytes.extend_from_slice(&[0; 4]);
100            }
101            if let Some(size_val) = self.size {
102                bytes.extend_from_slice(&size_val.to_le_bytes());
103            }
104            else {
105                // This should not happen if flags indicate timestamp mode
106                bytes.extend_from_slice(&[0; 4]);
107            }
108        }
109        bytes
110    }
111}
112
113/// Upvalue 信息
114#[derive(Debug, Clone, PartialEq, Eq)]
115pub struct Upvalue {
116    pub in_stack: u8, // 1 if in stack, 0 if in outer upvalue
117    pub idx: u8,      // register or upvalue index
118    pub name: String, // for debug info
119}
120
121/// 局部变量信息
122#[derive(Debug, Clone, PartialEq, Eq)]
123pub struct LocalVar {
124    pub name: String,
125    pub start_pc: u32,
126    pub end_pc: u32,
127}
128
129#[derive(Debug, Clone, PartialEq, Eq)]
130pub enum LuaObject {
131    Str(String),
132    Int(i32),
133    Code(LuacCodeObject),
134    None,
135}
136
137/// Lua 操作码
138#[allow(non_camel_case_types)]
139#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
140pub enum LuaOpCode {
141    MOVE,
142    LOAD_K,
143    LOAD_BOOL,
144    LOAD_NIL,
145    GET_UPVALUE,
146    GET_GLOBAL,
147    GET_TABLE,
148    SET_TABLE,
149    NEW_TABLE,
150    SET_GLOBAL,
151    SET_UPVALUE,
152    SELF,
153    ADD,
154    SUB,
155    MUL,
156    DIV,
157    MOD,
158    POW,
159    UNM,
160    NOT,
161    LEN,
162    CONCAT,
163    JMP,
164    EQ,
165    LT,
166    LE,
167    TEST,
168    TESTSET,
169    CALL,
170    TAILCALL,
171    RETURN,
172    FORLOOP,
173    TFORLOOP,
174    SETLIST,
175    CLOSE,
176    CLOSURE,
177    VARARG,
178    // Add more opcodes as needed
179    UNKNOWN(u8),
180}
181
182impl From<u8> for LuaOpCode {
183    fn from(byte: u8) -> Self {
184        match byte {
185            0 => LuaOpCode::MOVE,
186            1 => LuaOpCode::LOAD_K,
187            2 => LuaOpCode::LOAD_BOOL,
188            3 => LuaOpCode::LOAD_NIL,
189            4 => LuaOpCode::GET_UPVALUE,
190            5 => LuaOpCode::GET_GLOBAL,
191            6 => LuaOpCode::GET_TABLE,
192            7 => LuaOpCode::SET_GLOBAL,
193            8 => LuaOpCode::SET_UPVALUE,
194            9 => LuaOpCode::SET_TABLE,
195            10 => LuaOpCode::NEW_TABLE,
196            11 => LuaOpCode::SELF,
197            12 => LuaOpCode::ADD,
198            13 => LuaOpCode::SUB,
199            14 => LuaOpCode::MUL,
200            15 => LuaOpCode::DIV,
201            16 => LuaOpCode::MOD,
202            17 => LuaOpCode::POW,
203            18 => LuaOpCode::UNM,
204            19 => LuaOpCode::NOT,
205            20 => LuaOpCode::LEN,
206            21 => LuaOpCode::CONCAT,
207            22 => LuaOpCode::JMP,
208            23 => LuaOpCode::EQ,
209            24 => LuaOpCode::LT,
210            25 => LuaOpCode::LE,
211            26 => LuaOpCode::TEST,
212            27 => LuaOpCode::TESTSET,
213            28 => LuaOpCode::CALL,
214            29 => LuaOpCode::TAILCALL,
215            30 => LuaOpCode::RETURN,
216            31 => LuaOpCode::FORLOOP,
217            32 => LuaOpCode::TFORLOOP,
218            33 => LuaOpCode::SETLIST,
219            34 => LuaOpCode::CLOSE,
220            35 => LuaOpCode::CLOSURE,
221            36 => LuaOpCode::VARARG,
222            _ => LuaOpCode::UNKNOWN(byte),
223        }
224    }
225}
226
227/// Lua 指令结构
228#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
229pub struct LuaInstruction {
230    pub opcode: LuaOpCode,
231    pub a: u8,
232    pub b: u8,
233    pub c: u8,
234    pub bx: u16,
235    pub sbx: i16,
236    pub ax: u32,
237}
238
239#[derive(Debug, Clone, PartialEq, Eq)]
240pub struct LuacCodeObject {
241    pub source_name: String,
242    pub first_line: u32,
243    pub last_line: u32,
244    pub num_params: u8,
245    pub is_vararg: u8,
246    pub max_stack_size: u8,
247    pub nested_functions: Vec<LuacCodeObject>,
248    pub upvalues: Vec<Upvalue>,
249    pub local_vars: Vec<LocalVar>,
250    pub line_info: Vec<u8>,
251    pub co_argcount: u8,
252    pub co_nlocal: u8,
253    pub co_stacks: u8,
254    pub num_upval: u8,
255    pub co_code: Vec<u32>,
256    pub co_consts: Vec<LuaObject>,
257    pub upvalue_n: u8,
258}
259
260/// Python .pyc 程序的高层语义定义(以指令序列为核心)
261#[derive(Debug, Clone, PartialEq, Eq)]
262pub struct LuaProgram {
263    pub header: LuacHeader,
264    pub code_object: LuacCodeObject,
265}