diff --git a/examples/test.lua b/examples/test.lua index 3d02370..05a27c0 100644 --- a/examples/test.lua +++ b/examples/test.lua @@ -36,4 +36,10 @@ print(min(11, 9)) print(10 - 15) print("hello there!") print(true or 0) -print(123, f(10, 11, 12)) \ No newline at end of file + +global value, table = f(10, 11, 12) + +print("hello") +for i=1,10 do + print(table[i]) +end \ No newline at end of file diff --git a/src/ast.rs b/src/ast.rs index 3c900a3..c9d87b8 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -256,6 +256,13 @@ pub enum Statement { Return(ExpressionList), If(Node, Block), Expression(Node), + NumericalFor( + Node, + Node, + Node, + Node, + 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 { diff --git a/src/compile.rs b/src/compile.rs index 25e8636..1c9a6c8 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -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 { diff --git a/src/token_stream/lexer.rs b/src/token_stream/lexer.rs index a07bb50..cada511 100644 --- a/src/token_stream/lexer.rs +++ b/src/token_stream/lexer.rs @@ -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() } diff --git a/src/vm.rs b/src/vm.rs index 48fa0f1..35c4af3 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -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 {