Archive for the ‘Lua’ Category

Lua constants

By Lua’s nature, it is not possible to create constants. There is a workaround, though, using metatables:

function protect(tbl)
  return setmetatable({}, {
    __index = tbl,
    __newindex = function(t, key, value)
                   error("attempting to change constant " .. tostring(key) .. " to " .. tostring(value), 2)
                 end
  })
end

constants = {
  x = 1,
  y = 2,
}
constants = protect(constants)

print(constants.x) --> 3
constants.x = 3    --> error: attempting to change constant x to 3

Lua error message format

I work on the library, which will use Lua. Thinking about the possibility to give a good error structure instead of plain message, I’ve found that lua_pcall has a nice feature to specify custom error handler function:

lua_pushcfunction(L, error_handler);
luaL_loadfile(L, "file.lua");
lua_pcall(L, 0, 0, -2);

Using this there is a way to get a chunk name and it’s error line number:

int error_handler(lua_State* L) {
  lua_Debug d;

  lua_getstack(L, 1, &d);
  lua_getinfo(L, "Sln", &d);

  string err = lua_tostring(L, -1);
  lua_pop(L, 1);

  stringstream msg;
  msg << d.short_src << ":" << d.currentline;
  if(d.name != 0) {
    msg << "(" << d.namewhat << " " << d.name << ")";
  }
  msg << " > " << err;
  lua_pushstring(L, msg.str().c_str());

  return 1;
}

Work’s like a charm, except one thing. This is the output from this error handler:

[string "test"]:1 > [string "test"]:1: attempt to index global 'a' (a nil value)

Why? Oh, why the Lua guys are putting assembled error message with chunk name and line number if I use my own error handler? IMHO, this is wrong. There is no other way to give a user nice message except parsing. Actually parsing of such message is easy, but.. the Lua guys have changed error message format a few times already. I’m pissed!

C Lua snippets

Get currently executed chunk name:

lua_Debug lua_info;
lua_getstack(L, 0, &lua_info);
lua_getinfo(L, "n", &lua_info);
string name = lua_info.name;

Opposite to lua_register:

lua_pushnil(L);
lua_setglobal(L, name.c_str());

stack_dump in C++ flavour ;)

static void stack_dump (lua_State *L) {
  int top = lua_gettop(L);
  for(int i = 1; i <= top; i++) {
    int t = lua_type(L, i);
    switch(t) {
    case LUA_TSTRING:
      cout << "'" << lua_tostring(L, i) << "'";
      break;
    case LUA_TBOOLEAN:
      cout << (lua_toboolean(L, i) ? "true" : "false");
      break;
    case LUA_TNUMBER:
      cout << lua_tonumber(L, i);
      break;
    default:
      cout << lua_typename(L, t);
      break;
    }
    cout << "  ";
  }
  cout << endl;
}