Title: | 'LuaJIT' Scripting |
---|---|
Description: | An interface to 'LuaJIT' <https://luajit.org>, a just-in-time compiler for the 'Lua' scripting language <https://www.lua.org>. Allows users to run 'Lua' code from 'R'. |
Authors: | Mike Pall [aut, cph] (Author of the embedded LuaJIT compiler), Lua.org, PUC-Rio [cph] (Copyright holders over portions of Lua source code included in LuaJIT), Nicholas Davies [cre, ctb, cph] (Author of the R package wrapper, <https://orcid.org/0000-0002-1740-1412>), Scott Lembcke, Howling Moon Software [ctb, cph] (Authors of the embedded debugger.lua debugger) |
Maintainer: | Nicholas Davies <[email protected]> |
License: | MIT + file LICENSE |
Version: | 0.1.8.9000 |
Built: | 2025-02-13 03:57:28 UTC |
Source: | https://github.com/nicholasdavies/luajr |
'luajr' provides an interface to LuaJIT, a just-in-time compiler for the Lua scripting language. It allows users to run Lua code from R.
lua()
: run Lua code
lua_func()
: make a Lua function callable from R
lua_shell()
: run an interactive Lua shell
lua_open()
: create a new Lua state
lua_reset()
: reset the default Lua state
lua_parallel()
: run Lua code in parallel
For an introduction to 'luajr', see vignette("luajr")
Maintainer: Nicholas Davies [email protected] (ORCID) (Author of the R package wrapper) [contributor, copyright holder]
Authors:
Mike Pall (Author of the embedded LuaJIT compiler) [copyright holder]
Other contributors:
Lua.org, PUC-Rio (Copyright holders over portions of Lua source code included in LuaJIT) [copyright holder]
Scott Lembcke, Howling Moon Software (Authors of the embedded debugger.lua debugger) [contributor, copyright holder]
Useful links:
Report bugs at https://github.com/nicholasdavies/luajr/issues
Runs the specified Lua code.
lua(code, filename = NULL, L = NULL)
lua(code, filename = NULL, L = NULL)
code |
Lua code block to run. |
filename |
If non- |
L |
Lua state in which to run the code. |
Lua value(s) returned by the code block converted to R object(s).
Only a subset of all Lua types can be converted to R objects at present.
If multiple values are returned, these are packaged in a list
.
twelve <- lua("return 3*4") print(twelve)
twelve <- lua("return 3*4") print(twelve)
Takes any Lua expression that evaluates to a function and provides an R function that can be called to invoke the Lua function.
lua_func(func, argcode = "s", L = NULL)
lua_func(func, argcode = "s", L = NULL)
func |
Lua expression evaluating to a function. |
argcode |
How to wrap R arguments for the Lua function. |
L |
Lua state in which to run the code. |
The R types that can be passed to Lua are: NULL
, logical vector,
integer vector, numeric vector, string vector, list, external pointer, and
raw.
The parameter argcode
is a string with one character for each argument of
the Lua function, recycled as needed (e.g. so that a single character would
apply to all arguments regardless of how many there are).
In the following, the corresponding character of argcode
for a specific
argument is referred to as its argcode.
For NULL
or any argument with length 0, the result in Lua is nil
regardless of the corresponding argcode.
For logical, integer, double, and character vectors, if the corresponding
argcode is 's'
(simplify), then if the R vector has length one, it is
supplied as a Lua primitive (boolean, number, number, or string,
respectively), and if length > 1, as an array, i.e. a table with integer
indices starting at 1. If the code is 'a'
, the vector is always supplied as
an array, even if it only has length 1. If the argcode is the digit '1'
through '9'
, this is the same as 's'
, but the vector is required to have
that specific length, otherwise an error message is emitted.
Still focusing on the same vector types, if the argcode is 'r'
, then the
vector is passed by reference to Lua, adopting the type luajr.logical_r
,
luajr.integer_r
, luajr.numeric_r
, or luajr.character_r
as appropriate.
If the argcode is 'v'
, the vector is passed by value to Lua,
adopting the type luajr.logical
, luajr.integer
, luajr.numeric
, or
luajr.character
as appropriate.
For a raw vector, only the 's'
type is accepted and the result in Lua is
a string (potentially with embedded nulls).
For lists, if the argcode is 's'
(simplify), the list is passed as a Lua
table. Any entries of the list with non-blank names are named in the table,
while unnamed entries have the associated integer key in the table. Note that
Lua does not preserve the order of entries in tables. This means that an R
list with names will often go "out of order" when passed into Lua with 's'
and then returned back to R. This is avoided with argcode 'r'
or 'v'
.
If a list is passed in with the argcode 'r'
or 'v'
, the list is
passed to Lua as type luajr.list
, and all vector elements of the list are
passed by reference or by value, respectively.
For external pointers, the argcode is ignored and the external pointer is passed to Lua as type userdata.
When the function is called and Lua values are returned from the function, the Lua return values are converted to R values as follows.
If nothing is returned, the function returns invisible()
(i.e. NULL
).
If multiple arguments are returned, a list with all arguments is returned.
Reference types (e.g. luajr.logical_r
) and vector types (e.g.
luajr.logical
) are returned to R as such. A luajr.list
is returned as an
R list. Reference and list types respect R attributes set within Lua code.
A table is returned as a list. In the list, any table entries with a
number key come first (with indices 1 to n, i.e. the original number key's
value is discarded), followed by any table entries with a string key
(named accordingly). This may well scramble the order of keys, so beware.
Note in particular that Lua does not guarantee that it will traverse a table
in ascending order of keys. Entries with non-number, non-string keys are
discarded. It is probably best to avoid returning a table with anything
other than string keys, or to use luajr.list
.
A Lua string with embedded nulls is returned as an R raw type.
An R function which can be called to invoke the Lua function.
squared <- lua_func("function(x) return x^2 end") print(squared(7))
squared <- lua_func("function(x) return x^2 end") print(squared(7))
Run Lua code with the debugger or profiler activated, and control whether the LuaJIT just-in-time compiler is on.
lua_mode(expr, debug, profile, jit)
lua_mode(expr, debug, profile, jit)
expr |
An expression to run with the associated settings. If |
debug |
Control the debugger: |
profile |
Control the profiler: |
jit |
Control LuaJIT's just-in-time compiler: |
When called with no arguments, returns the current settings. When
called with expr
, calls the value returned by expr
. Otherwise, returns
nothing.
This function is experimental. Its interface and behaviour may change in subsequent versions of luajr.
lua_mode()
works in one of three ways, depending on which parameters are
provided.
When called with no arguments, lua_mode()
returns the current debug
,
profile
, and jit
settings.
When called without an expr
argument, but with at least one of debug
,
profile
, or jit
, the settings apply for any subsequent executions of Lua
code until the settings are changed by another call to lua_mode()
.
When called with an expr
argument, the settings for debug
, profile
,
and jit
are applied temporarily just for the evaluation of expr
in the
calling frame.
The debug
setting allows you to run Lua code in debug mode, using Scott
Lembcke's debugger.lua
.
Use debug = "step"
(or TRUE
or "on") to step through each line of the
code; use debug = "error"
to trigger the debugger on any Lua error; and
turn off the debugger with debug = "off"
(or FALSE
).
To trigger the debugger from a specific place within your Lua code, you can
also call luajr.dbg()
from your Lua code. Within Lua, use
luajr.dbg(CONDITION)
to trigger debugging only if CONDITION
evaluates to
false
or nil
.
debugger.lua
is more fully documented at its
github repo page, but briefly,
you enter commands of one character at the debugger.lua>
prompt. Use
n
to step to the next line, q
to quit, and h
to show a help page with
all the rest of the commands.
The profile
setting allows you to profile your Lua code run, generating
information useful for optimising its execution speed.
Use profile = "on"
(or TRUE
) to turn on the profiler with default
settings (namely, profile at the line level and sample at 1-millisecond
intervals).
Instead of "on"
, you can pass a string containing any of these options:
f
: enable profiling to the function level.
l
: enable profiling to the line level.
i<integer>
: set the sampling interval, in milliseconds (default: 1ms).
For example, the default options correspond to the string "li1"
.
You must use lua_profile()
to recover the generated profiling data.
The jit
setting allows you to turn LuaJIT's just-in-time compiler off
(with jit = "off"
or FALSE
). The default is for the JIT compiler to be
"on"
(alias TRUE
).
Lua code will generally run more slowly with the JIT off, although there have been issues reported with LuaJIT running more slowly with the JIT on for processors using ARM64 architecture, which includes Apple Silicon CPUs.
lua_profile()
for extracting the generated profiling data.
## Not run: # Debugger in "one-shot" mode lua_mode(debug = "on", sum <- lua(" local s = 0 for i = 1,10 do s = s + i end return s ") ) # Profiler in "switch on / switch off" mode lua_mode(profile = TRUE) pointless_computation = lua_func( "function() local s = startval for i = 1,10^8 do s = math.sin(s) s = math.exp(s^2) s = s + 1 end return s end") lua("startval = 100") pointless_computation() lua_mode(profile = FALSE) lua_profile() # Turn off JIT and turn it on again lua_mode(jit = "off") lua_mode(jit = "on") ## End(Not run)
## Not run: # Debugger in "one-shot" mode lua_mode(debug = "on", sum <- lua(" local s = 0 for i = 1,10 do s = s + i end return s ") ) # Profiler in "switch on / switch off" mode lua_mode(profile = TRUE) pointless_computation = lua_func( "function() local s = startval for i = 1,10^8 do s = math.sin(s) s = math.exp(s^2) s = s + 1 end return s end") lua("startval = 100") pointless_computation() lua_mode(profile = FALSE) lua_profile() # Turn off JIT and turn it on again lua_mode(jit = "off") lua_mode(jit = "on") ## End(Not run)
Creates a new, empty Lua state and returns an external pointer wrapping that state.
lua_open()
lua_open()
All Lua code is executed within a given Lua state. A Lua state is similar to
the global environment in R, in that it is where all variables and functions
are defined. luajr automatically maintains a "default" Lua state, so
most users of luajr will not need to use lua_open()
.
However, if for whatever reason you want to maintain multiple different Lua
states at a time, each with their own independent global variables and
functions, lua_open()
can be used to create a new Lua state which can then
be passed to lua()
, lua_func()
and lua_shell()
via the L
parameter.
These functions will then operate within that Lua state instead of the
default one. The default Lua state can be specified explicitly with
L = NULL
.
Note that there is currently no way (provided by luajr) of saving a
Lua state to disk so that the state can be restarted later. Also, there is
no lua_close
in luajr because Lua states are closed automatically
when they are garbage collected in R.
External pointer wrapping the newly created Lua state.
L1 <- lua_open() lua("a = 2") lua("a = 4", L = L1) lua("print(a)") # 2 lua("print(a)", L = L1) # 4
L1 <- lua_open() lua("a = 2") lua("a = 4", L = L1) lua("print(a)") # 2 lua("print(a)", L = L1) # 4
Runs a Lua function multiple times, with function runs divided among multiple threads.
lua_parallel(func, n, threads, pre = NA_character_)
lua_parallel(func, n, threads, pre = NA_character_)
func |
Lua expression evaluating to a function. |
n |
Number of function executions. |
threads |
Number of threads to create, or a list of existing Lua states
(e.g. as created by |
pre |
Lua code block to run once for each thread at creation. |
This function is experimental. Its interface and behaviour are likely to change in subsequent versions of luajr.
lua_parallel()
works as follows. A number threads
of new Lua states is
created with the standard Lua libraries and the luajr
module opened in
each (i.e. as though the states were created using lua_open()
). Then, a
thread is launched for each state. Within each thread, the code in pre
is
run in the corresponding Lua state. Then, func(i)
is called for each i
in 1:n
, with the calls spread across the states. Finally, the Lua states
are closed and the results are returned in a list. The list elements are
returned in the correct order, i.e. the ordering of the returned list does
not depend on the actual execution order of each call to func
.
Instead of an integer, threads
can be a list of Lua states, e.g. NULL
for the default Lua state or a state returned by lua_open()
. This saves
the time needed to open the new states, which takes a few milliseconds.
List of n
values returned from the Lua function func
.
Note that func
has to be thread-safe. All pure Lua code and built-in Lua
library functions are thread-safe, except for certain functions in the
built-in os and io libraries (search for "thread safe" in the
Lua 5.2 reference manual).
Additionally, use of luajr reference types is not thread-safe because
these use R to allocate and manage memory, and R is not thread-safe. This
means that you cannot safely use luajr.logical_r
, luajr.integer_r
,
luajr.numeric_r
, luajr.character_r
, or other reference types within
func
. luajr.list
and luajr.dataframe
are fine, provided the list
entries / dataframe columns are value types.
There is overhead associated with creating new Lua states and with gathering all the function results in an R list. It is advisable to check whether running your Lua code in parallel actually gives a substantial speed increase.
lua_parallel("function(i) return i end", n = 4, threads = 2)
lua_parallel("function(i) return i end", n = 4, threads = 2)
After running Lua code with the profiler active (using lua_mode()
), use
this function to get the profiling data that has been collected.
lua_profile(flush = TRUE)
lua_profile(flush = TRUE)
flush |
If |
This function is experimental. Its interface and behaviour may change in subsequent versions of luajr.
An object of class "lua_profile"
.
lua_mode()
for generating the profiling data.
## Not run: lua_mode(profile = TRUE) pointless_computation = lua_func( "function() local s = startval for i = 1,10^8 do s = math.sin(s) s = math.exp(s^2) s = s + 1 end return s end") lua("startval = 100") pointless_computation() lua_mode(profile = FALSE) prof = lua_profile() ## End(Not run)
## Not run: lua_mode(profile = TRUE) pointless_computation = lua_func( "function() local s = startval for i = 1,10^8 do s = math.sin(s) s = math.exp(s^2) s = s + 1 end return s end") lua("startval = 100") pointless_computation() lua_mode(profile = FALSE) prof = lua_profile() ## End(Not run)
Clears out all variables from the default Lua state, freeing up the associated memory.
lua_reset()
lua_reset()
This resets the default Lua state only. To reset a non-default
Lua state L
returned by lua_open()
, just do L <- lua_open()
again. The
memory previously used will be cleaned up at the next garbage collection.
None.
lua("a = 2") lua_reset() lua("print(a)") # nil
lua("a = 2") lua_reset() lua("print(a)") # nil
When in interactive mode, provides a basic read-eval-print loop with LuaJIT.
lua_shell(L = NULL)
lua_shell(L = NULL)
L |
Lua state in which to run the code. |
Enter an empty line to return to R.
As a convenience, lines starting with an equals sign have the "="
replaced
with "return "
, so that e.g. entering =x
will show the value of x
as
returned to R.
None.