All Projects → asciibeats → luaport

asciibeats / luaport

Licence: MIT License
An Erlang/Elixir port for scripting application logic in Lua. Works with Lua and LuaJIT.

Programming Languages

c
50402 projects - #5 most used programming language
erlang
1774 projects
Makefile
30231 projects
lua
6591 projects

Projects that are alternatives of or similar to luaport

Sol2
Sol3 (sol2 v3.0) - a C++ <-> Lua API wrapper with advanced features and top notch performance - is here, and it's great! Documentation:
Stars: ✭ 2,791 (+15405.56%)
Mutual labels:  luajit, lua-scripting
krypta
Generating random bits, passwords, recovery phrases and Bitcoin private keys / addresses (including QR codes) from text seed and salt.
Stars: ✭ 18 (+0%)
Mutual labels:  luajit
BadCoderz
Find unoptimized gmod addons and KILL the devs who made them
Stars: ✭ 66 (+266.67%)
Mutual labels:  luajit
luajit.me
LuaJIT compiler explorer
Stars: ✭ 127 (+605.56%)
Mutual labels:  luajit
LuaJIT-Benchmarks
LuaJIT Benchmark tests
Stars: ✭ 20 (+11.11%)
Mutual labels:  luajit
luajit-tcc
Tiny C Compiler 0.9.26 binding for LuaJIT
Stars: ✭ 58 (+222.22%)
Mutual labels:  luajit
godot-lua-pluginscript
Godot PluginScript for the Lua language, currently based on LuaJIT's FFI
Stars: ✭ 182 (+911.11%)
Mutual labels:  luajit
cdn-up-and-running
CDN Up and Running - an introduction about how modern CDNs works
Stars: ✭ 131 (+627.78%)
Mutual labels:  luajit
vita
Vita: simple and fast VPN gateway
Stars: ✭ 685 (+3705.56%)
Mutual labels:  luajit
luajit-glfw
GLFW bindings for LuaJIT
Stars: ✭ 51 (+183.33%)
Mutual labels:  luajit
ljdns
A contemporary DNS library using LuaJIT FFI.
Stars: ✭ 26 (+44.44%)
Mutual labels:  luajit
julia port
example project to invoke julia functions in elixir to do scientific computing using port and metaprogramming
Stars: ✭ 38 (+111.11%)
Mutual labels:  erlang-port
lua-resty-ipcidr
A simple and very fast function to check against CIDR
Stars: ✭ 17 (-5.56%)
Mutual labels:  luajit
iqm-exm
IQM & EXM model format specs, Blender exporter, and LÖVE loader.
Stars: ✭ 35 (+94.44%)
Mutual labels:  luajit
phi
an api-gateway based on openresty
Stars: ✭ 23 (+27.78%)
Mutual labels:  luajit
nvim-highlite
A colorscheme template that is "lite" on logic for the developer.
Stars: ✭ 163 (+805.56%)
Mutual labels:  luajit
apisix-website
Apache APISIX Website
Stars: ✭ 81 (+350%)
Mutual labels:  luajit
LuaParser
Customized Lua parser for [lua-language-server](https://github.com/sumneko/lua-language-server).
Stars: ✭ 43 (+138.89%)
Mutual labels:  luajit
lua-resty-aries
openresty and lua multi-function template
Stars: ✭ 47 (+161.11%)
Mutual labels:  luajit
nott
The New OTT Platform - an excuse to discuss and design a simple edge computing platform
Stars: ✭ 46 (+155.56%)
Mutual labels:  luajit

LuaPort

An Erlang/Elixir port for scripting application logic in Lua. Works with Lua and LuaJIT.

Use Erlang...

{ok, Pid, []} = luaport:spawn(some_id, "path/to/scripts"),
{ok, [6]} = luaport:call(Pid, multiply, [2, 3]).

...or Elixir...

{:ok, pid, []} = :luaport.spawn(:some_id, "path/to/scripts")
{:ok, [6]} = :luaport.call(pid, :multiply, [2, 3])

...to execute a Lua script.

function multiply(a, b)
  return a * b
end

Test

git clone https://github.com/asciibeats/luaport.git
cd luaport
rebar3 ct

Use

If you use Erlang and rebar3, add LuaPort as dependency to your rebar.config.

{deps, [
  {luaport, "~> 1.6"}
]}.

Or for Elixir and mix, add it to your mix.exs.

defp deps do
  [
    {:luaport, "~> 1.6"}
  ]
end

Create a Lua script at path/to/scripts called main.lua.

function subtract(a, b)
  return a - b
end

When using Erlang, don't forget to start the application.

application:start(luaport),
{ok, Pid, []} = luaport:spawn(myid, "path/to/scripts"),
{ok, [42]} = luaport:call(Pid, subtract, [43, 1]),
luaport:despawn(myid),
application:stop(luaport).

With Elixir it will start automatically.

{:ok, pid, []} = :luaport.spawn(:myid, "path/to/scripts")
{:ok, [42]} = :luaport.call(pid, :subtract, [43, 1])
:luaport.despawn(:myid)

To return results on spawn and respawn, just add a return statement to your main.lua...

function do()
  print('something')
end

return 23, 42

...and retrieve them like this:

{ok, Pid1, [23, 42]} = luaport:spawn(myid, "path/to/scripts"),
{ok, Pid2, [23, 42]} = luaport:respawn(myid).

To add static data to the port's context, add a map as third argument to the spawn function.

{ok, Pid, []} = luaport:spawn(myid, "path/to/scripts", #{config => {what, ever}, greeting => <<"moin">>}).

The elements of that map will be available as global variables. Be careful not to choose colliding names, as these variables will be named after the maps keys.

local a, b = unpack(config)

function greet()
  print(greeting)
end

To push global variables into the context during runtime, use the push function.

luaport:push(myid, #{name => <<"til">>}).

To pull dynamic data into the context, you may provide a callback module as the fourth argument to spawn.

{ok, Pid, []} = luaport:spawn(myid, "path/to/scripts", #{}, callback).
-module(callback).

-export([init/2, print/1]).

init(String, Number) ->
  [#{string => String}, Number].

print(Message) ->
  io:format("Message: ~p~n", [Message]).

Calls and casts will automagically be mapped to the module's function of the same name.

local map, number = port.call.init('sunshine', 49)
port.cast.print('some message')

If you want to insert or just execute some code during runtime, use the load function.

{ok, []} = luaport:load(Pid, <<"function something() return 666 end">>),
{ok, [666]} = luaport:call(Pid, something).
{ok, []} = luaport:load(Pid, <<"print('nice')">>).
{ok, [42]} = luaport:load(Pid, <<"return 42">>).

To be able to continuously call or cast functions after accidental or intended respawns, you could use {global, Name} or {local, Name} as reference to register the port.

{ok, Pid1, []} = luaport:spawn({local, myid}, "path/to/scripts"),
{ok, Pid2, []} = luaport:respawn({local, myid}),
luaport:cast({local, myid}, execute).

Requiring modules works normally. You may put a module.lua or module.so into path/to/scripts or any other path in Lua's package.path or package.cpath, respectively.

local module = require('module')

Lua has no delayed call mechanism, therefore LuaPort provides an interface to Erlang's timer functions. The first argument is the time to wait in milliseconds.

local tref = port.after(3000, function (str) print(str) end, 'call once, if not canceled')
port.cancel(tref)
local tref = port.interval(1000, function (str) print(str) end, 'call repeatedly until canceled')
port.cancel(tref)

Finally, to just suspend execution for a while, use the sleep function.

port.sleep(2000)

Quirks

Since Erlang and Lua datatypes do not align too nicely, there are some things to consider.

  • Lua has only one collection type, the table. It is like a map in Erlang. So when maps get translated to Lua they become tables.
  • When lists or tuples get translated they become tables with a metatype 'list' or 'tuple', respectively.
  • Strings in Erlang are lists and translated as such. Lua has no dedicated binary type. If you want to translate to strings, use binary strings.
  • Erlang has no boolean type and atoms serve no purpose in Lua context. So atom 'true' translates to true and atom 'false' to false.
  • Atom 'nil' translates to nil.
  • For convenience, all other atoms become strings. They will be handled like any other string on their way back.
  • If compiled to use LuaJIT, LuaPort has no integer type. By default, numbers that are almost integers get converted. You may modify this behaviour by defining LUAP_NOINT on compilation, disabling integer handling.
  • LuaPort uses a custom print function mimicking Lua's own. It differs slightly: It shows its output in Erlang's shell and prints tables in depth.

Translations

Erlang Elixir Lua Notes
23 23 23
"abc" 'abc' {97, 98, 99} Erlang strings are lists
<<"abc">> "abc" 'abc'
[1, 2] [1, 2] {1, 2} has metatype 'list'
{3, 4} {3, 4} {3, 4} has metatype 'tuple'
#{5 => 6} %{5 => 6} {[5] = 6} has no metatype
true true true
false false false
nil nil nil
atom :atom 'atom'

Helpers

Function Description
port.aslist(t) set metatype 'list'
port.astuple(t) set metatype 'tuple'
port.asmap(t) unset metatype
port.islist(v) if metatype 'list'
port.istuple(v) if metatype 'tuple'
port.ismap(v) if no metatype

Notes

  • Apologies for the occasional poor commit discipline/hygiene.
  • Thank you!
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].