Reference
Comments
Comments are unchanged from Lua Comments. Both line comments and block comments are supported.
-- this is a single line comment
--[[
this is a
block comment
]]
--[=[
this is a
block comment
with nested ']]'
]=]
Basic Types
true
, false
and nil
are unchanged from Lua.
Numbers
Erde supports all Lua numbers for any Lua target (note that Lua 5.4 numbers are a superset of all previous versions). This means that you can use the following, even when targeting Lua 5.1+:
print(0xA23p-4)
Erde will transpile this at compile time into a decimal form that all major Lua versions can understand.
Erde also supports binary literals, which are denoted with a 0b
prefix. These
will also be transpiled at compile time into decimals:
print(0b110) -- 6
Strings
Strings are mostly unchanged from Lua strings. Erde additionally allows for string interpolation inside of double quote or block strings (but not single quote strings) using braces. Braces may be escaped to be used literally. Escaping the end brace is optional.
local message = 'world'
print("hello {message}") -- hello world
print([[hello {message}]]) -- hello world
-- string interpolation is not allowed in single quote strings
print('hello {message}') -- hello {message}
-- escape for literal braces
print("hello \{message\}") -- hello {message}
-- escaping the end brace is optional
print("hello \{message}") -- hello {message}
Strings may also be indexed directly without the need for extra parentheses:
local x = ('hello %s!'):format('world')
local x = 'hello %s!':format('world')
Tables
Tables are unchanged from Lua tables.
local my_table = { hello = 'world', 'hello world' }
print(my_table.hello) -- world
print(my_table[1]) -- hello world
Unlike Lua, Erde does not allow using semicolons in table constructors.
Destructuring
Erde supports a simple form of destructuring, which is a convenient way to extract values from a table.
To extract keys from a table, you may specify a list of names in braces:
local my_table = { hello = 'world' }
-- equivalent to: `local hello = a.hello`
local { hello } = my_table
print(hello) -- world
To extract from the array section of a table, you can use brackets:
local my_table = {
'my first index',
'my second index',
}
-- equivalent to:
-- `local first = my_table[1]`
-- `local second = my_table[2]`
local [ first, second ] = my_table
print(first) -- my first index
print(second) -- my second index
Destructured values may be given default values, which will be applied when
the destructured value is nil
:
local my_table = {}
local { my_nonexistent_key = 'goodbye world' } = my_table
print(my_nonexistent_key) -- goodbye world
Destructured keys may also be given aliases. Aliases simply rename the destructured field and must come before defaults:
local my_table = { hello = 'world' }
-- Alias
local { hello: my_hello } = my_table
print(my_hello) -- world
-- Alias + Default
local { my_nonexistent_key: my_alias = 'James Bond' } = my_table
print(my_nonexistent_key) -- nil
print(my_alias) -- James Bond
Nested destructuring is not supported. This is intentional, as nested destructuring syntax often makes code much more cryptic and difficult to read.
Destructuring can be used in combination with the module
keyword to
achieve the import / export paradigm:
module function my_module_function() {
print('hello world')
}
local { my_module_function } = require('foo')
my_module_function() -- hello world
Functions
Functions are generally the same as Lua functions,
but use braces instead of end
.
Unlike Lua, function calls in Erde always require parentheses.
Parameters Defaults
Erde has support for parameter defaults:
local function greet(name = 'world') {
return 'hello ' .. name
}
greet() -- hello world
Since all parameters in Lua are optional, any parameter in Erde may be assigned a default value. In particular, defaulted parameters need not come after non-defaulted ones:
local function sum3(a, b = 2, c) {
return a + b + c
}
sum3(1, nil, 3) -- 6
Varargs
Erde supports Lua varargs:
local function sum(...) {
local summands = { ... }
local total = 0
for _, summand in ipairs(summands) {
total += summand
}
return total
}
Additionally, Erde allows for named varargs, which will automatically place them into a table:
local function sum(...summands) {
local total = 0
for _, summand in ipairs(summands) {
total += summand
}
return total
}
Arrow Functions
Lua's anonymous function syntax (function() ... end
) is not valid in Erde.
Instead, Erde opts for arrow functions:
local sum = (a, b) -> {
return a + b
}
Arrow functions can implicitly take self
as the first parameter by using a
fat arrow instead of a skinny one
(inspired by MoonScript):
local person = { name = 'world' }
person.introduce = () => {
print(self.name)
}
Arrow functions may also specify an expression instead of a function body. In this case, the expression becomes the return value.
local get_random = () -> math.random()
print(get_random()) -- 0.91273898151521
print(get_random()) -- 0.33174662440979
When using implicit returns for a table or multiple values, wrapping parentheses are necessary:
-- Return table (must use parentheses!)
local get_random_table = () -> ({
a = math.random(),
b = math.random(),
c = math.random(),
})
-- Return multiple values (must use parentheses!)
local get_random3 = () -> (
math.random(),
math.random(),
)
The parameter parentheses are optional if there is only one parameter, as long as it does not have a default and is not variadic. This also works for destructured parameters.
local greet = name -> print("hello {name}!")
greet('world')
-- w/ destructuring
local greet = { name } -> print("hello {name}!")
greet({ name = 'world' })
Scopes
Scopes apply to both normal declarations and function declarations. Their syntax
is the same as Lua, but Erde adds the additional global
and module
scope
keywords.
local
Local variables are unchanged from Lua local variables.
global
Global variables are unchanged from
Lua global variables.
However, variables declared w/ global
will always index the global table (_G
).
local my_var = 111
do {
global my_var = 222
-- Erde will automatically detect the most recent scope of the variable
-- `my_var`. Since `my_var` is global here, the following is equivalent to
-- `print(_G.my_var)`
print(my_var) -- 222
}
-- Now that the global `my_var` is "out of scope", Erde goes back to using the
-- local `my_var`.
print(my_var) -- 111
-- The global variable is still there and accessible via `_G`.
print(_G.my_var) -- 222
module
The module
keyword acts as an export statement. Any variable declared with
module
will automatically be placed into a table, which is then returned at
the end of the script.
module function echo(message) {
print(message)
}
local foo = require('foo')
foo.echo('hello world') -- hello world
If you need to modify the returned table, you can access it via _MODULE
:
setmetatable(_MODULE, { __index = _G })
module x = 'hello world'
The module
keyword may not be used in conjunction with a top-level return
,
as the return value will be ambiguous. In this case, Erde will throw a
compile error.
module my_var = 0
-- Error! Should Erde return `_MODULE` or `my_other_var`?
return my_other_var
The module
keyword conflicts with the built-in module
function in Lua 5.1,
which means the latter is unusable in Erde (although the use of Lua's module
function is
highly discouraged
anyways).
The module
keyword can be used in combination with destructuring
to achieve the import / export paradigm:
module function my_module_function() {
print('hello world')
}
local { my_module_function } = require('foo')
my_module_function() -- hello world
Operators
Arithmetic Operators
Arithmetic operators are the same as Lua arithmetic operators.
Syntax | Operator | Example |
---|---|---|
+ | addition | 1 + 2 == 3 |
- | subtraction | 1 - 2 == -1 |
- | unary minus | -4 |
* | multiplication | 2 * 4 == 8 |
/ | division | 10 / 2 == 5 |
// | floor division | 10 // 4 == 2 |
^ | exponentiation | 2 ^ 6 == 64 |
% | modulo | 6 % 2 == 0 |
Floor division (//
) was not introduced until Lua 5.3, but will be polyfilled
by the compiler when necessary.
Relational Operators
Relational operators are the same as
Lua relational operators
except for the NEQ operator, which uses !=
. You can read more
about this decision here.
Syntax | Operator | Example |
---|---|---|
== | equality | 1 + 1 == 2 |
!= | inequality | 1 + 1 != 3 |
< | less than | 3 < 5 |
> | greater than | 9 > 7 |
<= | less than or equal | 9 >= 8, 9 >= 9 |
>= | greater than or equal | 9 <= 11, 11 <= 11 |
Logical Operators
Erde keeps Lua's logical operators, but changes the syntax to use symbols over keywords:
Syntax | Operator | Example |
---|---|---|
|| | or | true || false == true |
&& | and | true && false == false |
! | unary NOT | !false == true |
Concatenation / Length Operators
Erde keeps Lua's concatenation operator and length operator:
print('hello ' .. 'world') -- hello world
print(#'hello world') -- 11
Bitwise Operators
Erde supports Lua's bitwise operators (Lua 5.3+):
Syntax | Operator | Example |
---|---|---|
| | or | 4 | 2 == 6 |
& | and | 6 & 5 == 4 |
~ | xor | 6 ~ 5 == 3 |
~ | unary NOT | ~4 == 3 |
>> | right shift | 2 >> 1 == 1 |
<< | left shift | 2 << 1 == 4 |
Compiling bitwise operators heavily depends on the Lua target. Erde uses the following table to determine how bit operations should be compiled:
Target | Compilation | Erde | Lua |
---|---|---|---|
jit | LuaBitOp | 6 & 5 | require('bit').band(6, 5) |
5.1 | LuaBitOp | 6 & 5 | require('bit').band(6, 5) |
5.1+ | Requires --bitlib flag | 6 & 5 | require('myBitLib').band(6, 5) |
5.2 | bit32 | 6 & 5 | require('bit32').band(6, 5) |
5.2+ | Requires --bitlib flag | 6 & 5 | require('myBitLib').band(6, 5) |
5.3 | Native Syntax | 6 & 5 | 6 & 5 |
5.3+ | Native Syntax | 6 & 5 | 6 & 5 |
5.4 | Native Syntax | 6 & 5 | 6 & 5 |
5.4+ | Native Syntax | 6 & 5 | 6 & 5 |
You may also specify your own bit library using the --bitlib
flag in the CLI.
The library methods are assumed to be:
Syntax | Operator | Method |
---|---|---|
| | or | require('myBitLib').bor |
& | and | require('myBitLib').band |
~ | xor | require('myBitLib').bxor |
~ | unary NOT | require('myBitLib').bnot |
>> | right shift | require('myBitLib').rshift |
<< | left shift | require('myBitLib').lshift |
Trying to compile bitwise operators when targeting 5.1+ or 5.2+ requires
the use of --bitlib
. This is because there really is no "sane" default here.
By far the most common bit libraries for Lua are
LuaBitOp (only works on 5.1 and 5.2) and
bit32 (only works on 5.2),
so it is left to the developer to decide which library to use.
Operator Assignments
All binary operators (except Relational Operators) support operator assignments:
local x = 4
x += 6
x /= 2
print(x) -- 5
Similar to regular assignments, operator assignments can also perform multiple assignments in a single statement:
local x, y, z = 0, 0, 0
x, y, z += 1, 2, 3
print(x, y, z) -- 1 2 3
Logic Constructs
Do Block
Same as Lua do blocks, but with braces:
do {
...
}
If Else
Same as Lua if-else, but with braces:
if n > 0 {
...
} elseif n < 0 {
...
} else {
...
}
For Loop
Same as Lua, but with braces. Both numeric for loops and generic for loops are supported.
-- numeric for loop
for i = 1, 10, 1 {
...
}
-- generic for loop
for i, v in ipairs({ 1, 2, 3 }) {
...
}
While Loop
Same as Lua while loop, but with braces:
while true {
...
}
Repeat Until
Same as Lua repeat-until, but with braces:
repeat {
...
} until true
Continue Statements
Erde adds support for continue
statements, which will advance to the next
iteration of the closest looping block (for
, while
, repeat...until
).
for i = 1, 10 {
if i % 2 == 0 {
continue
}
print('i is odd')
}
Goto
Erde has support for Lua's goto
(Lua 5.2+, LuaJIT):
goto my_jump
print('this will not be printed')
::my_jump::
print('hello world')
Since there is no way to polyfill goto
in Lua 5.1, trying to use goto
when
targeting 5.1 or 5.1+ will result in a compilation error.
Trailing Commas
In Erde, any enclosed list (i.e. surrounded by paired tokens such as {}
, []
, ()
)
is allowed to have trailing commas. For example:
local function my_function(
my_first_long_function_parameter,
my_second_long_function_parameter,
my_third_long_function_parameter, -- trailing comma allowed!
) {
print(
my_first_long_function_parameter,
my_second_long_function_parameter,
my_third_long_function_parameter, -- trailing comma allowed!
)
}
Semicolons
Similar to Lua, Erde supports semicolons for separating statements:
local x = 4;print(x) -- 4
In Lua, semicolons are most often used to avoid ambiguous syntax. In Erde, semicolons are usually not necessary.
Multiple Return Parentheses
Functions in Erde are allowed to wrap multiple returns with parentheses:
local function get_basic_pair_operations(a, b) {
return (
a + b,
a - b,
a * b,
a / b,
)
}