Skip to content

Commit e08253c

Browse files
committed
update
1 parent c699941 commit e08253c

File tree

6 files changed

+52
-36
lines changed

6 files changed

+52
-36
lines changed

crates/luars/src/compiler/code.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,7 +1415,16 @@ fn constfolding(_fs: &FuncState, op: BinaryOperator, e1: &mut ExpDesc, e2: &ExpD
14151415
OpSub => i1.checked_sub(i2),
14161416
OpMul => i1.checked_mul(i2),
14171417
OpIDiv => i1.checked_div(i2),
1418-
OpMod => Some(i1.rem_euclid(i2)),
1418+
OpMod => {
1419+
// Use Lua's modulo definition: a % b = a - floor(a/b) * b
1420+
// NOT Rust's rem_euclid which differs for negative divisors
1421+
let quot = (i1 as f64) / (i2 as f64);
1422+
let floor_quot = quot.floor() as i64;
1423+
match floor_quot.checked_mul(i2) {
1424+
Some(prod) => i1.checked_sub(prod),
1425+
None => None,
1426+
}
1427+
}
14191428
_ => unreachable!(),
14201429
};
14211430

@@ -1990,9 +1999,15 @@ fn is_kstr(e: &ExpDesc) -> bool {
19901999
e.kind == ExpKind::VK || e.kind == ExpKind::VKSTR
19912000
}
19922001

1993-
// Check if expression is a constant integer in valid range
2002+
// Check if expression is a constant integer in valid range for SETI
2003+
// SETI's B field is only 8 bits (0-255), matching Lua C's isCint check
19942004
fn is_cint(e: &ExpDesc) -> bool {
1995-
e.kind == ExpKind::VKINT
2005+
if e.kind == ExpKind::VKINT {
2006+
let val = unsafe { e.u.ival };
2007+
val >= 0 && val <= 255
2008+
} else {
2009+
false
2010+
}
19962011
}
19972012

19982013
// Port of luaK_self from lcode.c:1087-1097

crates/luars/src/compiler/expr_parser.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -506,10 +506,24 @@ fn field(fs: &mut FuncState, cc: &mut ConsControl) -> Result<(), String> {
506506
code::code_abrk(fs, OpCode::SetField, cc.table_reg as u32, key_idx, &mut val);
507507
}
508508
// Check if key is integer constant for SetI optimization
509+
// IMPORTANT: SETI's B field is only 8 bits (0-255), so we must check the range
509510
else if key.kind == ExpKind::VKINT {
510-
let key_int = unsafe { key.u.ival as u32 };
511-
// Use code_abrk to allow constant value optimization (e.g., [1] = 10)
512-
code::code_abrk(fs, OpCode::SetI, cc.table_reg as u32, key_int, &mut val);
511+
let key_int = unsafe { key.u.ival };
512+
// Only use SETI if key fits in 8 bits (matches Lua's isCint check)
513+
if key_int >= 0 && key_int <= 255 {
514+
// Use code_abrk to allow constant value optimization (e.g., [1] = 10)
515+
code::code_abrk(fs, OpCode::SetI, cc.table_reg as u32, key_int as u32, &mut val);
516+
} else {
517+
// Key too large for SETI, use SETTABLE instead
518+
let key_reg = code::exp2anyreg(fs, &mut key);
519+
code::code_abrk(
520+
fs,
521+
OpCode::SetTable,
522+
cc.table_reg as u32,
523+
key_reg as u32,
524+
&mut val,
525+
);
526+
}
513527
} else {
514528
// General case: SetTable instruction with RK optimization
515529
let key_reg = code::exp2anyreg(fs, &mut key);

crates/luars/src/compiler/parser/lua_token_data.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@ use crate::compiler::parser::{lua_token_kind::LuaTokenKind, text_range::SourceRa
44
pub struct LuaTokenData {
55
pub kind: LuaTokenKind,
66
pub range: SourceRange,
7+
pub line: usize, // line number at the END of this token (matches Lua's linenumber)
78
}
89

910
impl LuaTokenData {
1011
pub fn new(kind: LuaTokenKind, range: SourceRange) -> Self {
11-
LuaTokenData { kind, range }
12+
LuaTokenData { kind, range, line: 1 }
13+
}
14+
15+
pub fn with_line(kind: LuaTokenKind, range: SourceRange, line: usize) -> Self {
16+
LuaTokenData { kind, range, line }
1217
}
1318
}

crates/luars/src/compiler/parser/lua_tokenize.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ impl<'a> LuaTokenize<'a> {
3030
break;
3131
}
3232

33-
tokens.push(LuaTokenData::new(kind, self.reader.current_range()));
33+
// Save token with its ending line number (matches Lua's linenumber)
34+
tokens.push(LuaTokenData::with_line(kind, self.reader.current_range(), self.line));
3435
}
3536

3637
if let Some(err) = &self.error {

crates/luars/src/compiler/parser/mod.rs

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ impl<'a> LuaLexer<'a> {
5252
if self.tokens.is_empty() {
5353
self.current_token = LuaTokenKind::TkEof;
5454
} else {
55+
// Initialize line from first token
56+
self.line = self.tokens[0].line;
57+
self.lastline = 1; // lastline starts at 1
5558
self.current_token = self.tokens[0].kind;
5659
}
5760

@@ -128,14 +131,19 @@ impl<'a> LuaLexer<'a> {
128131
self.lastline = self.line;
129132

130133
let mut next_index = self.token_index + 1;
131-
self.skip_trivia_and_update_line(&mut next_index);
134+
// Skip trivia tokens to find next real token
135+
self.skip_trivia(&mut next_index);
132136
self.token_index = next_index;
133137

134138
if self.token_index >= self.tokens.len() {
135139
self.current_token = LuaTokenKind::TkEof;
136140
return;
137141
}
138142

143+
// CRITICAL FIX: Update line from token's ending line number
144+
// This ensures multi-line tokens (long strings, multi-line comments)
145+
// correctly update linenumber (matches Lua C's behavior in llex)
146+
self.line = self.tokens[self.token_index].line;
139147
self.current_token = self.tokens[self.token_index].kind;
140148
}
141149

@@ -164,24 +172,6 @@ impl<'a> LuaLexer<'a> {
164172
kind = self.tokens[*index].kind;
165173
}
166174
}
167-
168-
fn skip_trivia_and_update_line(&mut self, index: &mut usize) {
169-
if index >= &mut self.tokens.len() {
170-
return;
171-
}
172-
173-
let mut kind = self.tokens[*index].kind;
174-
while is_trivia_kind(kind) {
175-
if kind == LuaTokenKind::TkEndOfLine {
176-
self.line += 1;
177-
}
178-
*index += 1;
179-
if *index >= self.tokens.len() {
180-
break;
181-
}
182-
kind = self.tokens[*index].kind;
183-
}
184-
}
185175
}
186176

187177
fn is_trivia_kind(kind: LuaTokenKind) -> bool {

crates/luars_interpreter/src/bin/bytecode_dump.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -172,15 +172,6 @@ fn dump_chunk(
172172
let sbx = Instruction::get_sbx(instr);
173173
let k = Instruction::get_k(instr);
174174

175-
// Debug: check instruction 227 (pc=227, shown as instruction 228)
176-
if pc == 227 {
177-
eprintln!(
178-
"DEBUG instr 228 (pc=227): raw=0x{:08X}, opcode={:?} ({}), a={}, b={}, c={}",
179-
instr, opcode, opcode as u8, a, b, c
180-
);
181-
eprintln!(" Expected: CALL (opcode=24) 3 2 1");
182-
}
183-
184175
// Get line number for this instruction (luac format)
185176
let line = if pc < chunk.line_info.len() {
186177
chunk.line_info[pc]

0 commit comments

Comments
 (0)