luajr allows you to run Lua code from R.
Lua is a lightweight, simple, and fast scripting language that is used in a variety of settings. The standard Lua interpreter is already reasonably fast, but there is also a just-in-time compiler for Lua called LuaJIT that is even faster. luajr uses LuaJIT.
This is not a guide to Lua or LuaJIT; it is a quick-start guide to luajr for people who already know how to program in Lua. See the Lua web site for resources related to coding in Lua, and the LuaJIT web site for resources related to LuaJIT itself.
Running Lua code: lua() and
lua_shell()
To get a feel for luajr or to run “one-off” Lua code
from your R project, use lua() and
lua_shell().
When you pass a character string to lua(), it is run as
Lua code:
lua("return 'Hello ' .. 'world!'")
#> [1] "Hello world!"Assignments to global variables will persist between calls to
lua():
This is because luajr maintains a “default Lua state” which holds all global variables. This default Lua state is opened the first time a package function is used. You can create your own, separate Lua states, or reset the default Lua state (see Lua states, below).
Assignments to local variables will not persist between
calls to lua():
In this case, the second line returns "walrus" because
the local variable my_animal goes out of scope after the
first call to lua() ends, so the second call to
lua() is referring back to the global variable
my_animal from before.
You can include more than one statement in the code run by
lua():
lua("local my_veg = 'potato'; local my_dish = my_veg .. ' pie'; return my_dish")
#> [1] "potato pie"You can also use the filename argument to
lua() to load and run a Lua source file, instead of running
the contents of a string.
Call lua_shell() to open an interactive Lua shell at the
R prompt. This can be helpful for debugging or for testing Lua
statements.
Calling Lua functions from R: lua_func()
The key piece of functionality for luajr is probably
lua_func(). This allows you to call Lua functions from
R.
The first argument to lua_func(), func, is
a string that should evaluate to a Lua function. lua_func()
then returns an R function that can be used to call that Lua function
from R. For example, you can use lua_func() to access an
existing Lua function from R:
luaprint = lua_func("print")
luaprint("Hello, world")
#> NULLHere, "print" is just referring to the built-in Lua
function print which prints a Lua value to the console. You
can also use lua_func() to refer to a previously defined
function in the default Lua state:
lua("function excited_print(x) print(x .. '!') end")
lua("return excited_print('Hello, world')")
xp = lua_func("excited_print", "native")
xp("Wow")
#> NULLOr you can use lua_func() to define an anonymous Lua
function:
timestwo = lua_func("function(x) return x*2 end", "native")
timestwo(123)
#> [1] 246Under the hood, lua_func() just takes its first
parameter (a string), adds "return " to the front of it,
executes it as Lua code, and registers the result as the function.
The second argument to lua_func(), argcode,
is also very important. argcode determines how the
arguments passed to the function from R are translated into Lua
variables for use inside the function.
The most important argcodes are "auto" and
"native".
The argcode "auto" means that the parameter should be
passed as a luajr type providing direct access to the R
variable passed in. For example, with the argcode "auto",
an R numeric vector is passed as a luajr.numeric type, an R
character vector is passed as a luajr.character type, and
an R function is passed as a luajr.rfunction type. For a
guide to luajr types, see the vignette The luajr.lua module
The argcode "native" means that the R value passed in
should be converted to a native Lua type. For example, with the argcode
"native", a single number in R like 2.5 is
passed as a Lua number, a single string like "foo" is
passed as a Lua string, and a list like list(a = 1, b = 2)
or a vector like 10:12 is passed as a Lua table.
For example, suppose you want to pass the R numeric vector
c(1.1, 3.3, 2.2) into a Lua function from which you will
return the biggest number in the vector. If you want the numeric vector
to come into your function as a luajr.numeric type, you
could write:
x = c(1.1, 3.3, 2.2)
my_max = lua_func("
function(x)
local max = nil
for i = 1,#x do
if max == nil or x[i] > max then
max = x[i]
end
end
return max
end", "auto")
my_max(x)If you want the numeric vector to come into your function as a Lua table, you could write:
x = c(1.1, 3.3, 2.2)
my_max = lua_func("
function(x)
return math.max(unpack(x))
end", "native")
my_max(x)where the above example takes advantage of Lua’s built-in
math.max function that returns the biggest element from
among all the arguments passed in.
The permissible arg codes are:
| Arg code | Short form | Accepted R types | Resulting Lua type |
|---|---|---|---|
auto |
. |
any | |
sexp |
S |
any | R.sexp |
rfunction |
F |
function | luajr.rfunction |
environment |
E |
environment | luajr.environment |
logical |
L |
logical | luajr.logical |
integer |
I |
integer, numeric (coerced) | luajr.integer |
numeric |
N |
numeric, integer (coerced) | luajr.numeric |
character |
C |
character | luajr.character |
vector, list
|
V |
list | luajr.list |
pointer |
P |
external pointer | light userdata
|
native |
$. |
any native-compatible type | |
function |
$F |
function or external pointer to Lua function | function |
boolean |
$L |
length-1 logical | boolean |
number |
$N |
length-1 integer or numeric | number |
string |
$C |
length-1 character | string |
table |
$V |
list or atomic vector | table |
Arg codes should be separated from each other by a comma, semicolon,
or space within the string. “Short form” arg codes do not need to be
separated. For example, "S$L" is equivalent to
"sexp, boolean".
Above, the $ prefix specifies “native type”.
There is also the ! prefix, which can be used to specify
“strict” mode. In “strict” mode, there is no coercion between integer
and numeric types, and NULL yields an error instead of
nil when a Lua native type is requested.
The & prefix can be used to specify that an R vector
type should be passed by reference. When a vector (logical vector,
integer vector, numeric vector, character vector, or list) is passed
from R to Lua by reference, modifications made to the elements of that
passed-in vector persist back in the R calling frame. For example:
values = c(1.0, 2.0, 3.0)
keep = lua_func("function(x) x[1] = 999 end", ".") # passed by value
keep(values)
#> NULL
print(values)
#> [1] 1 2 3
change = lua_func("function(x) x[1] = 999 end", "&.") # passed by reference
change(values)
#> NULL
print(values)
#> [1] 999 2 3Vectors can never be resized by reference; only their already-existing elements can be changed by reference.
Working with Lua States: lua_open(),
lua_reset()
All the functions mentioned above (lua(),
lua_shell(), and lua_func()) can also take an
argument L that specifies a particular Lua state that the
function operates in.
When L = NULL (the default) the functions operate on the
default Lua state.
But you can also open alternative Lua states using
lua_open(), and then by passing the result as the parameter
L, specify that the function operates in that specific
state. For example:
L1 = lua_open()
lua("a = 2")
lua("a = 4", L = L1)
lua("return a")
#> [1] 2
lua("return a", L = L1)
#> [1] 4There is no lua_close in luajr because
Lua states are closed automatically when they are garbage collected in
R.
lua_reset() resets the default Lua state:
To reset a non-default Lua state L returned by
lua_open(), just do L = lua_open() again. The
memory previously used by L will be cleaned up at the next
garbage collection.
Further reading
For notes on how to create and manipulate R objects – such as vectors, lists, and data.frames – in your Lua code, see the luajr.lua module vignette.