For the getting started guide, see Introduction to luajr.
Introduction
This vignette is for advanced R users who know how to use R’s API from C code. If you normally use R without C, this vignette may not make a lot of sense to you. If you use the Rcpp or cpp11 packages to interface C++ code with R, but have not used R’s C API directly, this vignette may not make sense to you either. Just a warning!
The luajr package ships with two Lua modules
included. The more commonly-used module is luajr.lua, which
offers convenience and higher-level interaction with R. That module is
described in the vignette The luajr.lua
module.
But, if you need lower-level access to R’s internals from Lua, then
R.lua may be helpful to you. The R.lua module
provides access to R’s C API from Lua. If you understand what each
element of the following C code does:
then you may find this vignette helpful. If not, you will need to thoroughly consult the Writing R Extensions manual before proceeding, because this vignette assumes you are already familiar with R’s C API.
Loading R.lua
Any Lua state that has been opened through the luajr
package automatically loads the luajr.lua module, but
the R.lua module needs to be loaded
explicitly before use. The R.lua module
can be loaded in Lua code like so:
The above line of Lua code opens the R.lua module and
loads it into a global Lua variable R. Once that line has
been executed in a Lua state, you can start to use the R functions and
types that are part of the module. Of course, you can assign the module
to a local variable instead.
R.sexp
R’s C API represents R values using the type SEXP,
meaning “S expression”. The SEXP type is a pointer to an
opaque C struct SEXPREC – see R
Internals for full details. Within Lua code, R.sexp is
an alias for the SEXP type (through LuaJIT’s ctype
mechanism), which means you can use Lua variables of type
R.sexp to pass to R’s API functions.
Functions
R.lua exposes some (but not all) of R’s C API
functions.
The naming of R’s C API functions is all over the place. Some
functions have no prefix, others have the prefix R_, and
still others have the prefix Rf_, with no obvious pattern.
Function names can be UPPER_CASE, lower_case, camelCase or TitleCase. It
can be confusing.
R.lua drops all R_ and Rf_
prefixes because the module is typically loaded into a table named
R, so R.Rf_allocVector would seem redundant
(instead it is R.allocVector). But the case of the function
name is kept as-is for consistency with the C API, and when there is a
familiar C macro that maps to a function, the case of the macro is
preferred (for example, PROTECT in C is a macro mapping to
the function Rf_protect; the corresponding
R.lua function is named R.PROTECT, not
R.protect).
Assuming the R.lua module has been loaded into a table
named R, you can use the following R API functions:
| Lua name | corresponding C signature |
|---|---|
R.allocVector |
SEXP Rf_allocVector(SEXPTYPE type, R_xlen_t length) |
R.CHAR |
const char* R_CHAR(SEXP x) |
R.CheckUserInterrupt |
void R_CheckUserInterrupt(void) |
R.classgets |
SEXP Rf_classgets(SEXP vec, SEXP klass) |
R.coerceVector |
SEXP Rf_coerceVector(SEXP v, SEXPTYPE type) |
R.cons |
SEXP Rf_cons(SEXP car, SEXP cdr) |
R.copyMostAttrib |
void Rf_copyMostAttrib(SEXP inp, SEXP ans) |
R.DATAPTR_RO |
const void* DATAPTR_RO(SEXP x) |
R.defineVar |
void Rf_defineVar(SEXP symbol, SEXP value, SEXP rho) |
R.dimgets |
SEXP Rf_dimgets(SEXP vec, SEXP val) |
R.dimnamesgets |
SEXP Rf_dimnamesgets(SEXP vec, SEXP val) |
R.duplicate |
SEXP Rf_duplicate(SEXP s) |
R.DUPLICATE_ATTRIB |
void DUPLICATE_ATTRIB(SEXP to, SEXP from) |
R.eval |
SEXP Rf_eval(SEXP e, SEXP rho) |
R.ExternalPtrAddr |
void* R_ExternalPtrAddr(SEXP s) |
R.findFun |
SEXP Rf_findFun(SEXP symbol, SEXP rho) |
R.FlushConsole |
void R_FlushConsole(void) |
R.getAttrib |
SEXP Rf_getAttrib(SEXP vec, SEXP name) |
R.GetOption1 |
SEXP Rf_GetOption1(SEXP tag) |
R.getRegisteredNamespace* |
SEXP R_getRegisteredNamespace(const char* name) added in 4.6.0
|
R.getVarEx* |
SEXP R_getVarEx(SEXP sym, SEXP rho, Rboolean inherits, SEXP ifnotfound)
added in
4.5.0
|
R.inherits |
Rboolean Rf_inherits(SEXP s, const char* name) |
R.install |
SEXP Rf_install(const char* name) |
R.INTEGER |
int* INTEGER(SEXP x) |
R.isObject |
Rboolean Rf_isObject(SEXP s) |
R.lcons |
SEXP Rf_lcons(SEXP car, SEXP cdr) |
R.LOGICAL |
int* LOGICAL(SEXP x) |
R.lsInternal3 |
SEXP R_lsInternal3(SEXP env, Rboolean all, Rboolean sorted) |
R.MakeExternalPtr |
SEXP R_MakeExternalPtr(void *p, SEXP tag, SEXP prot) |
R.mkChar |
SEXP Rf_mkChar(const char* name) |
R.mkCharLen |
SEXP Rf_mkCharLen(const char* name, int len) |
R.namesgets |
SEXP Rf_namesgets(SEXP vec, SEXP val) |
R.NewEnv* |
SEXP R_NewEnv(SEXP enclos, int hash, int size) added in 4.1.0
|
R.ParentEnv* |
SEXP R_ParentEnv(SEXP x) added in 4.5.0
|
R.PreserveObject |
void R_PreserveObject(SEXP object) |
R.PrintValue |
void Rf_PrintValue(SEXP s) |
R.PROTECT |
SEXP Rf_protect(SEXP s) |
R.RAW |
Rbyte* RAW(SEXP x) |
R.ReadConsole |
int R_ReadConsole(const char* prompt, unsigned char* buf, int buflen, int hist) |
R.REAL |
double* REAL(SEXP x) |
R.ReleaseObject |
void R_ReleaseObject(SEXP object) |
R.removeVarFromFrame |
void R_removeVarFromFrame(SEXP name, SEXP env) |
R.ScalarInteger |
SEXP Rf_ScalarInteger(int x) |
R.ScalarLogical |
SEXP Rf_ScalarLogical(int x) |
R.ScalarReal |
SEXP Rf_ScalarReal(double x) |
R.ScalarString |
SEXP Rf_ScalarString(SEXP x) |
R.SET_STRING_ELT |
void SET_STRING_ELT(SEXP x, R_xlen_t i, SEXP v) |
R.SET_TAG |
void SET_TAG(SEXP x, SEXP y) |
R.SET_VECTOR_ELT |
SEXP SET_VECTOR_ELT(SEXP x, R_xlen_t i, SEXP v) |
R.setAttrib |
SEXP Rf_setAttrib(SEXP vec, SEXP name, SEXP val) |
R.SHALLOW_DUPLICATE_ATTRIB |
void SHALLOW_DUPLICATE_ATTRIB(SEXP to, SEXP from) |
R.STRING_ELT |
SEXP STRING_ELT(SEXP x, R_xlen_t i) |
R.STRING_PTR_RO |
const SEXP* STRING_PTR_RO(SEXP x) |
R.TAG |
SEXP TAG(SEXP e) |
R.type2char |
const char* Rf_type2char(SEXPTYPE t) |
R.TYPEOF |
int TYPEOF(SEXP x) |
R.UNPROTECT |
void Rf_unprotect(int l) |
R.VECTOR_ELT |
SEXP VECTOR_ELT(SEXP x, R_xlen_t i) |
* Entries marked with an asterisk were not present in R 4.0.0 (the minimum R version that luajr supports), but were added in later versions (as described in the table). However, they will work with any version of R (from 4.0.0 onward) because luajr implements backwards-compatible versions of these functions.
In addition to the functions above, the R.lua module
provides some convenience functions to wrap some helpful operations.
R.length(x)
Returns the length of SEXP x as a Lua number. This is a
wrapper for Rf_xlength() that converts the result from R’s
64-bit length type to a Lua number. You can use this anywhere you would
normally use Rf_length() or Rf_xlength() in
C.
R.type_string(x)
Returns the SEXP type of SEXP x as a Lua string. This is
a wrapper for Rf_type2char(TYPEOF(x)).
R.set_parent(env, parent)
Sets the parent environment of SEXP env, an
ENVSXP, to the ENVSXP parent.
This calls into R’s parent.env<- function because the R
C API does not currently provide a setter for environment parents.
Constants
Common R constants are exposed as follows:
| Lua name | C source |
|---|---|
R.TRUE |
1 |
R.FALSE |
0 |
R.NilValue |
R_NilValue |
R.NA_LOGICAL |
R_NaInt |
R.NA_INTEGER |
R_NaInt |
R.NA_REAL |
R_NaReal |
R.NA_STRING |
R_NaString |
R.UnboundValue |
R_UnboundValue |
R.MissingArg |
R_MissingArg |
R.GlobalEnv |
R_GlobalEnv |
R.EmptyEnv |
R_EmptyEnv |
R.BaseEnv |
R_BaseEnv |
R.BlankString |
R_BlankString |
R.NamesSymbol |
R_NamesSymbol |
R.ClassSymbol |
R_ClassSymbol |
R.DimSymbol |
R_DimSymbol |
R.DimNamesSymbol |
R_DimNamesSymbol |
R.RowNamesSymbol |
R_RowNamesSymbol |
R.NamespaceRegistry |
R_NamespaceRegistry |
In addition to the above, there is also a variable
R.version that holds the current R version as an integer in
the form MMmmpp (MM = major, mm = minor, pp = patch). For
example, R 4.6.0 is 040600 and R 4.0.5 is
040005.
The R type codes (SEXPTYPEs) are also exposed as Lua
numbers. These correspond to the values returned by
R.TYPEOF(x):
| Lua name | Value | Description |
|---|---|---|
R.NILSXP |
0 | NULL |
R.SYMSXP |
1 | symbols |
R.LISTSXP |
2 | pairlists |
R.CLOSXP |
3 | closures |
R.ENVSXP |
4 | environments |
R.PROMSXP |
5 | promises |
R.LANGSXP |
6 | language objects |
R.SPECIALSXP |
7 | special functions |
R.BUILTINSXP |
8 | builtin functions |
R.CHARSXP |
9 | internal character strings |
R.LGLSXP |
10 | logical vectors |
R.INTSXP |
13 | integer vectors |
R.REALSXP |
14 | numeric vectors |
R.CPLXSXP |
15 | complex vectors |
R.STRSXP |
16 | character vectors |
R.DOTSXP |
17 | dot-dot-dot object |
R.ANYSXP |
18 | make “any” args work |
R.VECSXP |
19 | list (generic vector) |
R.EXPRSXP |
20 | expression vector |
R.BCODESXP |
21 | byte code |
R.EXTPTRSXP |
22 | external pointer |
R.WEAKREFSXP |
23 | weak reference |
R.RAWSXP |
24 | raw vector |
R.OBJSXP |
25 | objects not of simple type |
If all of this makes sense to you, then enjoy and happy coding. If not, then stick to using the luajr.lua module and don’t worry about it too much – you probably don’t need this anyway!