---
source: src/main.rs
expression: compiled
input_file: test-data/lua5.2-tests/db.lua
---
debug = require("debug")
local fn dostring(s) {
return assert(load(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");
load(s)();
debug.sethook();
assert(#l == 0);
}
{
assert(!pcall(debug.getinfo, print, "X"));
assert(debug.getinfo(1000) == nil);
assert(debug.getinfo(-1) == nil);
local a = debug.getinfo(print)
assert(a.what == "C" && a.short_src == "[C]");
a = debug.getinfo(print, "L")
assert(a.activelines == nil);
local b = debug.getinfo(test, "SfL")
assert(b.name == nil && b.what == "Lua" && b.linedefined == 13 && 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 load(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(a .. string.format("; %s=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,
3,
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
`, {
1,
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,
3,
6
});
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('+');
assert(!pcall(debug.getlocal, 20, 1));
assert(!pcall(debug.setlocal, -1, 1, 10));
local fn foo(a, b, ...) {
local d, e
}
local co = coroutine.create(foo)
assert(debug.getlocal(foo, 1) == 'a');
assert(debug.getlocal(foo, 2) == 'b');
assert(debug.getlocal(foo, 3) == nil);
assert(debug.getlocal(co, foo, 1) == 'a');
assert(debug.getlocal(co, foo, 2) == 'b');
assert(debug.getlocal(co, foo, 3) == nil);
assert(debug.getlocal(print, 1) == nil);
local fn foo(a, ...) {
local t = table.pack(...)
for i = 1, t.n {
local n, v = debug.getlocal(1, -i)
assert(n == "(*vararg)" && v == t[(i)]);
}
assert(!debug.getlocal(1, -(t.n + 1)));
assert(!debug.setlocal(1, -(t.n + 1), 30));
if t.n > 0 {
(fn (x) {
assert(debug.setlocal(2, -1, x) == "(*vararg)");
assert(debug.setlocal(2, -t.n, x) == "(*vararg)");
})(430);
assert(... == 430);
}
}
foo();
foo(print);
foo(200, 3, 4);
local a = {}
for i = 1, 1000 {
a[(i)] = i
}
foo(table.unpack(a));
a = nil
local fn foo() {
return debug.getlocal(1, -1)
}
assert(foo(10) == nil);
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 == 1 && 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 arg = {
...
}
{
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 arg = {
...
}
local c = 13
}
debug.sethook(fn (e) {
assert(e == "call");
dostring("XX = 12");
assert(!pcall(load("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.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(string.gmatch("x", "x"), 1) == "");
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);
if !_no32 {
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");
assert(debug.getinfo(1, "t").istailcall == true);
local tail = debug.getinfo(2)
assert(tail.func == g1 && tail.istailcall == true);
assert(debug.getinfo(3, "S").what == "main");
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",
"tail call",
"call",
"tail call",
"return",
"return",
"call"
}
for i = 1, #res {
assert(res[(i)] == table.remove(b, 1));
}
b = 0
debug.sethook(fn (e) {
if e == "tail call" {
b = b + 1
assert(debug.getinfo(2, "t").istailcall == true);
} else {
assert(debug.getinfo(2, "t").istailcall == false);
}
}, "c");
h(false);
debug.sethook();
assert(b == 2);
lim = 30000
if _soft {
limit = 3000
}
local fn foo(x) {
if x == 0 {
assert(debug.getinfo(2).what == "main");
local info = debug.getinfo(1)
assert(info.istailcall == true && info.func == foo);
} else {
return foo(x - 1)
}
}
foo(lim);
print("+");
co = load([[
local A = function ()
return x
end
return
]])
local a = 0
debug.sethook(fn (e, l) {
if l == 3 {
a = a + 1
assert(debug.getlocal(2, 1) == "(*temporary)");
} elseif if l == 4 {
a = a + 1
assert(debug.getlocal(2, 1) == "A");
}
}, "l");
co();
debug.sethook();
assert(a == 2);
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 t = debug.getinfo(print, "u")
assert(t.isvararg == true && t.nparams == 0 && t.nups == 0);
t = debug.getinfo(fn (a, b, c) {
}, "u")
assert(t.isvararg == false && t.nparams == 3 && t.nups == 0);
t = debug.getinfo(fn (a, b, ...) {
return t[(a)]
}, "u")
assert(t.isvararg == true && t.nparams == 2 && t.nups == 1);
t = debug.getinfo(1)
assert(t.isvararg == true && t.nparams == 0 && t.nups == 1 && debug.getupvalue(t.func, 1) == "_ENV");
local fn checktraceback(co, p, level) {
local tb = debug.traceback(co, nil, level)
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 {
f(n - 1);
} else {
coroutine.yield();
}
}
local co = coroutine.create(f)
coroutine.resume(co, 3);
checktraceback(co, {
"yield",
"db.lua",
"db.lua",
"db.lua",
"db.lua"
});
checktraceback(co, {
"db.lua",
"db.lua",
"db.lua",
"db.lua"
}, 1);
checktraceback(co, {
"db.lua",
"db.lua",
"db.lua"
}, 2);
checktraceback(co, {
"db.lua"
}, 4);
checktraceback(co, {}, 40);
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) {
if l {
table.insert(tr, l);
}
}
debug.sethook(co, foo, "lcr");
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(#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(#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");
local a = {}
local fn f(t) {
local info = debug.getinfo(1)
assert(info.namewhat == "metamethod");
a.op = info.name
return info.name
}
setmetatable(a, {
__index = f,
__add = f,
__div = f,
__mod = f,
__concat = f,
__pow = f,
__eq = f,
__le = f,
__lt = f
});
local b = setmetatable({}, getmetatable(a))
assert(a[(3)] == "__index" && a ^ 3 == "__pow" && a .. a == "__concat");
assert(a / 3 == "__div" && 3 % a == "__mod");
assert(a == b && a.op == "__eq");
assert(a >= b && a.op == "__le");
assert(a > b && a.op == "__lt");
print("OK");