Skip to main content

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:

lua
local x = ('hello %s!'):format('world')
erde
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
caution

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
note

Nested destructuring is not supported. This is intentional, as nested destructuring syntax often makes code much more cryptic and difficult to read.

info

Destructuring can be used in combination with the module keyword to achieve the import / export paradigm:

foo.erde
module function my_module_function() {
print('hello world')
}
bar.erde
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.

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
info

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.

foo.erde
module function echo(message) {
print(message)
}
bar.erde
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
caution

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).

info

The module keyword can be used in combination with destructuring to achieve the import / export paradigm:

foo.erde
module function my_module_function() {
print('hello world')
}
bar.erde
local { my_module_function } = require('foo')
my_module_function() -- hello world

Operators

Arithmetic Operators

Arithmetic operators are the same as Lua arithmetic operators.

SyntaxOperatorExample
+addition1 + 2 == 3
-subtraction1 - 2 == -1
-unary minus-4
*multiplication2 * 4 == 8
/division10 / 2 == 5
//floor division10 // 4 == 2
^exponentiation2 ^ 6 == 64
%modulo6 % 2 == 0

info

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.

SyntaxOperatorExample
==equality1 + 1 == 2
!=inequality1 + 1 != 3
<less than3 < 5
>greater than9 > 7
<=less than or equal9 >= 8, 9 >= 9
>=greater than or equal9 <= 11, 11 <= 11

Logical Operators

Erde keeps Lua's logical operators, but changes the syntax to use symbols over keywords:

SyntaxOperatorExample
||ortrue || false == true
&&andtrue && 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+):

SyntaxOperatorExample
|or4 | 2 == 6
&and6 & 5 == 4
~xor6 ~ 5 == 3
~unary NOT~4 == 3
>>right shift2 >> 1 == 1
<<left shift2 << 1 == 4

Compiling bitwise operators heavily depends on the Lua target. Erde uses the following table to determine how bit operations should be compiled:

TargetCompilationErdeLua
jitLuaBitOp6 & 5require('bit').band(6, 5)
5.1LuaBitOp6 & 5require('bit').band(6, 5)
5.1+Requires --bitlib flag6 & 5require('myBitLib').band(6, 5)
5.2bit326 & 5require('bit32').band(6, 5)
5.2+Requires --bitlib flag6 & 5require('myBitLib').band(6, 5)
5.3Native Syntax6 & 56 & 5
5.3+Native Syntax6 & 56 & 5
5.4Native Syntax6 & 56 & 5
5.4+Native Syntax6 & 56 & 5

You may also specify your own bit library using the --bitlib flag in the CLI. The library methods are assumed to be:

SyntaxOperatorMethod
|orrequire('myBitLib').bor
&andrequire('myBitLib').band
~xorrequire('myBitLib').bxor
~unary NOTrequire('myBitLib').bnot
>>right shiftrequire('myBitLib').rshift
<<left shiftrequire('myBitLib').lshift

caution

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')
caution

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
info

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,
)
}