Lua Progamming Language
2024-04-02
Lua is a powerful, fast, lightweight and embeddable programming language. It is used by many frameworks, games and other applications. While it can be used by itself, it has been designed to be easy to embed in another application. It is implemented in ANSI C, a subset of C programming language that is very portable, which means it can run on many systems and many devices where the most other scripting languages would not be able to run.
"Lua" (pronounced LOO-ah) means "Moon" in Portuguese. As such, it is neither an acronym nor an abbreviation, but a noun. Lua comes from two languages: DEL and Sol. DEL means "Data Entry Language", While Sol means "Simple object language" and also means Sun in Portuguese.
One of main advantages of Lua is its simplicity. Programming which is also called scripting in the case of programs that run inside an embedded applications, is the process of writing computer program. A programming language is a language used to give instructions to a computer through computer code that is contained in a computer program. A programming language consists of two things: a syntax, which is like grammar in English, and libraries, basic functions provided with the language. These libraries could be compared with vocabulary in English.
1. Hello World!
Lua can either be used embedded in an application or by itself. The first example of Lua code in this book will be the basic and traditional hello world program.
A "Hello world" program is a computer program that outputs "Hello, world" on a display device. Because it is typically one of the simplest programs possible in most programming languages, it is by tradition often used to illustrate to beginners the most basic syntax of a programming language, or to verify that a language or system is operating correctly.
print("Hello World!")
The code above prints the text Hello, world! to the output. It does so by calling the print function with the string "Hello, world!" as an argument.
2. Syntax
Syntax of a programming language defines how statements and expressions must be written in that programming language, just like grammar defines how sentences and words must be written. Statements and expressions can be respectively compared to sentences and words.
Lua is a dynamically typed language intended for use as an extension language or scripting language.
Statements and expressions can be respectively compared to sentences and words. Expressions are pieces of code that have a value and that can be evaluated, while statements are pieces of code that can be executed and contain an instruction with one or many expressions to use that instruction with.
For example, 3 + 5
is an expression and variable = 3 + 5
is a statement
that sets the value of variable to that expression.
-- Different types
local x = 10 -- number
local name = "Neo" -- string
local is_alive = false -- boolean
local a = nil -- no value or invalid value
3. Obtaining Lua
Lua can be obtained on the official Lua website, on the download page.
4. Basics
If you are using the stand-alone Lua interpreter, all you have to do
to run your first program is to call the interpreter
-usually named lua
or lua5.3
/lua5.4
-
with the name of the text file that contains your program.
If you save the Hello World program in a file hello.lua
,
the following command should run it:
$ lua hello.lua
As a more complex example, the next program defines a function to compute the factorial of a given number, asks the user for a number, and prints its factorial:
-- defines a factorial function
function fact (n)
if n == 0 then
return 1
else
return n * fact(n - 1)
end
end
print("enter a number:")
a = io.read("*n") -- reads a number
print(fact(a))
5. Chuncks
We call each piece of code that Lua executes, such as a file or a single line in interactive mode, a chunk. A chunk is simply a sequence of commands (or statements).
A chunk can be as simple as a single statement, such as in the "Hello World" example, or it can be composed of a mix of statements and function definitions (which are actually assignments, as we will see later), such as the factorial example.
Instead of writing your program to a file, you can run the stand-alone interpreter
in interactive mode. If you call lua
without any arguments, you will get its prompt:
$ lua Lua 5.4.4 Copyright (C) 1994-2022 Lua.org, PUC-Rio >
Thereafter, each command that you type (such as print "Hello World"
)
executes immediately after you enter it. To exit the interactive mode
and the interpreter, just type the end-of-file control character
(ctrl-D
in POSIX, ctrl-Z
in Windows), or call the function os.exit
,
from the Operating System library - you have to type os.exit()
.
Starting in version 5.4, we can enter expressions directly in the interactive mode, and Lua will print their values:
$ lua Lua 5.4.4 Copyright (C) 1994-2022 Lua.org, PUC-Rio > math.pi / 4 --> 0.78539816339745 > a = 15 > a ^ 2 --> 225 > a + 2 --> 17
In older versions, we need to precede these expressions with an equals sign:
$ lua5.2 Lua 5.2.3 Copyright (C) 1994-2013 Lua.org, PUC-Rio > a = 15 > = a ^ 2 --> 225
For compatibility, Lua 5.4 still accepts these equals signs.
To run that code as a chunk (not in interactive mode), we must enclose
the expressions inside calls to print
:
print(math.pi / 4) --> 0.78539816339745
a = 15
print(a ^ 2) --> 225
print(a + 2) --> 17
Lua usually interprets each line that we type in interactive mode as a complete chunk or expression. However, if it detects that the line is not complete, it waits for more input, until it has a complete chunk. This way, we can enter a multi-line definition, such as the factorial function, directly in interactive mode. However, it is usually more convenient to put such definitions in a file and then call Lua to run the file.
We can use the -i
option to instruct Lua to start an interactive session
after running a given chunk:
$ lua -i prog
A command line like this one will run the chunk in the file prog
and then
prompt for interaction. This is especially useful for debugging and manual testing.
Another way to run chunks is with the function dofile
, which immediately executes
a file. For instance, suppose we have a file lib1.lua
with the following code:
function norm (x, y)
return math.sqrt(x^2 + y^2)
end
function twice (x)
return 2.0 * x
end
Then, in interactive mode, we can type this code:
> dofile("lib1.lua") -- load our library > n = norm(3.4, 1.0) > twice(n) --> 7.0880180586677
The function dofile
is useful also when we are testing a piece of code. We can work
with two windows: one is a text editor with our program (in a file prog.lua
, say)
and the other is a console running Lua in interactive mode. After saving a
modification in our program, we execute dofile("prog.lua")
in the Lua console to
load the new code; then we can exercise the new code, calling its functions and
printing the results.
5.1. Some Lexical Conventions
Identifiers (or names) in Lua can be any string of letters, digits, and underscores, not beginning with a digit; for instance
-
i
-
j
-
i10
-
_ij
-
aSomewhatLongName
-
_INPUT
You should avoid identifiers starting with an underscore followed by one or more
upper-case letters (e.g., _VERSION
); they are reserved for special uses in Lua.
Usually, I reserve the identifier _
(a single underscore) for dummy variables.
The following words are reserved; we cannot use them as identifiers:
and end if or until break false in repeat while do for local
return else function nil then elseif goto not true
6. Comments
A comment is a code annotation that is ignored by the programming language. Comments can be used to describe one or many lines of code, to document a program, to temporarily disable code, or for any other reason.
They need to be prefixed by two hyphens to be recognized by Lua and they can be put either on their own line or at the end of another line:
print("This is normal code.")
-- This is a comment
print("This is still normal code.") -- Comment at the end of a line of code.
These comments are called short comments. It is also possible to create long comments, which start with a long bracket and can continue on many lines:
print("This is normal code")
--[[Line 1
Line 2
]]
Long brackets consist of two brackets in the middle of which any number of equality signs may be put. That number is called the level of the long bracket. Long brackets will continue until the next bracket of the same level, if there is one.
A long bracket with no equal sign is called a long bracket of level 0. This approach makes it possible to use closing double brackets inside of long comments by adding equal signs in the middle of the two brackets. It is often useful to do this when using comments to disable blocks of code.
--[==[
This is a comment that contains a closing long bracket of level 0 which is here:
]]
However, the closing double bracket doesn't make the comment end, because the
comment was opened with an opening long bracket of level 2, and only a closing
long bracket of level 2 can close it.
]==]
In the example above, the closing long bracket of level 0 (]]
) does not close the comment,
but the closing long bracket of level 2 (]==]
) does.
Long comments can be more complex than that, as we will see in the section called "Long Strings".
7. Expressions
Expressions are pieces of code that have a value and that can be evaluated. They cannot be executed directly (with the exception of function calls), and thus, a script that would contain only the following code, which consists of an expression, would be erroneous:
3 + 5
The code above is erroneous because all it contains is an expression.
The computer cannot execute 3 + 5
, since that does not make sense.
Code must be comprised of a sequence of statements. These statements can contain expressions which will be values the statement has to manipulate or use to execute the instruction.
Some code examples in this chapter do not constitute valid code, because they consist of only expressions. In the next chapter, statements will be covered and it will be possible to start writing valid code.
Lua needs no separator between consecutive statements, but we can use a semicolon if we wish. Line breaks play no role in Lua’s syntax; for instance, the following four chunks are all valid and equivalent:
a = 1
b = a * 2
a = 1;
b = a * 2;
a = 1; b = a * 2
a = 1 b = a * 2 -- ugly, but valid
8. Global Variables
Global variables do not need declarations; we simply use them. It is not an error to access a non-initialized variable; we just get the value nil as the result:
> b --> nil > b = 10 > b --> 10
If we assign nil to a global variable, Lua behaves as if we have never used the variable:
> b = nil > b --> nil
Lua does not differentiate a non-initialized variable from one that we assigned nil. After the assignment, Lua can eventually reclaim the memory used by the variable.
9. Types and Values
Lua is a dynamically-typed language. There are no type definitions in the language; each value carries its own type.
There are eight basic types in Lua:
nil, Boolean, number, string, userdata, function, thread, and table.
The function type
gives the type name of any given value:
> type(nil) --> nil > type(true) --> boolean > type(10.4 * 3) --> number > type("Hello world") --> string > type(io.stdin) --> userdata > type(print) --> function > type(type) --> function > type({}) --> table > type(type(X)) --> string
The last line will result in “string” no matter the value of X
,
because the result of type
is always a string.
The userdata type allows arbitrary C data to be stored in Lua variables. It has no predefined operations in Lua, except assignment and equality test. Userdata are used to represent new types created by an application program or a library written in C; for instance, the standard I/O library uses them to represent open files. We will discuss more about userdata later, when we get to the C API.
Variables have no predefined types; any variable can contain values of any type:
> type(a) --> nil ('a' is not initialized) > a = 10 > type(a) --> number > a = "a string!!" > type(a) --> string > a = nil > type(a) --> nil
The list of data types for values are given below.
Type |
Description |
nil
|
Used to differentiate the value from having some data or no(nil) data. |
boolean
|
Includes true and false as values. Generally used for condition checking. |
number
|
Represents real(double precision floating point) numbers. |
string
|
Represents array of characters. |
function
|
Represents a method that is written in C or Lua. |
userdata
|
Represents arbitrary C data. |
thread
|
Represents independent threads of execution and it is used to implement coroutines. |
table
|
Represent ordinary arrays, symbol tables, sets, records, graphs, trees, etc., and implements associative arrays. It can hold any value (except nil). |
Usually, when we use a single variable for different types, the result is messy code. However, sometimes the judicious use of this facility is helpful, for instance in the use of nil to differentiate a normal return value from an abnormal condition.
By default, all the variables will point to nil until they are assigned a value or initialized.
We will discuss now the simple types nil and Boolean.
9.1. Nil
Nil is a type with a single value, nil, whose main property is to be different from any other value. Lua uses nil as a kind of non-value, to represent the absence of a useful value. As we have seen, a global variable has a nil value by default, before its first assignment, and we can assign nil to a global variable to delete it.
9.2. Booleans
The Boolean type has two values, false
and true
, which represent the
traditional Boolean values. However, Booleans do not hold a monopoly of
condition values: in Lua, any value can represent a condition. Conditional
tests (e.g., conditions in control structures) consider both the Boolean
false
and nil
as false and anything else as true. In particular, Lua
considers both zero and the empty string as true
in conditional tests.
Throughout this book, I will write "false" to mean any false value, that is,
the Boolean false
or nil. When I mean specifically the Boolean value, I will
write "false". The same holds for "true" and “true”.
Lua supports a conventional set of logical operators: and
, or
, and not
.
Like control structures, all logical operators consider both the Boolean
false
and nil as false, and anything else as true. The result of the and
operator is its first operand if that operand is false; otherwise, the result
is its second operand. The result of the or
operator is its first operand if
it is not false; otherwise, the result is its second operand:
> 4 and 5 --> 5 > nil and 13 --> nil > false and 13 --> false > 0 or 5 --> 0 > false or "hi" --> "hi" > nil or false --> false
Both and and or use short-circuit evaluation, that is, they evaluate
their second operand only when necessary. Short-circuit evaluation ensures that
expressions like (i ~= 0 and a/i > b
) do not cause run-time errors: Lua will
not try to evaluate a / i
when i
is zero.
A useful Lua idiom is x = x or v
, which is equivalent to
if not x then x = v end
That is, it sets x
to a default value v
when x
is not set
(provided that x
is not set to false).
Another useful idiom is ((a and b) or c)
or simply (a and b or c)
(given that and
has a higher precedence than or
). It is equivalent to the C
expression a ? b : c
, provided that b
is not false. For instance, we can select
the maximum of two numbers x
and y
with the expression (x > y) and x or y
.
When x > y
, the first expression of the and is true, so the and results
in its second operand (x
), which is always true (because it is a number),
and then the or expression results in the value of its first operand, x
.
When x > y
is false, the and expression is false and so the or results
in its second operand, y
.
The not operator always gives a Boolean value:
> not nil --> true > not false --> true > not 0 --> false > not not 1 --> true > not not nil --> false
The following operators are often used with boolean values, but can also be used with values of any data type:
Operation | Syntax | Description |
---|---|---|
Boolean negation |
|
If a is false or nil, returns true. Otherwise, returns false. |
Logical conjunction |
|
Returns the first argument if it is false or nil. Otherwise, returns the second argument. |
Logical disjunction |
|
Returns the first argument if it is neither false nor nil. Otherwise, returns the second argument. |
Essentially, the not
operator just negates the boolean value
(makes it false if it is true and makes it true if it is false),
the and
operator returns true if both are true and false if not
and the or
operator returns true if either of arguments is true and false otherwise.
local is_alive = true
print(is_alive) -- true
local is_alive = false
print(is_alive) -- false
9.3. Numbers
Numbers generally represent quantities, but they can be used for many other things. The number type in Lua works mostly in the same way as real numbers.
Numbers can be constructed as integers, decimal numbers, decimal exponents or even in hexadecimal. Here are some valid numbers:
-
3
-
3.0
-
3.1416
-
314.16e-2
-
0.31416E1
-
0xff
-
0x56
-- The Lua
local a = 1
local b = 2
local c = a + b
print(c) -- 3
local d = b - a
print(d)
local x = 1 * 3 * 4 -- 12
print(x)
local y = (1+3) * 2 -- 8
print(y)
print(10 / 2) -- 5
print(2 ^ 2) -- 4
print(5 % 2) -- 1
print(-b) -- -2
-- Incerment
local level = 1
level = level + 1
print(level)
9.3.1. Arithmetic operations
The operators for numbers in Lua are the following:
Operation | Syntax | Description | Example |
---|---|---|---|
Arithmetic negation |
|
Changes the sign of a and returns the value |
|
Addition |
|
Returns the sum of |
|
Subtraction |
|
Subtracts b from a and returns the result |
|
Multiplication |
|
Returns the product of a and b |
|
Exponentiation |
|
Returns a to the power b, or the exponentiation of a by b |
|
Division |
|
Divides a by b and returns the result |
|
Modulus operation |
|
Returns the remainder of the division of a by b |
|
9.3.2. Integers
A new subtype of numbers, integers, was added in Lua 5.3. Numbers can be either integers or floats. Floats are similar to numbers as described above, while integers are numbers with no decimal part.
Float division (/
) and exponentiation always convert their operands to
floats, while all other operators give integers if their two operands were
integers. In other cases, with the exception of the floor division operator
(//
) the result is a float.
9.4. Strings
Strings are sequences of characters that can be used to represent text. They can be written in Lua by being contained in double quotes, single quotes or long brackets (it should be noted that comments and strings have nothing in common other than the fact they can both be delimited by long brackets, preceded by two hyphens in the case of comments).
Strings that aren’t contained in long brackets will only continue for one line. Because of this, the only way to make a string that contains many lines without using long brackets is to use escape sequences. This is also the only way to insert single or double quotes in certain cases.
-
' '
-
" "
-
[[ ]]
local phrase = [[My name is ]]
local name = 'P J'
print(phrase .. name) -- My name is P J
-- Strings and Numbers
local age = 21
local name = "Billy"
print(name .. " is " .. age .. " Years old")
Escape sequence characters are used in string to change the normal interpretation of characters.
For example, to print double inverted commas
("")
, we have to use \"
in the string.
The escape sequence and its use is listed below in the table.
Escape Sequence |
Use |
\a
|
Bell |
\b
|
Backspace |
\f
|
Formfeed |
\n
|
New line |
\r
|
Carriage return |
\t
|
Tab |
\v
|
Vertical tab |
\\
|
Backslash |
\"
|
Double quotes |
\'
|
Single quotes |
\[
|
Left square bracket |
\]
|
Right square bracket |
It is possible to get the length of a string, as a number, by using the unary length operator
(#
):
print(#("This is a string")) --> 16
9.4.1. Concatenation
In formal language theory and computer programming string concatenation is the operation of joining two character strings end-to-end.
Example 1. "snowball"The concatenation of "snow" and "ball".
9.5. Other types
The four basic types in Lua (numbers, booleans, nil and strings) have been described in the previous sections, but four types are missing: functions, tables, userdata and threads.
Functions |
Pieces of code that can be called, receive values and return values back. |
Tables |
Data structures that can be used for data manipulation. |
Userdata |
Used internally by applications Lua is embedded in to allow Lua to communicate with that program through objects controlled by the application. |
Threads |
Used by coroutines, which allow many functions to run at the same time. |