Thursday
14
Jun 2007

Lua embedded in D - Simple First Example

(8:54 am) Tags: [Software, Projects, D Programming Language]

I have been looking for a scripting engine to embed in my D code, and since DMDScript was GPL, I needed something different.

Enter Lua.

After trying to find the right binary library, I finally got the Simple Lua API Example working in the D Programming Language.

So far, here is the header conversion that you need to make the example work:

module lua;

extern(C):

version (Windows) {
pragma (lib, “lua.lib”);
//extern (Windows):
} else {
pragma (msg, “You will need to manually link in the Lua library.”);
}

int LUA_MULTRET = -1;
int LUA_GLOBALSINDEX = -10002;

alias void lua_State;

extern (C) void lua_close (lua_State *L);
extern (C) lua_State *luaL_newstate();//lua_open()
extern (C) void luaL_openlibs(lua_State *L);
extern (C) int luaL_loadfile(lua_State *, char *);
extern (C) void lua_createtable(lua_State *, int=0, int=0);
extern (C) void lua_pushnumber(lua_State *, double=0.0);
extern (C) void lua_rawset(lua_State *, int);
extern (C) void lua_setfield(lua_State *, int, char *);
extern (C) int lua_pcall(lua_State *, int, int, int);
extern (C) double lua_tonumber(lua_State *, int);
extern (C) int lua_gettop(lua_State *);
extern (C) void lua_settop(lua_State *, int);

void lua_setglobal(lua_State *L, char* s) {
lua_setfield(L, LUA_GLOBALSINDEX, s);
}

void lua_pop(lua_State *L, int n=0) {
lua_settop(L, -(n)-1);
}

And here is the C example converted to D:

private import tango.util.log.Configurator, tango.util.log.Log;
private import tango.text.convert.Sprint;
private import lua;

void main() {
Configurator();
testSimple;
}

void testSimple() {
auto log = Log.getLogger(”testlua.testsimple”);
auto sprint = new Sprint!(char);

lua_State *L;

//AKA - L = lua_open();
L = luaL_newstate();

luaL_openlibs(L);

int status;

status = luaL_loadfile(L, “script.lua”);
log.info(sprint(”loadfile status: {}”, status));

/*
* Ok, now here we go: We pass data to the lua script on the stack.
* That is, we first have to prepare Lua’s virtual stack the way we
* want the script to receive it, then ask Lua to run it.
*/
log.info(”new table”);
lua_createtable(L);

/*
* To put values into the table, we first push the index, then the
* value, and then call lua_rawset() with the index of the table in the
* stack. Let’s see why it’s -3: In Lua, the value -1 always refers to
* the top of the stack. When you create the table with lua_newtable(),
* the table gets pushed into the top of the stack. When you push the
* index and then the cell value, the stack looks like:
*
* < - [stack bottom] -- table, index, value [top]
*
* So the -1 will refer to the cell value, thus -3 is used to refer to
* the table itself. Note that lua_rawset() pops the two last elements
* of the stack, so that after it has been called, the table is at the
* top of the stack.
*/
log.info("load the table");
for (int i = 1; i <= 5; i++) {
lua_pushnumber(L, i); /* Push the table index */
lua_pushnumber(L, i*2); /* Push the cell value */
lua_rawset(L, -3); /* Stores the pair in the table */
}

/* By which name is the script going to reference our table ? */
lua_setglobal(L, "foo");

/* Ask Lua to run our little script */
int result = lua_pcall(L, 0, LUA_MULTRET, 0);
log.info(sprint("pcall() status: {}", result));

/* Get the returned value at the top of the stack */
double sum = lua_tonumber(L, lua_gettop(L));
log.info(sprint("sum is: {}", sum));

lua_pop(L, 1); /* Take the returned value out of the stack */

log.info("Lua SimpleTest complete.");

/* Remember to destroy the Lua State */
lua_close(L);

}

Put your lua.lib and lua.dll in the appropriate places, and build:

D:\d\sc\lua>dsss clean

D:\d\sc\lua>dsss build testlua.d
testlua.d => testlua
+ D:\d\dsss-0.52-dmd-win\bin\rebuild.exe -Idsss_imports\ -I. -S.\ -ID:\d\dsss-0.52-dmd-win\include\d -SD:\d\dsss-0.52-dmd-win\lib\ -oqdsss_objs testlua.d -oftestlua
d:\d\dm\bin\link.exe dsss_objs\testlua+dsss_objs\tango-util-log-Configurator+dsss_objs\tango-util-log-Log+dsss_objs\tango-util-log-Logger+dsss_objs\tango-util-log-Appender+dsss_objs\tango-util-log-Event+dsss_objs\tango-sys-Common+dsss_objs\tango-util-time-Clock+dsss_objs\tango-util-time-Date+dsss_objs\tango-core-Type+dsss_objs\tango-util-log-model-ILevel+dsss_objs\tango-util-log-model-IHierarchy+dsss_objs\tango-util-log-Layout+dsss_objs\tango-uti
l-log-Hierarchy+dsss_objs\tango-util-log-ConsoleAppender+dsss_objs\tango-io-Console+dsss_objs\tango-io-Buffer+dsss_objs\tango-io-model-IBuffer+dsss_objs\tango-io-model-IConduit+dsss_objs\tango-io-DeviceConduit+dsss_objs\tango-io-Conduit+dsss_objs\tango-text-convert-Sprint+dsss_objs\tango-text-convert-Layout+dsss_objs\tango-text-convert-Utf+dsss_objs\tango-text-convert-Float+dsss_objs\tango-text-convert-Integer+dsss_objs\lua,testlua,,user32+kernel
32/noi+.\\+D:\d\dsss-0.52-dmd-win\lib\\;

And now run the example:

D:\d\sc\lua>testlua
1 INFO testlua.testsimple - loadfile status: 0
1 INFO testlua.testsimple - new table
1 INFO testlua.testsimple - load the table
The table the script received has:
1 2
2 4
3 6
4 8
5 10
Returning data back to C
3 INFO testlua.testsimple - pcall() status: 0
3 INFO testlua.testsimple - sum is: 30.00
4 INFO testlua.testsimple - Lua SimpleTest complete.

Popularity: 23%

Comments: (0)