Skip to content

Commit 49cdbcd

Browse files
committed
update
1 parent bc3f5cc commit 49cdbcd

File tree

3 files changed

+176
-8
lines changed

3 files changed

+176
-8
lines changed

crates/luars/src/compiler/binop.rs

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
//! Binary operation compilation helpers
2+
//!
3+
//! This module consolidates the common patterns for compiling binary operations,
4+
//! eliminating code duplication in expr.rs.
5+
6+
use super::exp2reg::exp_to_any_reg;
7+
use super::expdesc::*;
8+
use super::helpers::*;
9+
use super::{Compiler, TagMethod};
10+
use crate::lua_value::LuaValue;
11+
use crate::lua_vm::{Instruction, OpCode};
12+
use emmylua_parser::BinaryOperator;
13+
14+
/// Emit arithmetic binary operation (add, sub, mul, div, idiv, mod, pow)
15+
pub fn emit_arith_op(
16+
c: &mut Compiler,
17+
op: BinaryOperator,
18+
left_reg: u32,
19+
right_desc: &mut ExpDesc,
20+
can_reuse: bool,
21+
) -> Result<u32, String> {
22+
let result_reg = if can_reuse { left_reg } else { alloc_register(c) };
23+
24+
// Check if right is a constant
25+
let is_const = matches!(right_desc.kind, ExpKind::VKInt | ExpKind::VKFlt | ExpKind::VK);
26+
27+
// Check for small integer immediate
28+
let imm_val = if let ExpKind::VKInt = right_desc.kind {
29+
let v = right_desc.ival;
30+
if v >= -256 && v <= 255 { Some(v) } else { None }
31+
} else {
32+
None
33+
};
34+
35+
// Get opcode info
36+
let (op_rr, op_rk, tm) = match op {
37+
BinaryOperator::OpAdd => (OpCode::Add, Some(OpCode::AddK), TagMethod::Add),
38+
BinaryOperator::OpSub => (OpCode::Sub, Some(OpCode::SubK), TagMethod::Sub),
39+
BinaryOperator::OpMul => (OpCode::Mul, Some(OpCode::MulK), TagMethod::Mul),
40+
BinaryOperator::OpDiv => (OpCode::Div, Some(OpCode::DivK), TagMethod::Div),
41+
BinaryOperator::OpIDiv => (OpCode::IDiv, Some(OpCode::IDivK), TagMethod::IDiv),
42+
BinaryOperator::OpMod => (OpCode::Mod, Some(OpCode::ModK), TagMethod::Mod),
43+
BinaryOperator::OpPow => (OpCode::Pow, Some(OpCode::PowK), TagMethod::Pow),
44+
_ => return Err(format!("Not an arithmetic operator: {:?}", op)),
45+
};
46+
47+
// Try immediate form for ADD/SUB
48+
if let Some(imm) = imm_val {
49+
if matches!(op, BinaryOperator::OpAdd) {
50+
let enc_imm = ((imm + 127) & 0xff) as u32;
51+
let mm_imm = ((imm + 128) & 0xff) as u32;
52+
emit(c, Instruction::encode_abc(OpCode::AddI, result_reg, left_reg, enc_imm));
53+
emit(c, Instruction::create_abck(OpCode::MmBinI, left_reg, mm_imm, tm.as_u32(), false));
54+
return Ok(result_reg);
55+
} else if matches!(op, BinaryOperator::OpSub) {
56+
// SUB uses ADDI with negated immediate
57+
let neg_imm = ((-imm + 127) & 0xff) as u32;
58+
let neg_mm = ((-imm + 128) & 0xff) as u32;
59+
emit(c, Instruction::encode_abc(OpCode::AddI, result_reg, left_reg, neg_imm));
60+
emit(c, Instruction::create_abck(OpCode::MmBinI, left_reg, neg_mm, TagMethod::Sub.as_u32(), false));
61+
return Ok(result_reg);
62+
}
63+
}
64+
65+
// Try constant form
66+
if is_const {
67+
if let Some(op_k) = op_rk {
68+
let const_idx = ensure_constant_idx(c, right_desc);
69+
emit(c, Instruction::encode_abc(op_k, result_reg, left_reg, const_idx));
70+
emit(c, Instruction::create_abck(OpCode::MmBinK, left_reg, const_idx, tm.as_u32(), false));
71+
return Ok(result_reg);
72+
}
73+
}
74+
75+
// Fall back to register form
76+
let right_reg = exp_to_any_reg(c, right_desc);
77+
emit(c, Instruction::encode_abc(op_rr, result_reg, left_reg, right_reg));
78+
emit(c, Instruction::create_abck(OpCode::MmBin, left_reg, right_reg, tm.as_u32(), false));
79+
80+
Ok(result_reg)
81+
}
82+
83+
/// Emit bitwise binary operation (band, bor, bxor, shl, shr)
84+
pub fn emit_bitwise_op(
85+
c: &mut Compiler,
86+
op: BinaryOperator,
87+
left_reg: u32,
88+
right_desc: &mut ExpDesc,
89+
can_reuse: bool,
90+
) -> Result<u32, String> {
91+
let result_reg = if can_reuse { left_reg } else { alloc_register(c) };
92+
93+
// Check for constant
94+
let is_const = matches!(right_desc.kind, ExpKind::VKInt | ExpKind::VK);
95+
96+
// Check for shift immediate
97+
let shift_imm = if let ExpKind::VKInt = right_desc.kind {
98+
let v = right_desc.ival;
99+
if v >= -128 && v <= 127 { Some(v) } else { None }
100+
} else {
101+
None
102+
};
103+
104+
let (op_rr, op_rk) = match op {
105+
BinaryOperator::OpBAnd => (OpCode::BAnd, Some(OpCode::BAndK)),
106+
BinaryOperator::OpBOr => (OpCode::BOr, Some(OpCode::BOrK)),
107+
BinaryOperator::OpBXor => (OpCode::BXor, Some(OpCode::BXorK)),
108+
BinaryOperator::OpShl => (OpCode::Shl, None),
109+
BinaryOperator::OpShr => (OpCode::Shr, None),
110+
_ => return Err(format!("Not a bitwise operator: {:?}", op)),
111+
};
112+
113+
// Try shift immediate
114+
if let Some(imm) = shift_imm {
115+
if matches!(op, BinaryOperator::OpShr) {
116+
let enc = ((imm + 128) & 0xff) as u32;
117+
emit(c, Instruction::encode_abc(OpCode::ShrI, result_reg, left_reg, enc));
118+
return Ok(result_reg);
119+
} else if matches!(op, BinaryOperator::OpShl) {
120+
let enc = ((imm + 128) & 0xff) as u32;
121+
emit(c, Instruction::encode_abc(OpCode::ShlI, result_reg, left_reg, enc));
122+
return Ok(result_reg);
123+
}
124+
}
125+
126+
// Try constant form for band/bor/bxor
127+
if is_const {
128+
if let Some(op_k) = op_rk {
129+
let const_idx = ensure_constant_idx(c, right_desc);
130+
emit(c, Instruction::encode_abc(op_k, result_reg, left_reg, const_idx));
131+
return Ok(result_reg);
132+
}
133+
}
134+
135+
// Fall back to register form
136+
let right_reg = exp_to_any_reg(c, right_desc);
137+
emit(c, Instruction::encode_abc(op_rr, result_reg, left_reg, right_reg));
138+
139+
Ok(result_reg)
140+
}
141+
142+
/// Emit comparison operation
143+
pub fn emit_cmp_op(
144+
c: &mut Compiler,
145+
op: BinaryOperator,
146+
left_reg: u32,
147+
right_reg: u32,
148+
can_reuse: bool,
149+
) -> u32 {
150+
let result_reg = if can_reuse { left_reg } else { alloc_register(c) };
151+
152+
let (opcode, a, b) = match op {
153+
BinaryOperator::OpEq | BinaryOperator::OpNe => (OpCode::Eq, left_reg, right_reg),
154+
BinaryOperator::OpLt => (OpCode::Lt, left_reg, right_reg),
155+
BinaryOperator::OpLe => (OpCode::Le, left_reg, right_reg),
156+
BinaryOperator::OpGt => (OpCode::Lt, right_reg, left_reg), // Swap
157+
BinaryOperator::OpGe => (OpCode::Le, right_reg, left_reg), // Swap
158+
_ => unreachable!(),
159+
};
160+
161+
emit(c, Instruction::encode_abc(opcode, result_reg, a, b));
162+
result_reg
163+
}
164+
165+
/// Helper to get constant index from ExpDesc
166+
fn ensure_constant_idx(c: &mut Compiler, e: &ExpDesc) -> u32 {
167+
match e.kind {
168+
ExpKind::VKInt => add_constant_dedup(c, LuaValue::integer(e.ival)),
169+
ExpKind::VKFlt => add_constant_dedup(c, LuaValue::number(e.nval)),
170+
ExpKind::VK => e.info,
171+
_ => 0,
172+
}
173+
}

crates/luars/src/compiler/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Lua bytecode compiler - Main module
22
// Compiles Lua source code to bytecode using emmylua_parser
3+
mod binop;
34
mod exp2reg;
45
mod expdesc;
56
mod expr;

crates/luars/src/stdlib/debug.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,15 @@ use crate::lua_vm::{LuaResult, LuaVM};
1010

1111
pub fn create_debug_lib() -> LibraryModule {
1212
crate::lib_module!("debug", {
13-
// "debug" => debug_debug,
14-
// "gethook" => debug_gethook,
1513
// "getinfo" => debug_getinfo,
1614
// "getlocal" => debug_getlocal,
15+
// "setlocal" => debug_setlocal,
1716
// "getmetatable" => debug_getmetatable,
18-
// "getregistry" => debug_getregistry,
17+
// "setmetatable" => debug_setmetatable,
1918
// "getupvalue" => debug_getupvalue,
20-
// "getuservalue" => debug_getuservalue,
21-
// "sethook" => debug_sethook,
22-
// "setlocal" => debug_setlocal,
2319
// "setupvalue" => debug_setupvalue,
24-
// "setuservalue" => debug_setuservalue,
2520
"traceback" => debug_traceback,
2621
// "upvalueid" => debug_upvalueid,
27-
// "upvaluejoin" => debug_upvaluejoin,
2822
})
2923
}
3024

0 commit comments

Comments
 (0)