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