--- source: src/main.rs expression: compiled input_file: test-data/lua5.1-tests/db.lua --- local fn dostring(s) { return assert(loadstring(s))() } print("testing debug library and debug information"); { local a = 1 } global fn test(s, l, p) { collectgarbage(); local fn f(event, line) { assert(event == 'line'); local l = table.remove(l, 1) if p { print(l, line); } assert(l == line, "wrong trace!!"); } debug.sethook(f, "l"); loadstring(s)(); debug.sethook(); assert(table.getn(l) == 0); } { local a = debug.getinfo(print) assert(a.what == "C" && a.short_src == "[C]"); local b = debug.getinfo(test, "SfL") assert(b.name == nil && b.what == "Lua" && b.linedefined == 11 && b.lastlinedefined == b.linedefined + 10 && b.func == test && !string.find(b.short_src, "%[")); assert(b.activelines[(b.linedefined + 1)] && b.activelines[(b.lastlinedefined)]); assert(!b.activelines[(b.linedefined)] && !b.activelines[(b.lastlinedefined + 1)]); } a = "function f () end" local fn dostring(s, x) { return loadstring(s, x)() } dostring(a); assert(debug.getinfo(f).short_src == string.format('[string "%s"]', a)); dostring(a .. string.format("; %s\n=1", string.rep('p', 400))); assert(string.find(debug.getinfo(f).short_src, '^%[string [^\n]*%.%.%."%]$')); dostring("\n" .. a); assert(debug.getinfo(f).short_src == '[string "..."]'); dostring(a, ""); assert(debug.getinfo(f).short_src == '[string ""]'); dostring(a, "@xuxu"); assert(debug.getinfo(f).short_src == "xuxu"); dostring(a, "@" .. string.rep('p', 1000) .. 't'); assert(string.find(debug.getinfo(f).short_src, "^%.%.%.p*t$")); dostring(a, "=xuxu"); assert(debug.getinfo(f).short_src == "xuxu"); dostring(a, string.format("=%s", string.rep('x', 500))); assert(string.find(debug.getinfo(f).short_src, "^x*")); dostring(a, "="); assert(debug.getinfo(f).short_src == ""); a = nil f = nil loop { local g = { x = fn () { local a = debug.getinfo(2) assert(a.name == 'f' && a.namewhat == 'local'); a = debug.getinfo(1) assert(a.name == 'x' && a.namewhat == 'field'); return 'xixi' } } local f = fn () { return 1 + 1 && (!1 || g.x()) } assert(f() == 'xixi'); g = debug.getinfo(f) assert(g.what == "Lua" && g.func == f && g.namewhat == "" && !g.name); global fn f(x, name) { name = name || 'f' local a = debug.getinfo(1) assert(a.name == name && a.namewhat == 'local'); return x } if 3 > 4 { break } f(); if 3 < 4 { a = 1 } else { break } f(); while 1 { local x = 10 break } f(); local b = 1 if 3 > 4 { return math.sin(1) } f(); a = 3 < 4 f(); a = 3 < 4 || 1 f(); loop { local x = 20 if 4 > 3 { f(); } else { break } f(); } until 1 g = {} f(g).x = f(2) && f(10) + f(9) assert(g.x == f(19)); global fn g(x) { if !x { return 3 } return (x('a', 'x')) } assert(g(f) == 'a'); } until 1 test(`if math.sin(1) then a=1 else a=2 end `, { 2, 4, 7 }); test(`-- if nil then a=1 else a=2 end `, { 2, 5, 6 }); test(`a=1 repeat a=a+1 until a==3 `, { 1, 3, 4, 3, 4 }); test(` do return end `, { 2 }); test(`local a a=1 while a<=3 do a=a+1 end `, { 2, 3, 4, 3, 4, 3, 4, 3, 5 }); test(`while math.sin(1) do if math.sin(1) then break end end a=1`, { 1, 2, 4, 7 }); test(`for i=1,3 do a=i end `, { 1, 2, 1, 2, 1, 2, 1, 3 }); test(`for i,v in pairs{'a','b'} do a=i..v end `, { 1, 2, 1, 2, 1, 3 }); test(`for i=1,4 do a=1 end`, { 1, 1, 1, 1, 1 }); print('+'); a = {} L = nil local glob = 1 local oldglob = glob debug.sethook(fn (e, l) { collectgarbage(); local f, m, c = debug.gethook() assert(m == 'crl' && c == 0); if e == "line" { if glob != oldglob { L = l - 1 oldglob = glob } } elseif if e == "call" { local f = debug.getinfo(2, "f").func a[(f)] = 1 } else { assert(e == "return"); } }, "crl"); global fn f(a, b) { collectgarbage(); local _, x = debug.getlocal(1, 1) local _, y = debug.getlocal(1, 2) assert(x == a && y == b); assert(debug.setlocal(2, 3, "pera") == "AA" .. "AA"); assert(debug.setlocal(2, 4, "ma��") == "B"); x = debug.getinfo(2) assert(x.func == g && x.what == "Lua" && x.name == 'g' && x.nups == 0 && string.find(x.source, "^@.*db%.lua")); glob = glob + 1 assert(debug.getinfo(1, "l").currentline == L + 1); assert(debug.getinfo(1, "l").currentline == L + 2); } global fn foo() { glob = glob + 1 assert(debug.getinfo(1, "l").currentline == L + 1); } foo(); _ = 'alo\ alo' .. ` ` assert(debug.getinfo(1, "l").currentline == L + 11); global fn g(...) { { local a, b, c a = math.sin(40) } local feijao local AAAA, B = "xuxu", "mam�o" f(AAAA, B); assert(AAAA == "pera" && B == "ma��"); { local B = 13 local x, y = debug.getlocal(1, 5) assert(x == 'B' && y == 13); } } g(); assert(a[(f)] && a[(g)] && a[(assert)] && a[(debug.getlocal)] && !a[(print)]); local n, v = debug.getlocal(0, 1) assert(v == 0 && n == "(*temporary)"); local n, v = debug.getlocal(0, 2) assert(v == 2 && n == "(*temporary)"); assert(!debug.getlocal(0, 3)); assert(!debug.getlocal(0, 0)); global fn f() { assert(select(2, debug.getlocal(2, 3)) == 1); assert(!debug.getlocal(2, 4)); debug.setlocal(2, 3, 10); return 20 } global fn g(a, b) { return (a + 1) + f() } assert(g(0, 0) == 30); debug.sethook(nil); assert(debug.gethook() == nil); X = nil a = {} method a::f(a, b, ...) { local c = 13 } debug.sethook(fn (e) { assert(e == "call"); dostring("XX = 12"); assert(!pcall(loadstring("a='joao'+1"))); debug.sethook(fn (e, l) { assert(debug.getinfo(2, "l").currentline == l); local f, m, c = debug.gethook() assert(e == "line"); assert(m == 'l' && c == 0); debug.sethook(nil); assert(!X); X = {} local i = 1 local x, y while 1 { x, y = debug.getlocal(2, i) if x == nil { break } X[(x)] = y i = i + 1 } }, "l"); }, "c"); a::f(1, 2, 3, 4, 5); assert(X.self == a && X.a == 1 && X.b == 2 && X.arg.n == 3 && X.c == nil); assert(XX == 12); assert(debug.gethook() == nil); local fn getupvalues(f) { local t = {} local i = 1 while true { local name, value = debug.getupvalue(f, i) if !name { break } assert(!t[(name)]); t[(name)] = value i = i + 1 } return t } local a, b, c = 1, 2, 3 local fn foo1(a) { b = a return c } local fn foo2(x) { a = x return c + b } assert(debug.getupvalue(foo1, 3) == nil); assert(debug.getupvalue(foo1, 0) == nil); assert(debug.setupvalue(foo1, 3, "xuxu") == nil); local t = getupvalues(foo1) assert(t.a == nil && t.b == 2 && t.c == 3); t = getupvalues(foo2) assert(t.a == 1 && t.b == 2 && t.c == 3); assert(debug.setupvalue(foo1, 1, "xuxu") == "b"); assert(({ debug.getupvalue(foo2, 3) })[(2)] == "xuxu"); assert(debug.getupvalue(io.read, 1) == nil); assert(debug.setupvalue(io.read, 1, 10) == nil); local a = 0 debug.sethook(fn (e) { a = a + 1 }, "", 1); a = 0 for i = 1, 1000 { } assert(1000 < a && a < 1012); debug.sethook(fn (e) { a = a + 1 }, "", 4); a = 0 for i = 1, 1000 { } assert(250 < a && a < 255); local f, m, c = debug.gethook() assert(m == "" && c == 4); debug.sethook(fn (e) { a = a + 1 }, "", 4000); a = 0 for i = 1, 1000 { } assert(a == 0); debug.sethook(print, "", 2 ^ 24 - 1); local f, m, c = debug.gethook() assert(({ debug.gethook() })[(3)] == 2 ^ 24 - 1); debug.sethook(); local fn f(x) { if x { assert(debug.getinfo(1, "S").what == "Lua"); local tail = debug.getinfo(2) assert(!pcall(getfenv, 3)); assert(tail.what == "tail" && tail.short_src == "(tail call)" && tail.linedefined == -1 && tail.func == nil); assert(debug.getinfo(3, "f").func == g1); assert(getfenv(3)); assert(debug.getinfo(4, "S").what == "tail"); assert(!pcall(getfenv, 5)); assert(debug.getinfo(5, "S").what == "main"); assert(getfenv(5)); print("+"); } } global fn g(x) { return f(x) } global fn g1(x) { g(x); } local fn h(x) { local f = g1 return f(x) } h(true); local b = {} debug.sethook(fn (e) { table.insert(b, e); }, "cr"); h(false); debug.sethook(); local res = { "return", "call", "call", "call", "call", "return", "tail return", "return", "tail return", "call" } for _, k with ipairs(res) { assert(k == table.remove(b, 1)); } lim = 30000 local fn foo(x) { if x == 0 { assert(debug.getinfo(lim + 2).what == "main"); for i = 2, lim { assert(debug.getinfo(i, "S").what == "tail"); } } else { return foo(x - 1) } } foo(lim); print("+"); assert(debug.traceback(print) == print); assert(debug.traceback(print, 4) == print); assert(string.find(debug.traceback("hi", 4), "^hi\n")); assert(string.find(debug.traceback("hi"), "^hi\n")); assert(!string.find(debug.traceback("hi"), "'traceback'")); assert(string.find(debug.traceback("hi", 0), "'traceback'")); assert(string.find(debug.traceback(), "^stack traceback:\n")); local fn checktraceback(co, p) { local tb = debug.traceback(co) local i = 0 for l with string.gmatch(tb, "[^\n]+\n?") { assert(i == 0 || string.find(l, p[(i)])); i = i + 1 } assert(p[(i)] == nil); } local fn f(n) { if n > 0 { return f(n - 1) } else { coroutine.yield(); } } local co = coroutine.create(f) coroutine.resume(co, 3); checktraceback(co, { "yield", "db.lua", "tail", "tail", "tail" }); co = coroutine.create(fn (x) { local a = 1 coroutine.yield(debug.getinfo(1, "l")); coroutine.yield(debug.getinfo(1, "l").currentline); return a }) local tr = {} local foo = fn (e, l) { table.insert(tr, l); } debug.sethook(co, foo, "l"); local _, l = coroutine.resume(co, 10) local x = debug.getinfo(co, 1, "lfLS") assert(x.currentline == l.currentline && x.activelines[(x.currentline)]); assert(type(x.func) == "function"); for i = x.linedefined + 1, x.lastlinedefined { assert(x.activelines[(i)]); x.activelines[(i)] = nil } assert(next(x.activelines) == nil); assert(debug.getinfo(co, 2) == nil); local a, b = debug.getlocal(co, 1, 1) assert(a == "x" && b == 10); a, b = debug.getlocal(co, 1, 2) assert(a == "a" && b == 1); debug.setlocal(co, 1, 2, "hi"); assert(debug.gethook(co) == foo); assert(table.getn(tr) == 2 && tr[(1)] == l.currentline - 1 && tr[(2)] == l.currentline); a, b, c = pcall(coroutine.resume, co) assert(a && b && c == l.currentline + 1); checktraceback(co, { "yield", "in function <" }); a, b = coroutine.resume(co) assert(a && b == "hi"); assert(table.getn(tr) == 4 && tr[(4)] == l.currentline + 2); assert(debug.gethook(co) == foo); assert(debug.gethook() == nil); checktraceback(co, {}); global fn f(i) { if i == 0 { error(i); } else { coroutine.yield(); f(i - 1); } } co = coroutine.create(fn (x) { f(x); }) a, b = coroutine.resume(co, 3) t = { "'yield'", "'f'", "in function <" } while coroutine.status(co) == "suspended" { checktraceback(co, t); a, b = coroutine.resume(co) table.insert(t, 2, "'f'"); } t[(1)] = "'error'" checktraceback(co, t); local fn g(x) { coroutine.yield(x); } local fn f(i) { debug.sethook(fn () { }, "l"); for j = 1, 1000 { g(i + j); } } local co = coroutine.wrap(f) co(10); pcall(co); pcall(co); assert(type(debug.getregistry()) == "table"); print("OK");