--- title: "Introduction to luajr" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Introduction to luajr} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` **luajr** allows you to run [Lua](https://www.lua.org) 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](https://luajit.org) 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](https://www.lua.org) for resources related to coding in Lua, and the [LuaJIT web site](https://luajit.org) for resources related to LuaJIT itself. ## Running Lua code: `lua()` and `lua_shell()` ```{r setup} library(luajr) ``` 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: ```{r} lua("return 'Hello ' .. 'world!'") ``` Assignments to global variables will persist between calls to `lua()`: ```{r} lua("my_animal = 'walrus'") lua("return my_animal") ``` 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](#states), below). Assignments to local variables will *not* persist between calls to `lua()`: ```{r} lua("local my_animal = 'donkey'") lua("return my_animal") ``` 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()`: ```{r} lua("local my_veg = 'potato'; local my_dish = my_veg .. ' pie'; return my_dish") ``` 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: ```{r} luaprint = lua_func("print") luaprint("Hello, world") ``` Here, `"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: ```{r} lua("function excited_print(x) print(x .. '!') end") lua("return excited_print('Hello, world')") xp = lua_func("excited_print", "native") xp("Wow") ``` Or you can use `lua_func()` to define an anonymous Lua function: ```{r} timestwo = lua_func("function(x) return x*2 end", "native") timestwo(123) ``` Under 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](luajr-module.html) 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: ```r 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: ```r 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: ```{r} values = c(1.0, 2.0, 3.0) keep = lua_func("function(x) x[1] = 999 end", ".") # passed by value keep(values) print(values) change = lua_func("function(x) x[1] = 999 end", "&.") # passed by reference change(values) print(values) ``` Vectors can never be resized by reference; only their already-existing elements can be changed by reference. ## Working with Lua States: `lua_open()`, `lua_reset()` {#states} 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: ```{r} L1 = lua_open() lua("a = 2") lua("a = 4", L = L1) lua("return a") lua("return a", L = L1) ``` There 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: ```{r} lua("a = 2") lua("return a") lua_reset() lua("return a") #> NULL ``` 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](luajr-module.html) vignette.