summaryrefslogtreecommitdiff
path: root/library/LuaWrapper.cpp
diff options
context:
space:
mode:
authorAlexander Gavrilov2012-03-19 20:12:27 +0400
committerAlexander Gavrilov2012-03-19 20:12:27 +0400
commitdbbd9acfad8d5994f321840e3d695fe8a67ac315 (patch)
tree77d31425a26f6e4afd8a3b0c1a029c5ca78a9add /library/LuaWrapper.cpp
parent296d3a0af306a5247048ed4f38b2bc72eb582d89 (diff)
downloaddfhack-dbbd9acfad8d5994f321840e3d695fe8a67ac315.tar.gz
dfhack-dbbd9acfad8d5994f321840e3d695fe8a67ac315.tar.bz2
dfhack-dbbd9acfad8d5994f321840e3d695fe8a67ac315.tar.xz
Export the type tree with enum keys to lua.
Diffstat (limited to 'library/LuaWrapper.cpp')
-rw-r--r--library/LuaWrapper.cpp218
1 files changed, 218 insertions, 0 deletions
diff --git a/library/LuaWrapper.cpp b/library/LuaWrapper.cpp
new file mode 100644
index 00000000..3ed4a35c
--- /dev/null
+++ b/library/LuaWrapper.cpp
@@ -0,0 +1,218 @@
+/*
+https://github.com/peterix/dfhack
+Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com)
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must
+not claim that you wrote the original software. If you use this
+software in a product, an acknowledgment in the product documentation
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+*/
+
+#include "Internal.h"
+
+#include <string>
+#include <vector>
+#include <map>
+
+#include "MemAccess.h"
+#include "Core.h"
+#include "VersionInfo.h"
+#include "tinythread.h"
+// must be last due to MS stupidity
+#include "DataDefs.h"
+#include "DataIdentity.h"
+
+#include "MiscUtils.h"
+
+#include <lua.h>
+#include <lauxlib.h>
+
+using namespace DFHack;
+
+static luaL_Reg no_functions[] = { { NULL, NULL } };
+
+inline void lua_dup(lua_State *state) { lua_pushvalue(state, -1); }
+inline void lua_swap(lua_State *state) { lua_insert(state, -2); }
+
+static int change_error(lua_State *state)
+{
+ luaL_error(state, "Attempt to change a read-only table.\n");
+}
+
+static void freeze_table(lua_State *state, bool leave_metatable = false, const char *name = NULL)
+{
+ // rv = {}; setmetatable(rv, { __index = in, __newindex = change_error, __metatable = name })
+ int base = lua_gettop(state);
+ lua_newtable(state);
+ lua_swap(state);
+ lua_setfield(state, base, "__index");
+ lua_getfield(state, LUA_REGISTRYINDEX, "DFHack.ChangeError");
+ lua_setfield(state, base, "__newindex");
+ lua_newtable(state);
+ lua_swap(state);
+ lua_dup(state);
+ lua_setmetatable(state, base);
+ if (name)
+ {
+ lua_pushstring(state, name);
+ lua_setfield(state, -2, "__metatable");
+ }
+ // result: [frozen table] [metatable]
+ if (!leave_metatable)
+ lua_pop(state, 1);
+}
+
+static void SaveTypeInfo(lua_State *state, void *node)
+{
+ lua_getfield(state, LUA_REGISTRYINDEX, "DFHack.DFTypes");
+ lua_pushlightuserdata(state, node);
+ lua_pushvalue(state, -3);
+ lua_settable(state, -3);
+ lua_pop(state, 1);
+}
+
+static bool RegisterTypeInfo(lua_State *state, void *node)
+{
+ lua_getfield(state, LUA_REGISTRYINDEX, "DFHack.DFTypes");
+ int base = lua_gettop(state);
+
+ lua_pushlightuserdata(state, node);
+ lua_rawget(state, base);
+
+ bool added = false;
+
+ if (lua_isnil(state, -1))
+ {
+ lua_pop(state, 1);
+
+ lua_newtable(state);
+ lua_pushlightuserdata(state, node);
+ lua_pushvalue(state, -2);
+ lua_rawset(state, base);
+
+ added = true;
+ }
+
+ lua_remove(state, -2);
+ return added;
+}
+
+static void RenderTypeChildren(lua_State *state, const std::vector<compound_identity*> &children);
+
+static void RenderType(lua_State *state, compound_identity *node)
+{
+ assert(node->getName());
+
+ lua_newtable(state);
+ if (!lua_checkstack(state, 20))
+ return;
+
+ int base = lua_gettop(state);
+
+ lua_pushlightuserdata(state, node);
+ lua_setfield(state, base, "_identity");
+
+ switch (node->type())
+ {
+ case IDTYPE_ENUM:
+ {
+ enum_identity *eid = (enum_identity*)node;
+ const char *const *keys = eid->getKeys();
+
+ // For enums, set mapping between keys and values
+ for (int64_t i = eid->getFirstItem(), j = 0; i <= eid->getLastItem(); i++, j++)
+ {
+ if (!keys[j])
+ continue;
+
+ lua_pushinteger(state, i);
+ lua_pushstring(state, keys[j]);
+ lua_dup(state);
+ lua_pushinteger(state, i);
+
+ lua_settable(state, base);
+ lua_settable(state, base);
+ }
+
+ if (eid->getFirstItem() <= eid->getLastItem())
+ {
+ lua_pushstring(state, "_first_item");
+ lua_pushinteger(state, eid->getFirstItem());
+ lua_settable(state, base);
+
+ lua_pushstring(state, "_last_item");
+ lua_pushinteger(state, eid->getLastItem());
+ lua_settable(state, base);
+ }
+
+ SaveTypeInfo(state, node);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ RenderTypeChildren(state, node->getScopeChildren());
+
+ assert(base == lua_gettop(state));
+
+ freeze_table(state, false, node->getName());
+}
+
+static void RenderTypeChildren(lua_State *state, const std::vector<compound_identity*> &children)
+{
+ for (size_t i = 0; i < children.size(); i++)
+ {
+ RenderType(state, children[i]);
+ lua_pushstring(state, children[i]->getName());
+ lua_swap(state);
+ lua_settable(state, -3);
+ }
+}
+
+static void DoAttach(lua_State *state)
+{
+ int base = lua_gettop(state);
+
+ lua_pushcfunction(state, change_error);
+ lua_setfield(state, LUA_REGISTRYINDEX, "DFHack.ChangeError");
+
+ luaL_register(state, "df", no_functions);
+
+ {
+ // Assign df a metatable with read-only contents
+ lua_newtable(state);
+
+ // Render the type structure
+ RenderTypeChildren(state, compound_identity::getTopScope());
+
+ freeze_table(state, true, "df");
+ lua_remove(state, -2);
+ lua_setmetatable(state, -2);
+ }
+
+ lua_pop(state, 1);
+}
+
+void DFHack::AttachDFGlobals(lua_State *state)
+{
+ if (luaL_newmetatable(state, "DFHack.DFTypes"))
+ DoAttach(state);
+
+ lua_pop(state, 1);
+}