develop
Quietust 2012-03-27 14:14:04 -05:00
commit be2a7af362
3 changed files with 181 additions and 11 deletions

@ -65,8 +65,21 @@ void constructed_identity::lua_read(lua_State *state, int fname_idx, void *ptr)
push_object_internal(state, this, ptr);
}
static void invoke_assign(lua_State *state, type_identity *id, void *ptr, int val_index)
{
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME);
push_object_internal(state, id, ptr);
lua_pushvalue(state, val_index);
lua_call(state, 2, 0);
}
void constructed_identity::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index)
{
if (lua_istable(state, val_index))
{
invoke_assign(state, this, ptr, val_index);
}
else
field_error(state, fname_idx, "complex object", "write");
}
@ -150,6 +163,47 @@ void df::pointer_identity::lua_read(lua_State *state, int fname_idx, void *ptr)
lua_read(state, fname_idx, ptr, target);
}
static void autovivify_ptr(lua_State *state, int fname_idx, void **pptr,
type_identity *target, int val_index)
{
lua_getfield(state, val_index, "new");
if (!lua_isnil(state, -1))
{
int top = lua_gettop(state);
type_identity *suggested = get_object_identity(state, top, "autovivify", true, true);
if (!is_type_compatible(state, target, 0, suggested, top+1, false))
field_error(state, fname_idx, "incompatible suggested autovivify type", "write");
lua_pop(state, 1);
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_NEW_NAME);
lua_swap(state);
lua_call(state, 1, 1);
void *nval = get_object_internal(state, target, top, false);
if (!nval)
field_error(state, fname_idx, "inconsistent autovivify type", "write");
*pptr = nval;
}
else
{
if (!target)
field_error(state, fname_idx, "trying to autovivify void*", "write");
*pptr = target->allocate();
if (!*pptr)
field_error(state, fname_idx, "could not allocate in autovivify", "write");
}
lua_pop(state, 1);
}
void df::pointer_identity::lua_write(lua_State *state, int fname_idx, void *ptr,
type_identity *target, int val_index)
{
@ -157,6 +211,13 @@ void df::pointer_identity::lua_write(lua_State *state, int fname_idx, void *ptr,
if (lua_isnil(state, val_index))
*pptr = NULL;
else if (lua_istable(state, val_index))
{
if (!*pptr)
autovivify_ptr(state, fname_idx, pptr, target, val_index);
invoke_assign(state, target, *pptr, val_index);
}
else
{
void *nval = get_object_internal(state, target, val_index, false);
@ -435,10 +496,15 @@ static void write_field(lua_State *state, const struct_field_info *field, void *
case struct_field_info::POINTER:
df::pointer_identity::lua_write(state, 2, ptr, field->type, value_idx);
return;
case struct_field_info::STATIC_ARRAY:
case struct_field_info::STL_VECTOR_PTR:
field_error(state, 2, "complex object", "write");
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME);
read_field(state, field, ptr);
lua_pushvalue(state, value_idx);
lua_call(state, 2, 0);
return;
case struct_field_info::END:
return;

@ -255,7 +255,7 @@ static void fetch_container_details(lua_State *state, int meta, type_identity **
/**
* Check if type1 and type2 are compatible, possibly using additional metatable data.
*/
static bool is_type_compatible(lua_State *state, type_identity *type1, int meta1,
bool LuaWrapper::is_type_compatible(lua_State *state, type_identity *type1, int meta1,
type_identity *type2, int meta2, bool exact_equal)
{
if (type1 == type2)
@ -417,9 +417,9 @@ static bool is_valid_metatable(lua_State *state, int objidx, int metaidx)
/**
* Given a DF object reference or type, safely retrieve its identity pointer.
*/
static type_identity *get_object_identity(lua_State *state, int objidx,
const char *ctx, bool allow_type = false,
bool keep_metatable = false)
type_identity *LuaWrapper::get_object_identity(lua_State *state, int objidx,
const char *ctx, bool allow_type,
bool keep_metatable)
{
if (!lua_getmetatable(state, objidx))
luaL_error(state, "Invalid object in %s", ctx);
@ -608,6 +608,31 @@ static int meta_new(lua_State *state)
return 1;
}
static void invoke_resize(lua_State *state, int table, lua_Integer size)
{
lua_getfield(state, table, "resize");
lua_pushvalue(state, table);
lua_pushinteger(state, size);
lua_call(state, 2, 0);
}
static void copy_table(lua_State *state, int dest, int src, int skipkey)
{
lua_pushnil(state);
while (lua_next(state, src))
{
if (lua_equal(state, -2, skipkey))
lua_pop(state, 1);
else
{
lua_pushvalue(state, -2);
lua_swap(state);
lua_settable(state, dest);
}
}
}
/**
* Method: assign data between objects.
*/
@ -618,11 +643,83 @@ static int meta_assign(lua_State *state)
if (argc != 2)
luaL_error(state, "Usage: target:assign(src) or df.assign(target,src)");
if (!lua_istable(state, 2))
{
type_identity *id1, *id2;
check_type_compatible(state, 1, 2, &id1, &id2, "df.assign()", false, false);
if (!id1->copy(get_object_ref(state, 1), get_object_ref(state, 2)))
luaL_error(state, "No copy support for %s", id1->getFullName().c_str());
}
else
{
type_identity *id = get_object_identity(state, 1, "df.assign()", false);
if (id->isContainer())
{
lua_pushstring(state, "resize");
int resize_str = lua_gettop(state);
lua_dup(state);
lua_rawget(state, 2);
if (lua_isnil(state,-1))
{
/*
* nil or missing resize field => 1-based lua array
*/
int size = lua_objlen(state, 2);
lua_pop(state, 1);
invoke_resize(state, 1, size);
for (int i = 1; i <= size; i++)
{
lua_pushinteger(state, i-1);
lua_rawgeti(state, 2, i);
lua_settable(state, 1);
}
}
else
{
if (lua_isboolean(state, -1))
{
// resize=false => just assign
// resize=true => find the largest index
if (lua_toboolean(state, -1))
{
lua_Integer size = 0;
lua_pushnil(state);
while (lua_next(state, 2))
{
lua_pop(state, 1);
if (lua_isnumber(state,-1))
size = std::max(size, lua_tointeger(state,-1)+1);
}
invoke_resize(state, 1, size);
}
}
else
{
// otherwise, must be an explicit number
if (!lua_isnumber(state,-1))
luaL_error(state, "Invalid container.resize value in df.assign()");
invoke_resize(state, 1, lua_tointeger(state, -1));
}
lua_pop(state, 1);
copy_table(state, 1, 2, resize_str);
}
}
else
{
lua_pushstring(state, "new");
copy_table(state, 1, 2, lua_gettop(state));
}
}
return 0;
}

@ -149,6 +149,13 @@ namespace DFHack { namespace LuaWrapper {
*/
uint8_t *get_object_addr(lua_State *state, int obj, int field, const char *mode);
bool is_type_compatible(lua_State *state, type_identity *type1, int meta1,
type_identity *type2, int meta2, bool exact_equal);
type_identity *get_object_identity(lua_State *state, int objidx,
const char *ctx, bool allow_type = false,
bool keep_metatable = false);
void LookupInTable(lua_State *state, void *id, const char *tname);
void SaveInTable(lua_State *state, void *node, const char *tname);
void SaveTypeInfo(lua_State *state, void *node);