Merge branch 'master' of git://github.com/angavrilov/dfhack

Conflicts:
	library/xml
develop
Robert Heinrich 2012-03-29 16:12:54 +02:00
commit cc54d5dfa9
5 changed files with 341 additions and 62 deletions

@ -236,10 +236,17 @@ static int luaB_next (lua_State *L) {
static int luaB_pairs (lua_State *L) {
luaL_checktype(L, 1, LUA_TTABLE);
lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */
lua_pushvalue(L, 1); /* state, */
lua_pushnil(L); /* and initial value */
luaL_checkany(L, 1);
if (luaL_getmetafield(L, 1, "__pairs")) {
lua_pushvalue(L, 1);
lua_call(L, 1, 3);
}
else {
luaL_checktype(L, 1, LUA_TTABLE);
lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */
lua_pushvalue(L, 1); /* state, */
lua_pushnil(L); /* and initial value */
}
return 3;
}
@ -255,10 +262,17 @@ static int ipairsaux (lua_State *L) {
static int luaB_ipairs (lua_State *L) {
luaL_checktype(L, 1, LUA_TTABLE);
lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */
lua_pushvalue(L, 1); /* state, */
lua_pushinteger(L, 0); /* and initial value */
luaL_checkany(L, 1);
if (luaL_getmetafield(L, 1, "__ipairs")) {
lua_pushvalue(L, 1);
lua_call(L, 1, 3);
}
else {
luaL_checktype(L, 1, LUA_TTABLE);
lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */
lua_pushvalue(L, 1); /* state, */
lua_pushinteger(L, 0); /* and initial value */
}
return 3;
}

@ -189,14 +189,14 @@ FILE(GLOB GENERATE_INPUT_SCRIPTS ${dfapi_SOURCE_DIR}/xml/*.pm ${dfapi_SOURCE_DIR
FILE(GLOB GENERATE_INPUT_XMLS ${dfapi_SOURCE_DIR}/xml/*.xml)
ADD_CUSTOM_COMMAND(
OUTPUT ${dfapi_SOURCE_DIR}/include/df/static.inc
OUTPUT ${dfapi_SOURCE_DIR}/include/df/codegen.out.xml
COMMAND ${PERL_EXECUTABLE} xml/codegen.pl xml include/df
WORKING_DIRECTORY ${dfapi_SOURCE_DIR}
MAIN_DEPENDENCY ${dfapi_SOURCE_DIR}/xml/codegen.pl
DEPENDS ${GENERATE_INPUT_XMLS} ${GENERATE_INPUT_SCRIPTS}
)
ADD_CUSTOM_TARGET(generate_headers DEPENDS ${dfapi_SOURCE_DIR}/include/df/static.inc)
ADD_CUSTOM_TARGET(generate_headers DEPENDS ${dfapi_SOURCE_DIR}/include/df/codegen.out.xml)
IF(UNIX)
# Don't produce debug info for generated stubs

@ -215,12 +215,19 @@ static void autovivify_ptr(lua_State *state, int fname_idx, void **pptr,
lua_pop(state, 1);
}
static bool is_null(lua_State *state, int val_index)
{
return lua_isnil(state, val_index) ||
(lua_islightuserdata(state, val_index) &&
!lua_touserdata(state, val_index));
}
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))
if (is_null(state, val_index))
*pptr = NULL;
else if (lua_istable(state, val_index))
{
@ -389,6 +396,43 @@ static void *find_field(lua_State *state, int index, const char *mode)
return p;
}
static int cur_iter_index(lua_State *state, int len, int fidx, int first_idx = -1)
{
int rv;
if (lua_isnil(state, fidx))
rv = first_idx;
else
{
if (lua_isnumber(state, fidx))
rv = lua_tointeger(state, fidx);
else
{
lua_pushvalue(state, fidx);
lua_rawget(state, UPVAL_FIELDTABLE);
if (!lua_isnumber(state, -1))
field_error(state, fidx, "index not found", "iterate");
rv = lua_tointeger(state, -1);
lua_pop(state, 1);
}
if (rv < 0 || rv >= len)
field_error(state, fidx, "index out of bounds", "iterate");
}
return rv;
}
static void iter_idx_to_name(lua_State *state, int idx)
{
lua_pushvalue(state, idx);
lua_rawget(state, UPVAL_FIELDTABLE);
if (lua_isnil(state, -1))
lua_pop(state, 1);
else
lua_replace(state, idx);
}
static uint8_t *check_method_call(lua_State *state, int min_args, int max_args)
{
int argc = lua_gettop(state)-1;
@ -592,6 +636,24 @@ static int meta_struct_newindex(lua_State *state)
return 0;
}
/**
* Metamethod: iterator for structures.
*/
static int meta_struct_next(lua_State *state)
{
if (lua_gettop(state) < 2) lua_pushnil(state);
int len = lua_objlen(state, UPVAL_FIELDTABLE);
int idx = cur_iter_index(state, len+1, 2, 0);
if (idx == len)
return 0;
lua_rawgeti(state, UPVAL_FIELDTABLE, idx+1);
lua_dup(state);
lua_gettable(state, 1);
return 2;
}
/**
* Metamethod: __index for primitives, i.e. simple object references.
* Fields point to identity, or NULL for metafields.
@ -722,6 +784,39 @@ static int meta_container_newindex(lua_State *state)
return 0;
}
/**
* Metamethod: integer iterator for containers.
*/
static int meta_container_nexti(lua_State *state)
{
if (lua_gettop(state) < 2) lua_pushnil(state);
uint8_t *ptr = get_object_addr(state, 1, 2, "iterate");
auto id = (container_identity*)lua_touserdata(state, UPVAL_CONTAINER_ID);
int len = id->lua_item_count(state, ptr, container_identity::COUNT_LEN);
int idx = cur_iter_index(state, len, 2);
if (++idx >= len)
return 0;
lua_pushinteger(state, idx);
id->lua_item_read(state, 2, ptr, idx);
return 2;
}
/**
* Metamethod: name iterator for containers.
*/
static int meta_container_next(lua_State *state)
{
if (!meta_container_nexti(state))
return 0;
iter_idx_to_name(state, lua_gettop(state)-1);
return 2;
}
/**
* Method: resize container
*/
@ -781,6 +876,17 @@ static int meta_bitfield_len(lua_State *state)
return 1;
}
static void read_bitfield(lua_State *state, uint8_t *ptr, bitfield_identity *id, int idx)
{
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);
}
/**
* Metamethod: __index for bitfields.
*/
@ -803,13 +909,7 @@ static int meta_bitfield_index(lua_State *state)
}
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);
read_bitfield(state, ptr, id, idx);
return 1;
}
@ -846,6 +946,44 @@ static int meta_bitfield_newindex(lua_State *state)
return 0;
}
/**
* Metamethod: integer iterator for bitfields.
*/
static int meta_bitfield_nexti(lua_State *state)
{
if (lua_gettop(state) < 2) lua_pushnil(state);
uint8_t *ptr = get_object_addr(state, 1, 2, "iterate");
auto id = (bitfield_identity*)lua_touserdata(state, UPVAL_CONTAINER_ID);
int len = id->getNumBits();
int idx = cur_iter_index(state, len, 2);
if (idx < 0)
idx = 0;
else
idx += std::max(1, (int)id->getBits()[idx].size);
if (idx >= len)
return 0;
lua_pushinteger(state, idx);
read_bitfield(state, ptr, id, idx);
return 2;
}
/**
* Metamethod: name iterator for bitfields.
*/
static int meta_bitfield_next(lua_State *state)
{
if (!meta_bitfield_nexti(state))
return 0;
iter_idx_to_name(state, lua_gettop(state)-1);
return 2;
}
/**
* Metamethod: __index for df.global
*/
@ -906,36 +1044,43 @@ static void AddMethodWrapper(lua_State *state, int meta_idx, int field_idx,
/**
* Add fields in the array to the UPVAL_FIELDTABLE candidates on the stack.
*/
static void IndexFields(lua_State *state, struct_identity *pstruct)
static void IndexFields(lua_State *state, int base, struct_identity *pstruct)
{
// stack: metatable fieldtable
if (pstruct->getParent())
IndexFields(state, base, pstruct->getParent());
auto fields = pstruct->getFields();
if (!fields)
return;
int base = lua_gettop(state) - 2;
int cnt = lua_objlen(state, base+3); // field iter table
for (struct_identity *p = pstruct; p; p = p->getParent())
for (int i = 0; fields[i].mode != struct_field_info::END; ++i)
{
auto fields = p->getFields();
if (!fields)
continue;
// Qualify conflicting field names with the type
std::string name = fields[i].name;
for (int i = 0; fields[i].mode != struct_field_info::END; ++i)
lua_getfield(state, base+2, name.c_str());
if (!lua_isnil(state, -1))
name = pstruct->getName() + ("." + name);
lua_pop(state, 1);
// Handle the field
switch (fields[i].mode)
{
switch (fields[i].mode)
{
case struct_field_info::OBJ_METHOD:
AddMethodWrapper(state, base+1, base+2, fields[i].name,
(function_identity_base*)fields[i].type);
break;
case struct_field_info::OBJ_METHOD:
AddMethodWrapper(state, base+1, base+2, name.c_str(),
(function_identity_base*)fields[i].type);
break;
case struct_field_info::CLASS_METHOD:
break;
case struct_field_info::CLASS_METHOD:
break;
default:
lua_pushstring(state,fields[i].name);
lua_pushlightuserdata(state,(void*)&fields[i]);
lua_rawset(state,base+2);
break;
}
default:
AssociateId(state, base+3, ++cnt, name.c_str());
lua_pushlightuserdata(state, (void*)&fields[i]);
lua_setfield(state, base+2, name.c_str());
break;
}
}
}
@ -976,8 +1121,20 @@ static void MakeFieldMetatable(lua_State *state, struct_identity *pstruct,
MakeMetatable(state, pstruct, "struct"); // meta, fields
IndexFields(state, pstruct);
// Index the fields
lua_newtable(state);
IndexFields(state, base, pstruct);
// Add the iteration metamethods
PushStructMethod(state, base+1, base+3, meta_struct_next);
SetPairsMethod(state, base+1, "__pairs");
lua_pushnil(state);
SetPairsMethod(state, base+1, "__ipairs");
lua_setfield(state, base+1, "_index_table");
// Add the indexing metamethods
SetStructMethod(state, base+1, base+2, reader, "__index");
SetStructMethod(state, base+1, base+2, writer, "__newindex");
@ -995,8 +1152,21 @@ static void MakePrimitiveMetatable(lua_State *state, type_identity *type)
SetPtrMethods(state, base+1, base+2);
// Index the fields
lua_newtable(state);
EnableMetaField(state, base+2, "value", type);
AssociateId(state, base+3, 1, "value");
// Add the iteration metamethods
PushStructMethod(state, base+1, base+3, meta_struct_next);
SetPairsMethod(state, base+1, "__pairs");
lua_pushnil(state);
SetPairsMethod(state, base+1, "__ipairs");
lua_setfield(state, base+1, "_index_table");
// Add the indexing metamethods
SetStructMethod(state, base+1, base+2, meta_primitive_index, "__index");
SetStructMethod(state, base+1, base+2, meta_primitive_newindex, "__newindex");
}
@ -1048,7 +1218,15 @@ static void MakeContainerMetatable(lua_State *state, container_identity *type,
AddContainerMethodFun(state, base+1, base+2, method_container_erase, "erase", type, item, count);
AddContainerMethodFun(state, base+1, base+2, method_container_insert, "insert", type, item, count);
// push the index table
AttachEnumKeys(state, base+1, base+2, ienum);
PushContainerMethod(state, base+1, base+3, meta_container_next, type, item, count);
SetPairsMethod(state, base+1, "__pairs");
PushContainerMethod(state, base+1, base+3, meta_container_nexti, type, item, count);
SetPairsMethod(state, base+1, "__ipairs");
lua_pop(state, 1);
}
/*
@ -1078,6 +1256,13 @@ void bitfield_identity::build_metatable(lua_State *state)
AttachEnumKeys(state, base+1, base+2, this);
PushContainerMethod(state, base+1, base+3, meta_bitfield_next, this, NULL, -1);
SetPairsMethod(state, base+1, "__pairs");
PushContainerMethod(state, base+1, base+3, meta_bitfield_nexti, this, NULL, -1);
SetPairsMethod(state, base+1, "__ipairs");
lua_pop(state, 1);
EnableMetaField(state, base+2, "whole", this);
}

@ -496,14 +496,7 @@ static int meta_sizeof(lua_State *state)
luaL_error(state, "Usage: object:sizeof() or df.sizeof(object)");
// Two special cases: nil and lightuserdata for NULL and void*
if (lua_isnil(state, 1))
{
lua_pushnil(state);
lua_pushinteger(state, 0);
return 2;
}
if (lua_islightuserdata(state, 1))
if (lua_isnil(state, 1) || lua_islightuserdata(state, 1))
{
lua_pushnil(state);
lua_pushnumber(state, (size_t)lua_touserdata(state, 1));
@ -853,6 +846,23 @@ static int meta_enum_attr_index(lua_State *state)
return 1;
}
static int meta_nodata(lua_State *state)
{
return 0;
}
/**
* Metamethod: __pairs, returning 1st upvalue as iterator
*/
static int meta_pairs(lua_State *state)
{
luaL_checkany(state, 1);
lua_pushvalue(state, lua_upvalueindex(1));
lua_pushvalue(state, 1);
lua_pushnil(state);
return 3;
}
/**
* Make a metatable with most common fields, and an empty table for UPVAL_FIELDTABLE.
*/
@ -879,7 +889,8 @@ void LuaWrapper::MakeMetatable(lua_State *state, type_identity *type, const char
lua_pushstring(state, kind);
lua_setfield(state, base+1, "_kind");
lua_newtable(state); // fieldtable
// Create the field table
lua_newtable(state);
}
/**
@ -930,25 +941,49 @@ void LuaWrapper::SetPtrMethods(lua_State *state, int meta_idx, int read_idx)
EnableMetaField(state, read_idx, "_displace");
}
/**
* Add a __pairs/__ipairs metamethod using iterator on the top of stack.
*/
void LuaWrapper::SetPairsMethod(lua_State *state, int meta_idx, const char *name)
{
if (lua_isnil(state, -1))
{
lua_pop(state, 1);
lua_pushcfunction(state, meta_nodata);
}
lua_pushcclosure(state, meta_pairs, 1);
lua_setfield(state, meta_idx, name);
}
/**
* Add a struct-style (3 upvalues) metamethod to the metatable.
*/
void LuaWrapper::SetStructMethod(lua_State *state, int meta_idx, int ftable_idx,
lua_CFunction function, const char *name)
void LuaWrapper::PushStructMethod(lua_State *state, int meta_idx, int ftable_idx,
lua_CFunction function)
{
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_TYPETABLE_NAME);
lua_pushvalue(state, meta_idx);
lua_pushvalue(state, ftable_idx);
lua_pushcclosure(state, function, 3);
}
/**
* Add a struct-style (3 upvalues) metamethod to the metatable.
*/
void LuaWrapper::SetStructMethod(lua_State *state, int meta_idx, int ftable_idx,
lua_CFunction function, const char *name)
{
PushStructMethod(state, meta_idx, ftable_idx, function);
lua_setfield(state, meta_idx, name);
}
/**
* Add a 6 upvalue metamethod to the metatable.
*/
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)
void LuaWrapper::PushContainerMethod(lua_State *state, int meta_idx, int ftable_idx,
lua_CFunction function,
type_identity *container, type_identity *item, int count)
{
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_TYPETABLE_NAME);
lua_pushvalue(state, meta_idx);
@ -962,31 +997,48 @@ void LuaWrapper::SetContainerMethod(lua_State *state, int meta_idx, int ftable_i
lua_pushinteger(state, count);
lua_pushcclosure(state, function, 6);
}
/**
* Add a 6 upvalue metamethod to the metatable.
*/
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)
{
PushContainerMethod(state, meta_idx, ftable_idx, function, container, item, count);
lua_setfield(state, meta_idx, name);
}
/**
* If ienum refers to a valid enum, attach its keys to UPVAL_FIELDTABLE,
* and the enum itself to the _enum metafield.
* and the enum itself to the _enum metafield. Pushes the key table on the stack
*/
void LuaWrapper::AttachEnumKeys(lua_State *state, int meta_idx, int ftable_idx, type_identity *ienum)
{
EnableMetaField(state, ftable_idx, "_enum");
LookupInTable(state, ienum, DFHACK_TYPEID_TABLE_NAME);
lua_setfield(state, meta_idx, "_enum");
LookupInTable(state, ienum, DFHACK_ENUM_TABLE_NAME);
if (!lua_isnil(state, -1))
{
lua_dup(state);
lua_newtable(state);
lua_swap(state);
lua_setfield(state, -2, "__index");
lua_setmetatable(state, ftable_idx);
}
else
{
lua_pop(state, 1);
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_EMPTY_TABLE_NAME);
}
LookupInTable(state, ienum, DFHACK_TYPEID_TABLE_NAME);
lua_setfield(state, meta_idx, "_enum");
EnableMetaField(state, ftable_idx, "_enum");
lua_dup(state);
lua_setfield(state, meta_idx, "_index_table");
}
static void BuildTypeMetatable(lua_State *state, type_identity *type)
@ -1004,7 +1056,7 @@ static void BuildTypeMetatable(lua_State *state, type_identity *type)
static void RenderTypeChildren(lua_State *state, const std::vector<compound_identity*> &children);
static void AssociateId(lua_State *state, int table, int val, const char *name)
void LuaWrapper::AssociateId(lua_State *state, int table, int val, const char *name)
{
lua_pushinteger(state, val);
lua_pushstring(state, name);
@ -1157,6 +1209,8 @@ static void RenderType(lua_State *state, compound_identity *node)
lua_getfield(state, -1, "__newindex");
lua_setfield(state, base+2, "__newindex");
lua_getfield(state, -1, "__pairs");
lua_setfield(state, base+2, "__pairs");
lua_pop(state, 3);
return;
@ -1201,6 +1255,9 @@ static void DoAttach(lua_State *state)
lua_newtable(state);
lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_ENUM_TABLE_NAME);
lua_newtable(state);
lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_EMPTY_TABLE_NAME);
lua_pushcfunction(state, change_error);
lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_CHANGEERROR_NAME);
@ -1250,6 +1307,11 @@ static void DoAttach(lua_State *state)
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME);
lua_setfield(state, -2, "assign");
lua_pushlightuserdata(state, NULL);
lua_setfield(state, -2, "NULL");
lua_pushlightuserdata(state, NULL);
lua_setglobal(state, "NULL");
freeze_table(state, true, "df");
lua_remove(state, -2);
lua_setmetatable(state, -2);

@ -69,6 +69,7 @@ namespace DFHack { namespace LuaWrapper {
#define DFHACK_NEW_NAME "DFHack::New"
#define DFHACK_ASSIGN_NAME "DFHack::Assign"
#define DFHACK_DELETE_NAME "DFHack::Delete"
#define DFHACK_EMPTY_TABLE_NAME "DFHack::EmptyTable"
/*
* Upvalue: contents of DFHACK_TYPETABLE_NAME
@ -160,6 +161,8 @@ namespace DFHack { namespace LuaWrapper {
void SaveInTable(lua_State *state, void *node, const char *tname);
void SaveTypeInfo(lua_State *state, void *node);
void AssociateId(lua_State *state, int table, int val, const char *name);
/**
* Look up the key on the stack in DFHACK_TYPETABLE;
* if found, put result on the stack and return true.
@ -178,11 +181,26 @@ namespace DFHack { namespace LuaWrapper {
* Set metatable properties common to all actual DF object references.
*/
void SetPtrMethods(lua_State *state, int meta_idx, int read_idx);
/**
* Add a __pairs/__ipairs metamethod using iterator on the top of stack.
*/
void SetPairsMethod(lua_State *state, int meta_idx, const char *name);
/**
* Add a struct-style (3 upvalues) metamethod to the stack.
*/
void PushStructMethod(lua_State *state, int meta_idx, int ftable_idx,
lua_CFunction function);
/**
* Add a struct-style (3 upvalues) metamethod to the metatable.
*/
void SetStructMethod(lua_State *state, int meta_idx, int ftable_idx,
lua_CFunction function, const char *name);
/**
* Add a 6 upvalue metamethod to the stack.
*/
void PushContainerMethod(lua_State *state, int meta_idx, int ftable_idx,
lua_CFunction function,
type_identity *container, type_identity *item, int count);
/**
* Add a 6 upvalue metamethod to the metatable.
*/
@ -191,7 +209,7 @@ namespace DFHack { namespace LuaWrapper {
type_identity *container, type_identity *item, int count);
/**
* If ienum refers to a valid enum, attach its keys to UPVAL_FIELDTABLE,
* and the enum itself to the _enum metafield.
* and the enum itself to the _enum metafield. Pushes the key table on the stack.
*/
void AttachEnumKeys(lua_State *state, int meta_idx, int ftable_idx, type_identity *ienum);