Make enum attributes accessible through the lua wrapper.

TODO: make them completely read-only.
develop
Alexander Gavrilov 2012-03-25 19:12:59 +04:00
parent 0412aaebe4
commit 1d81cb56ba
7 changed files with 133 additions and 8 deletions

@ -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)
{
}

@ -31,6 +31,8 @@ namespace df {
bool_identity identity_traits<bool>::identity;
stl_string_identity identity_traits<std::string>::identity;
ptr_string_identity identity_traits<char*>::identity;
ptr_string_identity identity_traits<const char*>::identity;
pointer_identity identity_traits<void*>::identity;
stl_ptr_vector_identity identity_traits<std::vector<void*> >::identity;
stl_bit_vector_identity identity_traits<std::vector<bool> >::identity;

@ -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;

@ -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());

@ -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; }

@ -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 T>
class enum_list_attr_identity : public container_identity {
public:
typedef enum_list_attr<T> 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<type> { \
static number_identity<type> identity; \
@ -415,6 +447,16 @@ namespace df
static stl_string_identity *get() { return &identity; }
};
template<> struct identity_traits<char*> {
static ptr_string_identity identity;
static ptr_string_identity *get() { return &identity; }
};
template<> struct identity_traits<const char*> {
static ptr_string_identity identity;
static ptr_string_identity *get() { return &identity; }
};
template<> struct identity_traits<void*> {
static pointer_identity identity;
static pointer_identity *get() { return &identity; }
@ -466,6 +508,10 @@ namespace df
static container_identity *get();
};
template<class T> struct identity_traits<enum_list_attr<T> > {
static container_identity *get();
};
// Container definitions
template<class Enum, class FT>
@ -519,5 +565,11 @@ namespace df
static stl_container_identity<container> identity("DfArray", identity_traits<T>::get());
return &identity;
}
template<class T>
inline container_identity *identity_traits<enum_list_attr<T> >::get() {
static enum_list_attr_identity<T> identity(identity_traits<T>::get());
return &identity;
}
}

@ -1 +1 @@
Subproject commit 2f3525af4c7a99564cbffd662e6d0a0b24bedbe6
Subproject commit b9c7b74e8a1bb64532fe58e40a4c23e1d4aca8e3