summaryrefslogtreecommitdiff
path: root/library/LuaWrapper.cpp
diff options
context:
space:
mode:
authorAlexander Gavrilov2012-03-24 13:25:10 +0400
committerAlexander Gavrilov2012-03-24 13:25:10 +0400
commitd865d54a90dcff0d30b8c7c3a95f8d8c2f24de62 (patch)
treef9e61cc8fcd1153b63c4eca110920477e26360d8 /library/LuaWrapper.cpp
parent053bfe345c566864b2337a8429072a24a2558493 (diff)
downloaddfhack-d865d54a90dcff0d30b8c7c3a95f8d8c2f24de62.tar.gz
dfhack-d865d54a90dcff0d30b8c7c3a95f8d8c2f24de62.tar.bz2
dfhack-d865d54a90dcff0d30b8c7c3a95f8d8c2f24de62.tar.xz
Split LuaWrapper.cpp into two files.
Diffstat (limited to 'library/LuaWrapper.cpp')
-rw-r--r--library/LuaWrapper.cpp965
1 files changed, 39 insertions, 926 deletions
diff --git a/library/LuaWrapper.cpp b/library/LuaWrapper.cpp
index 9ba0b7eb..1e4574fd 100644
--- a/library/LuaWrapper.cpp
+++ b/library/LuaWrapper.cpp
@@ -35,6 +35,7 @@ distribution.
// must be last due to MS stupidity
#include "DataDefs.h"
#include "DataIdentity.h"
+#include "LuaWrapper.h"
#include "MiscUtils.h"
@@ -42,97 +43,14 @@ distribution.
#include <lauxlib.h>
using namespace DFHack;
+using namespace DFHack::LuaWrapper;
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); }
-
-/*
- * Registry name: hash of type metatables <-> type identities.
- */
-#define DFHACK_TYPETABLE_NAME "DFHack::DFTypes"
-
-/*
- * Registry name: hash of type identity -> node in df.etc...
- */
-#define DFHACK_TYPEID_TABLE_NAME "DFHack::DFTypeIds"
-
-/*
- * Registry name: hash of enum/bitfield identity -> index lookup table
- */
-#define DFHACK_ENUM_TABLE_NAME "DFHack::DFEnums"
-
-/*
- * Registry name: hash of pointer target identity <-> adhoc pointer identity userdata.
- */
-#define DFHACK_PTR_IDTABLE_NAME "DFHack::PtrDFTypes"
-
-// Function registry names
-#define DFHACK_CHANGEERROR_NAME "DFHack::ChangeError"
-#define DFHACK_COMPARE_NAME "DFHack::ComparePtrs"
-#define DFHACK_TYPE_TOSTRING_NAME "DFHack::TypeToString"
-#define DFHACK_SIZEOF_NAME "DFHack::Sizeof"
-#define DFHACK_DISPLACE_NAME "DFHack::Displace"
-#define DFHACK_NEW_NAME "DFHack::New"
-#define DFHACK_ASSIGN_NAME "DFHack::Assign"
-
-/*
- * Upvalue: contents of DFHACK_TYPETABLE_NAME
- */
-#define UPVAL_TYPETABLE lua_upvalueindex(1)
-
-/*
- * Expected metatable of the current object.
- */
-#define UPVAL_METATABLE lua_upvalueindex(2)
-
-/*
- * Table mapping field names to indices or data structure pointers.
- * Enum index table is linked into here via getmetatable($).__index.
- * Fields that are actually in UPVAL_METATABLE are marked with NULL light udata.
- */
-#define UPVAL_FIELDTABLE lua_upvalueindex(3)
-
-/*
- * Only for containers: light udata with container identity.
- */
-#define UPVAL_CONTAINER_ID lua_upvalueindex(4)
-
-/*
- * Only for containers: light udata with item identity.
- */
-#define UPVAL_ITEM_ID lua_upvalueindex(5)
-
-/*
- * Only for containers: if not nil, overrides the item count.
- */
-#define UPVAL_ITEM_COUNT lua_upvalueindex(6)
-
-namespace {
- /**
- * Object references are represented as userdata instances
- * with an appropriate metatable; the payload of userdata is
- * this structure:
- */
- struct DFRefHeader {
- void *ptr;
- };
-
- /*
- * The system might be extended to carry some simple
- * objects inline inside the reference buffer.
- */
- inline bool is_self_contained(DFRefHeader *ptr) {
- void **pp = &ptr->ptr;
- return **(void****)pp == (pp + 1);
- }
-}
-
/**
* Report an error while accessing a field (index = field name).
*/
-static void field_error(lua_State *state, int index, const char *err, const char *mode)
+void LuaWrapper::field_error(lua_State *state, int index, const char *err, const char *mode)
{
lua_getfield(state, UPVAL_METATABLE, "__metatable");
const char *cname = lua_tostring(state, -1);
@@ -141,12 +59,6 @@ static void field_error(lua_State *state, int index, const char *err, const char
mode, (cname ? cname : "?"), (fname ? fname : "?"), err);
}
-/*
- * If is_method is true, these use UPVAL_TYPETABLE to save a hash lookup.
- */
-static void push_object_internal(lua_State *state, type_identity *type, void *ptr, bool in_method = true);
-static void *get_object_internal(lua_State *state, type_identity *type, int val_index, bool exact_type, bool in_method = true);
-
void DFHack::PushDFObject(lua_State *state, type_identity *type, void *ptr)
{
push_object_internal(state, type, ptr, false);
@@ -157,180 +69,6 @@ void *DFHack::GetDFObject(lua_State *state, type_identity *type, int val_index,
return get_object_internal(state, type, val_index, exact_type, false);
}
-static void push_adhoc_pointer(lua_State *state, void *ptr, type_identity *target);
-
-/**************************************
- * Identity object read/write methods *
- **************************************/
-
-void constructed_identity::lua_read(lua_State *state, int fname_idx, void *ptr)
-{
- push_object_internal(state, this, ptr);
-}
-
-void constructed_identity::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index)
-{
- field_error(state, fname_idx, "complex object", "write");
-}
-
-void enum_identity::lua_read(lua_State *state, int fname_idx, void *ptr)
-{
- base_type->lua_read(state, fname_idx, ptr);
-}
-
-void enum_identity::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index)
-{
- base_type->lua_write(state, fname_idx, ptr, val_index);
-}
-
-void df::number_identity_base::lua_read(lua_State *state, int fname_idx, void *ptr)
-{
- lua_pushnumber(state, read(ptr));
-}
-
-void df::number_identity_base::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index)
-{
- if (!lua_isnumber(state, val_index))
- field_error(state, fname_idx, "number expected", "write");
-
- write(ptr, lua_tonumber(state, val_index));
-}
-
-void df::bool_identity::lua_read(lua_State *state, int fname_idx, void *ptr)
-{
- lua_pushboolean(state, *(bool*)ptr);
-}
-
-void df::bool_identity::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index)
-{
- char *pb = (char*)ptr;
-
- if (lua_isboolean(state, val_index) || lua_isnil(state, val_index))
- *pb = lua_toboolean(state, val_index);
- else if (lua_isnumber(state, val_index))
- *pb = lua_tointeger(state, val_index);
- else
- field_error(state, fname_idx, "boolean or number expected", "write");
-}
-
-void df::stl_string_identity::lua_read(lua_State *state, int fname_idx, void *ptr)
-{
- auto pstr = (std::string*)ptr;
- lua_pushlstring(state, pstr->data(), pstr->size());
-}
-
-void df::stl_string_identity::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index)
-{
- size_t size;
- const char *bytes = lua_tolstring(state, val_index, &size);
- if (!bytes)
- field_error(state, fname_idx, "string expected", "write");
-
- *(std::string*)ptr = std::string(bytes, size);
-}
-
-void df::pointer_identity::lua_read(lua_State *state, int fname_idx, void *ptr, type_identity *target)
-{
- push_object_internal(state, target, *(void**)ptr);
-}
-
-void df::pointer_identity::lua_read(lua_State *state, int fname_idx, void *ptr)
-{
- lua_read(state, fname_idx, ptr, target);
-}
-
-void df::pointer_identity::lua_write(lua_State *state, int fname_idx, void *ptr,
- type_identity *target, int val_index)
-{
- auto pptr = (void**)ptr;
-
- if (lua_isnil(state, val_index))
- *pptr = NULL;
- else
- {
- void *nval = get_object_internal(state, target, val_index, false);
- if (nval)
- *pptr = nval;
- else
- field_error(state, fname_idx, "incompatible pointer type", "write");
- }
-}
-
-void df::pointer_identity::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index)
-{
- lua_write(state, fname_idx, ptr, target, val_index);
-}
-
-int container_identity::lua_item_count(lua_State *state, void *ptr)
-{
- if (lua_isnumber(state, UPVAL_ITEM_COUNT))
- return lua_tointeger(state, UPVAL_ITEM_COUNT);
- else
- return item_count(ptr);
-}
-
-void container_identity::lua_item_reference(lua_State *state, int fname_idx, void *ptr, int idx)
-{
- auto id = (type_identity*)lua_touserdata(state, UPVAL_ITEM_ID);
- void *pitem = item_pointer(id, ptr, idx);
- push_object_internal(state, id, pitem);
-}
-
-void container_identity::lua_item_read(lua_State *state, int fname_idx, void *ptr, int idx)
-{
- auto id = (type_identity*)lua_touserdata(state, UPVAL_ITEM_ID);
- void *pitem = item_pointer(id, ptr, idx);
- id->lua_read(state, fname_idx, pitem);
-}
-
-void container_identity::lua_item_write(lua_State *state, int fname_idx, void *ptr, int idx, int val_index)
-{
- auto id = (type_identity*)lua_touserdata(state, UPVAL_ITEM_ID);
- void *pitem = item_pointer(id, ptr, idx);
- id->lua_write(state, fname_idx, pitem, val_index);
-}
-
-void ptr_container_identity::lua_item_reference(lua_State *state, int fname_idx, void *ptr, int idx)
-{
- auto id = (type_identity*)lua_touserdata(state, UPVAL_ITEM_ID);
- void *pitem = item_pointer(id, ptr, idx);
- push_adhoc_pointer(state, pitem, id);
-}
-
-void ptr_container_identity::lua_item_read(lua_State *state, int fname_idx, void *ptr, int idx)
-{
- auto id = (type_identity*)lua_touserdata(state, UPVAL_ITEM_ID);
- void *pitem = item_pointer(&df::identity_traits<void*>::identity, ptr, idx);
- df::pointer_identity::lua_read(state, fname_idx, pitem, id);
-}
-
-void ptr_container_identity::lua_item_write(lua_State *state, int fname_idx, void *ptr, int idx, int val_index)
-{
- auto id = (type_identity*)lua_touserdata(state, UPVAL_ITEM_ID);
- void *pitem = item_pointer(&df::identity_traits<void*>::identity, ptr, idx);
- df::pointer_identity::lua_write(state, fname_idx, pitem, id, val_index);
-}
-
-void bit_container_identity::lua_item_reference(lua_State *state, int, void *, int)
-{
- lua_pushnil(state);
-}
-
-void bit_container_identity::lua_item_read(lua_State *state, int fname_idx, void *ptr, int idx)
-{
- lua_pushboolean(state, get_item(ptr, idx));
-}
-
-void bit_container_identity::lua_item_write(lua_State *state, int fname_idx, void *ptr, int idx, int val_index)
-{
- if (lua_isboolean(state, val_index) || lua_isnil(state, val_index))
- set_item(ptr, idx, lua_toboolean(state, val_index));
- else if (lua_isnumber(state, val_index))
- set_item(ptr, idx, lua_tointeger(state, val_index) != 0);
- else
- field_error(state, fname_idx, "boolean or number expected", "write");
-}
-
/* */
static int change_error(lua_State *state)
@@ -377,7 +115,7 @@ static void LookupInTable(lua_State *state, const char *tname)
* Look up the key on the stack in DFHACK_TYPETABLE;
* if found, put result on the stack and return true.
*/
-static bool LookupTypeInfo(lua_State *state, bool in_method)
+bool LuaWrapper::LookupTypeInfo(lua_State *state, bool in_method)
{
// stack: [lookup key]
@@ -401,7 +139,7 @@ static bool LookupTypeInfo(lua_State *state, bool in_method)
return true;
}
-static void LookupInTable(lua_State *state, void *id, const char *tname)
+void LuaWrapper::LookupInTable(lua_State *state, void *id, const char *tname)
{
lua_getfield(state, LUA_REGISTRYINDEX, tname);
lua_pushlightuserdata(state, id);
@@ -409,7 +147,7 @@ static void LookupInTable(lua_State *state, void *id, const char *tname)
lua_remove(state, -2);
}
-static void SaveInTable(lua_State *state, void *node, const char *tname)
+void LuaWrapper::SaveInTable(lua_State *state, void *node, const char *tname)
{
// stack: [info]
lua_getfield(state, LUA_REGISTRYINDEX, tname);
@@ -426,7 +164,7 @@ static void SaveInTable(lua_State *state, void *node, const char *tname)
// stack: [info]
}
-static void SaveTypeInfo(lua_State *state, void *node)
+void LuaWrapper::SaveTypeInfo(lua_State *state, void *node)
{
SaveInTable(state, node, DFHACK_TYPETABLE_NAME);
}
@@ -436,7 +174,7 @@ static void BuildTypeMetatable(lua_State *state, type_identity *type);
/**
* Push the pointer as DF object ref using metatable on the stack.
*/
-static void push_object_ref(lua_State *state, void *ptr)
+void LuaWrapper::push_object_ref(lua_State *state, void *ptr)
{
// stack: [metatable]
auto ref = (DFRefHeader*)lua_newuserdata(state, sizeof(DFRefHeader));
@@ -447,7 +185,7 @@ static void push_object_ref(lua_State *state, void *ptr)
// stack: [userdata]
}
-static void *get_object_ref(lua_State *state, int val_index)
+void *LuaWrapper::get_object_ref(lua_State *state, int val_index)
{
assert(!lua_islightuserdata(state, val_index));
@@ -458,7 +196,7 @@ static void *get_object_ref(lua_State *state, int val_index)
/**
* Push the pointer using given identity.
*/
-static void push_object_internal(lua_State *state, type_identity *type, void *ptr, bool in_method)
+void LuaWrapper::push_object_internal(lua_State *state, type_identity *type, void *ptr, bool in_method)
{
/*
* If NULL pointer or no type, push something simple
@@ -605,7 +343,7 @@ static bool is_type_compatible(lua_State *state, int meta1, int meta2, bool exac
/**
* Verify that the value matches the identity, and return ptr if so.
*/
-static void *get_object_internal(lua_State *state, type_identity *type, int val_index, bool exact_type, bool in_method)
+void *LuaWrapper::get_object_internal(lua_State *state, type_identity *type, int val_index, bool exact_type, bool in_method)
{
/*
* Non-userdata results in NULL; nil for NULL gets handled here too.
@@ -890,31 +628,10 @@ static int meta_assign(lua_State *state)
}
/**
- * Resolve the field name in UPVAL_FIELDTABLE, die if not found.
- */
-static void lookup_field(lua_State *state, int index, const char *mode)
-{
- lua_pushvalue(state, index);
- lua_gettable(state, UPVAL_FIELDTABLE); // uses metatable with enum keys
-
- if (lua_isnil(state, -1))
- field_error(state, index, "not found", mode);
-}
-
-static void *find_field(lua_State *state, int index, const char *mode)
-{
- lookup_field(state, index, mode);
-
- void *p = lua_touserdata(state, -1);
- lua_pop(state, 1);
- return p;
-}
-
-/**
* Verify that the object is a DF ref with UPVAL_METATABLE.
* If everything ok, extract the address.
*/
-static uint8_t *get_object_addr(lua_State *state, int obj, int field, const char *mode)
+uint8_t *LuaWrapper::get_object_addr(lua_State *state, int obj, int field, const char *mode)
{
if (!lua_isuserdata(state, obj) ||
!lua_getmetatable(state, obj))
@@ -928,113 +645,6 @@ static uint8_t *get_object_addr(lua_State *state, int obj, int field, const char
return (uint8_t*)get_object_ref(state, obj);
}
-static void GetAdHocMetatable(lua_State *state, const struct_field_info *field);
-
-static void read_field(lua_State *state, const struct_field_info *field, void *ptr)
-{
- switch (field->mode)
- {
- case struct_field_info::STATIC_STRING:
- {
- int len = strnlen((char*)ptr, field->count);
- lua_pushlstring(state, (char*)ptr, len);
- return;
- }
-
- case struct_field_info::PRIMITIVE:
- case struct_field_info::SUBSTRUCT:
- field->type->lua_read(state, 2, ptr);
- return;
-
- case struct_field_info::POINTER:
- df::pointer_identity::lua_read(state, 2, ptr, field->type);
- return;
-
- case struct_field_info::CONTAINER:
- if (!field->eid || !field->type->isContainer() ||
- field->eid == ((container_identity*)field->type)->getIndexEnumType())
- {
- field->type->lua_read(state, 2, ptr);
- return;
- }
- // fallthrough
-
- case struct_field_info::STATIC_ARRAY:
- case struct_field_info::STL_VECTOR_PTR:
- GetAdHocMetatable(state, field);
- push_object_ref(state, ptr);
- return;
-
- case struct_field_info::END:
- break;
- }
-
- lua_pushnil(state);
-}
-
-static void field_reference(lua_State *state, const struct_field_info *field, void *ptr)
-{
- switch (field->mode)
- {
- case struct_field_info::PRIMITIVE:
- case struct_field_info::SUBSTRUCT:
- push_object_internal(state, field->type, ptr);
- return;
-
- case struct_field_info::POINTER:
- push_adhoc_pointer(state, ptr, field->type);
- return;
-
- case struct_field_info::CONTAINER:
- read_field(state, field, ptr);
- return;
-
- case struct_field_info::STATIC_STRING:
- case struct_field_info::STATIC_ARRAY:
- case struct_field_info::STL_VECTOR_PTR:
- GetAdHocMetatable(state, field);
- push_object_ref(state, ptr);
- return;
-
- case struct_field_info::END:
- break;
- }
-
- lua_pushnil(state);
-}
-
-static void write_field(lua_State *state, const struct_field_info *field, void *ptr, int value_idx)
-{
- switch (field->mode)
- {
- case struct_field_info::STATIC_STRING:
- {
- size_t size;
- const char *str = lua_tolstring(state, value_idx, &size);
- if (!str)
- field_error(state, 2, "string expected", "write");
- memcpy(ptr, str, std::min(size+1, size_t(field->count)));
- return;
- }
-
- case struct_field_info::PRIMITIVE:
- case struct_field_info::SUBSTRUCT:
- case struct_field_info::CONTAINER:
- field->type->lua_write(state, 2, ptr, value_idx);
- return;
-
- case struct_field_info::POINTER:
- df::pointer_identity::lua_write(state, 2, ptr, field->type, value_idx);
-
- case struct_field_info::STATIC_ARRAY:
- case struct_field_info::STL_VECTOR_PTR:
- field_error(state, 2, "complex object", "write");
-
- case struct_field_info::END:
- return;
- }
-}
-
/**
* Metamethod: represent a type node as string.
*/
@@ -1064,319 +674,39 @@ static int meta_ptr_tostring(lua_State *state)
return 1;
}
-// Resolve the field in the metatable and return
-static int get_metafield(lua_State *state)
-{
- lua_rawget(state, UPVAL_METATABLE);
- return 1;
-}
-
-/**
- * Metamethod: __index for structures.
- */
-static int meta_struct_index(lua_State *state)
-{
- uint8_t *ptr = get_object_addr(state, 1, 2, "read");
- auto field = (struct_field_info*)find_field(state, 2, "read");
- if (!field)
- return get_metafield(state);
- read_field(state, field, ptr + field->offset);
- return 1;
-}
-
-/**
- * Method: _field for structures.
- */
-static int meta_struct_field_reference(lua_State *state)
-{
- if (lua_gettop(state) != 2)
- luaL_error(state, "Usage: object._field(name)");
- uint8_t *ptr = get_object_addr(state, 1, 2, "reference");
- auto field = (struct_field_info*)find_field(state, 2, "reference");
- if (!field)
- field_error(state, 2, "builtin property", "reference");
- field_reference(state, field, ptr + field->offset);
- return 1;
-}
-
-/**
- * Metamethod: __newindex for structures.
- */
-static int meta_struct_newindex(lua_State *state)
-{
- uint8_t *ptr = get_object_addr(state, 1, 2, "write");
- auto field = (struct_field_info*)find_field(state, 2, "write");
- if (!field)
- field_error(state, 2, "builtin property", "write");
- write_field(state, field, ptr + field->offset, 3);
- return 0;
-}
-
-/**
- * Metamethod: __index for primitives, i.e. simple object references.
- * Fields point to identity, or NULL for metafields.
- */
-static int meta_primitive_index(lua_State *state)
-{
- uint8_t *ptr = get_object_addr(state, 1, 2, "read");
- auto type = (type_identity*)find_field(state, 2, "read");
- if (!type)
- return get_metafield(state);
- type->lua_read(state, 2, ptr);
- return 1;
-}
-
-/**
- * Metamethod: __newindex for primitives.
- */
-static int meta_primitive_newindex(lua_State *state)
-{
- uint8_t *ptr = get_object_addr(state, 1, 2, "write");
- auto type = (type_identity*)find_field(state, 2, "write");
- if (!type)
- field_error(state, 2, "builtin property", "write");
- type->lua_write(state, 2, ptr, 3);
- return 0;
-}
-
/**
- * Metamethod: __len for containers.
+ * Make a metatable with most common fields, and an empty table for UPVAL_FIELDTABLE.
*/
-static int meta_container_len(lua_State *state)
+void LuaWrapper::MakeMetatable(lua_State *state, type_identity *type, const char *kind)
{
- uint8_t *ptr = get_object_addr(state, 1, 0, "get length");
- auto id = (container_identity*)lua_touserdata(state, UPVAL_CONTAINER_ID);
- int len = id->lua_item_count(state, ptr);
- lua_pushinteger(state, len);
- return 1;
-}
+ int base = lua_gettop(state);
+ lua_newtable(state); // metatable
-/**
- * Field lookup for containers:
- *
- * - Numbers are indices and handled directly.
- * - NULL userdata are metafields; push and exit;
- */
-static int lookup_container_field(lua_State *state, int field, const char *mode = NULL)
-{
- if (lua_type(state, field) == LUA_TNUMBER)
- return field;
+ lua_pushstring(state, type->getFullName().c_str());
+ lua_setfield(state, base+1, "__metatable");
- lookup_field(state, field, mode ? mode : "read");
+ lua_pushlightuserdata(state, type);
+ lua_setfield(state, base+1, "_identity");
- if (lua_isuserdata(state, -1) && !lua_touserdata(state, -1))
+ LookupInTable(state, type, DFHACK_TYPEID_TABLE_NAME);
+ if (lua_isnil(state, -1))
{
- if (mode)
- field_error(state, field, "builtin property", mode);
-
+ // Copy the string from __metatable if no real type
lua_pop(state, 1);
- get_metafield(state);
- return 0;
- }
-
- return -1;
-}
-
-/**
- * Index verification: number and in range.
- */
-static int check_container_index(lua_State *state, int len,
- int fidx, int iidx, const char *mode)
-{
- if (!lua_isnumber(state, iidx))
- field_error(state, fidx, "invalid index", mode);
-
- int idx = lua_tointeger(state, iidx);
- if (idx < 0 || idx >= len)
- field_error(state, fidx, "index out of bounds", mode);
-
- return idx;
-}
-
-/**
- * Metamethod: __index for containers.
- */
-static int meta_container_index(lua_State *state)
-{
- uint8_t *ptr = get_object_addr(state, 1, 2, "read");
- int iidx = lookup_container_field(state, 2);
- if (!iidx)
- return 1;
-
- auto id = (container_identity*)lua_touserdata(state, UPVAL_CONTAINER_ID);
- int len = id->lua_item_count(state, ptr);
- int idx = check_container_index(state, len, 2, iidx, "read");
- id->lua_item_read(state, 2, ptr, idx);
- return 1;
-}
-
-/**
- * Method: _field for containers.
- */
-static int meta_container_field_reference(lua_State *state)
-{
- if (lua_gettop(state) != 2)
- luaL_error(state, "Usage: object._field(index)");
- uint8_t *ptr = get_object_addr(state, 1, 2, "reference");
- int iidx = lookup_container_field(state, 2, "reference");
-
- auto id = (container_identity*)lua_touserdata(state, UPVAL_CONTAINER_ID);
- int len = id->lua_item_count(state, ptr);
- int idx = check_container_index(state, len, 2, iidx, "reference");
- id->lua_item_reference(state, 2, ptr, idx);
- return 1;
-}
-
-/**
- * Metamethod: __index for containers.
- */
-static int meta_container_newindex(lua_State *state)
-{
- uint8_t *ptr = get_object_addr(state, 1, 2, "write");
- int iidx = lookup_container_field(state, 2, "write");
-
- auto id = (container_identity*)lua_touserdata(state, UPVAL_CONTAINER_ID);
- int len = id->lua_item_count(state, ptr);
- int idx = check_container_index(state, len, 2, iidx, "write");
- id->lua_item_write(state, 2, ptr, idx, 3);
- return 0;
-}
-
-/**
- * Metamethod: __len for bitfields.
- */
-static int meta_bitfield_len(lua_State *state)
-{
- uint8_t *ptr = get_object_addr(state, 1, 0, "get size");
- auto id = (bitfield_identity*)lua_touserdata(state, UPVAL_CONTAINER_ID);
- lua_pushinteger(state, id->getNumBits());
- return 1;
-}
-
-/**
- * Metamethod: __index for bitfields.
- */
-static int meta_bitfield_index(lua_State *state)
-{
- uint8_t *ptr = get_object_addr(state, 1, 2, "read");
- int iidx = lookup_container_field(state, 2);
- if (!iidx)
- return 1;
-
- auto id = (bitfield_identity*)lua_touserdata(state, UPVAL_CONTAINER_ID);
-
- // whole
- if (lua_isuserdata(state, iidx) && lua_touserdata(state, iidx) == id)
- {
- size_t intv = 0;
- memcpy(&intv, ptr, std::min(sizeof(intv), size_t(id->byte_size())));
- lua_pushnumber(state, intv);
- return 1;
- }
-
- int idx = check_container_index(state, id->getNumBits(), 2, iidx, "read");
- int size = id->getBits()[idx].size;
-
- int value = getBitfieldField(ptr, idx, size);
- if (size <= 1)
- lua_pushboolean(state, value != 0);
- else
- lua_pushinteger(state, value);
- return 1;
-}
-
-/**
- * Metamethod: __newindex for bitfields.
- */
-static int meta_bitfield_newindex(lua_State *state)
-{
- uint8_t *ptr = get_object_addr(state, 1, 2, "write");
- int iidx = lookup_container_field(state, 2, "write");
-
- auto id = (bitfield_identity*)lua_touserdata(state, UPVAL_CONTAINER_ID);
-
- // whole
- if (lua_isuserdata(state, iidx) && lua_touserdata(state, iidx) == id)
- {
- if (!lua_isnumber(state, 3))
- field_error(state, 2, "number expected", "write");
-
- size_t intv = (size_t)lua_tonumber(state, 3);
- memcpy(ptr, &intv, std::min(sizeof(intv), size_t(id->byte_size())));
- return 0;
+ lua_getfield(state, base+1, "__metatable");
}
+ lua_setfield(state, base+1, "_type");
- int idx = check_container_index(state, id->getNumBits(), 2, iidx, "write");
- int size = id->getBits()[idx].size;
-
- if (lua_isboolean(state, 3) || lua_isnil(state, 3))
- setBitfieldField(ptr, idx, size, lua_toboolean(state, 3));
- else if (lua_isnumber(state, 3))
- setBitfieldField(ptr, idx, size, lua_tointeger(state, 3));
- else
- field_error(state, 2, "number or boolean expected", "write");
- return 0;
-}
-
-/**
- * Metamethod: __index for df.global
- */
-static int meta_global_index(lua_State *state)
-{
- auto field = (struct_field_info*)find_field(state, 2, "read");
- if (!field)
- return get_metafield(state);
- void *ptr = *(void**)field->offset;
- if (!ptr)
- field_error(state, 2, "global address not known", "read");
- read_field(state, field, ptr);
- return 1;
-}
-
-/**
- * Metamethod: __newindex for df.global
- */
-static int meta_global_newindex(lua_State *state)
-{
- auto field = (struct_field_info*)find_field(state, 2, "write");
- if (!field)
- field_error(state, 2, "builtin property", "write");
- void *ptr = *(void**)field->offset;
- if (!ptr)
- field_error(state, 2, "global address not known", "write");
- write_field(state, field, ptr, 3);
- return 0;
-}
-
-/**
- * Add fields in the array to the UPVAL_FIELDTABLE candidates on the stack.
- */
-static void IndexFields(lua_State *state, struct_identity *pstruct)
-{
- // stack: fieldtable
-
- int base = lua_gettop(state);
-
- for (struct_identity *p = pstruct; p; p = p->getParent())
- {
- auto fields = p->getFields();
-
- for (; fields; ++fields)
- {
- if (fields->mode == struct_field_info::END)
- break;
+ lua_pushstring(state, kind);
+ lua_setfield(state, base+1, "_kind");
- lua_pushstring(state,fields->name);
- lua_pushlightuserdata(state,(void*)fields);
- lua_rawset(state,base);
- }
- }
+ lua_newtable(state); // fieldtable
}
/**
* Enable a metafield by injecting an entry into a UPVAL_FIELDTABLE.
*/
-static void EnableMetaField(lua_State *state, int ftable_idx, const char *name, void *id = NULL)
+void LuaWrapper::EnableMetaField(lua_State *state, int ftable_idx, const char *name, void *id)
{
lua_pushlightuserdata(state, id);
lua_setfield(state, ftable_idx, name);
@@ -1385,7 +715,7 @@ static void EnableMetaField(lua_State *state, int ftable_idx, const char *name,
/**
* Set metatable properties common to all actual DF object references.
*/
-static void SetPtrMethods(lua_State *state, int meta_idx, int read_idx)
+void LuaWrapper::SetPtrMethods(lua_State *state, int meta_idx, int read_idx)
{
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_COMPARE_NAME);
lua_setfield(state, meta_idx, "__eq");
@@ -1420,8 +750,8 @@ static void SetPtrMethods(lua_State *state, int meta_idx, int read_idx)
/**
* Add a struct-style (3 upvalues) metamethod to the metatable.
*/
-static void SetStructMethod(lua_State *state, int meta_idx, int ftable_idx,
- lua_CFunction function, const char *name)
+void LuaWrapper::SetStructMethod(lua_State *state, int meta_idx, int ftable_idx,
+ lua_CFunction function, const char *name)
{
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_TYPETABLE_NAME);
lua_pushvalue(state, meta_idx);
@@ -1431,75 +761,11 @@ static void SetStructMethod(lua_State *state, int meta_idx, int ftable_idx,
}
/**
- * Make a metatable with most common fields, and an empty table for UPVAL_FIELDTABLE.
- */
-static void MakeMetatable(lua_State *state, type_identity *type, const char *kind)
-{
- int base = lua_gettop(state);
- lua_newtable(state); // metatable
-
- lua_pushstring(state, type->getFullName().c_str());
- lua_setfield(state, base+1, "__metatable");
-
- lua_pushlightuserdata(state, type);
- lua_setfield(state, base+1, "_identity");
-
- LookupInTable(state, type, DFHACK_TYPEID_TABLE_NAME);
- if (lua_isnil(state, -1))
- {
- // Copy the string from __metatable if no real type
- lua_pop(state, 1);
- lua_getfield(state, base+1, "__metatable");
- }
- lua_setfield(state, base+1, "_type");
-
- lua_pushstring(state, kind);
- lua_setfield(state, base+1, "_kind");
-
- lua_newtable(state); // fieldtable
-}
-
-/**
- * Make a struct-style object metatable.
- */
-static void MakeFieldMetatable(lua_State *state, struct_identity *pstruct,
- lua_CFunction reader, lua_CFunction writer)
-{
- int base = lua_gettop(state);
-
- MakeMetatable(state, pstruct, "struct"); // meta, fields
-
- IndexFields(state, pstruct);
-
- SetStructMethod(state, base+1, base+2, reader, "__index");
- SetStructMethod(state, base+1, base+2, writer, "__newindex");
-
- // returns: [metatable readfields writefields];
-}
-
-/**
- * Make a primitive-style metatable
- */
-static void MakePrimitiveMetatable(lua_State *state, type_identity *type)
-{
- int base = lua_gettop(state);
-
- MakeMetatable(state, type, "primitive");
-
- SetPtrMethods(state, base+1, base+2);
-
- EnableMetaField(state, base+2, "value", type);
-
- SetStructMethod(state, base+1, base+2, meta_primitive_index, "__index");
- SetStructMethod(state, base+1, base+2, meta_primitive_newindex, "__newindex");
-}
-
-/**
* Add a 6 upvalue metamethod to the metatable.
*/
-static void SetContainerMethod(lua_State *state, int meta_idx, int ftable_idx,
- lua_CFunction function, const char *name,
- type_identity *container, type_identity *item, int count)
+void LuaWrapper::SetContainerMethod(lua_State *state, int meta_idx, int ftable_idx,
+ lua_CFunction function, const char *name,
+ type_identity *container, type_identity *item, int count)
{
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_TYPETABLE_NAME);
lua_pushvalue(state, meta_idx);
@@ -1520,7 +786,7 @@ static void SetContainerMethod(lua_State *state, int meta_idx, int ftable_idx,
* If ienum refers to a valid enum, attach its keys to UPVAL_FIELDTABLE,
* and the enum itself to the _enum metafield.
*/
-static void AttachEnumKeys(lua_State *state, int base, type_identity *ienum)
+void LuaWrapper::AttachEnumKeys(lua_State *state, int meta_idx, int ftable_idx, type_identity *ienum)
{
LookupInTable(state, ienum, DFHACK_ENUM_TABLE_NAME);
@@ -1529,93 +795,15 @@ static void AttachEnumKeys(lua_State *state, int base, type_identity *ienum)
lua_newtable(state);
lua_swap(state);
lua_setfield(state, -2, "__index");
- lua_setmetatable(state, base+2);
+ lua_setmetatable(state, ftable_idx);
}
else
lua_pop(state, 1);
LookupInTable(state, ienum, DFHACK_TYPEID_TABLE_NAME);
- lua_setfield(state, base+1, "_enum");
-
- EnableMetaField(state, base+2, "_enum");
-}
-
-/**
- * Make a container-style object metatable.
- */
-static void MakeContainerMetatable(lua_State *state, container_identity *type,
- type_identity *item, int count, type_identity *ienum)
-{
- int base = lua_gettop(state);
-
- MakeMetatable(state, type, "container");
- SetPtrMethods(state, base+1, base+2);
-
- // Update the type name using full info
- lua_pushstring(state, type->getFullName(item).c_str());
- lua_dup(state);
- lua_setfield(state, base+1, "__metatable");
- lua_setfield(state, base+1, "_type");
-
- lua_pushlightuserdata(state, item);
- lua_setfield(state, base+1, "_field_identity");
-
- if (count >= 0)
- {
- lua_pushinteger(state, count);
- lua_setfield(state, base+1, "_count");
- }
-
- SetContainerMethod(state, base+1, base+2, meta_container_len, "__len", type, item, count);
- SetContainerMethod(state, base+1, base+2, meta_container_index, "__index", type, item, count);
- SetContainerMethod(state, base+1, base+2, meta_container_newindex, "__newindex", type, item, count);
-
- SetContainerMethod(state, base+1, base+2, meta_container_field_reference, "_field", type, item, count);
-
- AttachEnumKeys(state, base, ienum);
-}
-
-/*
- * Metatable construction identity methods.
- */
-void type_identity::build_metatable(lua_State *state)
-{
- MakePrimitiveMetatable(state, this);
-}
+ lua_setfield(state, meta_idx, "_enum");
-void container_identity::build_metatable(lua_State *state)
-{
- MakeContainerMetatable(state, this, getItemType(), -1, getIndexEnumType());
-}
-
-void bitfield_identity::build_metatable(lua_State *state)
-{
- int base = lua_gettop(state);
-
- MakeMetatable(state, this, "bitfield");
-
- SetPtrMethods(state, base+1, base+2);
-
- SetContainerMethod(state, base+1, base+2, meta_bitfield_len, "__len", this, NULL, -1);
- SetContainerMethod(state, base+1, base+2, meta_bitfield_index, "__index", this, NULL, -1);
- SetContainerMethod(state, base+1, base+2, meta_bitfield_newindex, "__newindex", this, NULL, -1);
-
- AttachEnumKeys(state, base, this);
-
- EnableMetaField(state, base+2, "whole", this);
-}
-
-void struct_identity::build_metatable(lua_State *state)
-{
- int base = lua_gettop(state);
- MakeFieldMetatable(state, this, meta_struct_index, meta_struct_newindex);
- SetStructMethod(state, base+1, base+2, meta_struct_field_reference, "_field");
- SetPtrMethods(state, base+1, base+2);
-}
-
-void global_identity::build_metatable(lua_State *state)
-{
- MakeFieldMetatable(state, this, meta_global_index, meta_global_newindex);
+ EnableMetaField(state, ftable_idx, "_enum");
}
static void BuildTypeMetatable(lua_State *state, type_identity *type)
@@ -1627,81 +815,6 @@ static void BuildTypeMetatable(lua_State *state, type_identity *type)
SaveTypeInfo(state, type);
}
-/**
- * Construct a metatable for an object type folded into the field descriptor.
- * This is done to reduce compile-time symbol table bloat due to templates.
- */
-static void GetAdHocMetatable(lua_State *state, const struct_field_info *field)
-{
- lua_pushlightuserdata(state, (void*)field);
-
- if (!LookupTypeInfo(state, true))
- {
- switch (field->mode)
- {
- case struct_field_info::CONTAINER:
- {
- auto ctype = (container_identity*)field->type;
- MakeContainerMetatable(state, ctype, ctype->getItemType(), -1, field->eid);
- break;
- }
-
- case struct_field_info::STATIC_STRING:
- MakeContainerMetatable(state, &df::buffer_container_identity::base_instance,
- &df::identity_traits<char>::identity, field->count, NULL);
- break;
-
- case struct_field_info::STATIC_ARRAY:
- MakeContainerMetatable(state, &df::buffer_container_identity::base_instance,
- field->type, field->count, field->eid);
- break;
-
- case struct_field_info::STL_VECTOR_PTR:
- MakeContainerMetatable(state, &df::identity_traits<std::vector<void*> >::identity,
- field->type, -1, field->eid);
- break;
-
- default:
- luaL_error(state, "Invalid ad-hoc field: %d", field->mode);
- }
-
- lua_pop(state, 1);
-
- SaveTypeInfo(state, (void*)field);
- }
-}
-
-static void push_adhoc_pointer(lua_State *state, void *ptr, type_identity *target)
-{
- if (!target)
- {
- push_object_internal(state, &df::identity_traits<void*>::identity, ptr);
- return;
- }
-
- LookupInTable(state, target, DFHACK_PTR_IDTABLE_NAME);
-
- type_identity *id = (type_identity*)lua_touserdata(state, -1);
- lua_pop(state, 1);
-
- if (!id)
- {
- /*
- * HACK: relies on
- * 1) pointer_identity destructor being no-op
- * 2) lua gc never moving objects in memory
- */
-
- void *newobj = lua_newuserdata(state, sizeof(pointer_identity));
- id = new (newobj) pointer_identity(target);
-
- SaveInTable(state, target, DFHACK_PTR_IDTABLE_NAME);
- lua_pop(state, 1);
- }
-
- push_object_internal(state, id, ptr);
-}
-
/*
* Recursive walk of scopes to construct the df... tree.
*/