Add basic for loops

This commit is contained in:
Sofia 2026-03-18 20:39:00 +02:00
parent 954b8417b3
commit 3405f45169
5 changed files with 88 additions and 4 deletions

View File

@ -36,4 +36,10 @@ print(min(11, 9))
print(10 - 15)
print("hello there!")
print(true or 0)
print(123, f(10, 11, 12))
global value, table = f(10, 11, 12)
print("hello")
for i=1,10 do
print(table[i])
end

View File

@ -256,6 +256,13 @@ pub enum Statement {
Return(ExpressionList),
If(Node<Expression>, Block),
Expression(Node<Expression>),
NumericalFor(
Node<String>,
Node<Expression>,
Node<Expression>,
Node<Expression>,
Block,
),
}
impl Parse for Statement {
@ -316,6 +323,35 @@ impl Parse for Statement {
vec![(access.0, access.1.0)],
ExpressionList(vec![expression]),
))
} else if stream.peek() == Some(Token::Keyword(Keyword::For)) {
stream.next();
let counter_name = stream.parse()?;
stream.expect_symbol('=')?;
let init = stream.parse()?;
stream.expect_symbol(',')?;
let end = stream.parse()?;
let step = if let Some(Token::Symbol(',')) = stream.peek() {
stream.next();
stream.parse()?
} else {
Node {
kind: Expression::Literal(Literal::Integer(LuaInteger(1))),
meta: Metadata::empty(),
}
};
stream.expect(Token::Keyword(Keyword::Do))?;
let block = stream.parse()?;
stream.expect(Token::Keyword(Keyword::End))?;
Ok(Statement::NumericalFor(
counter_name,
init,
end,
step,
block,
))
} else if let Ok(expr) = stream.parse() {
Ok(Self::Expression(expr))
} else {

View File

@ -154,6 +154,14 @@ impl Statement {
constants
}
Statement::Expression(expr) => expr.kind.find_constants(scope),
Statement::NumericalFor(_, init, end, step, block) => {
let mut constants = HashSet::new();
constants.extend(init.kind.find_constants(scope));
constants.extend(end.kind.find_constants(scope));
constants.extend(step.kind.find_constants(scope));
constants.extend(block.find_constants(scope, Vec::new()));
constants
}
}
}
@ -332,8 +340,6 @@ impl Statement {
));
}
dbg!(&first_ret_register);
instructions.push(Instruction::Return(
first_ret_register,
if vararg {
@ -358,6 +364,36 @@ impl Statement {
let (instr, _) = expr.kind.compile(state, scope, None);
instructions.extend(instr);
}
Statement::NumericalFor(counter, init, end, step, block) => {
let (instr, init_reg) = init.kind.compile(state, scope, Some(1));
instructions.extend(instr);
let (instr, end_reg) = end.kind.compile(state, scope, Some(1));
instructions.extend(instr);
let (instr, step_reg) = step.kind.compile(state, scope, Some(1));
instructions.extend(instr);
let init_reg = init_reg.first().unwrap();
let end_reg = end_reg.first().unwrap();
let step_reg = step_reg.first().unwrap();
scope.locals.insert(counter.kind.clone(), *init_reg);
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));
let mut inner_scope = scope.clone();
let instr = block.compile(state, &mut inner_scope);
let instr_len = instr.len() as i32;
instructions.push(Instruction::Jmp(instr_len + 2));
instructions.extend(instr);
instructions.push(Instruction::Add(*init_reg, *init_reg, *step_reg));
instructions.push(Instruction::Jmp(-(instr_len + 5)));
}
}
for reg in 0..scope.register_counter.0 {

View File

@ -20,6 +20,8 @@ pub enum Keyword {
False,
Nil,
Not,
For,
Do,
}
impl Keyword {
@ -36,6 +38,8 @@ impl Keyword {
"false" => Keyword::False,
"nil" => Keyword::Nil,
"not" => Keyword::Not,
"for" => Keyword::For,
"do" => Keyword::Do,
_ => None?,
})
}
@ -55,6 +59,8 @@ impl ToString for Keyword {
Keyword::False => "false",
Keyword::Nil => "nil",
Keyword::Not => "not",
Keyword::For => "for",
Keyword::Do => "do",
}
.to_string()
}

View File

@ -888,7 +888,7 @@ impl ClosureRunner {
.map(|v| v.borrow().clone())
.unwrap_or(Value::Nil)
{
Value::Float(val) => (val.lua_number().0 as u16) == *c,
Value::Boolean(val) => (val.0 as u16) == *c,
_ => false,
};
if is_true {