---
source: src/main.rs
expression: compiled
input_file: test-data/lua5.4-tests/db.lua
---
local debug = require("debug")
local fn dostring(s) {
return assert(load(s))()
}
print("testing debug library and debug information");
{
local a = 1
}
assert(!debug.gethook());
local testline = 19
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(!pcall(debug.getinfo, 0, ">"));
assert(!debug.getinfo(1000));
assert(!debug.getinfo(-1));
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 == testline && 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(`
local function foo()
end
foo()
A = 1
A = 2
A = 3
`, {
2,
3,
2,
4,
5,
6
});
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=tostring(i) .. v
end
`, {
1,
2,
1,
2,
1,
3
});
test(`for i=1,4 do a=1 end`, {
1,
1,
1,
1
});
{
local a = {
1,
2,
3,
10,
124,
125,
126,
127,
128,
129,
130,
255,
256,
257,
500,
1000
}
local s = `
local b = {10}
a = b[1] X + Y b[1]
b = 4
`
for _, i with ipairs(a) {
local subs = {
X = string.rep("\n", i)
}
for _, j with ipairs(a) {
subs.Y = string.rep("\n", j)
local s = string.gsub(s, "[XY]", subs)
test(s, {
1,
2 + i,
2 + i + j,
2 + i,
2 + i + j,
3 + i + j
});
}
}
}
{
local fn checkactivelines(f, lines) {
local t = debug.getinfo(f, "SL")
for _, l with pairs(lines) {
l = l + t.linedefined
assert(t.activelines[(l)]);
t.activelines[(l)] = undef
}
assert(next(t.activelines) == nil);
}
checkactivelines(fn (...) {
local a = 20
local b = 30
}, {
4,
6,
8
});
checkactivelines(fn (a) {
local a = 20
local b = 30
}, {
3,
4,
6
});
checkactivelines(fn (a, b, ...) {
}, {
0
});
checkactivelines(fn (a, b) {
}, {
1
});
for _, n with pairs({
0,
1,
2,
10,
50,
100,
1000,
10000
}) {
checkactivelines(load(string.format("%s return 1", string.rep("\n", n))), {
n + 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));
assert(debug.getlocal(co, foo, 1) == 'a');
assert(debug.getlocal(co, foo, 2) == 'b');
assert(!debug.getlocal(co, foo, 3));
assert(!debug.getlocal(print, 1));
local fn foo() {
return (debug.getlocal(1, -1))
}
assert(!foo(10));
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, (_soft && 100 || 1000) {
a[(i)] = i
}
foo(table.unpack(a));
a = nil
{
assert(!debug.gethook());
local count = 0
local fn f() {
assert(debug.getinfo(1).namewhat == "hook");
local sndline = string.match(debug.traceback(), "\n(.-)\n")
assert(string.find(sndline, "hook"));
count = count + 1
}
debug.sethook(f, "l");
local a = 0
_ENV.a = a
a = 1
debug.sethook();
assert(count == 4);
}
assert(getmetatable(debug.getregistry()._HOOKKEY).__mode == 'k');
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 == 2 && 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 == "(C temporary)");
local n, v = debug.getlocal(0, 2)
assert(v == 2 && n == "(C 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());
{
assert(!debug.setuservalue(io.stdin, 10));
local a, b = debug.getuservalue(io.stdin, 10)
assert(a == nil && !b);
}
{
local fn f(...) {
return 3, ...
}
local count = 0
local a = {}
for i = 1, 100 {
a[(i)] = i
}
debug.sethook(fn () {
count = count + 1
}, "", 1);
local t = {
table.unpack(a)
}
assert(#t == 100);
t = {
table.unpack(a, 1, 3)
}
assert(#t == 3);
t = {
f(table.unpack(a, 1, 30))
}
assert(#t == 31);
}
local fn collectlocals(level) {
local tab = {}
for i = 1, math.huge {
local n, v = debug.getlocal(level + 1, i)
if !(n && string.find(n, "^[a-zA-Z0-9_]+$")) {
break
}
tab[(n)] = v
}
return tab
}
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 = collectlocals(2)
}, "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());
{
local X = false
local fn foo(a, b, ...) {
{
local x, y, z
}
local c, d = 10, 20
return
}
local fn aux() {
if debug.getinfo(2).name == "foo" {
X = true
local tab = {
a = 100,
b = 200,
c = 10,
d = 20
}
for n, v with pairs(collectlocals(2)) {
assert(tab[(n)] == v);
tab[(n)] = undef
}
assert(next(tab) == nil);
}
}
debug.sethook(aux, "r");
foo(100, 200);
debug.sethook();
assert(X);
}
local fn eqseq(t1, t2) {
assert(#t1 == #t2);
for i = 1, #t1 {
assert(t1[(i)] == t2[(i)]);
}
}
{
print("testing inspection of parameters/returned values");
local on = false
local inp, out
local fn hook(event) {
if !on {
return
}
local ar = debug.getinfo(2, "ruS")
local t = {}
for i = ar.ftransfer, ar.ftransfer + ar.ntransfer - 1 {
local _, v = debug.getlocal(2, i)
t[(#t + 1)] = v
}
if event == "return" {
out = t
} else {
inp = t
}
}
debug.sethook(hook, "cr");
on = true
math.sin(3);
on = false
eqseq(inp, {
3
});
eqseq(out, {
math.sin(3)
});
on = true
select(2, 10, 20, 30, 40);
on = false
eqseq(inp, {
2,
10,
20,
30,
40
});
eqseq(out, {
20,
30,
40
});
local fn foo(a, ...) {
return ...
}
local fn foo1() {
on = !on
return foo(20, 10, 0)
}
foo1();
on = false
eqseq(inp, {
20
});
eqseq(out, {
10,
0
});
debug.sethook();
}
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));
assert(!debug.getupvalue(foo1, 0));
assert(!debug.setupvalue(foo1, 3, "xuxu"));
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);
{
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 = _soft && 3000 || 30000
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"), "'debug.traceback'"));
assert(string.find(debug.traceback("hi", 0), "'debug.traceback'"));
assert(string.find(debug.traceback(), "^stack traceback:\n"));
{
local st, msg = (fn () {
return pcall
})()(debug.traceback)
assert(st == true && string.find(msg, "pcall"));
}
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");
t = debug.getinfo(math.sin)
assert(t.isvararg == true && t.nparams == 0 && t.nups == 0);
t = debug.getinfo(string.gmatch("abc", "a"))
assert(t.isvararg == true && t.nparams == 0 && t.nups > 0);
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)] == undef);
}
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)] = undef
}
assert(next(x.activelines) == nil);
assert(!debug.getinfo(co, 2));
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());
checktraceback(co, {});
co = coroutine.create(fn (x) {
local a, b = coroutine.yield(x)
assert(a == 100 && b == nil);
return x
})
a, b = coroutine.resume(co, 10)
assert(a && b == 10);
a, b = debug.getlocal(co, 1, 1)
assert(a == "x" && b == 10);
assert(!debug.getlocal(co, 1, 5));
assert(debug.setlocal(co, 1, 1, 30) == "x");
assert(!debug.setlocal(co, 1, 5, 40));
a, b = coroutine.resume(co, 100)
assert(a && b == 30);
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 = {
"'coroutine.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,
__mul = f,
__idiv = f,
__unm = f,
__len = f,
__sub = f,
__shl = f,
__shr = f,
__bor = f,
__bxor = f,
__eq = f,
__le = f,
__lt = f,
__unm = f,
__len = f,
__band = f,
__bnot = 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 + 3 == "add" && 3 - a == "sub" && a * 3 == "mul" && -a == "unm" && #a == "len" && a & 3 == "band");
assert(a + 30000 == "add" && a - 3.0 == "sub" && a * 3.0 == "mul" && -a == "unm" && #a == "len" && a & 3 == "band");
assert(a | 3 == "bor" && 3 ~ a == "bxor" && a << 3 == "shl" && a >> 1 == "shr");
assert(a == b && a.op == "eq");
assert(a >= b && a.op == "le");
assert("x" >= a && a.op == "le");
assert(a > b && a.op == "lt");
assert(a > 10 && a.op == "lt");
assert(^^a == "bnot");
{
local fn f() {
assert(debug.getinfo(1).name == "for iterator");
}
for i with f {
}
}
{
local name = nil
setmetatable({}, {
__gc = fn () {
local t = debug.getinfo(1)
assert(t.namewhat == "metamethod");
name = t.name
}
});
loop {
local a = {}
} until name
assert(name == "__gc");
}
{
print("testing traceback sizes");
local fn countlines(s) {
return select(2, string.gsub(s, "\n", ""))
}
local fn deep(lvl, n) {
if lvl == 0 {
return (debug.traceback("message", n))
} else {
return (deep(lvl - 1, n))
}
}
local fn checkdeep(total, start) {
local s = deep(total, start)
local rest = string.match(s, "^message\nstack traceback:\n(.*)$")
local cl = countlines(rest)
assert(cl <= 10 + 11 + 1);
local brk = string.find(rest, "%.%.%.")
if brk {
local rest1 = string.sub(rest, 1, brk)
local rest2 = string.sub(rest, brk, #rest)
assert(countlines(rest1) == 10 && countlines(rest2) == 11);
} else {
assert(cl == total - start + 2);
}
}
for d = 1, 51, 10 {
for l = 1, d {
coroutine.wrap(checkdeep)(d, l);
}
}
}
print("testing debug functions on chunk without debug info");
prog = `-- program to be loaded without debug information (strip)
local debug = require'debug'
local a = 12 -- a local variable
local n, v = debug.getlocal(1, 1)
assert(n == "(temporary)" and v == debug) -- unkown name but known value
n, v = debug.getlocal(1, 2)
assert(n == "(temporary)" and v == 12) -- unkown name but known value
-- a function with an upvalue
local f = function () local x; return a end
n, v = debug.getupvalue(f, 1)
assert(n == "(no name)" and v == 12)
assert(debug.setupvalue(f, 1, 13) == "(no name)")
assert(a == 13)
local t = debug.getinfo(f)
assert(t.name == nil and t.linedefined > 0 and
t.lastlinedefined == t.linedefined and
t.short_src == "?")
assert(debug.getinfo(1).currentline == -1)
t = debug.getinfo(f, "L").activelines
assert(next(t) == nil) -- active lines are empty
-- dump/load a function without debug info
f = load(string.dump(f))
t = debug.getinfo(f)
assert(t.name == nil and t.linedefined > 0 and
t.lastlinedefined == t.linedefined and
t.short_src == "?")
assert(debug.getinfo(1).currentline == -1)
return a
`
local f = assert(load(string.dump(load(prog), true)))
assert(f() == 13);
{
local fn foo() {
local a = 1
local b = 2
return b
}
local s = load(string.dump(foo, true))
local line = true
debug.sethook(fn (e, l) {
assert(e == "line");
line = l
}, "l");
assert(s() == 2);
debug.sethook(nil);
assert(line == nil);
}
{
local prog = `
return function (x)
return function (y)
return x + y
end
end
`
local name = string.rep("x", 1000)
local p = assert(load(prog, name))
local c = string.dump(p)
assert(#c > 1000 && #c < 2000);
local f = assert(load(c))
local g = f()
local h = g(3)
assert(h(5) == 8);
assert(debug.getinfo(f).source == name && debug.getinfo(g).source == name && debug.getinfo(h).source == name);
local c = string.dump(p, true)
assert(#c < 500);
local f = assert(load(c))
local g = f()
local h = g(30)
assert(h(50) == 80);
assert(debug.getinfo(f).source == '=?' && debug.getinfo(g).source == '=?' && debug.getinfo(h).source == '=?');
}
print("OK");