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.

GC_ERROR

external

Int

Status code returned when the garbage collector metamethod fails.

HANDLER_ERROR

external

Int

Status code returned when the error handler itself fails.

MEMORY_ERROR

external

Int

Status code returned when a memory allocation fails.

OK

external

Int

Status code returned on success.

RUNTIME_ERROR

external

Int

Status code returned when a runtime error occurs.

TYPE_BOOLEAN

external

Int

Type constant for boolean values.

TYPE_FUNCTION

external

Int

Type constant for function values.

TYPE_LIGHTUSERDATA

external

Int

Type constant for light userdata values.

TYPE_NIL

external

Int

Type constant for nil values.

TYPE_NUMBER

external

Int

Type constant for numeric values (both integer and float).

TYPE_STRING

external

Int

Type constant for string values.

TYPE_TABLE

external

Int

Type constant for table values.

TYPE_THREAD

external

Int

Type constant for thread (coroutine) values.

TYPE_USERDATA

external

Int

Type constant for full userdata values.

YIELD

external

Int

Status code returned when a coroutine yields.

call

external

(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

external

(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).

close

external

(Fn [(Ref Lua a)] ())

Close a Lua state and free all associated resources.

coroutine-status

external

(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

external

(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

instantiate

(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

external

(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

defn

(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

defn

(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

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-bool

external

(Fn [(Ref Lua a), Int] Bool)

Read the value at index as a boolean.

get-field

external

(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

external

(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

external

(Fn [(Ref Lua a), (Ptr CChar)] ())

Push the value of the named global onto the stack.

get-int

external

(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

external

(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

external

(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

defn

(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

external

(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

external

(Fn [(Ref Lua a)] Int)

Return the index of the top element, which equals the number of elements on the stack.

get-user-data

external

(Fn [(Ref Lua a), Int] (Ptr ()))

Read the value at index as a userdata pointer.

global-exists?

defn

(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.

is-yieldable?

instantiate

(Fn [(Ref Lua a)] Bool)

Return true if the given coroutine can yield.

libs

external

(Fn [(Ref Lua a)] ())

Open all standard Lua libraries in the given state.

load-buffer

external

(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

external

(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

external

(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

external

(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

instantiate

(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

external

(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.

pop

external

(Fn [(Ref Lua a), Int] ())

Remove n elements from the top of the stack.

prepare-cfunction

macro

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-bool

external

(Fn [(Ref Lua a), Bool] ())

Push a boolean onto the stack.

push-carp-str

defn

(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

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

external

(Fn [(Ref Lua a), Int] ())

Push a copy of the element at index onto the top of the stack.

push-float

external

(Fn [(Ref Lua a), Float] ())

Push a float (Lua number) onto the stack.

push-global-table

external

(Fn [(Ref Lua a)] ())

Push the global table onto the stack.

push-int

external

(Fn [(Ref Lua a), Int] ())

Push an integer onto the stack.

push-light-user-data

external

(Fn [(Ref Lua a), (Ptr ())] ())

Push a light userdata pointer onto the stack.

push-nil

external

(Fn [(Ref Lua a)] ())

Push nil onto the stack.

push-string

instantiate

(Fn [(Ref Lua a), (Ptr CChar)] (Ptr CChar))

Push a C string onto the stack. For Carp strings, use push-carp-str instead.

push-thread

external

(Fn [(Ref Lua a)] ())

Push the current thread onto the stack.

raw-get

external

(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

external

(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

instantiate

(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

external

(Fn [(Ref Lua a), Int] ())

Like set-table but bypasses metamethods. Pops both the key and the value from the stack.

raw-seti

external

(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

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

instantiate

(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

external

(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

external

(Fn [(Ref Lua a), (Ptr CChar)] ())

Pop the top value from the stack and set it as the named global.

set-metatable

instantiate

(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

external

(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

defn

(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

external

(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

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

defn

(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

external

(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

instantiate

(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

instantiate

(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

external

(Fn [(Ref Lua a), Int] Int)

Return the type constant of the value at index. Compare against TYPE_NIL, TYPE_NUMBER, etc.

val

defn

(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

macro

Macro

                        (with-lua body)
                    

Like with-lua-as but binds the state to lua.

with-lua-as

macro

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

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

instantiate

(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.