diff --git a/library/DataDefs.cpp b/library/DataDefs.cpp index 3d6354743..755477d47 100644 --- a/library/DataDefs.cpp +++ b/library/DataDefs.cpp @@ -149,10 +149,11 @@ enum_identity::enum_identity(size_t size, compound_identity *scope_parent, const char *dfhack_name, type_identity *base_type, int64_t first_item_value, int64_t last_item_value, - const char *const *keys) + const char *const *keys, + const void *attrs, struct_identity *attr_type) : compound_identity(size, NULL, scope_parent, dfhack_name), first_item_value(first_item_value), last_item_value(last_item_value), - keys(keys), base_type(base_type) + keys(keys), base_type(base_type), attrs(attrs), attr_type(attr_type) { } diff --git a/library/DataStaticsFields.cpp b/library/DataStaticsFields.cpp index 02a12b972..29816bbc5 100644 --- a/library/DataStaticsFields.cpp +++ b/library/DataStaticsFields.cpp @@ -31,6 +31,8 @@ namespace df { bool_identity identity_traits::identity; stl_string_identity identity_traits::identity; + ptr_string_identity identity_traits::identity; + ptr_string_identity identity_traits::identity; pointer_identity identity_traits::identity; stl_ptr_vector_identity identity_traits >::identity; stl_bit_vector_identity identity_traits >::identity; diff --git a/library/LuaTypes.cpp b/library/LuaTypes.cpp index c4b58b00a..536bcd72a 100644 --- a/library/LuaTypes.cpp +++ b/library/LuaTypes.cpp @@ -110,6 +110,20 @@ void df::bool_identity::lua_write(lua_State *state, int fname_idx, void *ptr, in field_error(state, fname_idx, "boolean or number expected", "write"); } +void df::ptr_string_identity::lua_read(lua_State *state, int fname_idx, void *ptr) +{ + auto pstr = (char**)ptr; + if (*pstr) + lua_pushstring(state, *pstr); + else + lua_pushnil(state); +} + +void df::ptr_string_identity::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index) +{ + field_error(state, fname_idx, "raw pointer string", "write"); +} + void df::stl_string_identity::lua_read(lua_State *state, int fname_idx, void *ptr) { auto pstr = (std::string*)ptr; diff --git a/library/LuaWrapper.cpp b/library/LuaWrapper.cpp index c38d6f288..4758f04f1 100644 --- a/library/LuaWrapper.cpp +++ b/library/LuaWrapper.cpp @@ -698,6 +698,30 @@ static int meta_ptr_tostring(lua_State *state) return 1; } +/** + * Metamethod: __index for enum.attrs + */ +static int meta_enum_attr_index(lua_State *state) +{ + if (!lua_isnumber(state, 2)) + lua_rawget(state, UPVAL_FIELDTABLE); + if (!lua_isnumber(state, 2)) + luaL_error(state, "Invalid index in enum.attrs[]"); + + auto id = (enum_identity*)lua_touserdata(state, lua_upvalueindex(2)); + + int64_t idx = lua_tonumber(state, 2); + if (idx < id->getFirstItem() || idx > id->getLastItem()) + idx = id->getLastItem()+1; + idx -= id->getFirstItem(); + + uint8_t *ptr = (uint8_t*)id->getAttrs(); + auto atype = id->getAttrType(); + + push_object_internal(state, atype, ptr + unsigned(atype->byte_size()*idx)); + return 1; +} + /** * Make a metatable with most common fields, and an empty table for UPVAL_FIELDTABLE. */ @@ -864,23 +888,48 @@ static void FillEnumKeys(lua_State *state, int ftable, enum_identity *eid) { const char *const *keys = eid->getKeys(); + // Create a new table attached to ftable as __index + lua_newtable(state); + + lua_dup(state); + lua_setmetatable(state, ftable); + + int base = lua_gettop(state); + + lua_newtable(state); + // For enums, set mapping between keys and values for (int64_t i = eid->getFirstItem(), j = 0; i <= eid->getLastItem(); i++, j++) { if (keys[j]) - AssociateId(state, ftable, i, keys[j]); + AssociateId(state, base+1, i, keys[j]); } if (eid->getFirstItem() <= eid->getLastItem()) { lua_pushinteger(state, eid->getFirstItem()); - lua_setfield(state, ftable, "_first_item"); + lua_setfield(state, base+1, "_first_item"); lua_pushinteger(state, eid->getLastItem()); - lua_setfield(state, ftable, "_last_item"); + lua_setfield(state, base+1, "_last_item"); } SaveInTable(state, eid, DFHACK_ENUM_TABLE_NAME); + + // Add an attribute table if any + if (eid->getAttrs()) + { + lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_TYPETABLE_NAME); + lua_pushlightuserdata(state, eid); + lua_pushvalue(state, base+1); + lua_pushcclosure(state, meta_enum_attr_index, 3); + + freeze_table(state, false, (eid->getFullName()+".attrs").c_str()); + lua_setfield(state, ftable, "attrs"); + } + + lua_setfield(state, base, "__index"); + lua_pop(state, 1); } static void FillBitfieldKeys(lua_State *state, int ftable, bitfield_identity *eid) @@ -904,7 +953,6 @@ static void FillBitfieldKeys(lua_State *state, int ftable, bitfield_identity *ei SaveInTable(state, eid, DFHACK_ENUM_TABLE_NAME); } - static void RenderType(lua_State *state, compound_identity *node) { assert(node->getName()); diff --git a/library/include/DataDefs.h b/library/include/DataDefs.h index ca77e504f..b2c86ec11 100644 --- a/library/include/DataDefs.h +++ b/library/include/DataDefs.h @@ -183,6 +183,8 @@ namespace DFHack virtual void build_metatable(lua_State *state); }; + class struct_identity; + class DFHACK_EXPORT enum_identity : public compound_identity { const char *const *keys; int64_t first_item_value; @@ -190,6 +192,9 @@ namespace DFHack type_identity *base_type; + const void *attrs; + struct_identity *attr_type; + protected: virtual bool can_allocate() { return true; } virtual void *do_allocate(); @@ -201,7 +206,8 @@ namespace DFHack compound_identity *scope_parent, const char *dfhack_name, type_identity *base_type, int64_t first_item_value, int64_t last_item_value, - const char *const *keys); + const char *const *keys, + const void *attrs, struct_identity *attr_type); virtual identity_type type() { return IDTYPE_ENUM; } @@ -211,6 +217,8 @@ namespace DFHack const char *const *getKeys() { return keys; } type_identity *getBaseType() { return base_type; } + const void *getAttrs() { return attrs; } + struct_identity *getAttrType() { return attr_type; } virtual bool isPrimitive() { return true; } virtual bool isConstructed() { return false; } diff --git a/library/include/DataIdentity.h b/library/include/DataIdentity.h index a135fc00b..840c9688f 100644 --- a/library/include/DataIdentity.h +++ b/library/include/DataIdentity.h @@ -205,6 +205,16 @@ namespace df virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index); }; + class ptr_string_identity : public primitive_identity { + public: + ptr_string_identity() : primitive_identity(sizeof(char*)) {}; + + std::string getFullName() { return "char*"; } + + virtual void lua_read(lua_State *state, int fname_idx, void *ptr); + virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index); + }; + class stl_string_identity : public DFHack::constructed_identity { public: stl_string_identity() @@ -388,6 +398,28 @@ namespace df } }; + template + class enum_list_attr_identity : public container_identity { + public: + typedef enum_list_attr container; + + enum_list_attr_identity(type_identity *item) + : container_identity(sizeof(container), NULL, item, NULL) + {} + + std::string getFullName(type_identity *item) { + return "enum_list_attr" + container_identity::getFullName(item); + } + + protected: + virtual int item_count(void *ptr, CountMode cm) { + return cm == COUNT_WRITE ? 0 : ((container*)ptr)->size; + } + virtual void *item_pointer(type_identity *item, void *ptr, int idx) { + return (void*)&((container*)ptr)->items[idx]; + } + }; + #define NUMBER_IDENTITY_TRAITS(type) \ template<> struct identity_traits { \ static number_identity identity; \ @@ -415,6 +447,16 @@ namespace df static stl_string_identity *get() { return &identity; } }; + template<> struct identity_traits { + static ptr_string_identity identity; + static ptr_string_identity *get() { return &identity; } + }; + + template<> struct identity_traits { + static ptr_string_identity identity; + static ptr_string_identity *get() { return &identity; } + }; + template<> struct identity_traits { static pointer_identity identity; static pointer_identity *get() { return &identity; } @@ -466,6 +508,10 @@ namespace df static container_identity *get(); }; + template struct identity_traits > { + static container_identity *get(); + }; + // Container definitions template @@ -519,5 +565,11 @@ namespace df static stl_container_identity identity("DfArray", identity_traits::get()); return &identity; } + + template + inline container_identity *identity_traits >::get() { + static enum_list_attr_identity identity(identity_traits::get()); + return &identity; + } } diff --git a/library/xml b/library/xml index 2f3525af4..b9c7b74e8 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 2f3525af4c7a99564cbffd662e6d0a0b24bedbe6 +Subproject commit b9c7b74e8a1bb64532fe58e40a4c23e1d4aca8e3