|
|
|
@ -1291,11 +1291,27 @@ void LuaWrapper::SetFunctionWrappers(lua_State *state, const FunctionReg *reg)
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add fields in the array to the UPVAL_FIELDTABLE candidates on the stack.
|
|
|
|
|
*
|
|
|
|
|
* flags:
|
|
|
|
|
* GLOBALS: if true, pstruct is a global_identity and fields with addresses of 0 are skipped
|
|
|
|
|
* RAW: if true, no fields are skipped (supersedes `GLOBALS` flag) and
|
|
|
|
|
* special-case fields like OBJ_METHODs are not added to the metatable
|
|
|
|
|
*
|
|
|
|
|
* Stack in & out:
|
|
|
|
|
* base+1: metatable
|
|
|
|
|
* base+2: fields table (to be populated, map of name -> struct_field_info*)
|
|
|
|
|
* base+3: field iter table (to be populated, bimap of name <-> integer index)
|
|
|
|
|
*/
|
|
|
|
|
static void IndexFields(lua_State *state, int base, struct_identity *pstruct, bool globals)
|
|
|
|
|
namespace IndexFieldsFlags {
|
|
|
|
|
enum IndexFieldsFlags {
|
|
|
|
|
GLOBALS = 1 << 0,
|
|
|
|
|
RAW = 1 << 1,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
static void IndexFields(lua_State *state, int base, struct_identity *pstruct, int flags)
|
|
|
|
|
{
|
|
|
|
|
if (pstruct->getParent())
|
|
|
|
|
IndexFields(state, base, pstruct->getParent(), globals);
|
|
|
|
|
IndexFields(state, base, pstruct->getParent(), flags);
|
|
|
|
|
|
|
|
|
|
auto fields = pstruct->getFields();
|
|
|
|
|
if (!fields)
|
|
|
|
@ -1315,6 +1331,7 @@ static void IndexFields(lua_State *state, int base, struct_identity *pstruct, bo
|
|
|
|
|
|
|
|
|
|
bool add_to_enum = true;
|
|
|
|
|
|
|
|
|
|
if (!(flags & IndexFieldsFlags::RAW))
|
|
|
|
|
// Handle the field
|
|
|
|
|
switch (fields[i].mode)
|
|
|
|
|
{
|
|
|
|
@ -1337,10 +1354,10 @@ static void IndexFields(lua_State *state, int base, struct_identity *pstruct, bo
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Do not add invalid globals to the enumeration order
|
|
|
|
|
if (globals && !*(void**)fields[i].offset)
|
|
|
|
|
if ((flags & IndexFieldsFlags::GLOBALS) && !*(void**)fields[i].offset)
|
|
|
|
|
add_to_enum = false;
|
|
|
|
|
|
|
|
|
|
if (add_to_enum)
|
|
|
|
|
if (add_to_enum || (flags & IndexFieldsFlags::RAW))
|
|
|
|
|
AssociateId(state, base+3, ++cnt, name.c_str());
|
|
|
|
|
|
|
|
|
|
lua_pushlightuserdata(state, (void*)&fields[i]);
|
|
|
|
@ -1348,10 +1365,86 @@ static void IndexFields(lua_State *state, int base, struct_identity *pstruct, bo
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void AddFieldInfoTable(lua_State *state, int ftable_idx, struct_identity *pstruct)
|
|
|
|
|
{
|
|
|
|
|
Lua::StackUnwinder base{state};
|
|
|
|
|
|
|
|
|
|
// metatable
|
|
|
|
|
lua_newtable(state);
|
|
|
|
|
int ix_meta = lua_gettop(state);
|
|
|
|
|
|
|
|
|
|
// field info table (name -> struct_field_info*)
|
|
|
|
|
lua_newtable(state);
|
|
|
|
|
int ix_fieldinfo = lua_gettop(state);
|
|
|
|
|
|
|
|
|
|
// field iter table (int <-> name)
|
|
|
|
|
lua_newtable(state);
|
|
|
|
|
int ix_fielditer = lua_gettop(state);
|
|
|
|
|
IndexFields(state, base, pstruct, IndexFieldsFlags::RAW);
|
|
|
|
|
|
|
|
|
|
PushStructMethod(state, ix_meta, ix_fielditer, meta_struct_next);
|
|
|
|
|
SetPairsMethod(state, ix_meta, "__pairs");
|
|
|
|
|
|
|
|
|
|
// field table (name -> table representation of struct_field_info)
|
|
|
|
|
lua_newtable(state);
|
|
|
|
|
int ix_fields = lua_gettop(state);
|
|
|
|
|
|
|
|
|
|
// wrapper table (empty, indexes into field table with metamethods)
|
|
|
|
|
lua_newtable(state);
|
|
|
|
|
int ix_wrapper = lua_gettop(state);
|
|
|
|
|
|
|
|
|
|
// set up metatable for the wrapper
|
|
|
|
|
// use field table for __index
|
|
|
|
|
lua_pushstring(state, "__index");
|
|
|
|
|
lua_pushvalue(state, ix_fields);
|
|
|
|
|
lua_settable(state, ix_meta);
|
|
|
|
|
|
|
|
|
|
// use change_error() for __newindex
|
|
|
|
|
lua_pushstring(state, "__newindex");
|
|
|
|
|
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_CHANGEERROR_NAME);
|
|
|
|
|
lua_settable(state, ix_meta);
|
|
|
|
|
|
|
|
|
|
lua_pushvalue(state, ix_meta);
|
|
|
|
|
lua_setmetatable(state, ix_wrapper);
|
|
|
|
|
|
|
|
|
|
// convert field info table (struct_field_info) to field table (lua tables)
|
|
|
|
|
lua_pushnil(state); // initial key for next()
|
|
|
|
|
while (lua_next(state, ix_fieldinfo)) {
|
|
|
|
|
auto field = static_cast<const struct_field_info*>(lua_touserdata(state, -1));
|
|
|
|
|
lua_pushvalue(state, -2); // field name
|
|
|
|
|
lua_newtable(state); // new field info
|
|
|
|
|
Lua::TableInsert(state, "name", field->name);
|
|
|
|
|
Lua::TableInsert(state, "offset", field->offset);
|
|
|
|
|
|
|
|
|
|
if (field->type) {
|
|
|
|
|
Lua::TableInsert(state, "type_name", field->type->getFullName());
|
|
|
|
|
|
|
|
|
|
lua_pushstring(state, "type");
|
|
|
|
|
lua_rawgetp(state, LUA_REGISTRYINDEX, &DFHACK_TYPEID_TABLE_TOKEN);
|
|
|
|
|
lua_rawgetp(state, -1, field->type);
|
|
|
|
|
lua_remove(state, -2); // TYPEID_TABLE
|
|
|
|
|
lua_settable(state, -3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lua_settable(state, ix_fields);
|
|
|
|
|
|
|
|
|
|
lua_pop(state, 1); // field name
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lua_pushvalue(state, ix_wrapper);
|
|
|
|
|
lua_setfield(state, ftable_idx, "_fields");
|
|
|
|
|
lua_pushvalue(state, ix_fieldinfo);
|
|
|
|
|
lua_setfield(state, ftable_idx, "_fieldsinfo");
|
|
|
|
|
lua_pushvalue(state, ix_meta);
|
|
|
|
|
lua_setfield(state, ftable_idx, "_fieldsmeta");
|
|
|
|
|
lua_pushvalue(state, ix_fielditer);
|
|
|
|
|
lua_setfield(state, ftable_idx, "_fieldsiter");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LuaWrapper::IndexStatics(lua_State *state, int meta_idx, int ftable_idx, struct_identity *pstruct)
|
|
|
|
|
{
|
|
|
|
|
// stack: metatable fieldtable
|
|
|
|
|
|
|
|
|
|
AddFieldInfoTable(state, ftable_idx, pstruct);
|
|
|
|
|
for (struct_identity *p = pstruct; p; p = p->getParent())
|
|
|
|
|
{
|
|
|
|
|
auto fields = p->getFields();
|
|
|
|
@ -1387,8 +1480,7 @@ static void MakeFieldMetatable(lua_State *state, struct_identity *pstruct,
|
|
|
|
|
|
|
|
|
|
// Index the fields
|
|
|
|
|
lua_newtable(state);
|
|
|
|
|
|
|
|
|
|
IndexFields(state, base, pstruct, globals);
|
|
|
|
|
IndexFields(state, base, pstruct, globals ? IndexFieldsFlags::GLOBALS : 0);
|
|
|
|
|
|
|
|
|
|
// Add the iteration metamethods
|
|
|
|
|
PushStructMethod(state, base+1, base+3, iterator);
|
|
|
|
|