diff options
| author | Alexander Gavrilov | 2012-03-24 13:25:10 +0400 |
|---|---|---|
| committer | Alexander Gavrilov | 2012-03-24 13:25:10 +0400 |
| commit | d865d54a90dcff0d30b8c7c3a95f8d8c2f24de62 (patch) | |
| tree | f9e61cc8fcd1153b63c4eca110920477e26360d8 /library/LuaWrapper.cpp | |
| parent | 053bfe345c566864b2337a8429072a24a2558493 (diff) | |
| download | dfhack-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.cpp | 965 |
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. */ |
