Introduction

What is Lua

Where did come from where is it used

What flavours are there

Lua 5.1.x
Most widely used standard Lua distribution
Supports any system that can compile ANSI C Lua 5.2.x
The newest Lua.
Not that widely supported yet.
Supports any system that can compile ANSI C LuaJit
Blindingly fast just in time compiler that is Lua 5.1.x compatible.
Supports dynamic FFI to C shared libraries

Supported OS

  • Linux
  • Android
  • BSD
  • OSX
  • iOS
  • Windows

Supported CPU

  • x86 32 bit 64 bit
  • ARMv5+, ARM9E+
  • PPC/e500v2
  • MIPS

How to get it

The Language

Comments

-- This is a single line comment
--[[ This is a multiline 
     comment
--]]
--[=[ This is a multiline 
     comment
    --[[ 
        With a nested multiline 
        comment
    --]]

    Any amount of `=` allowed the start and end count must just match
--]=]

Statements

Statements continued

Types

All values in Lua are first-class (stored in variables; passed as arguments; returned as results)

nil
The bottom type signifying nothing boolean
The logical type can either be true or false.
nil and false counts as false everything else is true. number
The only arithmetic type.
Runtime dependant usually double (could be char, short, int, float). string
Immutable array of 8-bit char values.
8-bit clean i.e. may include embedded zeros '\0'

Types continued

function
Any function defined in Lua
Any function defined in C and exposed to Lua
Any compiled file or string of Lua statements thread
Represents independent thread of execution.
Not OS threads used for coroutines userdata
Arbitrary C data to be stored in Lua
Only operations are assignment and identity test table
The only data structure in Lua
Associative arrays
Heterogeneous in value and key (any type except nil)

Strings

Tables

Functions

Functions continued

Functions continued

Functions continued

Control structures

do block end

Introduces local scope

do
    local onlyVisibleHere = 5
end

if then else

Conditional branching with each branch introducing a local scope.

if a == b then      -- start if branch
    e = 2
elseif a == c then  -- optional else if branch
    e = 3 
else                -- optional else branch
    e = 4
end                 -- required terminator

Control structures continued

while

If condition is true then repeatedly execute block until false

local a,b = 1,5
while a < b do
    a = a + 1       -- executes 4 times
end

repeat

Execute block and if condition is true repeat until false

local a,b = 4,5
repeat
   a = a + 1        -- executes 2 times
until a == b

break

Forces enclosing looping structure to terminate immediately

local a = 1
while true do
    break
    a = a + 1       -- never executes a remains 1
end

Control structures continued

numerical for

Repeat the block until initial value passes limit incrementing by optional step size. Default step size is 1.

local a = 1
for u=1,10 do
    a = u       -- executes 10 times (at end a == 10)
end
for u=10,1,-1 do
    a = u       -- executes 10 times (at end a == 1)
end
generic for

The generic for loop works over functions called iterators. On each iteration, the iterator function is called to produce a new value, stopping when this new value is nil.

local a = 1
for k,v in ipairs {0,1,2,3,4,5,6,7,8,9} do
    a = k + v       -- executes 10 times (at end a == 10 + 9)
end

Extensibility (Meta table)

Metatable example

local mtFibber = {}
function makeFibber(n)
    local f = {n = n}
    setmetatable(f, mtFibber)
    return f
end
do
    function mtFibber:__call()
        local n = math.max(self.n,0)
        local function _fib(fn2, fn1, at)
            if at == n then 
                return fn1 + fn2
            else
                return _fib(fn1, fn1 + fn2, at+1)
            end
        end
        if n <= 0 then return 0
        elseif n == 1 then return 1
        else return _fib(0, 1, 2) end
    end
    function mtFibber.__add(lhs, rhs) return makeFibber(lhs.n + rhs.n) end
    function mtFibber.__sub(lhs, rhs) return makeFibber(lhs.n - rhs.n) end
    function mtFibber:__newindex(k,v) assert(false, "can't add members") end
end
local f1 = makeFibber(10)
local f2 = makeFibber(5)
local f3 = makeFibber(100)
local f4 = (f3 + f2 - f1)
-- The 95th fibonacci is 3.194043463499e+019
print ("The " .. f4.n .. "nth fibonacci number is " .. f4())

Addons

IUP

IUP Dialog

IUP Dialog

require "iuplua"
require "iupluacontrols"
local label
local text = ""
local function onText(self)
    text = string.upper(self.value)
end
local function modifyLabel(self)
    if label then 
        label.title = text
    end
end

dlg = iup.dialog
{
    iup.vbox
    {
        iup.label{title = 'A silly little dialog', map_cb = function(self) label = self end},
        iup.vbox
            {
                iup.hbox
                {
                    iup.label{title='Write text', size="80"},
                    iup.text{size="80", valuechanged_cb = onText}
                    ;margin="0", gap="10"
                };
                iup.hbox
                {
                    iup.button{title="Ok",size="40", action = modifyLabel},
                    iup.button{title="Cancel",size="40" , action = function () return iup.CLOSE end}
                    ;margin="0", gap="10"
                };  
            }
        ;margin="5x5", gap="5"
    }
    ;title="Some dialog", resize="NO"
}
dlg:popup()

Cosmo

local cosmo = require "cosmo"
mycards = { {rank="Ace", suit="Spades"}
          , {rank="Queen", suit="Diamonds"}
          , {rank="10", suit="Hearts"} 
          } 
template = "$do_cards[[$rank of $suit, ]]"
-- prints Ace of Spades, Queen of Diamonds, 10 of Hearts,
print (cosmo.fill(template, {do_cards = mycards}))

Penlight

local List = require 'pl.List'  
local func = require 'pl.func'  
print (List{10,20,30}:map(_1+1):reduce '+') -- prints 63
 class = require 'pl.class'

 class.Animal()
 function Animal:_init(name)
     self.name = name
 end
 function Animal:__tostring()
   return self.name..': '..self:speak()
 end

 class.Dog(Animal)
 function Dog:speak()
   return 'bark'
 end

 class.Cat(Animal)
 function Cat:_init(name,breed)
     self:super(name)  -- must init base!
     self.breed = breed
 end
 function Cat:speak()
   return 'meow'
 end

fido = Dog('Fido')
felix = Cat('Felix','Tabby')

print(fido,felix)        -- Fido: bark Felix: meow
print(felix:is_a(Animal) -- true
print(felix:is_a(Dog))   -- false
print(felix:is_a(Cat))   -- true

MetaLua

-{extension "clist"}

-- integers from 2 to 50, by steps of 2:
x = { i for i = 2, 50, 2 }

-- the same, obtained by filtering over all integers <= 50:
y = { i for i = 1, 50 if i%2==0 }


-{extension 'match'}

match { { 'o', 'k', '!' } } with
| { t } -> match t with
   | { a, b }      -> print 'KO'
   | { a, b, ... } -> print (a..b)
   | _             -> print 'KO'
   end
| _ -> print 'KO'
end

How do we use it

Build Automation

Data definition language

FLiDataCompiler
{INCLUDE_PCH = [[#include "fliModelsPCH.h"]];
 INCLUDE_LIB = [[#include "../fliModelsLib.h"]];
 EXPORT_DECL = [[fliMODELS_API]];
 INCLUDES = {"dmlGoalState.dsd", "dmlGoalChildrenConstraint.dsd", "dmlTrigger.dmd"};
 [[ @brief  Goals are a hierarchical way to define what an entity is required to achieve. 
 ]];
 MODEL = {"fli::act::DGoal";
    [[@brief String used to categorize the goal with categories seperated by / also used to identify the goal]];
    {"Category", {"string", 1}};
 
    [[@brief The current active state of the goal]];
    {"State", {"EGoalState", 2, default='GOAL_INACTIVE'}};
 
    [[@brief Constrain how the goal's children become active when it is active]];
    {"ChildrenConstraint", {"EGoalChildrenConstraint", 3, default="GOAL_CHILDREN_ACTIVE_CONCURRENTLY"}};

    [[@brief Child goals]];
    {"Children", {"array<DGoal>", 4}};

    ...
    ...

    [[@brief The number of times the goal has passed]];
    {"PassedCount", {"int32", 9, set=false}};

    [[@brief The number of times the goal has failed]];
    {"FailedCount", {"int32", 10, set=false}};

 };
};

Data description language

fli_data.ScopeModelCreate()
local DoNotRegister = true  -- Do not register with fli::data::CManager

-----------------------------------------------------
-- Scenario world
-----------------------------------------------------
-- Define the whole world for the scenario defining which extensions the world has as well as all the entities which are
-- present in the world. 
return Root(fli__ent__DWorld("World"), DoNotRegister)
{
    Extensions =
    {
        -- Extension that defines information related to the scenario but not a specific entity
        fli__ent__DScenarioInfo
        {
            Name = "Tutorial_03_SimpleVehicle";     
            FocusEntity = RefModel("World:Entities.1");
        };
    };
    
    Entities = 
    {
        Import(assert(RelToData "FLiTutorials/Tutorial_03_SimpleVehicle/Scripts/Terrain.lua"))
        {           
            InInitialTimeOfDay = 16 * 60 * 60;
        };
    
        Import(assert(RelToData "FLiTutorials/Tutorial_03_SimpleVehicle/Scripts/SimpleEntityOfTutorial2.lua"))
        {           
            InName = "My Imported Entity";
            InPhysicsEnableDebugDrawing = true;
            InPosition = {x=-100;y=50;z=0;};
            InOrientation = QuaternionToTable( OrientFromYPRd(0, 0, 0) );
            InVisualColour = {r=0, g=1, b=0, a=1};
        };
        
        Import(assert(RelToData "FLiTutorials/Tutorial_03_SimpleVehicle/Scripts/SimpleEntityOfTutorial2.lua"))
        {           
            InName = "My Second Imported Entity";
            InPhysicsEnableDebugDrawing = true;
            InPosition = {x=-100;y=50;z=10;};
            InOrientation = QuaternionToTable( OrientFromYPRd(DEG_TO_RAD(60), 0, 0) );
            InVisualColour = {r=0, g=1, b=1, a=1};
        };
        
        Import(assert(RelToData "FLiTutorials/Tutorial_03_SimpleVehicle/Scripts/SimpleEntityOfTutorial2.lua"))
        {           
            InName = "My Third Imported Entity";
            InPhysicsEnableDebugDrawing = true;
            InPosition = {x=-110;y=50;z=10;};
            InOrientation = QuaternionToTable( OrientFromYPRd(0, 0, DEG_TO_RAD(30)) );
            InVisualColour = {r=1, g=0, b=1, a=0.5};
        };
    };
}

The End