Lua Reference Manual : https://pgl.yoyo.org/luai/i/
-
-
Save sheharyaar/946eb2850ccb10aa54d80cf4351981b8 to your computer and use it in GitHub Desktop.
lua_State
- all the Lua state in this dynamic variable.luaopen_LIBNAME
- opens table and registers the functions (io.read
,io.write
, etc.) inside it usingluaL_newlib
luaL_loadbuffer
- compile the code and push the chunk to the *stack , returns 0 on no error, else push error message on stacklua_pcall
- pops the chunk from the stack and runs it in protected mode, returns 0 on no error, else push error message on stacklua_tostring
to get the message string andlua_pop
to remove the error from the stack
(1) state created → (2) libraries populated → (3) compile the code → (4) run the code → (5) get errors (if any)
Lua | C | |
---|---|---|
variable types | dynamic | static |
memory management | automatic | manual |
garbage collection | yes | no |
- Lua needs to track the variables for proper garbage collection.
- Issues can arise if Lua garbage collects a variable whose reference is still held by the C function
- Sharing of dynamic type variables with C is a difficult task
To prevent creating a function for each type of variable, Lua uses a stack to share variables between Lua and C programs :
- Each slot of the stack can hold any value.
- Whenever you want to ask for a value from Lua (such as the value of a global variable), you call Lua → which pushes the required value on the stack.
- Whenever you want to pass a value to Lua, you first push the value on the stack → then you call Lua (which will pop the value).
- the stack is managed by Lua, so Lua garbage collector knows which values are being used by C.
Important points to note :
- Lua manipulates the stack in strictly LIFO order.
- The C programs are allowed to inspect any element and insert/delete in any arbitrary position.
- positive index : bottom to top (1 being the first object pushed – bottom of stack)
- negative index : top to bottom (-1 being the top element)
-
lua_gettop
- returns the number of elements in the stack or the index of the top element (postive). -
lua_settop
- sets the top (number of elements) to a value.- if new
top
is less than prev top : then extra elements are discarded. - if new
top
is more than prev top : then extranils
are placed. lua_settop(L, 0)
empties the stack
- if new
-
lua_pop(L,n)
- pops n elements from the stack, implemented as :
#define lua_pop(L,n) lua_settop(L, -(n)-1)
lua_remove
- removes the element at the given index, shifting down all elements on top of that position to fill in the gaplua_insert
- moves the top element into the given position, shifting up all elements on top of that position to open spacelua_replace
pops a value from the top and sets it as the value of the given index, without moving anything
- Strings in Lua are not zero-terminated
- Lua never keeps pointers to external strings (or to any other object, except to C functions, which are always static).
- Lua either makes an internal copy or reuses one. Therefore, you can free or modify your buffer as soon as these functions return.
- Whenever you push an element onto the stack, it is your responsibility to ensure that the stack has space for it.
lua_checkstack (lua_State *L, int sz)
to check if there is space on the stack.lua_is*
functions for checking the type of the element.- Any string that
lua_tostring
returns always has a zero at its end, but it can have other zeros inside it. Thelua_strlen
function returns the correct length of the string.
- Lua uses the
setjmp
facility from C for exception handling - Instead of using error codes for each operation in its API, Lua uses exceptions to signal these errors.
- Almost all API functions may throw an error (that is, call
longjmp
) instead of returning. - When Lua faces an error like "not enough memory", there is not much that it can do. It calls a panic function and, if the function returns, exits the application (can be set using
lua_atpanic
)
Make sure to run your code in protected mode, in unprotected mode, Lua cannot call
setjmp
to handle exceptions. Protected mode is when the function is called usinglua_pcall
, which returns an error code even in case of memory-allocation failure.
- Whenever a C function detects an error, it simply calls
lua_error
, (or better yetluaL_error
, which formats the error message and then callslua_error
). - The
lua_error
function clears whatever needs to be cleared in Lua and jumps back to thelua_pcall
that originated that execution, passing along the error message.
lua_getglobal(L,name)
- Lua pushes onto the stack the value of the globalname
.lua_setglobal(L,name)
- Lua pops a value from the stack and sets it as the new value of globalname
.lua_istable(L,idx)
- Check if the element at idx is a tablelua_gettable(L,idx)
- pushes on to the stack the value t[k] where t is a table at idx in the stack. This function pops the key from the stack and pushes the value on top. It also may trigger the metamethod for theindex
event.lua_getfield(L,idx,k)
- pushes on to the stack the value t[k], no popping in this case, this may also trigger the metamethod for theindex
event.lua_settable(L,idx)
- equivalent tot[k] = v
, wheret
is the value at the given valid index,v
is the value at the top of the stack, andk
is the value just below the top. Pops both the key and the value from the stack. May trigger a metamethod for thenewindex
event
lua_setfield(L,idx,k)
- Does the equivalent tot[k] = v
, wheret
is the value at the given valid index andv
is the value at the top of the stack. Pops the value from the stack. As in Lua, this function may trigger a metamethod for thenewindex
event
lua_pcall(L,nargs,nresults,errfunc)
calls a function in protected mode.- if there is any error,
lua_pcall
catches it, pushes a single value on the stack (the error message), and returns an error code - If
errfunc
is 0, then the error message returned on the stack is exactly the original error message - Else,
errfunc
is the stack index of an error handler function. (cannot be a pseudo-index)- this function will be called with the error message and its return value will be the message returned on the stack by
lua_pcall
.
- this function will be called with the error message and its return value will be the message returned on the stack by
Typically, the error handler function is used to add more debug information to the error message, such as a stack traceback. Such information cannot be gathered after the return of
lua_pcall
, since by then the stack has unwound.
LUA_ERRRUN
: a runtime error.LUA_ERRMEM
: memory allocation error. For such errors, Lua does not call the error handler function.LUA_ERRERR
: error while running theerror handler
function.
- Lua reference manual : https://pgl.yoyo.org/luai/i/lua_pcall
- ordinary Lua table that defines the behavior of the original value under certain special operations (keys →
events
and values →metamethods
) - Example, if a non-numeric value is the operand of an addition, Lua checks for a function in the field
__add
in its metatable. If it finds one, Lua calls this function to perform the addition. (Similar to__string
and other such functions in python)
getmetatable(object)
- nil if the object does not have a metatable, if the object's metatable has a__metatable
field, returns the associated value. Otherwise, returns the metatable of the given object.setmetatable(table, metatable)
- we can set metatable only for a table from Lua, for other types we can do it from C. If metatable is nil, it removes the metatable. If the original metatable has a__metatable
field, raises an error. This function returnstable
.lua_getmetatable(L,index)
- C API for getting the mtetatable.- Pushes onto the stack the metatable of the value at the given acceptable index.
- If the index is not valid, or if the value does not have a metatable, → returns 0 and pushes nothing on the stack.
lua_setmetatable(L,index)
- C API for setting the metatable. Pops a table from the stack and sets it as the new metatable for the value at the given acceptable index.
- the keys are prefixed by two underscores
__
- Available events are :
event | operation |
---|---|
index | indexing access table[key] |
newindex | indexing assignment table[key] = value |
call | Lua calls a value |
add | + add |
sub | - subtract |
mul | * multiply |
div | / divide |
mod | % mod |
pow | ^ exponent |
unm | unary minus |
concat | .. operation |
len | # length |
eq | == equality |
lt | < less than |
le | ≤ less than equal to |
Why a registry ??
- C functions need to keep some non-local data which outlive the invocation
- You cannot store a generic Lua value in a C variable, library that uses such variables cannot be used in multiple Lua states
- An alternative approach is to store such values into Lua global variables
- Lua global variables store any Lua value and each independent state has its own independent set of global variables
- However, this is not always a satisfactory solution, because Lua code can tamper with those global variables and therefore compromise the integrity of C data
C code can freely use the registry, but Lua code cannot access it.
Q) What is a registry
- registry is a regular Lua table
- you can index it with any Lua value but **nil
- always located at a pseudo-index, whose value is defined by
LUA_REGISTRYINDEX
- A pseudo-index is like an index into the stack, except that its associated value is not in the stack.
Note: all C libraries share the same registry
- you must choose with care what values you use as keys, to avoid collisions. A bulletproof method is to use as key the address of a static variable in your code: The C link editor ensures that this key is unique among all libraries
lua_pushlightuserdata(L,p)
can be used to do this – it pushes a pointer to the stack- It is a value (like a number) and not a variable: you do not create it, it has no individual metatable, and it is not collected (as it was never created)
/* variable with an unique address */
static const char Key = 'k';
/* store a number */
lua_pushlightuserdata(L, (void *)&Key); /* push address */
lua_pushnumber(L, myNumber); /* push value */
/* registry[&Key] = myNumber */
lua_settable(L, LUA_REGISTRYINDEX);
/* retrieve a number */
lua_pushlightuserdata(L, (void *)&Key); /* push address */
lua_gettable(L, LUA_REGISTRYINDEX); /* retrieve value */
myNumber = lua_tonumber(L, -1); /* convert to number */
- You can also use strings as keys into the registry, as long as you choose unique names
String keys are particularly useful when you want to allow other independent libraries to access your data, because all they need to know is the key name.
- Never use numbers as keys in the registry, because such keys are reserved for the reference system.
- A userdatum offers a raw memory area with no predefined operations in Lua.
- A full userdata represents a block of memory.
- It is an object (like a table): you must create it
- It can have its own metatable
- You can detect when it is being collected
- A full userdata is only equal to itself (under raw equality).
- When Lua collects a full userdata with a
gc
metamethod (only for userdatata), Lua calls the metamethod and marks the userdata as finalized. When this userdata is collected again then Lua frees its corresponding memory.
lua_newuserdata(L,size)
- allocates a new block of memory with the given size, pushes onto the stack a new full userdata with the block address, and returns this address.
To distinguish
<userdata>
from other userdata, we create a unique metatable for it. Then, every time we create a<userdata>
, we mark it with this metatable; and every time we get an<userdata>
, we check whether it has the right metatable.Because Lua code cannot change the metatable of a userdatum, it cannot fake our code.
luaL_newmetatable(L,name)
- If the registry already has the key
tname
, returns 0 - Otherwise, creates a new table to be used as a metatable for userdata, adds it to the registry with key
tname
, and returns 1. - In both cases pushes onto the stack the final value associated with
tname
in the registry.
- If the registry already has the key
luaL_getmetatable(L,name)
: Pushes onto the stack the metatable associated with nametname
in the registry*luaL_checkudata(L,narg,tname)
: Checks whether the function argumentnarg
is a userdata of the typetname
- Light userdata are not buffers, but single pointers.
- They have no metatables.
- Like numbers, light userdata do not need to be managed by the garbage collector (and are not). You have to manage memory by yourself.
The real use of light userdata comes from equality.
As a full userdata is an object, it is only equal to itself. A light userdata, on the other hand, represents a C pointer value. As such, it is equal to any userdata that represents the same pointer. Therefore, we can use light userdata to find C objects inside Lua.
If a table has key as light user data and value as full userdata → the table should have weak values. Otherwise, those full userdata would never be collected.