Thread overview
Started to work on a Lua wrapper. Please provide feedback & guidance
Aug 03, 2013
Gabi
Aug 03, 2013
John Colvin
Aug 05, 2013
Jesse Phillips
Aug 05, 2013
Gabi
August 03, 2013
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");
}


August 03, 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
August 05, 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..

You'll probably like the LuaD wrapper

https://github.com/JakobOvrum/LuaD

It uses 5.1, but may be usable with 5.2 or simple to get the basics working. There is currently a bug open:

https://github.com/JakobOvrum/LuaD/issues/19

So if you get it working for yourself, contributing back would be good.
August 05, 2013
On Monday, 5 August 2013 at 19:14:25 UTC, Jesse Phillips wrote:
> 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..
>
> You'll probably like the LuaD wrapper
>
> https://github.com/JakobOvrum/LuaD
>
> It uses 5.1, but may be usable with 5.2 or simple to get the basics working. There is currently a bug open:
>
> https://github.com/JakobOvrum/LuaD/issues/19
>
> So if you get it working for yourself, contributing back would be good.

Right! I like this approach. That what I tried to achieve in my
Lua class above.
 Will be happy to contribute if I can