Lua
provides bindings for embedding Lua in Carp. It wraps the Lua C API directly, following its stack-based model: you push values onto a virtual stack, call Lua operations, and read results back from the stack.
All interaction starts with a Lua state. Use with-lua-do to
create one, do work, and close it automatically. Call libs to make
the Lua standard library available.
(Lua.with-lua-do
(Lua.libs lua)
(ignore (Lua.do-string lua (cstr "print('hello from lua')"))))
Values are passed between Carp and Lua through the stack. Push values with
push-int, push-float,
push-bool, push-carp-str, etc. Read them
back with get-int, get-float, and so on, using
negative indices to address from the top of the stack (-1 is the top element).
; push two values, read the top one
(Lua.push-int lua 42)
(Lua.push-float lua 3.14f)
(let [f (Lua.get-float lua -1) ; 3.14
i (Lua.get-int lua -2)] ; 42
(Lua.pop lua 2))
To call a Lua function at the low level, push the function, then its arguments,
then use call with the argument and result counts. The result
replaces the function and arguments on the stack.
(Lua.get-global lua (cstr "math"))
(ignore (Lua.get-field lua -1 (cstr "sqrt")))
(Lua.push-float lua 9.0f)
(ignore (Lua.call lua 1 1 0))
(IO.println &(str (Lua.get-float lua -1))) ; 3.0
(Lua.pop lua 2) ; pop result and math table
Tables are built by creating an empty table with create-table,
setting fields with set-field, and optionally assigning the
table to a global with set-global. Raw table access
(raw-get, raw-set, raw-geti,
raw-seti) bypasses metamethods for direct table manipulation.
Metatables enable object-oriented patterns and operator overloading. Use
new-metatable to create a named metatable in the registry,
set-metatable to attach it to a table or userdata, and
get-metatable to retrieve it.
Full userdata (new-userdata) allocates GC-managed memory on
the Lua side, useful for exposing Carp-created objects to Lua scripts with
metatables for method dispatch.
Coroutines are created with new-thread, which returns a new
execution context sharing the parent’s globals. Push a function onto the
coroutine’s stack, then drive it with resume. The coroutine
yields values back via coroutine.yield() (Lua side) or yield
(C function side, tail-call only). Check coroutine-status
or the return value of resume (OK vs YIELD) to
distinguish completion from suspension.
(Lua.with-lua-do
(Lua.libs lua)
(ignore (Lua.do-string lua
(cstr "function gen() coroutine.yield(1); return 2 end")))
(let [co (Lua.new-thread lua)]
(do
(Lua.get-global co (cstr "gen"))
(ignore (Lua.resume co lua 0)) ; yields 1
(IO.println &(str (Lua.get-int co -1)))
(Lua.pop co 1)
(ignore (Lua.resume co lua 0)) ; returns 2
(IO.println &(str (Lua.get-int co -1))))))
The module also provides convenience macros: fun defines a Lua
function from inline source, val evaluates a Lua expression into
a global, and register-fn registers a Carp function as a
Lua global so that Lua scripts can call back into Carp:
(defn double-it [l]
(let [x (Lua.get-int l 1)]
(do (Lua.push-int l (* x 2)) 1)))
(Lua.prepare-cfunction double-it)
(Lua.with-lua-do
(Lua.libs lua)
(Lua.register-fn lua double double-it)
(ignore (Lua.do-string lua (cstr "print(double(21))"))))
For higher-level functions that handle type checking and error
wrapping automatically, see Luax.
call
(Fn [(Ref Lua a), Int, Int, Int] Int)
Call a function on the stack with nargs arguments and nresults
expected results. The last argument is the error handler stack index (0 for
none). Returns a status code; use Luax.call-fn for a safer
interface.
check-userdata
(Fn [(Ref Lua a), Int, (Ptr CChar)] (Ptr ()))
Return a pointer to the userdata at index if it has the
metatable name from the registry. Raises a Lua error otherwise (catchable with
call).
coroutine-status
(Fn [(Ref Lua a)] Int)
Return the status of a coroutine: OK if the
coroutine has not started or finished successfully, YIELD if it is
suspended, or an error code if it terminated with an error.
create-table
(Fn [(Ref Lua a), Int, Int] ())
Push a new empty table onto the stack. narr and nrec are
size hints for the array and hash parts.
do-file
(Fn [(Ref Lua a), (Ptr CChar)] Int)
Load and execute a Lua file. Returns a status code. Use
eval-file for a version that returns Result.
do-string
(Fn [(Ref Lua a), (Ptr CChar)] Int)
Compile and execute a Lua string. Returns a status code.
Use Luax.do-in for a version that returns Result.
eval-file
(Fn [(Ref Lua a), (Ref String b)] (Result String String))
(eval-file lua path)
Load and execute the Lua file at path. Returns (Success "")
on success or (Error msg) with the Lua error message on failure.
evaluate
(Fn [a] (Result String String))
(evaluate s)
Create a temporary Lua state, evaluate the expression s, and
return its string representation as a Result. Useful for one-off evaluations
without managing a state manually.
(match (Lua.evaluate "1 + 2")
(Result.Success v) (IO.println &v)
(Result.Error e) (IO.errorln &e))
fun
Macro
(fun lua name args body)
Define a Lua function from a Carp macro call. name becomes a Lua
global, args is a list of parameter names, and body is the Lua source.
(Lua.fun lua add [x y] "return x + y")
get-field
(Fn [(Ref Lua a), Int, (Ptr CChar)] Int)
Push the value of field name from the table at index onto
the stack. Returns a type constant.
get-float
(Fn [(Ref Lua a), Int] Float)
Read the value at index as a float. Does not check the
type—use Luax.maybe-get-float for a safe version.
get-global
(Fn [(Ref Lua a), (Ptr CChar)] ())
Push the value of the named global onto the stack.
get-int
(Fn [(Ref Lua a), Int] Int)
Read the value at index as an integer. Does not check the
type—use Luax.maybe-get-int for a safe version.
get-metatable
(Fn [(Ref Lua a), Int] Bool)
Push the metatable of the value at index onto the stack.
Returns true if the value has a metatable, false otherwise (and nothing is
pushed).
get-string
(Fn [(Ref Lua a), Int] (Ptr CChar))
Read the value at index as a C string pointer. Returns a
raw pointer; prefer Luax.get-carp-str or
Luax.maybe-get-string for safe access.
get-string-global
(Fn [(Ref Lua a), (Ref String b)] String)
(get-string-global lua name)
Fetch the global name and return it as a Carp
String. Returns an empty string if the global is nil or not a string. For a
safe version returning Maybe, see Luax.get-string-global.
get-table
(Fn [(Ref Lua a), Int] Int)
Pop a key from the stack and push the corresponding value from
the table at index. Returns a type constant.
get-top
(Fn [(Ref Lua a)] Int)
Return the index of the top element, which equals the number of elements on the stack.
get-user-data
(Fn [(Ref Lua a), Int] (Ptr ()))
Read the value at index as a userdata pointer.
global-exists?
(Fn [(Ref Lua a), (Ref String b)] Bool)
(global-exists? lua name)
Check whether the global name is defined (non-nil).
Pushes and pops internally, leaving the stack unchanged.
load-buffer
(Fn [(Ref Lua a), (Ptr CChar), Int, (Ptr CChar)] Int)
Load a Lua chunk from a buffer without executing it. Returns a status code.
new
(Fn [] (Ref Lua a))
Create a new Lua state. Must be closed with close when
done, or use with-lua-do to manage the lifecycle
automatically.
new-metatable
(Fn [(Ref Lua a), (Ptr CChar)] Bool)
Create or look up a named metatable in the Lua registry and
push it onto the stack. Returns true if a new table was created, false if
the name already existed. Either way the metatable is on top of the stack
afterward.
new-thread
(Fn [(Ref Lua a)] (Ref Lua b))
Create a new coroutine as a thread of the given state. Pushes
the new thread onto the stack and returns a pointer to it. The coroutine shares
the global environment with the parent but has its own execution stack. Do not
call close on the returned thread—it is garbage-collected by the
parent state.
new-userdata
(Fn [(Ref Lua a), Int] (Ptr ()))
Allocate size bytes as a full userdata, push it onto the
stack, and return a pointer to the allocated block. The userdata is
garbage-collected by Lua. Use set-metatable or
set-named-metatable to attach a metatable.
next
(Fn [(Ref Lua a), Int] Int)
Pop a key and push the next key-value pair from the table at
index. Returns 0 when there are no more entries. Used for iterating tables
with push-nil as the initial key.
prepare-cfunction
Macro
(prepare-cfunction fn-sym)
Declare a Carp function as pushable onto a Lua stack.
Must be called at the top level, before any use of
push-cfunction or register-fn with this
function. The function must be a top-level defn with signature
(Fn [&Lua] Int).
(defn square [l]
(let [x (Lua.get-int l 1)]
(do (Lua.push-int l (* x x)) 1)))
(Lua.prepare-cfunction square)
push-carp-str
(Fn [(Ref Lua a), (Ref String b)] ())
(push-carp-str lua s)
Push a Carp String reference onto the Lua stack. Wraps
push-string with automatic cstr conversion.
push-cfunction
Macro
(push-cfunction lua fn-sym)
Push a prepared Carp function onto the Lua stack as a
C function. The function must have been declared with
prepare-cfunction at the top level first.
(defn square [l]
(let [x (Lua.get-int l 1)]
(do (Lua.push-int l (* x x)) 1)))
(Lua.prepare-cfunction square)
(Lua.with-lua-do
(Lua.push-cfunction lua square)
(Lua.set-global lua (cstr "square")))
push-copy
(Fn [(Ref Lua a), Int] ())
Push a copy of the element at index onto the top of the stack.
push-light-user-data
(Fn [(Ref Lua a), (Ptr ())] ())
Push a light userdata pointer onto the stack.
push-string
(Fn [(Ref Lua a), (Ptr CChar)] (Ptr CChar))
Push a C string onto the stack. For Carp strings, use
push-carp-str instead.
raw-get
(Fn [(Ref Lua a), Int] Int)
Like get-table but bypasses metamethods. Pops the
key from the stack and pushes the value. Returns the type of the result.
raw-geti
(Fn [(Ref Lua a), Int, Int] Int)
Push t[n] onto the stack without invoking metamethods, where t
is the table at index. Returns the type of the result.
raw-len
(Fn [(Ref Lua a), Int] Int)
Return the raw length of the value at index (table, string, or
full userdata) without invoking the __len metamethod.
raw-set
(Fn [(Ref Lua a), Int] ())
Like set-table but bypasses metamethods. Pops both
the key and the value from the stack.
raw-seti
(Fn [(Ref Lua a), Int, Int] ())
Pop the top value and set it as t[n] without invoking
metamethods, where t is the table at index.
register-fn
Macro
(register-fn lua name fn-sym)
Register a Carp function as a Lua global, making it callable
from Lua scripts. The function must have been declared with
prepare-cfunction at the top level first. name is the
Lua-side name (a symbol).
The function must be a top-level defn with signature (Fn [&Lua] Int):
it receives arguments via the Lua stack (1-indexed from the bottom) and
must return the number of results pushed.
(defn my-add [l]
(let [a (Lua.get-int l 1)
b (Lua.get-int l 2)]
(do (Lua.push-int l (+ a b)) 1)))
(Lua.prepare-cfunction my-add)
(Lua.with-lua-do
(Lua.libs lua)
(Lua.register-fn lua add my-add)
(ignore (Lua.do-string lua (cstr "print(add(3, 4))"))))
resume
(Fn [(Ref Lua a), (Ref Lua b), Int] Int)
Resume a suspended coroutine. Before the first resume, push the
function to call onto the coroutine’s stack; on subsequent resumes, push values
to return from yield. nargs is the number of values pushed.
from is the calling state. Returns OK when the coroutine finishes,
YIELD when it suspends, or an error code. Results are left on the
coroutine’s stack.
set-field
(Fn [(Ref Lua a), Int, (Ptr CChar)] ())
Pop the top value and set it as field name on the table at
index. Note: pushing a value shifts relative stack indices, so if the table
is at -1, use -2 as the index after pushing. See Luax.set-int-field
and friends for a safer interface.
set-global
(Fn [(Ref Lua a), (Ptr CChar)] ())
Pop the top value from the stack and set it as the named global.
set-metatable
(Fn [(Ref Lua a), Int] ())
Pop the table from the top of the stack and set it as the
metatable for the value at index.
set-named-metatable
(Fn [(Ref Lua a), (Ptr CChar)] ())
Set the metatable of the value on top of the stack to
the metatable associated with name in the registry. The value remains on the
stack.
set-string-global
(Fn [(Ref Lua a), (Ref String b), (Ref String c)] ())
(set-string-global lua name s)
Push s and assign it to the global name. For other
types, see Luax.set-int-global and friends.
set-table
(Fn [(Ref Lua a), Int] ())
Pop a key and value from the stack and set them on the table at
index. The value must be on top, with the key below it.
setup
Dynamic
(setup location :rest cflag)
Set up Lua includes and linking. location is the include path
(e.g. "lua" or "lua5.4"). An optional second argument overrides the
library name for linking (defaults to "lua").
table-length
(Fn [(Ref Lua a), Int] Int)
(table-length lua index)
Count the entries in the table at index by iterating with
next. Returns -1 if the value at index is not a table. Leaves the
stack unchanged.
test-userdata
(Fn [(Ref Lua a), Int, (Ptr CChar)] (Ptr ()))
Like check-userdata but returns a null
pointer instead of raising a Lua error when the check fails.
to-string
(Fn [(Ref Lua a), Int] (Ptr CChar))
Read the value at index as a C string pointer. Low-level
alias; prefer Luax.get-carp-str.
to-thread
(Fn [(Ref Lua a), Int] (Ref Lua b))
Read the value at index as a Lua state pointer. Returns a
null pointer if the value is not a thread.
type-of
(Fn [(Ref Lua a), Int] Int)
Return the type constant of the value at index. Compare against
TYPE_NIL, TYPE_NUMBER, etc.
val
(Fn [(Ref Lua a), (Ref String b), c] Int)
(val lua name value)
Evaluate the Lua expression value and assign the result to the
global name. Returns OK on success.
(Lua.val lua "pi" "3.14159")
with-lua-as
Macro
(with-lua-as name body)
Create a Lua state bound to name, evaluate body, then
close the state. Returns the result of body.
(Lua.with-lua-as L
(do (Lua.libs L) (Lua.do-string L (cstr "print('hi')"))))
with-lua-do
Macro
(with-lua-do :rest body)
Like with-lua but wraps multiple body forms
in a do block. This is the most common entry point.
(Lua.with-lua-do
(Lua.libs lua)
(Lua.push-int lua 42)
(IO.println &(str (Lua.get-int lua -1))))
yield
(Fn [(Ref Lua a), Int] Int)
Yield the current coroutine with nresults values from the top of
the stack. Can only be used as the return expression of a C function registered
with prepare-cfunction.