Added support for unpack() in lua 5.3, fixed a bug in tostring, and

added is_instance().
This commit is contained in:
Bruce Hill 2018-02-11 13:41:37 -08:00
parent 1b43ee552b
commit 96e1d36f37
2 changed files with 70 additions and 12 deletions

View File

@ -201,6 +201,17 @@ static int Lfrom_table(lua_State *L)
return 1;
}
static int Lis_instance(lua_State *L)
{
if (lua_type(L, 2) != LUA_TUSERDATA) {
lua_pushboolean(L, 0);
return 1;
}
lua_getmetatable(L, 2);
lua_pushboolean(L, lua_rawequal(L, -1, 1));
return 1;
}
static int Llen(lua_State *L)
{
if (! lua_getmetatable(L, 1)) {
@ -225,7 +236,7 @@ static int Lindex(lua_State *L)
// Stack: [mt, indices, k]
lua_gettable(L, -2);
// Stack: [mt, indices, i]
if (! lua_isnil(L, -1)) {
if (! lua_isnil(L, -1)) { // Found the field name
// Stack: [mt, indices, i]
lua_getfield(L, -3, "__instances");
// Stack: [mt, indices, i, buckets]
@ -241,15 +252,43 @@ static int Lindex(lua_State *L)
// Stack: [mt, indices, i, buckets, bucket, inst_table]
lua_rawgeti(L, -1, lua_tointeger(L, -4));
return 1;
} else if (lua_type(L, 2) == LUA_TNUMBER) {
lua_pop(L, 2);
// Stack: [mt]
lua_getfield(L, -1, "__instances");
// Stack: [mt, buckets]
lua_Integer* hash_address = (lua_Integer*)lua_touserdata(L, 1);
if (! hash_address) {
luaL_error(L, "invalid type");
}
lua_rawgeti(L, -1, *hash_address);
// Stack: [mt, buckets, bucket]
lua_pushvalue(L, 1);
// Stack: [mt, buckets, bucket, inst_udata]
lua_rawget(L, -2);
// Stack: [mt, buckets, bucket, inst_table]
lua_rawgeti(L, -1, lua_tointeger(L, 2));
if (! lua_isnil(L, -1)) {
// Found numeric index
return 1;
} else {
// Fall back to class
// Stack: [mt, buckets, bucket, inst_table, v, k]
lua_pushvalue(L, 2);
// Stack: [mt, key]
lua_gettable(L, -6);
return 1;
}
} else {
// Fall back to class:
// Stack: [mt, indices, i]
lua_pop(L, 2);
// Stack: [mt]
lua_pushvalue(L, 2);
// Stack: [mt, key]
lua_gettable(L, -2);
return 1;
}
// Fall back to class:
// Stack: [mt, indices, i]
lua_pop(L, 2);
// Stack: [mt]
lua_pushvalue(L, 2);
// Stack: [mt, key]
lua_gettable(L, -2);
return 1;
}
static int Ltostring(lua_State *L)
@ -284,7 +323,7 @@ static int Ltostring(lua_State *L)
// Stack: [mt, buckets, bucket, inst_table]
lua_getglobal(L, "tostring");
// Stack: [mt, buckets, bucket, inst_table, tostring]
lua_getfield(L, -4, "__fields");
lua_getfield(L, -5, "__fields");
// Stack: [mt, buckets, bucket, inst_table, tostring, fields]
lua_pushnil(L);
@ -300,15 +339,20 @@ static int Ltostring(lua_State *L)
lua_pushvalue(L, -4);
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, i, fieldname, tostring]
lua_insert(L, -2);
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, i, tostring, fieldname]
lua_call(L, 1, 1);
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, i, field string]
luaL_addvalue(&b);
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, i]
luaL_addstring(&b, "=");
lua_rawgeti(L, -3, lua_tonumber(L, -1));
lua_rawgeti(L, -4, lua_tonumber(L, -1));
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, i, value]
lua_pushvalue(L, -4);
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, i, value, tostring]
lua_insert(L, -2);
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, i, tostring, value]
lua_call(L, 1, 1);
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, i, value string]
luaL_addvalue(&b);
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, i]
}
@ -411,6 +455,7 @@ static const luaL_Reg R[] =
{ "__ipairs", Lipairs},
{ "__pairs", Lpairs},
{ "from_table", Lfrom_table},
{ "is_instance", Lis_instance},
{ NULL, NULL}
};

View File

@ -140,7 +140,7 @@ test("Testing stupid metamethods", function()
end)
test("Testing similar class", function()
local FooVec = immutable({"x","y"}, {
FooVec = immutable({"x","y"}, {
len2=function(self)
return self.x*self.x + self.y*self.y
end,
@ -155,6 +155,12 @@ test("Testing similar class", function()
assert(FooVec(1,1) ~= Vec(1,1))
end)
test("Testing is_instance", function()
fv = FooVec(1,2)
assert(FooVec:is_instance(fv))
assert(not FooVec:is_instance(v))
end)
test("Testing spoofing", function()
local t = {99,100}
setmetatable(t, Vec)
@ -163,6 +169,13 @@ test("Testing spoofing", function()
assert(not pcall(function() return Vec.__tostring(t) end))
end)
test("Testing unpacking", function()
if table.unpack then
local a, b = table.unpack(Vec(5,6))
assert(a == 5 and b == 6)
end
end)
if num_errors == 0 then
print(green.."All tests passed!"..reset)
else