Implement numerical for loops

This commit is contained in:
Sofia 2026-03-18 20:52:02 +02:00
parent 3405f45169
commit 93493ce283
3 changed files with 33 additions and 5 deletions

View File

@ -40,6 +40,6 @@ print(true or 0)
global value, table = f(10, 11, 12)
print("hello")
for i=1,10 do
for i=#table,1,-1 do
print(table[i])
end

View File

@ -380,9 +380,7 @@ impl Statement {
scope.locals.insert("_END".to_owned(), *end_reg);
scope.locals.insert("_STEP".to_owned(), *step_reg);
let is_eql = scope.register_counter.next();
instructions.push(Instruction::LessThan(is_eql, *end_reg, *init_reg));
instructions.push(Instruction::Test(scope.register_counter.next(), is_eql, 1));
instructions.push(Instruction::ForTest(*init_reg, *end_reg, *step_reg));
let mut inner_scope = scope.clone();
let instr = block.compile(state, &mut inner_scope);
@ -392,7 +390,7 @@ impl Statement {
instructions.extend(instr);
instructions.push(Instruction::Add(*init_reg, *init_reg, *step_reg));
instructions.push(Instruction::Jmp(-(instr_len + 5)));
instructions.push(Instruction::Jmp(-(instr_len + 4)));
}
}

View File

@ -152,6 +152,12 @@ pub enum Instruction {
Jmp(i32),
/// if (R(B) <=> C) then R(A) := R(B) else PC++
Test(u16, u16, u16),
/// if R(C) >= 0
/// then if R(A) < R(B)
/// PC ++
/// otherwise if R(A) > R(B)
/// PC ++
ForTest(u16, u16, u16),
/// [func] [params.len()] [ret_regs.len()]
/// R(A), ... R(A+C-2) := R(A)(R(A+1), ... R(A+B-1))
Call(u16, u16, u16),
@ -185,6 +191,9 @@ impl Debug for Instruction {
Instruction::NewTable(arg0) => write!(f, "NEWTABLE {}", arg0),
Instruction::Jmp(arg0) => write!(f, "JMP {}", arg0),
Instruction::Test(arg0, arg1, arg2) => write!(f, "TEST {} {} {}", arg0, arg1, arg2),
Instruction::ForTest(arg0, arg1, arg2) => {
write!(f, "FORTEST {} {} {}", arg0, arg1, arg2)
}
Instruction::Call(arg0, arg1, arg2) => write!(f, "CALL {} {} {}", arg0, arg1, arg2),
Instruction::Close(arg0) => write!(f, "CLOSE {}", arg0),
Instruction::Closure(arg0, arg1) => write!(f, "CLOSURE {} {}", arg0, arg1),
@ -898,6 +907,27 @@ impl ClosureRunner {
self.program_counter += 1;
}
}
Instruction::ForTest(counter_reg, end_reg, step_reg) => {
let step_gte_0 = match self.get_stack(*step_reg) {
StackValue::Value(value) => Value::Integer(LuaInteger(0)).lt(&value),
};
let counter = match self.get_stack(*counter_reg) {
StackValue::Value(value) => value,
};
let end = match self.get_stack(*end_reg) {
StackValue::Value(value) => value,
};
if step_gte_0?.is_truthy() {
if !end.lt(&counter)?.is_truthy() {
self.program_counter += 1;
}
} else {
if !counter.lt(&end)?.is_truthy() {
self.program_counter += 1;
}
}
}
Instruction::Call(func_reg, param_len, ret_len) => {
let param_start_func_reg = *func_reg;