www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Started to work on a Lua wrapper. Please provide feedback & guidance

reply "Gabi" <galim120 bezeqint.net> writes:
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");
}
Aug 03 2013
next sibling parent "John Colvin" <john.loughran.colvin gmail.com> writes:
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
Aug 03 2013
prev sibling parent reply "Jesse Phillips" <Jesse.K.Phillips+D gmail.com> writes:
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.
Aug 05 2013
parent "Gabi" <galim120 bezeqint.net> writes:
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
Aug 05 2013