Started to work on a Lua wrapper. Please provide feedback & guidance
John Colvin
john.loughran.colvin at gmail.com
Sat Aug 3 15:34:57 PDT 2013
On Saturday, 3 August 2013 at 22:17:32 UTC, Gabi wrote:
> I need a Lua 5.2.2 wrapper, So I started working on one..
> I am new to D so probably there is a lot of room for
> improvements..
> Any feedback is welcome..
>
> import std.stdio:writeln, writefln;
> import std.exception:enforce;
> import std.conv;
> import std.string;
>
>
> alias void lua_State;
> alias long lua_Integer;
> alias double lua_Number;
>
> enum LUA_OK = 0;
> enum LUA_MULTRET = -1;
>
> extern (C)
> {
>
> lua_State *luaL_newstate ();
> void lua_close (lua_State *L);
> void luaL_openlibs (lua_State *L);
>
> int lua_gettop (lua_State *L);
> void lua_settop (lua_State *L, int index);
>
> int luaL_loadstring (lua_State *L, const char *s);
> int lua_pcallk (lua_State *L, int nargs, int nresults, int
> errfunc, int ctx, void*);
>
> void lua_setglobal (lua_State *L, const char *name);
> void lua_getglobal (lua_State *L, const char *name);
> void lua_getfield (lua_State *L, int index, const char *k);
>
> lua_Number lua_tonumberx (lua_State *L, int index, int
> *isnum);
> lua_Integer lua_tointegerx (lua_State *L, int index, int
> *isnum);
> const char *lua_tolstring (lua_State *L, int index, size_t
> *len);
>
> const char *lua_pushstring (lua_State *L, const char *s);
> void lua_pushinteger (lua_State *L, lua_Integer n);
> void lua_pushnumber (lua_State *L, lua_Number n);
> }
>
> class LuaException:Exception
> {
> this (string msg)
> {
> super(msg);
> }
> }
>
> class Lua
> {
> private:
> lua_State* _luaState;
> void _pushArg(long arg)
> {
> lua_pushinteger(_luaState, arg);
> }
> void _pushArg(int arg)
> {
> lua_pushinteger(_luaState, to!long(arg));
> }
> void _pushArg(double arg)
> {
> lua_pushnumber(_luaState, arg);
> }
> void _pushArg(float arg)
> {
> lua_pushnumber(_luaState, to!double(arg));
> }
> void _pushArg(string arg)
> {
> lua_pushstring(_luaState, arg.ptr);
> }
> void _pushArg(const char* arg)
> {
> lua_pushstring(_luaState, arg);
> }
>
> void _runFun(ARGS...)(string packageName, string funName,
> ARGS args)
> {
>
> if(packageName.length == 0 || packageName == ".")
> {
> lua_getglobal(_luaState, funName.ptr);
> }
> else
> {
> lua_getglobal(_luaState, packageName.ptr);
> lua_getfield(_luaState, -1, funName.ptr);
> }
>
> //Push arguments
> foreach(arg; args)
> {
> _pushArg(arg);
> }
> int rv = lua_pcallk(_luaState, cast(int)args.length, 1,
> 0, 0, null );
> enforce(rv == LUA_OK, new
> LuaException("runFun:lua_pcallk failed"));
> }
>
> public:
> this()
> {
> _luaState = luaL_newstate();
> enforce(_luaState != null, new
> LuaException("luaL_newstate() failed"));
> luaL_openlibs(_luaState);
> }
>
> ~this()
> {
> close();
> }
>
> void close()
> {
> if(_luaState != null)
> lua_close(_luaState);
> }
>
> @property
> lua_State* luaState()
> {
> return _luaState;
> }
> /*
> * Load function
> * Throw LuaException on error
> */
> void loadFun(string funBody)
> {
> int rv = luaL_loadstring(_luaState, funBody.ptr);
> enforce(rv == LUA_OK, new
> LuaException("loadFun:luaL_loadstring failed"));
> rv = lua_pcallk(_luaState, 0, LUA_MULTRET, 0, 0, null);
> enforce(rv == LUA_OK, new
> LuaException("loadFun:lua_pcallk failed"));
> }
> /*
> * Load function and give it a name.
> * funBody should be anonymous function like
> "function(x,y)..end"
> * Throw LuaException on error
> */
> void loadFun(string funName, string funBody)
> {
> loadFun(funName ~ "=" ~funBody);
> }
> /*
> * Execute the given function and return it rv
> * packageName can be empty or "." for global scope function
> * Throw LuaException on error
> */
> T runFun(T:double, ARGS...)(string packageName, string
> funName, ARGS args)
> {
> int top = lua_gettop(_luaState);
> _runFun(packageName, funName, args);
> scope(exit) lua_settop(_luaState, top);
> return lua_tonumberx(_luaState, -1, null);
> }
>
> T runFun(T:long, ARGS...)(string packageName, string
> funName, ARGS args)
> {
> int top = lua_gettop(_luaState);
> _runFun(packageName, funName, args);
> scope(exit) lua_settop(_luaState, top);
> return lua_tointegerx(_luaState, -1, null);
> }
>
> T runFun(T:string, ARGS...)(string packageName, string
> funName, ARGS args)
> {
> int top = lua_gettop(_luaState);
> scope(exit) lua_settop(_luaState, top);
> _runFun(packageName, funName, args);
>
> const char* rv = lua_tolstring(_luaState, -1, null);
> return to!string(rv);
> }
>
> T runFun(T:const char*, ARGS...)(string packageName, string
> funName, ARGS args)
> {
> int top = lua_gettop(_luaState);
> scope(exit) lua_settop(_luaState, top);
> _runFun(packageName, funName, args);
> return lua_tolstring(_luaState, -1, null);
> }
> }
>
> unittest
> {
> string fn1 =
> """
> function add(x, y)
> return (x+y)
> end
> """;
>
> string fn2 =
> """
> function (x, y)
> return (x..y)
> end
> """;
>
> Lua l = new Lua();
> l.loadFun(fn1);
> assert(l.runFun!double(".", "add", 6, 3) == 9);
>
> assert(l.runFun!long(".", "add", 3, -3) == 0L);
>
> l.loadFun("concat", fn2);
> assert(l.runFun!(string)(".", "concat", "AAA", "BBB") ==
> "AAABBB");
> }
2 projects you might be interested in with regards to D and Lua:
Quite comprehensive, no Lua 5.2 yet though.
https://github.com/JakobOvrum/LuaD
Lua bindings, amongst other good stuff:
https://github.com/aldacron/Derelict3
More information about the Digitalmars-d-learn
mailing list