Erlang C Node to run Lua scripts
This library provides a way to run Lua code from within Erlang. It differs from the other Lua - Erlang integrations available, in that it runs the Lua VM as an external Node (using Erlang's Port and C Node capabilities).
It's early days in making this available to the public, so be aware that some assembly is required.
The Erlang-Lua C C Node code currently compiles and tests successfully on Mac OS X (10.9, using XCode command line utilities) and Ubuntu (Trusty 14.04.1 LTS). It probably works on further Mac OS X versions and Linux distros, but I've not tried it yet.
A Lua installation (5.1 or 5.2) is required to be on the system.
It's needed for the header files and to link the C Node. You can
get Lua from http://www.lua.org/ . The current 5.1 source package
can be downloaded from http://www.lua.org/ftp/lua-5.1.5.tar.gz ,
and the 5.2 one from http://www.lua.org/ftp/lua-5.2.3.tar.gz . To
build on Mac OS X, you run make macosx test
, and on Ubuntu run
make linux test
. You'll need to install it somewhere, run make INSTALL_TOP=Path_to_Lua_installation install
.
Building the Erlang-Lua C Node uses rebar
(https://github.com/rebar/rebar), and a small Makefile
is provided
to wrap around the calls to rebar
. You need to edit the rebar.config
file and edit the setting of the Lua path to point to your Lua
installation:
{ port_env,[
{"LUA", "/Path_to_Lua_installation"},
...
]}.
After that, make compile
compiles it all up (expect a warning
about missing braces around initializer
) and make test
runs the
Eunit test suite. The latter produces a whole bunch of logging to
standard output and, if all is good, ends with All 87 tests passed.
A make clean
does the obvious.
Starting a Lua VM through
(rtr@127.0.0.1)1> erlang_lua:start_link(foo).
{ok,<0.40.0>}
brings up a gen_server
that provides the interface to running and
monitoring the Lua VM. It starts a C program to run the Lua VM via
open_port
, monitors it and receives logging from it. The C program
itself initialises itself as an Erlang C Node and connects to the
Erlang Node that launched it.
Running Lua code on the external Lua VM is accomplished by sending messages to the C Node and receiving answers back. The Lua results are converted to Erlang terms.
(rtr@127.0.0.1)2> erlang_lua:lua(foo, <<"return {x=1, y='foo'}">>).
{lua,[[{y,<<"foo">>},{x,1}]]}
(rtr@127.0.0.1)3> erlang_lua:lua(foo, <<" x = 42 + 'fourty two' ">>).
{error,"[string \" x = 42 + 'fourty two' \"]:1: attempt to perform
arithmetic on a string value"}
Some support for automatically translating Erlang values to Lua is
available via the call
interface:
(rtr@127.0.0.1)4> erlang_lua:lua(foo, <<"find = string.find">>).
{lua,ok}
(rtr@127.0.0.1)5> erlang_lua:call(foo, find, [<<"foobar">>, <<"(o)b(a)">>]).
{lua,[3,5,<<"o">>,<<"a">>]}
It is also possible to call back into Erlang from Lua:
(rtr@127.0.0.1)6> erlang_lua:lua(foo, <<"return erl_rpc('date')">>).
{lua,[[2014,12,3]]}
(rtr@127.0.0.1)7> erlang_lua:lua(foo, <<"return erl_rpc('erlang', 'date')">>).
{lua,[[2014,12,3]]}
(rtr@127.0.0.1)8> erlang_lua:lua(foo, <<"return erl_rpc('lists', 'seq', 2, 15, 3)">>).
{lua,[[2,5,8,11,14]]}
(rtr@127.0.0.1)9> S = <<"foobar">>.
<<"foobar">>
(rtr@127.0.0.1)10> {lua, [ R ]} = erlang_lua:call(foo, erl_rpc, [base64, encode, S]).
{lua,[<<"Zm9vYmFy">>]}
(rtr@127.0.0.1)11> {lua, [ S ]} = erlang_lua:call(foo, erl_rpc, [base64, decode, R]).
{lua,[<<"foobar">>]}
The Lua VM is stopped using
(rtr@127.0.0.1)12> erlang_lua:stop(foo).
ok
nil -> 'nil' Atom
true -> 'true' Atom
false -> 'false' Atom
erl_atom"string" -> 'string' Atom
integer number -> Integer Number
floating point number -> Float Number
"string" -> Binary
erl_string"string" -> "string" String
erl_tuple{ V1, V2, V3, ..., Vn } -> { V1, V2, V3, ..., Vn }
{ V1, V2, V3, ..., Vn } -> [ V1, V2, V3, ..., Vn ]
{ K1=V1, K2=V2, K3=V3, ..., Kn=Vn } -> [ {K1, V1}, {K2, V2}, {K3, V3}, ..., {Kn, Vn} ]
/ Order of pairs not guaranteed,
/ If type(K) == "string" and #K < 256 then Erlang K is Atom
{ V1, V2, ..., Vn, Kn+1=Vn+1, Kn+2=Vn+2, ..., Kn+k=Vn+k }
-> [ V1, V2, ..., Vn, {Kn+1, Vn+1}, {Kn+1, Vn+2}, ..., {Kn+1, Vn+n} ]
/ Order of {K, V} pairs not guaranteed
/ If type(K) == "string" and #K < 256 then Erlang K is Atom
Unusable types:
function -> 'function' Atom
userdata -> 'userdata' Atom
thread -> 'thread' Atom
lightuserdata -> 'lightuserdata' Atom
'nil' Atom -> nil
'true' Atom -> true
'false' Atom -> false
Atom -> string
Integer Number -> number
Float Number -> number
Binary -> string
/ Note: Regular Erlang Strings are Lists: "abc" -> { 97, 98, 99 }
{ V1, V2, V3, ..., Vn } -> { V1, V2, V3, ..., Vn }
[ V1, V2, V3, ..., Vn ] -> { V1, V2, V3, ..., Vn }
[ {K1, V1}, {K2, V2}, {K3, V3}, ..., {Kn, Vn} ] -> { K1=V1, K2=V2, K3=V3, ..., Kn=Vn }
/ If all Erlang K are Atoms
[ V1, {K2, V2}, V3, {K4, V4}, V5, ..., Vn, {Kn+1, Vn+1}, ... ] -> { V1, V3, V4, ..., Vn, K2=V2, K4=V4, ..., Kn+1=Vn+1 }
/ If Erlang K is Atom
/ Note: All elements that are not a 2-tuple with the first element an Atom, become array elements in Lua
/ Only the ordering of non 2-tuples is preserved!
Unusable types:
Reference, Fun, Port, Pid -> nil