Skip to content

1. Code blocks

Felice D'Angelo edited this page Jan 29, 2023 · 1 revision

Code blocks in Clue start with { and end with }.

Note that { and } are also used for defining tables:

local x = {} //x is a table, not a code block

{
    //while this is a code block
}

Below is a list of all code blocks in Clue and their differences with Lua's.

If statements/elseif chains

These work pretty much the same way as Lua's:

if condition {
    //code
} elseif other {
    //more code
} else {
    //even more code
}

Match blocks

Match blocks compare an expression and run the code block corresponding to a value matching the expression:

match expr {
    1 => {
        //this code block will be run if expr equals to 1
    }
    2 || 3 => {
        //this other code block will be run instead if expr equals to either 2 or 3
    }
}

This code will be converted to:

local _match = expr;
if (_match == 1) then
	
elseif (_match == 2) or (_match == 3) then
	
end

default

If the expression does not match with any other block, a special case can be set:

match expr {
    1 => {
        //this code block will be run if expr equals to 1
    }
    2 || 3 => {
        //this other code block will be run instead if expr equals to either 2 or 3
    }
    default => {
        //this last code block will be run if expr does not match with any other value
    }
}

This code will be converted to:

local _match = expr;
if (_match == 1) then
	
elseif (_match == 2) or (_match == 3) then
	
else 
	
end

Try catch blocks

The try block will run the given code block in protected mode: if the code errors your program will still continue:

try {
    //code
}

(Note: try blocks are converted into pcall calls, but they should not always be used instead of pcall: try blocks create a new function for pcall every time the block is ran in the code (this is to keep the scope working), if your try block only calls functions use pcall directly!)

After a try block a catch block can be added, the catch block will only be ran if the try block resulted in an error:

try {
    error("error message");
} catch {
    print("an error happened!");
}

If you want to know the error message you can supply a variable name to the catch block:

try {
    error("error message");
} catch msg {
    print(msg); //will print "error message"
}

This will be converted to:

local _check, msg = pcall(function()
    error("error message");
end)
if not _check then
    print(msg);
end
--you can also use _check and msg outside of the try catch block if you need to

Do blocks

These ones don't use the do keyword anymore, they only need { and }:

{
    //code
}

Functions

Clue's functions work the exact same way as Lua's but with a different keyword (fn) and some additions:

Local functions

These remain the exact same as Lua's:

local fn foo() {
    //code
}

Global functions

These must be defined with the global keyword:

global fn bar() {
    //code
}

Static functions

These must be defined with the static keyword.

Just like static variables these functions will be at file scope in the output file, so they will be available to only all Clue files.

Static functions also count towards the 200 locals limit that the file scope can have.

While you can define static functions anywhere, they should be put in the Clue code's file scope as they will always be put at file scope in the output file too: if you define a static function inside another function the static function will not be able to use the other function's locals (unless they are passed as arguments when calling the static function).

static fn fizz() {
    //code
}

Methods and functions inside tables

Methods work the same way but are defined and called with :: instead of :.

To define methods/functions inside tables the method keyword has to be used:

local t = {}
method t::foo() {
    //code
}
t::foo()

Default values

A function's arguments can have default values, if that argument is nil it will set to the default value.

The arguments are checked from last to first:

local fn foo(x = 3, y = 5) {
    //code
}

This code will be converted to:

local function foo(x, y)
    if y == nil then
        y = 5
    end
    if x == nil then
        x = 3
    end
	
end

Anonymous functions

Like in Lua functions can be used as values and as arguments in other functions:

local foo = fn(x, y) {/*...*/}

bar(fn {
    //if an anonymous function does not have any arguments the () can be omitted
})

Loops

Clue has all Lua's loops, but adds a few more loops.

Numerical for loops

These loops remain unchanged from Lua:

for i = 1, 10 {
    print(i) //will print from 1 to 10
}

for i = 10, 1, -1 {
    print(i) //will print from 10 to 1
}

Function for loops

These loops are slightly changed and now use the keywords of, in and with:

for k, v of t {
    //uses the iterator pairs with the table t
}

for k, v in t {
    //uses the iterator ipairs with the table t
}

for k, v with myiter(...) {
    //uses any custom iterator function with any amount of arguments
    //it's pretty much Lua's for loop but with a different keyword
}

While loops

These loops remain unchanged from Lua:

while condition {
    //code
}

Until loops

These loops are the opposite of a while loop, looping until the condition is true

until condition {
    //code
}

Loop until loops

Lua's repeat until loops work the same way in Clue but use a different keyword:

loop {
    //code
} until x

Loop loops

These loops with a funny name will iterate forever until something external (like break) ends the loop:

local x = 1
loop {
    x += 1
    if x == 5 {break}
}

Continue

continue is obviously not a loop itself but it can be used inside them, it works like break but instead of ending the loop it skips to the next iteration:

for i = 1, 10 {
    if i == 5 {continue}
    print(i) //this will print from 1 to 10 except 5
}

Clue will assume the version of Lua you're compiling to also has a continue keyword and it will use it in the output, if your Lua version doesn't have that keyword the --continue flag can be used to alter the output:

If your Lua has goto you can tell Clue to use a ::continue:: label and goto continue; with the --continue=luajit flag:

--without the flag enabled
for i = 1, 10, 1 do
    if i==5 then
        continue;
    end
    print(i)
end
--with the flag enabled
for i = 1, 10, 1 do
    if i==5 then
        goto continue;
    end
    print(i)
    ::continue::
end

Otheriwise, --continue=moonscript can be used:

for i = 1, 10, 1 do
    local _internal0 = false;
        repeat 
            if i==5 then
                _internal0 = true;
                break;
            end
        print(i);
        _internal0 = true;
    until true
    if not _internal0 then
        break;
    end
end