Fix for tostring relying on stack indices, and some general cleanup.

This commit is contained in:
Bruce Hill 2018-02-12 20:44:18 -08:00
parent da4dbf89c2
commit 565250d326
2 changed files with 44 additions and 23 deletions

View File

@ -19,8 +19,6 @@
// The C API changed from 5.1 to 5.2, so these shims help the code compile on >=5.2
#if LUA_VERSION_NUM >= 502
#define lua_objlen(L, i) lua_rawlen(L, i)
#define lua_equal(L, i, j) lua_compare(L, i, j, LUA_OPEQ)
#define luaH_getnum(t, k) luaH_getint(t, k)
#define luaL_register(L, _, R) luaL_setfuncs(L, R, 0)
#endif
@ -182,6 +180,10 @@ static int Lfrom_table(lua_State *L)
lua_pushvalue(L, 1);
// Stack: [mt]
lua_getfield(L, -1, "__fields");
int n = lua_objlen(L, -1);
if (! lua_checkstack(L, n)) {
luaL_error(L, "Insufficient stack space!");
}
// Stack: [mt, fields]
lua_pushnil(L);
int num_args = 0;
@ -323,47 +325,50 @@ static int Ltostring(lua_State *L)
lua_pushvalue(L, 1);
// Stack: [mt, buckets, bucket, inst_udata]
lua_rawget(L, -2);
int inst_table_index = lua_absindex(L, -1);
// Stack: [mt, buckets, bucket, inst_table]
lua_getglobal(L, "tostring");
// Stack: [mt, buckets, bucket, inst_table, tostring]
int tostring_index = lua_absindex(L, -1);
lua_getfield(L, -5, "__fields");
// Stack: [mt, buckets, bucket, inst_table, tostring, fields]
int num_fields = lua_objlen(L, -1);
int fields_index = lua_absindex(L, -1);
lua_pushnil(L);
int needs_comma = 0;
int numeric_index = 1;
while (lua_next(L, -2) != 0) {
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, i, fieldname]
for (int i = 1; i <= num_fields; i++) {
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, ...]
if (needs_comma) {
luaL_addstring(&b, ", ");
} else {
needs_comma = 1;
}
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, i, fieldname]
if (lua_type(L, -1) == LUA_TNUMBER && lua_tointeger(L, -1) == numeric_index) {
lua_rawgeti(L, fields_index, i);
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, ..., fieldname]
if (lua_type(L, -1) == LUA_TNUMBER && lua_tointeger(L, -1) == i) {
lua_pop(L, 1);
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, ...]
} else {
lua_pushvalue(L, -4);
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, i, fieldname, tostring]
lua_pushvalue(L, tostring_index);
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, ..., fieldname, tostring]
lua_insert(L, -2);
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, i, tostring, fieldname]
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, ..., tostring, fieldname]
lua_call(L, 1, 1);
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, i, field string]
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, ..., field string]
luaL_addvalue(&b);
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, i]
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, ...]
luaL_addstring(&b, "=");
}
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_rawgeti(L, inst_table_index, i);
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, ..., value]
lua_pushvalue(L, tostring_index);
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, ..., value, tostring]
lua_insert(L, -2);
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, i, tostring, value]
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, ..., tostring, value]
lua_call(L, 1, 1);
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, i, value string]
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, ..., value string]
luaL_addvalue(&b);
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, i]
numeric_index++;
// Stack: [mt, buckets, bucket, inst_table, tostring, fields, ...]
}
luaL_addstring(&b, ")");
luaL_pushresult(&b);

View File

@ -26,13 +26,13 @@ local function test(description, fn)
io.write(red)
local ok, err = pcall(fn)
if not ok then
io.write(reset..dim.."\r..................................")
io.write(reset..dim.."\r....................................")
io.write(reset.."["..bright..red.."FAILED"..reset.."]\r")
io.write("\r"..description.."\n"..reset)
print(reset..red..(err or "")..reset)
num_errors = num_errors + 1
else
io.write(reset..dim.."\r..................................")
io.write(reset..dim.."\r....................................")
io.write(reset.."["..green.."PASSED"..reset.."]\r")
io.write(description.."\n")
end
@ -218,6 +218,22 @@ test("Testing tostring(class)", function()
assert(tostring(C2):match("immutable type: 0x.*"))
end)
test("Testing tuple tostring", function()
local tup3 = immutable(3)
assert(tostring(tup3(1,2,3)) == "(1, 2, 3)")
assert(tostring(tup3(1,tup3(2,3,4),5)) == "(1, (2, 3, 4), 5)")
end)
test("Testing giant immutable table", function()
local keys = {}
local N = 100000
for i=1,N do keys[i] = "key_"..tostring(i) end
local T = immutable(keys)
local values = {}
for i,key in ipairs(keys) do values[key] = i*i end
assert(T:from_table(values))
end)
if num_errors == 0 then
print(green.."All tests passed!"..reset)
else