summaryrefslogtreecommitdiff
path: root/library/LuaWrapper.cpp
diff options
context:
space:
mode:
authorAlexander Gavrilov2012-03-23 12:55:29 +0400
committerAlexander Gavrilov2012-03-23 12:55:29 +0400
commit2b1f8aa2bbb2bc67a661c2930f6d379bae55ca75 (patch)
tree308f9a68cac6aa0eaac9b25033b6e5d69dddf3d3 /library/LuaWrapper.cpp
parent6b2006361dfc2e976c70f8b5507acb9f8a7224db (diff)
downloaddfhack-2b1f8aa2bbb2bc67a661c2930f6d379bae55ca75.tar.gz
dfhack-2b1f8aa2bbb2bc67a661c2930f6d379bae55ca75.tar.bz2
dfhack-2b1f8aa2bbb2bc67a661c2930f6d379bae55ca75.tar.xz
Add a _field method that returns refs to struct and container items.
Hack: allocate ad-hoc pointer identities as full lua userdata.
Diffstat (limited to 'library/LuaWrapper.cpp')
-rw-r--r--library/LuaWrapper.cpp145
1 files changed, 139 insertions, 6 deletions
diff --git a/library/LuaWrapper.cpp b/library/LuaWrapper.cpp
index 9214a4c5..d6edef4e 100644
--- a/library/LuaWrapper.cpp
+++ b/library/LuaWrapper.cpp
@@ -63,6 +63,11 @@ inline void lua_swap(lua_State *state) { lua_insert(state, -2); }
*/
#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"
@@ -150,6 +155,8 @@ void *DFHack::GetDFObject(lua_State *state, type_identity *type, int val_index)
return get_object_internal(state, type, val_index, false);
}
+static void push_adhoc_pointer(lua_State *state, void *ptr, type_identity *target);
+
/**************************************
* Identity object read/write methods *
**************************************/
@@ -260,6 +267,13 @@ int container_identity::lua_item_count(lua_State *state, void *ptr)
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);
@@ -274,6 +288,13 @@ void container_identity::lua_item_write(lua_State *state, int fname_idx, void *p
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);
@@ -288,6 +309,11 @@ void ptr_container_identity::lua_item_write(lua_State *state, int fname_idx, voi
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));
@@ -761,6 +787,37 @@ static void read_field(lua_State *state, const struct_field_info *field, void *p
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)
@@ -843,6 +900,21 @@ static int meta_struct_index(lua_State *state)
}
/**
+ * 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)
@@ -900,17 +972,17 @@ static int meta_container_len(lua_State *state)
* - Numbers are indices and handled directly.
* - NULL userdata are metafields; push and exit;
*/
-static int lookup_container_field(lua_State *state, int field, bool write = false)
+static int lookup_container_field(lua_State *state, int field, const char *mode = NULL)
{
if (lua_type(state, field) == LUA_TNUMBER)
return field;
- lookup_field(state, field, write ? "write" : "read");
+ lookup_field(state, field, mode ? mode : "read");
if (lua_isuserdata(state, -1) && !lua_touserdata(state, -1))
{
- if (write)
- field_error(state, field, "builtin property", "write");
+ if (mode)
+ field_error(state, field, "builtin property", mode);
lua_pop(state, 1);
get_metafield(state);
@@ -954,12 +1026,29 @@ static int meta_container_index(lua_State *state)
}
/**
+ * 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, true);
+ 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);
@@ -1017,7 +1106,7 @@ static int meta_bitfield_index(lua_State *state)
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, true);
+ int iidx = lookup_container_field(state, 2, "write");
auto id = (bitfield_identity*)lua_touserdata(state, UPVAL_CONTAINER_ID);
@@ -1130,6 +1219,8 @@ static void SetPtrMethods(lua_State *state, int meta_idx, int read_idx)
EnableMetaField(state, read_idx, "_type");
EnableMetaField(state, read_idx, "_kind");
+ EnableMetaField(state, read_idx, "_field");
+
EnableMetaField(state, read_idx, "sizeof");
EnableMetaField(state, read_idx, "_displace");
}
@@ -1287,6 +1378,8 @@ static void MakeContainerMetatable(lua_State *state, container_identity *type,
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);
}
@@ -1324,6 +1417,7 @@ 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);
}
@@ -1360,6 +1454,11 @@ static void GetAdHocMetatable(lua_State *state, const struct_field_info *field)
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);
@@ -1380,6 +1479,37 @@ static void GetAdHocMetatable(lua_State *state, const struct_field_info *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.
*/
@@ -1534,6 +1664,9 @@ static void DoAttach(lua_State *state)
int base = lua_gettop(state);
lua_newtable(state);
+ lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_PTR_IDTABLE_NAME);
+
+ lua_newtable(state);
lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_TYPEID_TABLE_NAME);
lua_newtable(state);