Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
32 changes: 23 additions & 9 deletions crates/luars/src/compiler/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,19 @@ use emmylua_parser::{
LuaNameExpr, LuaUnaryExpr, LuaVarExpr,
};

//======================================================================================
// Helper functions
//======================================================================================

/// Check if an expression is a vararg (...) literal
fn is_vararg_expr(expr: &LuaExpr) -> bool {
if let LuaExpr::LiteralExpr(lit) = expr {
matches!(lit.get_literal(), Some(LuaLiteralToken::Dots(_)))
} else {
false
}
}

//======================================================================================
// NEW API: ExpDesc-based expression compilation (Lua 5.4 compatible)
//======================================================================================
Expand Down Expand Up @@ -585,11 +598,14 @@ fn compile_binary_expr_desc(c: &mut Compiler, expr: &LuaBinaryExpr) -> Result<Ex
let concat_base = c.freereg;
alloc_register(c); // for left operand copy
alloc_register(c); // for right operand

emit_move(c, concat_base, left_reg);
emit_move(c, concat_base + 1, right_reg);
emit(c, Instruction::encode_abc(OpCode::Concat, concat_base, 1, 0));

emit(
c,
Instruction::encode_abc(OpCode::Concat, concat_base, 1, 0),
);

result_reg = concat_base;
// Reset freereg to result_reg + 1 (concat consumes right operand)
c.freereg = result_reg + 1;
Expand Down Expand Up @@ -1676,10 +1692,10 @@ fn compile_binary_expr_to(
emit_move(c, concat_reg, left_reg);
emit_move(c, concat_reg + 1, right_reg);
emit(c, Instruction::encode_abc(OpCode::Concat, concat_reg, 1, 0));

// Reset freereg (concat consumes right operand)
c.freereg = concat_reg + 1;

if let Some(d) = dest {
if d != concat_reg {
emit_move(c, d, concat_reg);
Expand Down Expand Up @@ -2618,8 +2634,7 @@ fn compile_table_expr_to(
if field.is_value_field() {
// Check if it's a simple value (not ... or call as last element)
if let Some(value_expr) = field.get_value_expr() {
let is_dots = matches!(&value_expr, LuaExpr::LiteralExpr(lit)
if matches!(lit.get_literal(), Some(LuaLiteralToken::Dots(_))));
let is_dots = is_vararg_expr(&value_expr);
let is_call = matches!(&value_expr, LuaExpr::CallExpr(_));
let is_last = i == fields.len() - 1;

Expand Down Expand Up @@ -2684,8 +2699,7 @@ fn compile_table_expr_to(
if field.is_value_field() {
// Array element or special case (vararg/call at end)
if let Some(value_expr) = field.get_value_expr() {
let is_dots = matches!(&value_expr, LuaExpr::LiteralExpr(lit)
if matches!(lit.get_literal(), Some(LuaLiteralToken::Dots(_))));
let is_dots = is_vararg_expr(&value_expr);
let is_call = matches!(&value_expr, LuaExpr::CallExpr(_));

if is_last_field && is_dots {
Expand Down
8 changes: 7 additions & 1 deletion crates/luars/src/compiler/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,13 @@ pub fn emit_set_global(c: &mut Compiler, name: &str, src_reg: u32) {
// k=false means C is a register index (not constant)
emit(
c,
Instruction::create_abck(OpCode::SetTabUp, env_index as u32, const_idx, src_reg, false),
Instruction::create_abck(
OpCode::SetTabUp,
env_index as u32,
const_idx,
src_reg,
false,
),
);
}

Expand Down
15 changes: 10 additions & 5 deletions crates/luars/src/compiler/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ use emmylua_parser::{
LuaRepeatStat, LuaReturnStat, LuaStat, LuaVarExpr, LuaWhileStat,
};

/// Check if an expression is a vararg (...) literal
fn is_vararg_expr(expr: &LuaExpr) -> bool {
if let LuaExpr::LiteralExpr(lit) = expr {
matches!(lit.get_literal(), Some(LuaLiteralToken::Dots(_)))
} else {
false
}
}

/// Check if a block contains only a single unconditional jump statement (break/return only)
/// Note: goto is NOT optimized by luac, so we don't include it here
#[allow(dead_code)]
Expand Down Expand Up @@ -641,11 +650,7 @@ fn compile_return_stat(c: &mut Compiler, stat: &LuaReturnStat) -> Result<(), Str

// Check if last expression is varargs (...) or function call - these can return multiple values
let last_is_multret = if let Some(last_expr) = exprs.last() {
matches!(last_expr, LuaExpr::CallExpr(_))
|| matches!(last_expr, LuaExpr::LiteralExpr(lit) if matches!(
lit.get_literal(),
Some(emmylua_parser::LuaLiteralToken::Dots(_))
))
matches!(last_expr, LuaExpr::CallExpr(_)) || is_vararg_expr(last_expr)
} else {
false
};
Expand Down
Loading