Skip to main content

Statements & Control Flow

Blocks

A block is a sequence of statements. Execution is sequential.

do
-- this is a block
local x = 10
print(x)
end

Assignment

-- Single
x = 10
t.key = "value"

-- Multiple (all RHS evaluated first, then assigned)
a, b = 1, 2
a, b = b, a -- swap

-- Extra/missing values
a, b = 1, 2, 3 -- 3 discarded
a, b = 1 -- b = nil

[!warning] Global assignment side effects x = 10 triggers __newindex on _ENV if its metatable has one.


Control structures

if / elseif / else

if condition then
-- ...
elseif other_condition then
-- ...
else
-- ...
end
  • Conditions: only nil and false are falsy
  • No parentheses required (but allowed)

while

while condition do
-- body
end

repeat...until

repeat
-- body
until condition
  • Condition is evaluated after body (body runs at least once)
  • Variables declared inside are visible in the condition
repeat
local line = io.read()
until line ~= "" -- 'line' is visible here

Numeric for

for var = start, stop, step do
-- body
end
  • step defaults to 1
  • Control variable is local to the loop
  • Values are evaluated once at start
  • Loop runs while var <= stop (step > 0) or var >= stop (step < 0)
for i = 1, 10 do print(i) end -- 1 to 10
for i = 10, 1, -1 do print(i) end -- 10 to 1
for i = 0, 1, 0.1 do print(i) end -- floats work too

[!tip] Don't modify the control variable It's local and re-assigned each iteration. Changes are overwritten.

Generic for

for var_list in explist do
-- body
end

The iterator function is called each iteration. Three forms you'll see most:

-- pairs: all key-value pairs (unordered)
for k, v in pairs(t) do print(k, v) end

-- ipairs: sequential integer keys (1, 2, 3, ...)
for i, v in ipairs(t) do print(i, v) end

-- io.lines: lines of a file
for line in io.lines("file.txt") do print(line) end

Under the hood, the generic for calls f(state, var) repeatedly until it returns nil:

-- Equivalent to: for var_1, ..., var_n in explist do body end
local f, s, var = explist
while true do
local var_1, ..., var_n = f(s, var)
if var_1 == nil then break end
var = var_1
body
end

break

Exits the innermost loop (while, repeat, for).

for i = 1, 100 do
if i > 10 then break end
print(i)
end

goto

Jumps to a label in the same function/block scope.

for i = 1, 10 do
if i == 5 then goto skip end
print(i)
::skip::
end
  • Labels are written ::name::
  • Forward and backward jumps allowed
  • Cannot jump into a block (only out of one)
  • Useful for breaking out of nested loops
::retry::
local ok, err = try_something()
if not ok then goto retry end

return

Must be the last statement in a block. To return in the middle, use do...end:

function f()
if condition then
do return early_value end
end
return final_value
end

Can return multiple values:

function swap(a, b)
return b, a
end

No return → function returns nothing (no values).


Labels and goto rules

-- Valid: jumping out of loop
for i = 1, 10 do
if done then goto exit end
end
::exit::

-- INVALID: jumping into a block
goto inside
do
::inside:: -- error: label is visible but jump enters scope
end

Statement summary

StatementSyntax
Assignmentvar = expr
Locallocal var = expr
Blockdo ... end
Ifif cond then ... elseif ... else ... end
Whilewhile cond do ... end
Repeatrepeat ... until cond
Numeric forfor i = start, stop, step do ... end
Generic forfor vars in iter do ... end
Breakbreak
Gotogoto label / ::label::
Returnreturn exprs
Function callfunc(args)