Git Product home page Git Product logo

erlualib's Introduction

Erlualib enables us to implement arbitrary Erlang behavious in Lua. This library makes embedding Lua code to Erlang codebase very easy. How to do it:

  1. Create an Erlang module which you want to implement in Lua
  2. Add 4 lines:
    1. -module(my_mod).
    2. -behaviour(abitrary_behaviour).
    3. -implemented_in({priv, "/module_impl.lua"}). % where to forward calls
    4. -compile({parse_transform, lua_behaviour}). % this does the hard work
  3. Compile and use my_mod as if it was written in pure Erlang.

Below is an example of simple key-value name server. It has 2 operations:

  • {add_name, Key :: binary(), Value :: binary()} -> ok.
  • {get_addr, Key :: binary()} -> 'error' | Value :: binary().

==== name_server.erl ====

-module(name_server).
-behaviour(gen_server).
-implemented_in({priv, "/name_server.lua"}).
-compile({parse_transform, lua_behaviour}).

==== priv/name_server.lua ====

function init()
    return erlang.atom("ok"), {} -- This empty table will be our state
end
-- Forwards the call to function which is specified in req[1]. Returns
-- {reply, Return, NewTable}. Return and NewTable are values from the
-- forwarded module.
function handle_call(req, from, tbl)
    return erlang.atom("reply"), call(tbl, req)
end
-- Adds name to State. Returns {ok, Table}.
function add_name(tbl, name, address)
    tbl[name] = address
    return erlang.atom("ok"), tbl
end
-- Gets name table and current name. Returns: { 'error' | Value, Table}
function get_addr(tbl, name)
    return tbl[name] or erlang.atom("error"), tbl
end
-- Call req[1](tbl, req[2], req[3], ...)
function call(tbl, req) return _G[req[1]](tbl, unpack(req, 2)) end

That's it! Compile name_server.erl and call it. Alternatively, download the example and make test.

Performance

luam:one_call/3 (the "do all" function) consists of 3 parts:

  1. lua:new_state/0, takes ~220-250µs.
  2. luam:call/4, takes ~12-15µs.
  3. lua:close/1, negligible.

For lua_behaviour, new Lua state is created on every request, which adds significant overhead. In gen_(server|fsm) case (as well as many others), it will be possible to reuse the state, and performance will be much, much better. I just need to create gen_(server|fsm) specific parse_transform for it, which is planned for near future.

Tested on Intel Core 2 Q9400. Performance tests are not scientific, in order to give general overview. Tests were executed serially, with SMP support. More scientific benchmarks are upcoming.

Type conversions Lua -> Erlang

As you already noticed in the Lua example, "erlang" lua library is available! Now it has only one method atom, which takes a string and returns atom. Analogue tuple method is planned (now, when you return an indexed table in Lua, it is treated as a proplist with numeric indices, so there is no way to return nested tuples).

Error handling

When Lua code encounters an error in luam:call/3, lua:multipcall/2 or lua:one_call/3, Erlang exception is thrown: {lua_error, Error}, where Error is a string(), the exception value from Lua.

Some words about erlualib

erlualib is a library for embedding Lua into Erlang. It provides a simple interface that is very similar to the Lua C API, as well as some very useful high-level functions.

This is a fork of Ray Morgan's Erl-Lua library with the following changes:

  • High test coverage (and PropEr tests)
  • New low-level commands
  • Strings in Lua are Binaries in Erlang (instead of lists of numbers)
  • Many bugfixes
  • Dialyzer is happy about this project
  • Rebarized
  • luam:call/4.
  • arbitrary erlang behaviours in Lua

Erlualib is a nice example how and when to PropErly test things. Tests for parse_transforms are coming soon.

Lower level function examlpes

Example how to use luam:call/4:

1> {ok, L} = lua:new_state(),
2> ok = lual:dostring(L, <<"function t(when, tab) return tab[when] end">>),
3> Args = [noon, [{ morning, breakfast }, { noon, lunch }, {evening, dinner} ] ],
4> luam:call(L, "t", Args),
<<"lunch">>.

Gist: you can pass (almost) arbitrary Erlang values to the Lua call, and get (almost) arbitrary values back, deserialized, after the call. This will be especially powerful combined with with Erlang behaviours in Lua. As said, stay tuned.

Low level API example:

{ok, L} = lua:new_state().
lua:getfield(L, global, "print").
lua:pushlstring(L, <<"Hello from Lua!">>).
lua:call(L, 1, 0).
% (Lua) => Hello from Lua!

lua:getfield(L, global, "type").
lua:pushnumber(L, 23).
lua:call(L, 1, 1).
S = lua:tolstring(L, 1).
lua:remove(L, 1). % always rebalance the stack.. it is the right thing to do!
S. % => <<"number">>

For more examples, see the tests.

There is also a simple way to run one off simple Lua code snippets:

(continued from above)
lual:dostring(L, <<"print 'Howdy!'">>).
% (Lua) => Howdy!

Testing

To test the whole project and see eUnit and PropEr in action, run:

make test

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.