It is possible to create Erlang interface functions to expose an API for your application to Lua.
In this example we will create an Erlang function to calculate the factorial of a number, and then call it from our Lua code.
Using rebar3 we will first create a new application
$ rebar3 new app factorialua
===> Writing factorialua/src/factorialua_app.erl
===> Writing factorialua/src/factorialua_sup.erl
===> Writing factorialua/src/factorialua.app.src
===> Writing factorialua/rebar.config
===> Writing factorialua/.gitignore
===> Writing factorialua/LICENSE
===> Writing factorialua/README.md
In the factorialua
directory, you can modify rebar.config
with your favorite editor and add Luerl as a dependency. Here we use the develop
branch, but you may use other branches at your discretion.
$ cat rebar.config
{erl_opts, [debug_info]}.
{deps, [{luerl, {git, "https://github.com/rvirding/luerl.git", {branch, "develop"}}}]}.
{shell, [
% {config, "config/sys.config"},
{apps, [factorialua]}
]}.
Running rebar3 get-deps
ought to fetch the dependency and configure your Erlang paths appropriately.
Next we will create a module with our factorial function, and export an install
function for Luerl. This module should live in the application's src
directory, e.g. factorialua/src/fac.erl
-module(fac).
-include_lib("luerl/src/luerl.hrl").
-import(luerl_lib, [lua_error/2,badarg_error/3]).
-export([install/1]).
install(St0) ->
luerl_heap:alloc_table(table(), St0).
table() ->
[{<<"fac">>,#erl_func{code=fun fac/2}}].
fac(As, St) ->
case get_number_args(As) of
[N|_] when is_number(N) -> {[fac(N)], St};
_ -> badarg_error(fac, As, St)
end.
get_number_args(As) ->
lists:map(fun luerl_lib:arg_to_number/1, As).
fac(0) -> 1;
fac(N) -> N * fac(N-1).
Now that the fac
module is in place, we will create another module that loads the factorial function into Lua and executes the function from Lua.
-module(run_fac).
-export([run/0]).
run() ->
St0 = luerl:init(),
St1 = load_lib(<<"factorialua">>,fac,St0),
% Calculate the factorial of 10
{[Return], St2} = luerl:do("return factorialua.fac(10)", St1),
Return.
load_lib(Key, Mod, St0) ->
{Tab,St1} = Mod:install(St0),
%% Add key to global and to package.loaded.
St2 = luerl_emul:set_global_key(Key, Tab, St1),
luerl_emul:set_table_keys([<<"package">>,<<"loaded">>,Key], Tab, St2).
Finally start an Erlang shell and see the code in action:
1> run_fac:run().
3628800