Lua

This article introduce the programming language Lua.

Overview

What is Lua?

Lua is a powerful, efficient, lightweight, embeddable scripting language. It supports procedural programming, object-oriented programming, functional programming, data-driven programming, and data description.

Lua combines simple procedural syntax with powerful data description constructs based on associative arrays and extensible semantics. Lua is dynamically typed, runs by interpreting bytecode with a register-based virtual machine, and has automatic memory management with incremental garbage collection, making it ideal for configuration, scripting, and rapid prototyping.

Where does Lua come from?

Lua is designed, implemented, and maintained by a team at PUC-Rio, the Pontifical Catholic University of Rio de Janeiro in Brazil. Lua was born and raised in Tecgraf, formerly the Computer Graphics Technology Group of PUC-Rio. Lua is now housed at LabLua, a laboratory of the Department of Computer Science of PUC-Rio.

What’s in a name?

“Lua” (pronounced LOO-ah) means “Moon” in Portuguese. As such, it is neither an acronym nor an abbreviation, but a noun. More specifically, “Lua” is a name, the name of the Earth’s moon and the name of the language. Like most names, it should be written in lower case with an initial capital, that is, “Lua”. Please do not write it as “LUA”, which is both ugly and confusing, because then it becomes an acronym with different meanings for different people. So, please, write Lua right!

Showcase

Lua is used in many products and projects around the world. And here are some highlights.

Lua Tutorial

Refer to the following links:

Keywords

Identifiers in Lua can be any string of letters, digits, and underscores, not beginning with a digit.

You should avoid identifiers starting with an underscore followed by one or more uppercase letters (e.g., _VERSION); they are reserved for special uses in Lua. Usually, I reserve the identifier _ (a single underscore) for a dummy variable.

The following words are reserved; we cannot use them as identifiers:

and       break     do        else      elseif
end       false     for       function  if
in        local     nil       not       or
repeat    return    then      true      until
while

Lua is case-sensitive: and is a reserved word, but And and AND are two other different identifiers.

Operators

Arithmetic Operators

Lua supports the usual arithmetic operators:

  • the binary: + (addition), - (subtraction), * (multiplication), / (division)
  • the unary: - (negation)

All of them operate on real numbers.

Lua also offers partial support for ^ (exponentiation).

Relational operators

<   >   <=  >=  ==  ~=

All these operators always result in true or false.

Logical Operators

The logical operators are and, or, and not:

  • All logical operators consider false and nil as false and anything else as true.
  • The operator and returns its first argument if it is false; otherwise, it returns its second argument.
  • The operator or returns its first argument if it is not false; otherwise, it returns its second argument.
print(4 and 5)         --> 5
print(nil and 13)      --> nil
print(false and 13)    --> false
print(4 or 5)          --> 4
print(false or 5)      --> 5

Concatenation

Lua denotes the string concatenation operator by .. (two dots). If any of its operands is a number, Lua converts that number to a string.

print("Hello " .. "World")  --> Hello World
print(0 .. 1)               --> 01

Operator Precedence

According to Lua 5.4 Operator Precedence, the operator precedence in Lua follows the table below, from lower to higher priority:

or
and
<     >     <=    >=    ~=    ==
|
~
&
<<    >>
..
+     -
*     /     //    %
unary operators (not   #     -     ~)
^

All binary operators are left associative, except for ^ (exponentiation) and .. (concatenation), which are right associative.

Comments

A comment starts anywhere with a double hyphen -- and runs until the end of the line. Lua also offers block comments, which start with --[[ and run until the corresponding ]]. A common trick, when we want to comment out a piece of code, is to write the following:

--[[
print(10)         -- no action (comment)
--]]

Now, if we add a single hyphen to the first line, the code is in again:

---[[
print(10)         --> 10
--]]

Variables

Variables are places that store values. There are three kinds of variables in Lua:

  • Global variables: Any variable name is assumed to be global unless explicitly declared as a local.
  • Local variables: Local variables are lexically scoped: local variables can be freely accessed by functions defined inside their scope.
  • Table fields: This is a special type of variable that can hold anything except nil including functions.

Global Variables

Lua keeps all its global variables in a regular table, called the environment. Lua stores the environment itself in a global variable _G. The following code prints the names of all global variables defined in the current environment:

for n in pairs(_G) do
    print(n)
end

Take lua5.3 for instance:

chenwx@chenwx:~ $ lua5.3
Lua 5.3.3  Copyright (C) 1994-2016 Lua.org, PUC-Rio
> for n in pairs(_G) do print(n) end
next
tostring
rawget
rawset
dofile
print
rawlen
xpcall
_G
utf8
pairs
error
table
load
rawequal
setmetatable
pcall
collectgarbage
tonumber
bit32
package
select
assert
io
type
loadfile
arg
debug
require
math
getmetatable
os
string
ipairs
coroutine
_VERSION

Local Variable

It is good programming style to use local variables whenever possible. Local variables help you avoid cluttering the global environment with unnecessary names. Moreover, the access to local variables is faster than to global ones.

Control Structures

if-then-else-end

if op == "+" then
    r = a + b
elseif op == "-" then
    r = a - b
elseif op == "*" then
    r = a*b
elseif op == "/" then
    r = a/b
else
    error("invalid operation")
end

while-do-end

local i = 1

while a[i] do
    print(a[i])
    i = i + 1
end

repeat-until

The test is done after the body, so the body is always executed at least once.

-- print the first non-empty line
repeat
    line = os.read()
until line ~= ""

print(line)

for

The for statement has two variants: the numeric for and the generic for.

Numeric for

A numeric for has the following syntax:

for var=exp1,exp2,exp3 do
    something
end

That loop will execute something for each value of var from exp1 to exp2, using exp3 as the step to increment var. This third expression is optional; when absent, Lua assumes one as the step value. As typical examples of such loops, we have

for i=1,f(x) do
    print(i)
end

for i=10,1,-1 do
    print(i)
end

The for loop has some subtleties that you should learn in order to make good use of it.

  • First, all three expressions are evaluated once, before the loop starts. For instance, in the first example, f(x) is called only once.

  • Second, the control variable is a local variable automatically declared by the for statement and is visible only inside the loop. A typical mistake is to assume that the variable still exists after the loop ends:

for i=1,10 do
    print(i)
end

max = i      -- probably wrong! 'i' here is global
  • Third, you should never change the value of the control variable: The effect of such changes is unpredictable. If you want to break a for loop before its normal termination, use break.

Generic for

The generic for loop allows you to traverse all values returned by an iterator function. For each step in below code, i gets an index, while v gets the value associated with that index:

-- print all values of array 'a'
for i,v in ipairs(a) do
    print(v)
end

The generic loop shares two properties with the numeric loop: The loop variables are local to the loop body and you should never assign any value to the loop variables.

Functions

If the function call has no arguments, we must write an empty list () to indicate the call. There is a special case to this rule: If the function has one single argument and this argument is either a literal string or a table constructor, then the parentheses are optional:

print "Hello World"     <-->     print("Hello World")
dofile 'a.lua'          <-->     dofile ('a.lua')
print [[a multi-line    <-->     print([[a multi-line
message]]                        message]])
f{x=10, y=20}           <-->     f({x=10, y=20})
type{}                  <-->     type({})

Lua also offers a special syntax for object-oriented calls, the colon operator. An expression like o:foo(x) is just another way to write o.foo(o, x), that is, to call o.foo adding o as a first extra argument.

Functions used by a Lua program can be defined both in Lua and in C (or in any other language used by the host application).

-- add all elements of array `a'
function add (a)
    local sum = 0
    for i,v in ipairs(a) do
        sum = sum + v
    end
    return sum
end

You can call a function with a number of arguments different from its number of parameters. Lua adjusts the number of arguments to the number of parameters, as it does in a multiple assignment: Extra arguments are thrown away; extra parameters get nil. For instance, if we have a function like:

function f(a, b)
    return a or b
end

we will have the following mapping from arguments to parameters:

CALL             PARAMETERS

f(3)             a=3, b=nil
f(3, 4)          a=3, b=4
f(3, 4, 5)       a=3, b=4   (5 is discarded)

Although this behavior can lead to programming errors (easily spotted at run time), it is also useful, especially for default arguments. For instance, consider the following function, to increment a global counter.

function incCount (n)
    n = n or 1
    count = count + n
end

This function has 1 as its default argument; that is, the call incCount(), without arguments, increments count by one. When you call incCount(), Lua first initializes n with nil; the or results in its second operand; and as a result Lua assigns a default 1 to n.

Multiple Results

An unconventional, but quite convenient feature of Lua is that functions may return multiple results. Functions written in Lua also can return multiple results, by listing them all after the return keyword.

In a multiple assignment, a function call as the last (or only) expression produces as many results as needed to match the variables.

If a function has no results, or not as many results as we need, Lua produces nils.

A function call that is not the last element in the list always produces one result.

When a function call is the last (or the only) argument to another call, all results from the first call go as arguments.

You can force a call to return exactly one result by enclosing it in an extra pair of parentheses.

A special function with multiple returns is unpack. It receives an array and returns as results all elements from the array, starting from index 1.

Variable Number of Arguments

The three dots ... in the parameter list indicate that the function has a variable number of arguments. When this function is called, all its arguments are collected in a single table, which the function accesses as a hidden parameter named arg. Besides those arguments, the arg table has an extra field, n, with the actual number of arguments collected.

function print (...)
    print(arg[n] .. " elements in input parameter arg:")
    for i,v in ipairs(arg) do
        print(tostring(i) .. tostring(v) .. "\n")
    end
end

When we write a function that returns multiple values into an expression, only its first result is used. However, sometimes we want another result. A typical solution is to use dummy variables; for instance, if we want only the second result from string.find, we may write the following code:

local _, x = string.find(s, p)
-- now use `x'
...

An alternative solution is to define a select function, which selects a specific return from a function:

print(string.find("hello hello", " hel"))         --> 6  9
print(select(1, string.find("hello hello", " hel"))) --> 6
print(select(2, string.find("hello hello", " hel"))) --> 9

More about Functions

Functions in Lua are first-class values with proper lexical scoping:

  • first-class values means that, in Lua, a function is a value with the same rights as conventional values like numbers and strings. Functions can be stored in variables (both global and local) and in tables, can be passed as arguments, and can be returned by other functions.

  • lexical scoping means that functions can access variables of its enclosing functions. (It also means that Lua contains the lambda calculus properly.)

A somewhat difficult notion in Lua is that functions, like all other values, are anonymous; they do not have names. When we talk about a function name, say print, we are actually talking about a variable that holds that function. Like any other variable holding any other value, we can manipulate such variables in many ways.

In fact, the usual way to write a function in Lua, like:

function foo (x) return 2*x end

is just an instance of what we call syntactic sugar; in other words, it is just a pretty way to write:

foo = function (x) return 2*x end

That is, a function definition is in fact a statement (an assignment, more specifically) that assigns a value of type function to a variable. We can see the expression function (x) ... end as a function constructor, just as {} is a table constructor. We call the result of such function constructors an anonymous function. Although we usually assign functions to global names, giving them something like a name, there are several occasions when functions remain anonymous.

A function that gets another function as an argument, such as sort, is what we call a higher-order function. Higher-order functions are a powerful programming mechanism and the use of anonymous functions to create their function arguments is a great source of flexibility. But remember that higher-order functions have no special rights; they are a simple consequence of the ability of Lua to handle functions as first-class values.

Data Structures

Install Lua on LinuxMint

Install Lua via APT

One way to install Lua on LinuxMint is using apt to install it in binary:

chenwx@chenwx:~ $ sudo apt install lua
[sudo] password for chenwx:       
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Package lua is a virtual package provided by:
  lua50 5.0.3-8
  lua5.3 5.3.3-1
  lua5.2 5.2.4-1.1build1
  lua5.1 5.1.5-8.1build2
You should explicitly select one to install.

E: Package 'lua' has no installation candidate

chenwx@chenwx:~ $ sudo apt install lua5.3
Reading package lists... Done
Building dependency tree       
Reading state information... Done
lua5.3 is already the newest version (5.3.3-1).
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

chenwx@chenwx:~ $ which lua5.3
/usr/bin/lua5.3

chenwx@chenwx:~ $ lua5.3 -v
Lua 5.3.3  Copyright (C) 1994-2016 Lua.org, PUC-Rio

Build Lua from Source Code

Lua is free software distributed in source code. So, it’s possible to download Lua’s source code and build it from scratch:

chenwx@chenwx:~ $ mkdir lua
chenwx@chenwx:~ $ cd lua

chenwx@chenwx:~/lua $ curl -R -O http://www.lua.org/ftp/lua-5.3.1.tar.gz
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  275k  100  275k    0     0  36275      0  0:00:07  0:00:07 --:--:-- 66151

chenwx@chenwx:~/lua $ tar zxf lua-5.3.1.tar.gz
chenwx@chenwx:~/lua $ cd lua-5.3.1

chenwx@chenwx:~/lua/lua-5.3.1 $ make linux test
cd src && make linux
make[1]: Entering directory '/home/chenwx/lua/lua-5.3.1/src'
make all SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline"
make[2]: Entering directory '/home/chenwx/lua/lua-5.3.1/src'
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lapi.o lapi.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lcode.o lcode.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lctype.o lctype.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o ldebug.o ldebug.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o ldo.o ldo.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o ldump.o ldump.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lfunc.o lfunc.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lgc.o lgc.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o llex.o llex.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lmem.o lmem.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lobject.o lobject.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lopcodes.o lopcodes.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lparser.o lparser.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lstate.o lstate.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lstring.o lstring.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o ltable.o ltable.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o ltm.o ltm.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lundump.o lundump.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lvm.o lvm.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lzio.o lzio.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lauxlib.o lauxlib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lbaselib.o lbaselib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lbitlib.o lbitlib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lcorolib.o lcorolib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o ldblib.o ldblib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o liolib.o liolib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lmathlib.o lmathlib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o loslib.o loslib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lstrlib.o lstrlib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o ltablib.o ltablib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lutf8lib.o lutf8lib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o loadlib.o loadlib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o linit.o linit.c
ar rcu liblua.a lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o lauxlib.o lbaselib.o lbitlib.o lcorolib.o ldblib.o liolib.o lmathlib.o loslib.o lstrlib.o ltablib.o lutf8lib.o loadlib.o linit.o
ar: `u' modifier ignored since `D' is the default (see `U')
ranlib liblua.a
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lua.o lua.c
gcc -std=gnu99 -o lua   lua.o liblua.a -lm -Wl,-E -ldl -lreadline
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o luac.o luac.c
gcc -std=gnu99 -o luac   luac.o liblua.a -lm -Wl,-E -ldl -lreadline
make[2]: Leaving directory '/home/chenwx/lua/lua-5.3.1/src'
make[1]: Leaving directory '/home/chenwx/lua/lua-5.3.1/src'
src/lua -v
Lua 5.3.1  Copyright (C) 1994-2015 Lua.org, PUC-Rio

chenwx@chenwx:~/lua/lua-5.3.1 $ ll src/lua src/luac
-rwxr-xr-x 1 chenwx chenwx 254K Jan  8 22:23 src/lua
-rwxr-xr-x 1 chenwx chenwx 167K Jan  8 22:23 src/luac

chenwx@chenwx:~/lua/lua-5.3.1 $ ./src/lua -v
Lua 5.3.1  Copyright (C) 1994-2015 Lua.org, PUC-Rio

chenwx@chenwx:~/lua/lua-5.3.1 $ ./src/luac -v
Lua 5.3.1  Copyright (C) 1994-2015 Lua.org, PUC-Rio

Usage of Lua Interpreter

man page of Lua interpreter:

chenwx@chenwx:~ $ which lua5.3
/usr/bin/lua5.3

chenwx@chenwx:~ $ man lua
LUA5.3(1)                  General Commands Manual                 LUA5.3(1)

NAME
       lua - Lua interpreter

SYNOPSIS
       lua [ options ] [ script [ args ] ]

DESCRIPTION
       lua  is  the  standalone  Lua interpreter.  It loads and executes Lua
       programs, either in textual source  form  or  in  precompiled  binary
       form.   (Precompiled  binaries are output by luac, the Lua compiler.)
       lua can be used as a batch interpreter and also interactively.

       The given options are handled in order and then the  Lua  program  in
       file  script is loaded and executed.  The given args are available to
       script as strings in a global table named  arg.   If  no  options  or
       arguments are given, then -v -i is assumed when the standard input is
       a terminal; otherwise, - is assumed.

       In interactive mode, lua prompts the user, reads lines from the stan-
       dard input, and executes them as they are read.  If the line contains
       an expression or list of expressions, then the line is evaluated  and
       the  results  are  printed.   If  a  line does not contain a complete
       statement, then a secondary prompt is displayed and  lines  are  read
       until a complete statement is formed or a syntax error is found.

       At  the very start, before even handling the command line, lua checks
       the contents of the environment variables LUA_INIT_5_3  or  LUA_INIT,
       in  that  order.   If  the  contents is of the form '@filename', then
       filename is executed.  Otherwise, the string is assumed to be  a  Lua
       statement and is executed.

OPTIONS
       -e stat
              execute statement stat.

       -i     enter interactive mode after executing script.

       -l name
              execute  the equivalent of name=require('name') before execut-
              ing script.

       -v     show version information.

       -E     ignore environment variables.

       --     stop handling options.

       -      stop handling options and execute  the  standard  input  as  a
              file.

SEE ALSO
       luac(1)
       The  documentation  at lua.org, especially section 7 of the reference
       manual.

DIAGNOSTICS
       Error messages should be self explanatory.

AUTHORS
       R. Ierusalimschy, L. H. de Figueiredo, W. Celes

                        $Date: 2014/12/10 15:55:45 $               LUA5.3(1)

Usage of Lua Compiler

man page of Lua compiler:

chenwx@chenwx:~ $ which luac5.3
/usr/bin/luac5.3

chenwx@chenwx:~ $ man lua
	LUAC5.3(1)                 General Commands Manual                LUAC5.3(1)

NAME
       luac - Lua compiler

SYNOPSIS
       luac [ options ] [ filenames ]

DESCRIPTION
       luac  is the Lua compiler.  It translates programs written in the Lua
       programming language into binary files containing precompiled  chunks
       that can be later loaded and executed.

       The  main advantages of precompiling chunks are: faster loading, pro-
       tecting source code from accidental user changes, and off-line syntax
       checking.   Precompiling  does  not imply faster execution because in
       Lua chunks are always compiled into bytecodes before being  executed.
       luac  simply  allows  those bytecodes to be saved in a file for later
       execution.  Precompiled chunks are not necessarily smaller  than  the
       corresponding  source.  The main goal in precompiling is faster load-
       ing.

       In the command line, you can mix text files containing Lua source and
       binary  files  containing precompiled chunks.  luac produces a single
       output file containing the combined bytecodes for  all  files  given.
       Executing  the  combined  file  is  equivalent to executing the given
       files.  By default, the output file is named luac.out,  but  you  can
       change this with the -o option.

       Precompiled  chunks  are not portable across different architectures.
       Moreover, the internal format of  precompiled  chunks  is  likely  to
       change when a new version of Lua is released.  Make sure you save the
       source files of all Lua programs that you precompile.

OPTIONS
       -l     produce a listing of the compiled bytecode for  Lua's  virtual
              machine.   Listing  bytecodes  is  useful to learn about Lua's
              virtual machine.  If no  files  are  given,  then  luac  loads
              luac.out  and  lists its contents.  Use -l -l for a full list-
              ing.

       -o file
              output to file, instead of the default luac.out.  (You can use
              '-'  for standard output, but not on platforms that open stan-
              dard output in text mode.)  The output file may be one of  the
              given  files  because  all  files are loaded before the output
              file is written.  Be careful not to overwrite precious files.

       -p     load files but do not generate any output file.   Used  mainly
              for  syntax  checking and for testing precompiled chunks: cor-
              rupted files will probably generate errors when loaded.  If no
              files  are  given, then luac loads luac.out and tests its con-
              tents.  No messages are displayed if the  file  loads  without
              errors.

       -s     strip  debug information before writing the output file.  This
              saves some space in very large chunks,  but  if  errors  occur
              when running a stripped chunk, then the error messages may not
              contain the full information they usually do.  In  particular,
              line numbers and names of local variables are lost.

       -v     show version information.

       --     stop handling options.

       -      stop handling options and process standard input.

SEE ALSO
       lua(1)
       The documentation at lua.org.

DIAGNOSTICS
       Error messages should be self explanatory.

AUTHORS
       R. Ierusalimschy, L. H. de Figueiredo, W. Celes

                        $Date: 2011/11/16 13:53:40 $              LUAC5.3(1)

Compile Lua Code to Bytecode

The Lua compiler luac translates programs written in the Lua programming language into binary files containing precompiled chunks that can be later loaded and executed. Refer to luac man page for details.

chenwx@chenwx:~/lua $ cat hello.lua
function max(num1, num2)

   if (num1 > num2) then
      result = num1;
   else
      result = num2;
   end

   return result;
end

print("max value is ", max(10,4))
print("max value is ", max(5,6))

chenwx@chenwx:~/lua $ luac5.3 hello.lua
chenwx@chenwx:~/lua $ ll
-rw-r--r--  1 chenwx chenwx  201 Jan  8 23:10 hello.lua
drwxr-xr-x  4 chenwx chenwx 4.0K Jun 10  2015 lua-5.3.1
-rw-r--r--  1 chenwx chenwx  435 Jan  8 23:10 luac.out
drwxr-xr-x 18 chenwx chenwx 4.0K Jan  8 23:06 luadec

chenwx@chenwx:~/lua $ hexdump -C luac.out
00000000  1b 4c 75 61 53 00 19 93  0d 0a 1a 0a 04 08 04 08  |.LuaS...........|
00000010  08 78 56 00 00 00 00 00  00 00 00 00 00 00 28 77  |.xV...........(w|
00000020  40 01 0b 40 68 65 6c 6c  6f 2e 6c 75 61 00 00 00  |@..@hello.lua...|
00000030  00 00 00 00 00 00 01 05  11 00 00 00 2c 00 00 00  |............,...|
00000040  08 00 00 80 06 40 40 00  41 80 00 00 86 00 40 00  |.....@@.A.....@.|
00000050  c1 c0 00 00 01 01 01 00  a4 00 80 01 24 40 00 00  |............$@..|
00000060  06 40 40 00 41 80 00 00  86 00 40 00 c1 40 01 00  |.@@.A.....@..@..|
00000070  01 81 01 00 a4 00 80 01  24 40 00 00 26 00 80 00  |........$@..&...|
00000080  07 00 00 00 04 04 6d 61  78 04 06 70 72 69 6e 74  |......max..print|
00000090  04 0e 6d 61 78 20 76 61  6c 75 65 20 69 73 20 13  |..max value is .|
000000a0  0a 00 00 00 00 00 00 00  13 04 00 00 00 00 00 00  |................|
000000b0  00 13 05 00 00 00 00 00  00 00 13 06 00 00 00 00  |................|
000000c0  00 00 00 01 00 00 00 01  00 01 00 00 00 00 01 00  |................|
000000d0  00 00 0a 00 00 00 02 00  03 08 00 00 00 20 00 80  |............. ..|
000000e0  00 1e 40 00 80 08 00 00  80 1e 00 00 80 08 40 00  |..@...........@.|
000000f0  80 86 00 40 00 a6 00 00  01 26 00 80 00 01 00 00  |...@.....&......|
00000100  00 04 07 72 65 73 75 6c  74 01 00 00 00 00 00 00  |...result.......|
00000110  00 00 00 08 00 00 00 03  00 00 00 03 00 00 00 04  |................|
00000120  00 00 00 04 00 00 00 06  00 00 00 09 00 00 00 09  |................|
00000130  00 00 00 0a 00 00 00 02  00 00 00 05 6e 75 6d 31  |............num1|
00000140  00 00 00 00 08 00 00 00  05 6e 75 6d 32 00 00 00  |.........num2...|
00000150  00 08 00 00 00 01 00 00  00 05 5f 45 4e 56 11 00  |.........._ENV..|
00000160  00 00 0a 00 00 00 01 00  00 00 0c 00 00 00 0c 00  |................|
00000170  00 00 0c 00 00 00 0c 00  00 00 0c 00 00 00 0c 00  |................|
00000180  00 00 0c 00 00 00 0d 00  00 00 0d 00 00 00 0d 00  |................|
00000190  00 00 0d 00 00 00 0d 00  00 00 0d 00 00 00 0d 00  |................|
000001a0  00 00 0d 00 00 00 00 00  00 00 01 00 00 00 05 5f  |..............._|
000001b0  45 4e 56                                          |ENV|
000001b3

chenwx@chenwx:~/lua $ lua5.3 luac.out
max value is 	10
max value is 	6

Encode/Decode Lua Bytecode via Base64

The Lua bytecode can be encoded or decoded by tool base64:

chenwx@chenwx:~/lua $ base64 --help
Usage: base64 [OPTION]... [FILE]
Base64 encode or decode FILE, or standard input, to standard output.

With no FILE, or when FILE is -, read standard input.

Mandatory arguments to long options are mandatory for short options too.
  -d, --decode          decode data
  -i, --ignore-garbage  when decoding, ignore non-alphabet characters
  -w, --wrap=COLS       wrap encoded lines after COLS character (default 76).
                          Use 0 to disable line wrapping

      --help     display this help and exit
      --version  output version information and exit

The data are encoded as described for the base64 alphabet in RFC 4648.
When decoding, the input may contain newlines in addition to the bytes of
the formal base64 alphabet.  Use --ignore-garbage to attempt to recover
from any other non-alphabet bytes in the encoded stream.

GNU coreutils online help: <http://www.gnu.org/software/coreutils/>
Report base64 translation bugs to <http://translationproject.org/team/>
Full documentation at: <http://www.gnu.org/software/coreutils/base64>
or available locally via: info '(coreutils) base64 invocation'

chenwx@chenwx:~/lua $ base64 luac.out > luac.out.encode

chenwx@chenwx:~/lua $ cat luac.out.encode
G0x1YVMAGZMNChoKBAgECAh4VgAAAAAAAAAAAAAAKHdAAQtAaGVsbG8ubHVhAAAAAAAAAAAAAQUR
AAAALAAAAAgAAIAGQEAAQYAAAIYAQADBwAAAAQEBAKQAgAEkQAAABkBAAEGAAACGAEAAwUABAAGB
AQCkAIABJEAAACYAgAAHAAAABARtYXgEBnByaW50BA5tYXggdmFsdWUgaXMgEwoAAAAAAAAAEwQA
AAAAAAAAEwUAAAAAAAAAEwYAAAAAAAAAAQAAAAEAAQAAAAABAAAACgAAAAIAAwgAAAAgAIAAHkAA
gAgAAIAeAACACEAAgIYAQACmAAABJgCAAAEAAAAEB3Jlc3VsdAEAAAAAAAAAAAAIAAAAAwAAAAMA
AAAEAAAABAAAAAYAAAAJAAAACQAAAAoAAAACAAAABW51bTEAAAAACAAAAAVudW0yAAAAAAgAAAAB
AAAABV9FTlYRAAAACgAAAAEAAAAMAAAADAAAAAwAAAAMAAAADAAAAAwAAAAMAAAADQAAAA0AAAAN
AAAADQAAAA0AAAANAAAADQAAAA0AAAAAAAAAAQAAAAVfRU5W

chenwx@chenwx:~/lua $ base64 -d luac.out.encode > luac.out.decode

chenwx@chenwx:~/lua $ hexdump -C luac.out.decode
00000000  1b 4c 75 61 53 00 19 93  0d 0a 1a 0a 04 08 04 08  |.LuaS...........|
00000010  08 78 56 00 00 00 00 00  00 00 00 00 00 00 28 77  |.xV...........(w|
00000020  40 01 0b 40 68 65 6c 6c  6f 2e 6c 75 61 00 00 00  |@..@hello.lua...|
00000030  00 00 00 00 00 00 01 05  11 00 00 00 2c 00 00 00  |............,...|
00000040  08 00 00 80 06 40 40 00  41 80 00 00 86 00 40 00  |.....@@.A.....@.|
00000050  c1 c0 00 00 01 01 01 00  a4 00 80 01 24 40 00 00  |............$@..|
00000060  06 40 40 00 41 80 00 00  86 00 40 00 c1 40 01 00  |.@@.A.....@..@..|
00000070  01 81 01 00 a4 00 80 01  24 40 00 00 26 00 80 00  |........$@..&...|
00000080  07 00 00 00 04 04 6d 61  78 04 06 70 72 69 6e 74  |......max..print|
00000090  04 0e 6d 61 78 20 76 61  6c 75 65 20 69 73 20 13  |..max value is .|
000000a0  0a 00 00 00 00 00 00 00  13 04 00 00 00 00 00 00  |................|
000000b0  00 13 05 00 00 00 00 00  00 00 13 06 00 00 00 00  |................|
000000c0  00 00 00 01 00 00 00 01  00 01 00 00 00 00 01 00  |................|
000000d0  00 00 0a 00 00 00 02 00  03 08 00 00 00 20 00 80  |............. ..|
000000e0  00 1e 40 00 80 08 00 00  80 1e 00 00 80 08 40 00  |..@...........@.|
000000f0  80 86 00 40 00 a6 00 00  01 26 00 80 00 01 00 00  |...@.....&......|
00000100  00 04 07 72 65 73 75 6c  74 01 00 00 00 00 00 00  |...result.......|
00000110  00 00 00 08 00 00 00 03  00 00 00 03 00 00 00 04  |................|
00000120  00 00 00 04 00 00 00 06  00 00 00 09 00 00 00 09  |................|
00000130  00 00 00 0a 00 00 00 02  00 00 00 05 6e 75 6d 31  |............num1|
00000140  00 00 00 00 08 00 00 00  05 6e 75 6d 32 00 00 00  |.........num2...|
00000150  00 08 00 00 00 01 00 00  00 05 5f 45 4e 56 11 00  |.........._ENV..|
00000160  00 00 0a 00 00 00 01 00  00 00 0c 00 00 00 0c 00  |................|
00000170  00 00 0c 00 00 00 0c 00  00 00 0c 00 00 00 0c 00  |................|
00000180  00 00 0c 00 00 00 0d 00  00 00 0d 00 00 00 0d 00  |................|
00000190  00 00 0d 00 00 00 0d 00  00 00 0d 00 00 00 0d 00  |................|
000001a0  00 00 0d 00 00 00 00 00  00 00 01 00 00 00 05 5f  |..............._|
000001b0  45 4e 56                                          |ENV|
000001b3
chenwx@chenwx:~/lua $ diff luac.out luac.out.decode
chenwx@chenwx:~/lua $

chenwx@chenwx:~/lua $ ./lua-5.3.1/src/lua luac.out.decode
max value is 	10
max value is 	6

Decode Lua Bytecode

Lua bytecode has format as specified on Lua 5.3 Bytecode Reference. It’s possible to use LuaDec to decode Lua bytecode:

chenwx@chenwx:~/lua $ git clone https://github.com/viruscamp/luadec
Cloning into 'luadec'...
remote: Enumerating objects: 2117, done.
remote: Total 2117 (delta 0), reused 0 (delta 0), pack-reused 2117
Receiving objects: 100% (2117/2117), 2.65 MiB | 56.00 KiB/s, done.
Resolving deltas: 100% (1308/1308), done.

chenwx@chenwx:~/lua $ cd luadec/
chenwx@chenwx:~/lua/luadec $ git submodule update --init lua-5.3
Submodule 'lua-5.3' (https://github.com/viruscamp/lua5) registered for path 'lua-5.3'
Cloning into '/home/chenwx/lua/luadec/lua-5.3'...
Submodule path 'lua-5.3': checked out 'f9785d609d20af8d28b05a05a757dad5ed770852'

chenwx@chenwx:~/lua/luadec $ cd lua-5.3
chenwx@chenwx:~/lua/luadec/lua-5.3 $ git lhg -10
* f9785d609d20 2016-09-22 VirusCamp  (HEAD, tag: 5.3.3) lua-5.3.3 2016-05-30
* 36ebdad2ed40 2016-09-22 VirusCamp  (tag: 5.3.2) lua-5.3.2 2015-11-25
* 8071eaea5ad7 2016-09-22 VirusCamp  (tag: 5.3.1) lua-5.3.1 2015-06-10
* 23c9a0ef6222 2015-03-28 VirusCamp  (tag: 5.3.0) lua-5.3.0 2015-01-06
* 06b0e58ae7f2 2014-11-12 VirusCamp  lua-5.3.0-beta 2014-10-23
* 267b4bd00ed6 2014-11-12 VirusCamp  lua-5.3.0-alpha 2014-07-31
* 680bf808e382 2014-11-12 VirusCamp  lua-5.3.0-work3 2014-06-19
* 47cf35766408 2014-11-12 VirusCamp  lua-5.3.0-work2 2014-03-21
* 184a12c4a46d 2014-11-12 VirusCamp  lua-5.3.0-work1 2013-07-06
* 5a39d6da6297 2014-10-18 viruscamp  (tag: 5.2.3) lua-5.2.3 2013-11-11

chenwx@chenwx:~/lua/luadec/lua-5.3 $ git co 5.3.1
Previous HEAD position was f9785d609d20 lua-5.3.3 2016-05-30
HEAD is now at 8071eaea5ad7 lua-5.3.1 2015-06-10

chenwx@chenwx:~/lua/luadec/lua-5.3 $ cd ../
chenwx@chenwx:~/lua/luadec $ git submodule status
-e496bc6df2e49ea0beebb26f216aca3821a2b28e LuaAssemblyTools
-c9ef6799113e71d89d629b29b266d1eba4105038 ilua
-cdcfa70f2f731409046374e797a62314b4924b77 lua-5.1
-0137406b0635f22f5c9b894e0da1d15abdb036bc lua-5.2
+8071eaea5ad72343d6873ade47d947c42d76bae9 lua-5.3 (5.3.1)
-79c86d1b258b13dc0d1a2a66f28aadc0f6e23944 memwatch

chenwx@chenwx:~/lua/luadec $ cd lua-5.3/
chenwx@chenwx:~/lua/luadec/lua-5.3 $ make linux
cd src && make linux
make[1]: Entering directory '/home/chenwx/lua/luadec/lua-5.3/src'
make all SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline"
make[2]: Entering directory '/home/chenwx/lua/luadec/lua-5.3/src'
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lapi.o lapi.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lcode.o lcode.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lctype.o lctype.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o ldebug.o ldebug.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o ldo.o ldo.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o ldump.o ldump.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lfunc.o lfunc.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lgc.o lgc.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o llex.o llex.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lmem.o lmem.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lobject.o lobject.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lopcodes.o lopcodes.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lparser.o lparser.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lstate.o lstate.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lstring.o lstring.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o ltable.o ltable.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o ltm.o ltm.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lundump.o lundump.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lvm.o lvm.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lzio.o lzio.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lauxlib.o lauxlib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lbaselib.o lbaselib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lbitlib.o lbitlib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lcorolib.o lcorolib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o ldblib.o ldblib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o liolib.o liolib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lmathlib.o lmathlib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o loslib.o loslib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lstrlib.o lstrlib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o ltablib.o ltablib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lutf8lib.o lutf8lib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o loadlib.o loadlib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o linit.o linit.c
ar rcu liblua.a lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o lauxlib.o lbaselib.o lbitlib.o lcorolib.o ldblib.o liolib.o lmathlib.o loslib.o lstrlib.o ltablib.o lutf8lib.o loadlib.o linit.o
ar: `u' modifier ignored since `D' is the default (see `U')
ranlib liblua.a
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lua.o lua.c
gcc -std=gnu99 -o lua   lua.o liblua.a -lm -Wl,-E -ldl -lreadline
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o luac.o luac.c
gcc -std=gnu99 -o luac   luac.o liblua.a -lm -Wl,-E -ldl -lreadline
make[2]: Leaving directory '/home/chenwx/lua/luadec/lua-5.3/src'
make[1]: Leaving directory '/home/chenwx/lua/luadec/lua-5.3/src'

chenwx@chenwx:~/lua/luadec/lua-5.3 $ cd ../luadec
chenwx@chenwx:~/lua/luadec/luadec $ make LUAVER=5.3
gcc -O2 -Wall -DSRCVERSION=\"895d92313fab\" -I../lua-5.3/src    -c -o guess.o guess.c
...
gcc -o luaopswap  luaopswap.o ../lua-5.3/src/liblua.a -lm

chenwx@chenwx:~/lua/luadec/luadec $ cd ../..
chenwx@chenwx:~/lua $ ll
-rw-r--r--  1 chenwx chenwx  201 Jan  8 23:10 hello.lua
drwxr-xr-x  4 chenwx chenwx 4.0K Jun 10  2015 lua-5.3.1
-rw-r--r--  1 chenwx chenwx  435 Jan  8 23:10 luac.out
-rw-r--r--  1 chenwx chenwx  435 Jan  9 21:19 luac.out.decode
-rw-r--r--  1 chenwx chenwx  588 Jan  9 21:19 luac.out.encode
drwxr-xr-x 18 chenwx chenwx 4.0K Jan  8 23:06 luadec

chenwx@chenwx:~/lua $ ./luadec/luadec/luadec luac.out
-- Decompiled using luadec 2.2 rev: 895d92313fab for Lua 5.3 from https://github.com/viruscamp/luadec
-- Command line: luac.out

-- params : ...
-- function num : 0 , upvalues : _ENV
max = function(num1, num2)
  -- function num : 0_0 , upvalues : _ENV
  if num2 < num1 then
    result = num1
  else
    result = num2
  end
  return result
end

print("max value is ", max(10, 4))
print("max value is ", max(5, 6))

chenwx@chenwx:~/lua $ ./luadec/luadec/luadec luac.out.decode
-- Decompiled using luadec 2.2 rev: 895d92313fab for Lua 5.3 from https://github.com/viruscamp/luadec
-- Command line: luac.out.decode

-- params : ...
-- function num : 0 , upvalues : _ENV
max = function(num1, num2)
  -- function num : 0_0 , upvalues : _ENV
  if num2 < num1 then
    result = num1
  else
    result = num2
  end
  return result
end

print("max value is ", max(10, 4))
print("max value is ", max(5, 6))

Projects

LuatOS

LuatOS

Examples

Example 1: Print global variables

local g_str_key    = "key      : "
local g_str_type   = "type     : "
local g_str_len    = "length   : "
local g_str_value  = "value    : "
local g_str_prefix = "    "
local g_max_layer  = 10


function print_table(table, num_of_layer)

    local type_of_table = type(table)

    if type_of_table ~= "table" then
        return
    end

    local str_prefix = string.rep(g_str_prefix, num_of_layer)

    -- loop all elements in this table

    for key, value in pairs(table) do

        str_tmp = string.format("\n%s%s%s", str_prefix, g_str_key, key)
        print(str_tmp)

        local type_of_value = type(value)
        str_tmp = string.format("%s%s%s", str_prefix, g_str_type, type_of_value)
        print(str_tmp)
        
        if type_of_value == "string" then

            str_tmp = string.format("%s%s%s", str_prefix, g_str_value, value)
            print(str_tmp)
        
        elseif (type_of_value == "table") and      -- loop next table
               (key ~= "_G") and                   -- exclude table _G
               (num_of_layer <= g_max_layer) then  -- limit number of layers
        
            local len_of_table = 0
            for _, _ in pairs(value) do
                len_of_table = len_of_table + 1
            end

            str_tmp = string.format("%s%s%s", str_prefix, g_str_len, len_of_table)
            print(str_tmp)

            print_table(value, num_of_layer + 1)
        
        end

    end

end


-- print table _G

function print_G()

    local num_of_layer = 0
    local str_prefix = string.rep(g_str_prefix, num_of_layer)

    local str_tmp = string.format("%s%s%s", str_prefix, g_str_key, "_G")
    print(str_tmp)

    local type_of_value = type(_G)
    str_tmp = string.format("%s%s%s", str_prefix, g_str_type, type_of_value)
    print(str_tmp)

    local len_of_table = 0

    for _, _ in pairs(_G) do
        len_of_table = len_of_table + 1
    end

    str_tmp = string.format("%s%s%s", str_prefix, g_str_len, len_of_table)
    print(str_tmp)

    print_table(_G, 0)

end


-- main entry

print_G()

Example 2: Print boolean variables

function print_boolean(arg)
    print(arg and "true" or "false")
end

print_boolean(true)
print_boolean(false)

Example 3: Get length of table

Lua code:

function get_len(t)
   local len = 0
   for k, v in pairs(t) do
       len = len + 1
   end
   return len
end

function print_table(t)
   print("{")
   for k, v in pairs(t) do
       print("  [" .. k .. "] = " .. v .. ",")
   end
   print("}")
end

t = { [1] = 11, [2] = 22, [4] = 44 }

print("get_len(t) = " .. get_len(t))
print("#t = " .. #t)
-- print("table.concat(t) = " .. table.concat(t))
print_table(t)

t = { 11, 22, 44 }

print("get_len(t) = " .. get_len(t))
print("#t = " .. #t)
print("table.concat(t, ', ') = " .. table.concat(t, ', '))
print_table(t)

Output:

get_len(t) = 3
#t = 4
{
  [1] = 11,
  [2] = 22,
  [4] = 44,
}
get_len(t) = 3
#t = 3
table.concat(t, ', ') = 11, 22, 44
{
  [1] = 11,
  [2] = 22,
  [3] = 44,
}

References