Skip to content

Commit 174cad5

Browse files
committed
update
1 parent 97dafd6 commit 174cad5

File tree

3 files changed

+99
-91
lines changed

3 files changed

+99
-91
lines changed

crates/luars/src/compiler/expr.rs

Lines changed: 24 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -20,88 +20,6 @@ use emmylua_parser::{
2020
LuaNameExpr, LuaUnaryExpr, LuaVarExpr,
2121
};
2222

23-
//======================================================================================
24-
// Helper functions
25-
//======================================================================================
26-
27-
/// Check if an expression is a vararg (...) literal
28-
fn is_vararg_expr(expr: &LuaExpr) -> bool {
29-
if let LuaExpr::LiteralExpr(lit) = expr {
30-
matches!(lit.get_literal(), Some(LuaLiteralToken::Dots(_)))
31-
} else {
32-
false
33-
}
34-
}
35-
36-
/// Result of parsing a Lua number literal
37-
#[derive(Debug, Clone, Copy)]
38-
enum ParsedNumber {
39-
/// Successfully parsed as integer
40-
Int(i64),
41-
/// Number is too large for i64, use float instead
42-
Float(f64),
43-
}
44-
45-
/// Parse a Lua integer literal from text, handling hex numbers that overflow i64
46-
/// Lua treats 0xFFFFFFFFFFFFFFFF as -1 (two's complement interpretation)
47-
/// For decimal numbers that overflow i64 range, returns Float instead
48-
fn parse_lua_int(text: &str) -> ParsedNumber {
49-
let text = text.trim();
50-
if text.starts_with("0x") || text.starts_with("0X") {
51-
// Hex number - parse as u64 first, then reinterpret as i64
52-
// This handles the case like 0xFFFFFFFFFFFFFFFF which should be -1
53-
let hex_part = &text[2..];
54-
// Remove any trailing decimal part (e.g., 0xFF.0)
55-
let hex_part = hex_part.split('.').next().unwrap_or(hex_part);
56-
if let Ok(val) = u64::from_str_radix(hex_part, 16) {
57-
return ParsedNumber::Int(val as i64); // Reinterpret bits as signed
58-
}
59-
}
60-
// Decimal case: parse as i64 only, if overflow use float
61-
// (Unlike hex, decimal numbers should NOT be reinterpreted as two's complement)
62-
if let Ok(val) = text.parse::<i64>() {
63-
return ParsedNumber::Int(val);
64-
}
65-
// Decimal number is too large for i64, parse as float
66-
if let Ok(val) = text.parse::<f64>() {
67-
return ParsedNumber::Float(val);
68-
}
69-
// Default fallback
70-
ParsedNumber::Int(0)
71-
}
72-
73-
/// Lua left shift: x << n (returns 0 if |n| >= 64)
74-
/// Negative n means right shift
75-
#[inline(always)]
76-
fn lua_shl(l: i64, r: i64) -> i64 {
77-
if r >= 64 || r <= -64 {
78-
0
79-
} else if r >= 0 {
80-
(l as u64).wrapping_shl(r as u32) as i64
81-
} else {
82-
// Negative shift means right shift (logical)
83-
(l as u64).wrapping_shr((-r) as u32) as i64
84-
}
85-
}
86-
87-
/// Lua right shift: x >> n (logical shift, returns 0 if |n| >= 64)
88-
/// Negative n means left shift
89-
#[inline(always)]
90-
fn lua_shr(l: i64, r: i64) -> i64 {
91-
if r >= 64 || r <= -64 {
92-
0
93-
} else if r >= 0 {
94-
(l as u64).wrapping_shr(r as u32) as i64
95-
} else {
96-
// Negative shift means left shift
97-
(l as u64).wrapping_shl((-r) as u32) as i64
98-
}
99-
}
100-
101-
//======================================================================================
102-
// NEW API: ExpDesc-based expression compilation (Lua 5.4 compatible)
103-
//======================================================================================
104-
10523
/// Core function: Compile expression and return ExpDesc
10624
/// This is the NEW primary API that replaces the old u32-based compile_expr
10725
pub fn compile_expr_desc(c: &mut Compiler, expr: &LuaExpr) -> Result<ExpDesc, String> {
@@ -2357,7 +2275,6 @@ pub fn compile_call_expr_with_returns_and_dest(
23572275
} else {
23582276
false
23592277
};
2360-
23612278
// Track if we need to move return values back to original dest
23622279
let mut need_move_to_dest = false;
23632280
let original_dest = dest;
@@ -3086,7 +3003,7 @@ fn compile_table_expr_to(
30863003
while c.freereg < array_values_end {
30873004
alloc_register(c);
30883005
}
3089-
let mut has_call_at_end = false;
3006+
let mut call_at_end_idx: Option<usize> = None;
30903007

30913008
// Process all fields in source order
30923009
// Array elements are loaded to registers, hash fields are set immediately
@@ -3107,7 +3024,7 @@ fn compile_table_expr_to(
31073024
} else if is_last_field && is_call {
31083025
// Call as last element: returns multiple values
31093026
// Will be handled after all hash fields
3110-
has_call_at_end = true;
3027+
call_at_end_idx = Some(field_idx);
31113028
continue;
31123029
}
31133030

@@ -3339,15 +3256,32 @@ fn compile_table_expr_to(
33393256
return Ok(reg);
33403257
}
33413258

3342-
if has_call_at_end {
3343-
// Call as last element - for now treat as single value
3344-
// TODO: handle multiple return values properly
3259+
if let Some(idx) = call_at_end_idx {
3260+
// Call as last element: compile call with all return values
33453261
let target_reg = values_start + array_idx;
3262+
eprintln!("[DEBUG] call_at_end: target_reg={}, freereg={}, values_start={}, array_idx={}", target_reg, c.freereg, values_start, array_idx);
33463263
while c.freereg <= target_reg {
33473264
alloc_register(c);
33483265
}
3349-
// Simplified: just count as one more array element
3350-
array_idx += 1;
3266+
3267+
// Get the call expression and compile it
3268+
if let Some(field) = fields.get(idx) {
3269+
if let Some(value_expr) = field.get_value_expr() {
3270+
if let LuaExpr::CallExpr(call_expr) = value_expr {
3271+
// Compile the call with all return values (usize::MAX means all)
3272+
eprintln!("[DEBUG] before compile_call_expr");
3273+
compile_call_expr_with_returns_and_dest(c, &call_expr, usize::MAX, Some(target_reg))?;
3274+
eprintln!("[DEBUG] after compile_call_expr");
3275+
}
3276+
}
3277+
}
3278+
3279+
// SetList with B=0 (all remaining values including call returns)
3280+
let c_param = (array_idx as usize / 50) as u32;
3281+
emit(c, Instruction::encode_abc(OpCode::SetList, reg, 0, c_param));
3282+
3283+
c.freereg = reg + 1;
3284+
return Ok(reg);
33513285
}
33523286

33533287
// Emit SETLIST for all array elements at the end

crates/luars/src/compiler/helpers.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,3 +675,77 @@ pub fn check_unresolved_gotos(c: &Compiler) -> Result<(), String> {
675675
pub fn clear_scope_labels(c: &mut Compiler) {
676676
c.labels.retain(|l| l.scope_depth < c.scope_depth);
677677
}
678+
679+
/// Check if an expression is a vararg (...) literal
680+
pub fn is_vararg_expr(expr: &LuaExpr) -> bool {
681+
if let LuaExpr::LiteralExpr(lit) = expr {
682+
matches!(lit.get_literal(), Some(LuaLiteralToken::Dots(_)))
683+
} else {
684+
false
685+
}
686+
}
687+
688+
/// Result of parsing a Lua number literal
689+
#[derive(Debug, Clone, Copy)]
690+
pub enum ParsedNumber {
691+
/// Successfully parsed as integer
692+
Int(i64),
693+
/// Number is too large for i64, use float instead
694+
Float(f64),
695+
}
696+
697+
/// Parse a Lua integer literal from text, handling hex numbers that overflow i64
698+
/// Lua treats 0xFFFFFFFFFFFFFFFF as -1 (two's complement interpretation)
699+
/// For decimal numbers that overflow i64 range, returns Float instead
700+
pub fn parse_lua_int(text: &str) -> ParsedNumber {
701+
let text = text.trim();
702+
if text.starts_with("0x") || text.starts_with("0X") {
703+
// Hex number - parse as u64 first, then reinterpret as i64
704+
// This handles the case like 0xFFFFFFFFFFFFFFFF which should be -1
705+
let hex_part = &text[2..];
706+
// Remove any trailing decimal part (e.g., 0xFF.0)
707+
let hex_part = hex_part.split('.').next().unwrap_or(hex_part);
708+
if let Ok(val) = u64::from_str_radix(hex_part, 16) {
709+
return ParsedNumber::Int(val as i64); // Reinterpret bits as signed
710+
}
711+
}
712+
// Decimal case: parse as i64 only, if overflow use float
713+
// (Unlike hex, decimal numbers should NOT be reinterpreted as two's complement)
714+
if let Ok(val) = text.parse::<i64>() {
715+
return ParsedNumber::Int(val);
716+
}
717+
// Decimal number is too large for i64, parse as float
718+
if let Ok(val) = text.parse::<f64>() {
719+
return ParsedNumber::Float(val);
720+
}
721+
// Default fallback
722+
ParsedNumber::Int(0)
723+
}
724+
725+
/// Lua left shift: x << n (returns 0 if |n| >= 64)
726+
/// Negative n means right shift
727+
#[inline(always)]
728+
pub fn lua_shl(l: i64, r: i64) -> i64 {
729+
if r >= 64 || r <= -64 {
730+
0
731+
} else if r >= 0 {
732+
(l as u64).wrapping_shl(r as u32) as i64
733+
} else {
734+
// Negative shift means right shift (logical)
735+
(l as u64).wrapping_shr((-r) as u32) as i64
736+
}
737+
}
738+
739+
/// Lua right shift: x >> n (logical shift, returns 0 if |n| >= 64)
740+
/// Negative n means left shift
741+
#[inline(always)]
742+
pub fn lua_shr(l: i64, r: i64) -> i64 {
743+
if r >= 64 || r <= -64 {
744+
0
745+
} else if r >= 0 {
746+
(l as u64).wrapping_shr(r as u32) as i64
747+
} else {
748+
// Negative shift means left shift
749+
(l as u64).wrapping_shl((-r) as u32) as i64
750+
}
751+
}

crates/luars/src/stdlib/string.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1450,7 +1450,7 @@ fn string_packsize(vm: &mut LuaVM) -> LuaResult<MultiValue> {
14501450
break;
14511451
}
14521452
}
1453-
let n: usize = if size_str.is_empty() {
1453+
let _n: usize = if size_str.is_empty() {
14541454
std::mem::size_of::<usize>() // default size_t
14551455
} else {
14561456
size_str.parse().unwrap_or(std::mem::size_of::<usize>())

0 commit comments

Comments
 (0)