The Lua scripting language
Moonstruck
The Lua scripting language celebrates its 20th birthday this year. Because it is used more often as an embedded scripting language than as an independent programming language (e.g., Python or Perl), Lua is less familiar to many people.
Lua [1] is very widespread in games and game engines. In fact, Wikipedia lists nearly 150 games that use Lua in a separate category of "Lua-scripted video games." However, Lua can also be found in a variety of network and system programs, such as the Wireshark network analyzer, the Nmap scanner [2], the MySQL Proxy program, the Rspamd anti-spam solution, the FreeSWITCH VoIP software, the Redis NoSQL database, the Apache web server [3], and the Nginx reverse proxy service (see the OpenResty article in this issue).
Homegrown
Lua was developed at the Catholic University of Rio de Janeiro by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, and Waldemar Celes. Because Brazil was subject to strong import restrictions for hardware and software in 1992, the three decided to develop a separate scripting language for their own purposes, which eventually culminated in Lua (Portuguese for "moon"). Ierusalimschy still controls the development today and has published the standard work Programming in Lua , third edition, which was published early last year. The first edition, available online [4] refers to Lua 5.0. The language has now moved to version 5.2, but the online book is still up to date to a large extent.
As mentioned, Lua is primarily designed as a library that application programmers can integrate into their software to add scripting capabilities. However, you can also use Lua without additional software. The Lua distribution, which is available for all major operating systems, contains an interpreter that weighs in at just a few hundred lines of code and otherwise relies on the existing library functions. This compactness (Figure 1) characterizes the entire Lua distribution and, along with a fairly high execution speed, is repeatedly touted as one of Lua's advantages. Nevertheless, the interpreter also offers features such as garbage collection (i.e., it automatically cleans up unused data structures to release memory).
Calling the Lua interpreter with lua
, launches in an interactive mode, in which you can enter code. Alternatively, it executes Lua scripts that it accepts as a parameter.
The Lua compiler is called luac
; it converts programs to Lua bytecode before execution, which saves a bit of compile time when running but does not otherwise offer any performance benefits.
Manageable
Lua offers a few exciting features. The syntax is quite conventional; for example, it marks blocks with the key words do
and end
instead of using braces. All told, Lua includes only about 20 reserved keywords (Table 1), which makes it quite easy to learn.
Table 1
Lua Keywords
and
|
break
|
do
|
else
|
elseif
|
end
|
false
|
for
|
function
|
if
|
in
|
local
|
nil
|
not
|
or
|
repeat
|
return
|
then
|
true
|
until
|
while
|
Lua is a dynamically typed language that supports types nil
, boolean
, number
, string
, function
, thread
, table
, and userdata
. The type of a variable is thus determined when a script runs and can optionally be converted to another type.
It is no problem to assign a number to a variable and then to a string later on in the program. In the case of the Boolean type, which accepts logical values, false
and nil
are both false, whereas an empty string or 0
represent a true value.
This is unique and unlike PHP, for example, where the assignment of arbitrary types to logical values tends to be quite chaotic rather than adhering to a specific method.
Strings
Strings are defined – as in other languages – in single or double quotes. However, strings enclosed by double brackets that span multiple lines are a special feature of Lua. An HTML string thus looks like this:
html = [[ <html> <head> ... ]]
The special operator for connecting strings is ..
. Using +
, as in other languages, does not work in Lua, which reserves this operator for numbers. Formatting strings is similar to C programming, such as
string.format("%.7f", math.pi)
for numbers. The string
module also provides a set of functions that allow you to search for characters in strings. For example,
string.find (string, search_string)
returns two numbers representing the beginning and the end of the string found. string.gmatch
returns an iterator; if you provide a search pattern, it successively returns all the found results.
Other functions return the length of a string, convert uppercase and lowercase (or vice versa), invert a string, and so on.
In principle, Lua can store UTF-8 in its strings because they use 8 bits. However, the language core does not provide any further features for processing UTF-8. Currently, a few modules, such as slnunicode
, handle this type of operation. The Lua core language will add support for UTF-8 in a future version.
Numeric typing is straightforward, with just number
, which largely corresponds to a floating-point number (float) in other languages. In particular, Lua has no integer variable type. The only data structure offered by Lua is tables, which replace the arrays and hashes of other programming languages.
Tables basically work like hashes or dictionaries: Instead of holding a single value, a variable uses keys, which can be of different types, to store a variety of values. In a table, neither the keys nor the values need to be of the same type. A new table is initialized in Lua with the curly brackets constructors, {}
:
t = {} t['foo'] = 'bar' t['123'] = 'linux'
As the Lua developers emphasize, tables are not really variables or types but dynamic objects, whose values you can only reference in your program.
This sounds more complicated than it is. Also, it is not important when programming, but you should keep in mind that tables are not copied during allocation, even though you always use the same table:
x = {} x['os'] = "linux" y = x print(y['os']) linux
Note the content of y['os']
is the string linux
, as the output from the print statement shows. To save the programmer some typing, Lua also provides a shorthand notation for specifying the key:
print(y.os) linux
Tables also allow programmers to implement arrays through the use of continuous numeric values for the keys. In principle, arrays can thus also begin at any value (i.e., 0 or 1). Following Lua convention, however, they start with 1. Two-dimensional data structures such as matrices are created by defining a table that contains tables.