Module Lua_api_lib


module Lua_api_lib: sig .. end

The Lua Application Program Interface (OCaml binding)




Difference with the original Lua API



Here is a list of functions of which you should read documentation:

Types definitions


type state 
See lua_State documentation.
type oCamlFunction = state -> int 
This type corresponds to lua_CFunction. See lua_CFunction documentation.

type thread_status =
| LUA_OK
| LUA_YIELD
| LUA_ERRRUN
| LUA_ERRSYNTAX
| LUA_ERRMEM
| LUA_ERRERR
See lua_status documentation.

type gc_command =
| GCSTOP
| GCRESTART
| GCCOLLECT
| GCCOUNT
| GCCOUNTB
| GCSTEP
| GCSETPAUSE
| GCSETSTEPMUL
This type is not present in the official API and is used by the function gc

type lua_type =
| LUA_TNONE
| LUA_TNIL
| LUA_TBOOLEAN
| LUA_TLIGHTUSERDATA
| LUA_TNUMBER
| LUA_TSTRING
| LUA_TTABLE
| LUA_TFUNCTION
| LUA_TUSERDATA
| LUA_TTHREAD
This type is a collection of the possible types of a Lua value, as defined by the macros in lua.h. As a reference, see the documentation of the lua_type function, and the corresponding OCaml Lua_api_lib.type_.
type 'a lua_Reader = state -> 'a -> string option 
See lua_Reader documentation.

type writer_status =
| NO_WRITING_ERROR (*No errors, go on writing*)
| WRITING_ERROR (*An error occurred, stop writing*)
type 'a lua_Writer = state -> string -> 'a -> writer_status 
See lua_Writer documentation.

Constant values


val multret : int
Option for multiple returns in `Lua.pcall' and `Lua.call'. See lua_call documentation.
val registryindex : int
Pseudo-index to access the registry. See Registry documentation.
val environindex : int
Pseudo-index to access the environment of the running C function. See Registry documentation.
val globalsindex : int
Pseudo-index to access the thread environment (where global variables live). See Registry documentation.

Exceptions


exception Error of thread_status
exception Type_error of string

Functions not present in the Lua API


val thread_status_of_int : int -> thread_status
Convert an integer into a thread_status. Raises failure on invalid parameter.
val int_of_thread_status : thread_status -> int
Convert a thread_status into an integer.
val lua_type_of_int : int -> lua_type
Convert an integer into a lua_type. Raises failure on invalid parameter.
val int_of_lua_type : lua_type -> int
Convert a lua_type into an integer.

Lua API functions


val atpanic : state -> oCamlFunction -> oCamlFunction
See lua_atpanic documentation.
val call : state -> int -> int -> unit
See lua_call documentation.
val checkstack : state -> int -> bool
See lua_checkstack documentation.

The function lua_close is not present because all the data structures of a Lua state are managed by the OCaml garbage collector.
val concat : state -> int -> unit
See lua_concat documentation.
val cpcall : state ->
oCamlFunction -> 'a -> thread_status
See lua_cpcall documentation.

NOTE: this function is not a binding of the original lua_cpcall, it's rather an OCaml function with the same semantics.

WARNING: the OCaml function you want to execute in a protected environment is actually protected againt Lua errors, even memory errors, but not against OCaml errors, i.e. exceptions. If for example you run:

let ls = LuaL.newstate ();;
let my_func ls = failwith "Sorry, my fault..."; 0;;
let cpcall_result = Lua.cpcall ls my_func 42;;
    
cpcall will actually raise a failure, because that exception is not generated by Lua but by OCaml.
val createtable : state -> int -> int -> unit
See lua_createtable documentation.
val dump : state ->
'a lua_Writer -> 'a -> writer_status
See lua_dump documentation.
val equal : state -> int -> int -> bool
See lua_equal documentation.
val error : state -> 'a
See lua_error documentation.
val gc : state -> gc_command -> int -> int
See lua_gc documentation.

lua_getallocf not implemented in this binding
val getfenv : state -> int -> unit
See lua_getfenv documentation.
val getfield : state -> int -> string -> unit
See lua_getfield documentation.
val getglobal : state -> string -> unit
See lua_getglobal documentation. Like in the original Lua source code this function is implemented in OCaml using getfield.
val getmetatable : state -> int -> bool
See lua_getmetatable documentation.
val gettable : state -> int -> unit
See lua_gettable documentation.
val gettop : state -> int
See lua_gettop documentation.
val insert : state -> int -> unit
See lua_insert documentation.
val isboolean : state -> int -> bool
See lua_isboolean documentation.
val iscfunction : state -> int -> bool
See lua_iscfunction documentation.
val isfunction : state -> int -> bool
See lua_isfunction documentation.
val islightuserdata : state -> int -> bool
See lua_islightuserdata documentation.
val isnil : state -> int -> bool
See lua_isnil documentation.
val isnone : state -> int -> bool
See lua_isnone documentation.
val isnoneornil : state -> int -> bool
See lua_isnoneornil documentation.
val isnumber : state -> int -> bool
See lua_isnumber documentation.
val isstring : state -> int -> bool
See lua_isstring documentation.
val istable : state -> int -> bool
See lua_istable documentation.
val isthread : state -> int -> bool
See lua_isthread documentation.
val isuserdata : state -> int -> bool
See lua_isuserdata documentation.
val lessthan : state -> int -> int -> bool
See lua_lessthan documentation.
val load : state ->
'a lua_Reader -> 'a -> string -> thread_status
See lua_load documentation.

The function lua_newstate is not present because it makes very little sense to specify a custom allocator written in OCaml. To create a new Lua state, use the function Lua_aux_lib.newstate.
val newtable : state -> unit
See lua_newtable documentation.
val newthread : state -> state
See lua_newthread documentation.

When you create a new thread, this binding guaranties that the Lua object will remain "living" (protected from both the Lua and the OCaml garbage collectors) until a valid copy exists in at least one of the two contexts.

Remember that all the threads obtained by newthread and Lua_api_lib.tothread are shared copies, for example:

let state = LuaL.newstate ();;
let th = Lua.newthread state;;
let th' = match Lua.tothread state 1 with Some s -> s | None -> failwith "not an option!";;
Lua.settop state 0;;
    
Now the stack of state is empty and you have two threads, th and th', but they are actually the very same data structure and operations performed on the first will be visible on the second!

Another important issue regarding the scope of a state object representing a thread (coroutine): this binding don't prevent you from accessing invalid memory in case of misuse of the library. Please, carefully consider this fragment:

let f () =
  let state = LuaL.newstate () in
  let th = Lua.newthread state in
  th;;

let th' = f ();;
Gc.compact ();; (* This will collect [state] inside [f] *)
(* Here something using [th'] *)
    
After Gc.compact the value inside th' has lost any possible meaning, because it's a thread (a coroutine) of a state object that has been already collected. Using th' will lead to a segmentation fault, at best, and to an undefined behaviour if you are unlucky.
val default_gc : state -> int
This is the default "__gc" function attached to any new userdatum created with newuserdata. See documentation of Lua_api_lib.newuserdata below.
val make_gc_function : oCamlFunction -> oCamlFunction
This function takes an Lua_api_lib.oCamlFunction you have created to be executed as "__gc" metamethod and "decorates" it with some default actions needed to deallocate all the memory.

If you want to create a "__gc" method for your userdata, you must register the value from make_gc_function.

val newuserdata : state -> 'a -> unit
newuserdata is the binding of lua_newuserdata but it works in a different way if compared to the original function, and the signature is slightly different.

In C lua_newuserdata allocates an area for you, returns a void* and you cast it as needed. Moreover, it pushes the new userdata on the stack.

In OCaml, however, you never allocates a value and so the resulting signature provides you a way to push an already created value on the top of the Lua stack.

Very important remark, read carefully. The original Lua lua_newuserdata doesn't associate to the new userdatum any metatable, it's up to you to define a metatable with metamethods, if you need it. On the other hand, this binding silently creates a metatable with only one metamethod ("__gc") and associates the function Lua_api_lib.default_gc defined above. This function takes care of managing the memory between the two garbage collectors when needed. This is transparent to you, unless you want to attach to the userdatum a metatable of your, which is very likely to happen.

In case you want to attach a metatable to your userdatum you must include the "__gc" metamethod, and you must create the function using Lua_api_lib.make_gc_function described above.If you want a metatable for your userdatum but you don't need a "__gc", use in any case the Lua_api_lib.default_gc. Don't create a userdatum with a metatable and without "__gc" or your program will leak memory!

WARNING: using this function could be harmful because it actually breaks the type system. It has the same semantics of Obj.magic, allowing the programmer to push an OCaml value into the Lua state, and then retrieve it with a different type. Be very careful!

val next : state -> int -> int
See lua_next documentation.
val objlen : state -> int -> int
See lua_objlen documentation.
val pcall : state -> int -> int -> int -> thread_status
See lua_pcall documentation.
val pop : state -> int -> unit
See lua_pop documentation.
val pushboolean : state -> bool -> unit
See lua_pushboolean documentation.

The function lua_pushcclosure is not present because it makes very little sense to specify a "closure" written in OCaml, using the Lua upvalues machinery. Use instead Lua_api_lib.pushcfunction
val pushcfunction : state -> oCamlFunction -> unit
See lua_pushcfunction documentation.
val pushocamlfunction : state -> oCamlFunction -> unit
Alias of Lua_api_lib.pushcfunction
val pushfstring : state -> ('a, unit, string, string) Pervasives.format4 -> 'a
Pushes onto the stack a formatted string and returns the string itself. It is similar to the standard library function sprintf.

Warning: this function has a different behavior with respect to the original lua_pushfstring because the conversion specifiers are not restricted as specified in the Lua documentation, but you can use all the conversions of the Printf module.

val pushinteger : state -> int -> unit
See lua_pushinteger documentation.
val pushlightuserdata : state -> 'a -> unit
See lua_pushlightuserdata documentation. Raises Not_a_block_value if you try to push a non-block value (e.g. an immediate integer) as a light userdata.

In Lua a light userdata is a way to store inside the Lua state a C pointer. It's up the programmer to carefully check for the lifetime of the data structures passed to Lua via a light userdata. If you malloc a pointer and pass it to Lua, then you free it from C and then you retrieve the same pointer from Lua (using lua_touserdata), you are most probably shooting yourself in the foot.

To avoid this class of problems I decided to implement some logic in the binding of this function. When you push an OCaml value as a Lua light userdata, a global reference to that (OCaml) value is kept inside the Lua state L. So, if the original value goes out of scope it is not collected by the garbage collector. In this scenario:

let push_something state =
  let ocaml_value = get_some_complex_value () in
  pushlightuserdata state ocaml_value;
  state
;;
    
when the push_something function returns the Lua state, the ocaml_value is not collected and can be retrieved at a later time from state.

This behaviour has a major drawback: while ensuring the lifetime of objects, it wastes memory. All the OCaml values pushed as light userdata will in fact be collected when the garbage collector decide to collect the Lua state itself. This means that if you have a long running task (e.g. a server) with a Lua state and you use pushlightuserdata, the values pushed will be never collected!

Moreover, if you push a value that have some resources associated with it (e.g. a channel, a socket or a DB handler) the resources will be released only when the Lua state goes out of scope.

val pushliteral : state -> string -> unit
See lua_pushliteral documentation.
val pushlstring : state -> string -> unit
See lua_pushlstring documentation.
val pushnil : state -> unit
See lua_pushnil documentation.
val pushnumber : state -> float -> unit
See lua_pushnumber documentation.
val pushstring : state -> string -> unit
See lua_pushstring documentation.
val pushthread : state -> bool
See lua_pushthread documentation.
val pushvalue : state -> int -> unit
See lua_pushvalue documentation.
val pushvfstring : state -> ('a, unit, string, string) Pervasives.format4 -> 'a
Alias of Lua_api_lib.pushfstring
val rawequal : state -> int -> int -> bool
See lua_rawequal documentation.
val rawget : state -> int -> unit
See lua_rawget documentation.
val rawgeti : state -> int -> int -> unit
See lua_rawgeti documentation.
val rawset : state -> int -> unit
See lua_rawset documentation.
val rawseti : state -> int -> int -> unit
See lua_rawseti documentation.
val register : state -> string -> oCamlFunction -> unit
See lua_register documentation. The function is implemented in OCaml using pushcfunction and setglobal.
val remove : state -> int -> unit
See lua_remove documentation.
val replace : state -> int -> unit
See lua_replace documentation.
val resume : state -> int -> thread_status
See lua_resume documentation.

lua_setallocf not implemented in this binding
val setfenv : state -> int -> bool
See lua_setfenv documentation.
val setfield : state -> int -> string -> unit
See lua_setfield documentation.
val setglobal : state -> string -> unit
See lua_setglobal documentation.
val setmetatable : state -> int -> int
See lua_setmetatable documentation.
val settable : state -> int -> int
See lua_settable documentation.
val settop : state -> int -> unit
See lua_settop documentation.
val status : state -> thread_status
See lua_status documentation.
val toboolean : state -> int -> bool
See lua_toboolean documentation.
val tocfunction : state -> int -> oCamlFunction option
See lua_tocfunction documentation.
val toocamlfunction : state -> int -> oCamlFunction option
Alias of Lua_api_lib.tocfunction
val tointeger : state -> int -> int
See lua_tointeger documentation.
val tolstring : state -> int -> string option
See lua_tolstring documentation.

NOTE: The original len argument is missing because, unlike in C, there is no impedance mismatch between OCaml and Lua strings

val tonumber : state -> int -> float
See lua_tonumber documentation.

The function lua_topointer is not available
val tostring : state -> int -> string option
Alias of Lua_api_lib.tolstring
val tothread : state -> int -> state option
See lua_tothread documentation.
val touserdata : state ->
int -> [> `Light_userdata of 'a | `Userdata of 'a ] option
If the value at the given acceptable index is a full userdata, returns its value as Some `Userdata v. If the value is a light userdata, returns its value as Some `Light_userdata v. Otherwise, returns None.

WARNING: using this function could be harmful because it actually breaks the type system. It has the same semantics of Obj.magic, allowing the programmer to push an OCaml value into the Lua state, and then retrieve it with a different type. Be very careful!

val type_ : state -> int -> lua_type
See lua_type documentation.
val typename : state -> lua_type -> string
See lua_typename documentation.
val xmove : state -> state -> int -> unit
See lua_xmove documentation.
val yield : state -> int -> int
See lua_yield documentation.