Friday, September 9, 2011

mini lua primer


-------------------------
-- tables are general container can be indexed by anything (numbers, 
-- tables, strings, functions...)

local function blah()
  print("blah")
end
tab[blah] = blubb
tab.name  = blubb -- is same as
tab["name"] = blubb


-- tables are always passed as "pointers/references" never copied
-- array index starts with 1 !!
-- they become garbage collected when not referenced anymore

pos = {1,2,3}
a = { pos = pos }
pos[3] = 4
pos = {1,1,1} -- overwrites local variable pos
a.pos[3] -- is still 4


-------------------------
--[[ multiline 
comment ]]

blah = [==[ multiline string and comment 
can use multiple = for bracketing to nest  ]==]

-------------------------
--- multiple return values allow easy swapping
a,b = b,a

-------------------------
-- object oriented stuff
-- : operator passes first arg
a.func(a,blah) -- is same as 
a:func(blah)

-- metatables allow to index class tables
myclass = {}
myclassmeta = {__index = myclass}
function myclass:func() 
  self --automatic variable through : definiton for the first 
       --arg passed to func
end
-- above is equivalent to 
myclass.func = function (self) 

end



object = {}
setmetatable(object,myclassmeta)
object:func() -- is now same as
myclass.func(object)

-- until func gets specialized per object
function object:func()
  -- lua will look up first in the object table, then in the metatable
  -- it will ony write to the object table
end

-------------------------
--- upvalues for function specialization

function func(obj)
  return function ()
    return obj * 2
  end

end

a = func(1)
b = func(2)

a() -- returns 2
b() -- returns 4

--- non passed function arguments become nil automatically
function func (a,b)
  return a,b
end
a,b = func(1) -- b is "nil"

--- variable args
function func(...)
  local a,b = ...
  --- a,b would be first two args
  --- you can also put args in a table
  local t = {...}
end


-------------------------
--- conditional assignment chaining
--- 0 is not "false", only "false" or "nil" are

a = 0
b = a or 1 -- b is 0, if a was false/nil it would be 1

c = (a == 0) and b or 2 -- c is 0 (b's value)

-- the first time a value is "valid" (non-false/nil) that value is taken
-- that way you can do default values

function func(a,b)
  a = a or 1
  b = b or 1
 
end


-------------------------
--- sandboxing

function sandboxedfunc()
  -- after setfenv below we can only call what is enabled in the enviroment
  -- so in the example below doing stuff like io.open wouldn't work here
  -- blubb becomes created in the current enviornment
  blubb = doit()
end

local enva = { 
  doit = function () return 1 end
}

local envb = { 
  doit = function () return 2 end
}

setfenv(sandboxedfunc,enva)()
--enva.blubb is now 1

setfenv(sandboxedfunc,envb)()
--envb.blubb is now 2

-- sandboxedfunc could also come from a file, which makes creating fileformats
-- quite easy, as they can internally be lua code


-------------------------
--- functions without () and function chaining

-- to make ini/config files quite easy, lua allows omitting () for function 
-- calls when the argument is either a string or a table

function testfunc( a )

end

-- valid calls to above function
testfunc "blah"
testfunc {1,2,3}

-- we can even expand this to create fileformat like structures

function group( name)
  return function (content)
    local grp = {
      name = name,
      content = content,
    }
    return grp
  end
end

local grp = group "test" {1,3,5}
-- equvialent to: group("test")({1,3,5})
-- grp.content[2] = would be 3

-- could also build a hierarchy
local grp = group "root" {
  group "child a" {},
  group "child b" {},
}

-- grp.content[1].name would be "child a"