|
|
|
@ -616,6 +616,16 @@ static int meta_struct_index(lua_State *state)
|
|
|
|
|
if (!field)
|
|
|
|
|
return 1;
|
|
|
|
|
read_field(state, field, ptr + field->offset);
|
|
|
|
|
if (field->mode == struct_field_info::SUBSTRUCT || field->mode == struct_field_info::CONTAINER)
|
|
|
|
|
{
|
|
|
|
|
auto struct_type = (struct_identity*)get_object_identity(state, 1, "read", false);
|
|
|
|
|
if (auto tag_field = find_union_tag(struct_type, field))
|
|
|
|
|
{
|
|
|
|
|
get_object_ref_header(state, -1)->tag_ptr = ptr + tag_field->offset;
|
|
|
|
|
get_object_ref_header(state, -1)->tag_identity = tag_field->type;
|
|
|
|
|
get_object_ref_header(state, -1)->tag_attr = field->extra ? field->extra->union_tag_attr : nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -631,6 +641,16 @@ static int meta_struct_field_reference(lua_State *state)
|
|
|
|
|
if (!field)
|
|
|
|
|
field_error(state, 2, "builtin property or method", "reference");
|
|
|
|
|
field_reference(state, field, ptr + field->offset);
|
|
|
|
|
if (field->mode == struct_field_info::SUBSTRUCT || field->mode == struct_field_info::CONTAINER)
|
|
|
|
|
{
|
|
|
|
|
auto struct_type = (struct_identity*)get_object_identity(state, 1, "reference", false);
|
|
|
|
|
if (auto tag_field = find_union_tag(struct_type, field))
|
|
|
|
|
{
|
|
|
|
|
get_object_ref_header(state, -1)->tag_ptr = ptr + tag_field->offset;
|
|
|
|
|
get_object_ref_header(state, -1)->tag_identity = tag_field->type;
|
|
|
|
|
get_object_ref_header(state, -1)->tag_attr = field->extra ? field->extra->union_tag_attr : nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -679,6 +699,81 @@ static int meta_struct_next(lua_State *state)
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Metamethod: iterator for unions.
|
|
|
|
|
*/
|
|
|
|
|
static int meta_union_next(lua_State *state)
|
|
|
|
|
{
|
|
|
|
|
if (lua_gettop(state) < 2) lua_pushnil(state);
|
|
|
|
|
|
|
|
|
|
int len = lua_rawlen(state, UPVAL_FIELDTABLE);
|
|
|
|
|
int idx = cur_iter_index(state, len+1, 2, 0);
|
|
|
|
|
if (idx == len)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
auto header = get_object_ref_header(state, 1);
|
|
|
|
|
if (header->tag_ptr)
|
|
|
|
|
{
|
|
|
|
|
if (idx != 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
auto enum_id = (enum_identity*)header->tag_identity;
|
|
|
|
|
auto tag_val = *(int64_t*)header->tag_ptr;
|
|
|
|
|
size_t tag_shift = 64 - 8 * enum_id->byte_size();
|
|
|
|
|
tag_val <<= tag_shift;
|
|
|
|
|
tag_val >>= tag_shift;
|
|
|
|
|
|
|
|
|
|
size_t tag_index = tag_val - enum_id->getFirstItem();
|
|
|
|
|
if (auto complex = enum_id->getComplex())
|
|
|
|
|
tag_index = complex->value_index_map.count(tag_val) ? complex->value_index_map.at(tag_val) : size_t(-1);
|
|
|
|
|
|
|
|
|
|
if (tag_index >= size_t(enum_id->getCount()))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
const char *tag_name = nullptr;
|
|
|
|
|
if (header->tag_attr)
|
|
|
|
|
{
|
|
|
|
|
for (auto enum_field = enum_id->getAttrType()->getFields(); enum_field->mode != struct_field_info::END; enum_field++)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp(enum_field->name, header->tag_attr))
|
|
|
|
|
{
|
|
|
|
|
if (enum_field->type == df::identity_traits<const char*>::get())
|
|
|
|
|
{
|
|
|
|
|
auto attrs = ((uint8_t*)enum_id->getAttrs()) + (tag_index * enum_id->getAttrType()->byte_size());
|
|
|
|
|
tag_name = *(const char **)(attrs + enum_field->offset);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tag_name = enum_id->getKeys()[tag_index];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!tag_name)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
lua_getfield(state, UPVAL_FIELDTABLE, tag_name);
|
|
|
|
|
if (lua_isnil(state, lua_gettop(state)))
|
|
|
|
|
{
|
|
|
|
|
lua_pop(state, 1);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lua_pop(state, 1);
|
|
|
|
|
lua_pushstring(state, tag_name);
|
|
|
|
|
lua_getfield(state, 1, tag_name);
|
|
|
|
|
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lua_rawgeti(state, UPVAL_FIELDTABLE, idx+1);
|
|
|
|
|
lua_dup(state);
|
|
|
|
|
lua_gettable(state, 1);
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Field lookup for primitive refs: behave as a quasi-array with numeric indices.
|
|
|
|
|
*/
|
|
|
|
@ -806,6 +901,25 @@ static int check_container_index(lua_State *state, int len,
|
|
|
|
|
return idx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void attach_container_item_tagged_union(lua_State *state, int container, int item, int idx)
|
|
|
|
|
{
|
|
|
|
|
auto header = get_object_ref_header(state, container);
|
|
|
|
|
if (header->tag_ptr)
|
|
|
|
|
{
|
|
|
|
|
// TODO: handle bit vector for tag
|
|
|
|
|
|
|
|
|
|
auto tag_container = (container_identity*)header->tag_identity;
|
|
|
|
|
|
|
|
|
|
auto ref = get_object_ref_header(state, item);
|
|
|
|
|
|
|
|
|
|
// on both msvc and gcc, vectors have the same memory layout
|
|
|
|
|
auto item_type = tag_container->getItemType();
|
|
|
|
|
ref->tag_ptr = (*(uint8_t**)header->tag_ptr) + size_t(idx) * item_type->byte_size();
|
|
|
|
|
ref->tag_identity = item_type;
|
|
|
|
|
ref->tag_attr = header->tag_attr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Metamethod: __index for containers.
|
|
|
|
|
*/
|
|
|
|
@ -820,6 +934,7 @@ static int meta_container_index(lua_State *state)
|
|
|
|
|
int len = id->lua_item_count(state, ptr, container_identity::COUNT_READ);
|
|
|
|
|
int idx = check_container_index(state, len, 2, iidx, "read");
|
|
|
|
|
id->lua_item_read(state, 2, ptr, idx);
|
|
|
|
|
attach_container_item_tagged_union(state, 1, -1, idx);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -837,6 +952,7 @@ static int meta_container_field_reference(lua_State *state)
|
|
|
|
|
int len = id->lua_item_count(state, ptr, container_identity::COUNT_WRITE);
|
|
|
|
|
int idx = check_container_index(state, len, 2, iidx, "reference");
|
|
|
|
|
id->lua_item_reference(state, 2, ptr, idx);
|
|
|
|
|
attach_container_item_tagged_union(state, 1, -1, idx);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -873,6 +989,7 @@ static int meta_container_nexti(lua_State *state)
|
|
|
|
|
|
|
|
|
|
lua_pushinteger(state, idx);
|
|
|
|
|
id->lua_item_read(state, 2, ptr, idx);
|
|
|
|
|
attach_container_item_tagged_union(state, 1, -1, idx);
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1194,7 +1311,6 @@ static void IndexFields(lua_State *state, int base, struct_identity *pstruct, bo
|
|
|
|
|
lua_pop(state, 1);
|
|
|
|
|
|
|
|
|
|
bool add_to_enum = true;
|
|
|
|
|
const struct_field_info *tag_field = nullptr;
|
|
|
|
|
|
|
|
|
|
// Handle the field
|
|
|
|
|
switch (fields[i].mode)
|
|
|
|
@ -1208,16 +1324,11 @@ static void IndexFields(lua_State *state, int base, struct_identity *pstruct, bo
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
case struct_field_info::POINTER:
|
|
|
|
|
// Skip class-typed pointers within unions and other bad pointers
|
|
|
|
|
if ((pstruct->type() == IDTYPE_UNION || (fields[i].count & 2) != 0) && fields[i].type)
|
|
|
|
|
// Skip potentially bad pointers
|
|
|
|
|
if ((fields[i].count & 2) != 0 && fields[i].type)
|
|
|
|
|
add_to_enum = false;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case struct_field_info::SUBSTRUCT:
|
|
|
|
|
case struct_field_info::CONTAINER:
|
|
|
|
|
tag_field = find_union_tag(fields, &fields[i]);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
@ -1229,17 +1340,6 @@ static void IndexFields(lua_State *state, int base, struct_identity *pstruct, bo
|
|
|
|
|
if (add_to_enum)
|
|
|
|
|
AssociateId(state, base+3, ++cnt, name.c_str());
|
|
|
|
|
|
|
|
|
|
if (tag_field)
|
|
|
|
|
{
|
|
|
|
|
// TODO: handle tagged unions
|
|
|
|
|
//
|
|
|
|
|
// tagged unions are treated as if they have at most one field,
|
|
|
|
|
// with the same name as the corresponding enumeration value.
|
|
|
|
|
//
|
|
|
|
|
// if no field's name matches the enumeration value's name,
|
|
|
|
|
// the tagged union is treated as a structure with no fields.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lua_pushlightuserdata(state, (void*)&fields[i]);
|
|
|
|
|
lua_setfield(state, base+2, name.c_str());
|
|
|
|
|
}
|
|
|
|
@ -1275,7 +1375,8 @@ void LuaWrapper::IndexStatics(lua_State *state, int meta_idx, int ftable_idx, st
|
|
|
|
|
* Make a struct-style object metatable.
|
|
|
|
|
*/
|
|
|
|
|
static void MakeFieldMetatable(lua_State *state, struct_identity *pstruct,
|
|
|
|
|
lua_CFunction reader, lua_CFunction writer, bool globals = false)
|
|
|
|
|
lua_CFunction reader, lua_CFunction writer,
|
|
|
|
|
lua_CFunction iterator, bool globals = false)
|
|
|
|
|
{
|
|
|
|
|
int base = lua_gettop(state);
|
|
|
|
|
|
|
|
|
@ -1287,7 +1388,7 @@ static void MakeFieldMetatable(lua_State *state, struct_identity *pstruct,
|
|
|
|
|
IndexFields(state, base, pstruct, globals);
|
|
|
|
|
|
|
|
|
|
// Add the iteration metamethods
|
|
|
|
|
PushStructMethod(state, base+1, base+3, meta_struct_next);
|
|
|
|
|
PushStructMethod(state, base+1, base+3, iterator);
|
|
|
|
|
SetPairsMethod(state, base+1, "__pairs");
|
|
|
|
|
lua_pushnil(state);
|
|
|
|
|
SetPairsMethod(state, base+1, "__ipairs");
|
|
|
|
@ -1434,7 +1535,15 @@ void bitfield_identity::build_metatable(lua_State *state)
|
|
|
|
|
void struct_identity::build_metatable(lua_State *state)
|
|
|
|
|
{
|
|
|
|
|
int base = lua_gettop(state);
|
|
|
|
|
MakeFieldMetatable(state, this, meta_struct_index, meta_struct_newindex);
|
|
|
|
|
MakeFieldMetatable(state, this, meta_struct_index, meta_struct_newindex, meta_struct_next);
|
|
|
|
|
SetStructMethod(state, base+1, base+2, meta_struct_field_reference, "_field");
|
|
|
|
|
SetPtrMethods(state, base+1, base+2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void union_identity::build_metatable(lua_State *state)
|
|
|
|
|
{
|
|
|
|
|
int base = lua_gettop(state);
|
|
|
|
|
MakeFieldMetatable(state, this, meta_struct_index, meta_struct_newindex, meta_union_next);
|
|
|
|
|
SetStructMethod(state, base+1, base+2, meta_struct_field_reference, "_field");
|
|
|
|
|
SetPtrMethods(state, base+1, base+2);
|
|
|
|
|
}
|
|
|
|
@ -1442,7 +1551,7 @@ void struct_identity::build_metatable(lua_State *state)
|
|
|
|
|
void other_vectors_identity::build_metatable(lua_State *state)
|
|
|
|
|
{
|
|
|
|
|
int base = lua_gettop(state);
|
|
|
|
|
MakeFieldMetatable(state, this, meta_struct_index, meta_struct_newindex);
|
|
|
|
|
MakeFieldMetatable(state, this, meta_struct_index, meta_struct_newindex, meta_struct_next);
|
|
|
|
|
|
|
|
|
|
EnableMetaField(state, base+2, "_enum");
|
|
|
|
|
|
|
|
|
@ -1464,7 +1573,7 @@ void other_vectors_identity::build_metatable(lua_State *state)
|
|
|
|
|
void global_identity::build_metatable(lua_State *state)
|
|
|
|
|
{
|
|
|
|
|
int base = lua_gettop(state);
|
|
|
|
|
MakeFieldMetatable(state, this, meta_global_index, meta_global_newindex, true);
|
|
|
|
|
MakeFieldMetatable(state, this, meta_global_index, meta_global_newindex, meta_struct_next, true);
|
|
|
|
|
SetStructMethod(state, base+1, base+2, meta_global_field_reference, "_field");
|
|
|
|
|
SetPtrMethods(state, base+1, base+2);
|
|
|
|
|
}
|
|
|
|
|