---
source: src/main.rs
expression: compiled
input_file: test-data/lua5.1-tests/closure.lua
---
print("testing closures and coroutines");
local A, B = 0, {
g = 10
}
global fn f(x) {
local a = {}
for i = 1, 1000 {
local y = 0
{
a[(i)] = fn () {
B.g = B.g + 1
y = y + x
return y + A
}
}
}
local dummy = fn () {
return a[(A)]
}
collectgarbage();
A = 1
assert(dummy() == a[(1)]);
A = 0
assert(a[(1)]() == x);
assert(a[(3)]() == x);
collectgarbage();
assert(B.g == 12);
return a
}
a = f(10)
local x = {
1 = {}
}
setmetatable(x, {
__mode = 'kv'
});
while x[(1)] {
local a = A .. A .. A .. A
A = A + 1
}
assert(a[(1)]() == 20 + A);
assert(a[(1)]() == 30 + A);
assert(a[(2)]() == 10 + A);
collectgarbage();
assert(a[(2)]() == 20 + A);
assert(a[(2)]() == 30 + A);
assert(a[(3)]() == 20 + A);
assert(a[(8)]() == 10 + A);
assert(getmetatable(x).__mode == 'kv');
assert(B.g == 19);
a = {}
for i = 1, 10 {
a[(i)] = {
set = fn (x) {
i = x
},
get = fn () {
return i
}
}
if i == 3 {
break
}
}
assert(a[(4)] == nil);
a[(1)].set(10);
assert(a[(2)].get() == 2);
a[(2)].set('a');
assert(a[(3)].get() == 3);
assert(a[(2)].get() == 'a');
a = {}
for i, k with pairs({
'a',
'b'
}) {
a[(i)] = {
set = fn (x, y) {
i = x
k = y
},
get = fn () {
return i, k
}
}
if i == 2 {
break
}
}
a[(1)].set(10, 20);
local r, s = a[(2)].get()
assert(r == 2 && s == 'b');
r, s = a[(1)].get()
assert(r == 10 && s == 20);
a[(2)].set('a', 'b');
r, s = a[(2)].get()
assert(r == "a" && s == "b");
for i = 1, 3 {
f = fn () {
return i
}
break
}
assert(f() == 1);
for k, v with pairs({
"a",
"b"
}) {
f = fn () {
return k, v
}
break
}
assert(({
f()
})[(1)] == 1);
assert(({
f()
})[(2)] == "a");
local b
global fn f(x) {
local first = 1
while 1 {
if x == 3 && !first {
return
}
local a = 'xuxu'
b = fn (op, y) {
if op == 'set' {
a = x + y
} else {
return a
}
}
if x == 1 {
{
break
}
} elseif if x == 2 {
return
} else {
if x != 3 {
error();
}
}
first = nil
}
}
for i = 1, 3 {
f(i);
assert(b('get') == 'xuxu');
b('set', 10);
assert(b('get') == 10 + i);
b = nil
}
pcall(f, 4);
assert(b('get') == 'xuxu');
b('set', 10);
assert(b('get') == 14);
local w
global fn f(x) {
return fn (y) {
return fn (z) {
return w + x + y + z
}
}
}
y = f(10)
w = 1.345
assert(y(20)(30) == 60 + w);
local a = {}
local i = 1
loop {
local x = i
a[(i)] = fn () {
i = x + 1
return x
}
} until i > 10 || a[(i)]() != x
assert(i == 11 && a[(1)]() == 1 && a[(3)]() == 3 && i == 4);
print('+');
local fn t() {
local fn c(a, b) {
assert(a == "test" && b == "OK");
}
local fn v(f, ...) {
c("test", f() != 1 && "FAILED" || "OK");
}
local x = 1
return v(fn () {
return x
})
}
t();
local f
assert(coroutine.running() == nil);
local fn foo(a) {
setfenv(0, a);
coroutine.yield(getfenv());
assert(getfenv(0) == a);
assert(getfenv(1) == _G);
assert(getfenv(loadstring("")) == a);
return getfenv()
}
f = coroutine.wrap(foo)
local a = {}
assert(f(a) == _G);
local a, b = pcall(f)
assert(a && b == _G);
local fn eqtab(t1, t2) {
assert(table.getn(t1) == table.getn(t2));
for i, v with ipairs(t1) {
assert(t2[(i)] == v);
}
}
_G.x = nil
global fn foo(a, ...) {
assert(coroutine.running() == f);
assert(coroutine.status(f) == "running");
local arg = {
...
}
for i = 1, table.getn(arg) {
_G.x = {
coroutine.yield(unpack(arg[(i)]))
}
}
return unpack(a)
}
f = coroutine.create(foo)
assert(type(f) == "thread" && coroutine.status(f) == "suspended");
assert(string.find(tostring(f), "thread"));
local s, a, b, c, d
s, a, b, c, d = coroutine.resume(f, {
1,
2,
3
}, {}, {
1
}, {
'a',
'b',
'c'
})
assert(s && a == nil && coroutine.status(f) == "suspended");
s, a, b, c, d = coroutine.resume(f)
eqtab(_G.x, {});
assert(s && a == 1 && b == nil);
s, a, b, c, d = coroutine.resume(f, 1, 2, 3)
eqtab(_G.x, {
1,
2,
3
});
assert(s && a == 'a' && b == 'b' && c == 'c' && d == nil);
s, a, b, c, d = coroutine.resume(f, "xuxu")
eqtab(_G.x, {
"xuxu"
});
assert(s && a == 1 && b == 2 && c == 3 && d == nil);
assert(coroutine.status(f) == "dead");
s, a = coroutine.resume(f, "xuxu")
assert(!s && string.find(a, "dead") && coroutine.status(f) == "dead");
local fn foo(i) {
return coroutine.yield(i)
}
f = coroutine.wrap(fn () {
for i = 1, 10 {
assert(foo(i) == _G.x);
}
return 'a'
})
for i = 1, 10 {
_G.x = i
assert(f(i) == i);
}
_G.x = 'xuxu'
assert(f('xuxu') == 'a');
global fn pf(n, i) {
coroutine.yield(n);
pf(n * i, i + 1);
}
f = coroutine.wrap(pf)
local s = 1
for i = 1, 10 {
assert(f(1, 1) == s);
s = s * i
}
global fn gen(n) {
return coroutine.wrap(fn () {
for i = 2, n {
coroutine.yield(i);
}
})
}
global fn filter(p, g) {
return coroutine.wrap(fn () {
while 1 {
local n = g()
if n == nil {
return
}
if math.mod(n, p) != 0 {
coroutine.yield(n);
}
}
})
}
local x = gen(100)
local a = {}
while 1 {
local n = x()
if n == nil {
break
}
table.insert(a, n);
x = filter(n, x)
}
assert(table.getn(a) == 25 && a[(table.getn(a))] == 97);
global fn foo() {
assert(debug.getinfo(1).currentline == debug.getinfo(foo).linedefined + 1);
assert(debug.getinfo(2).currentline == debug.getinfo(goo).linedefined);
coroutine.yield(3);
error(foo);
}
global fn goo() {
foo();
}
x = coroutine.wrap(goo)
assert(x() == 3);
local a, b = pcall(x)
assert(!a && b == foo);
x = coroutine.create(goo)
a, b = coroutine.resume(x)
assert(a && b == 3);
a, b = coroutine.resume(x)
assert(!a && b == foo && coroutine.status(x) == "dead");
a, b = coroutine.resume(x)
assert(!a && string.find(b, "dead") && coroutine.status(x) == "dead");
global fn all(a, n, k) {
if k == 0 {
coroutine.yield(a);
} else {
for i = 1, n {
a[(k)] = i
all(a, n, k - 1);
}
}
}
local a = 0
for t with coroutine.wrap(fn () {
all({}, 5, 4);
}) {
a = a + 1
}
assert(a == 5 ^ 4);
local C = {}
setmetatable(C, {
__mode = "kv"
});
local x = coroutine.wrap(fn () {
local a = 10
local fn f() {
a = a + 10
return a
}
while true {
a = a + 1
coroutine.yield(f);
}
})
C[(1)] = x
local f = x()
assert(f() == 21 && x()() == 32 && x() == f);
x = nil
collectgarbage();
assert(C[(1)] == nil);
assert(f() == 43 && f() == 53);
global fn co_func(current_co) {
assert(coroutine.running() == current_co);
assert(coroutine.resume(current_co) == false);
assert(coroutine.resume(current_co) == false);
return 10
}
local co = coroutine.create(co_func)
local a, b = coroutine.resume(co, co)
assert(a == true && b == 10);
assert(coroutine.resume(co, co) == false);
assert(coroutine.resume(co, co) == false);
local x = coroutine.create(fn () {
local a = 10
_G.f = fn () {
a = a + 1
return a
}
error('x');
})
assert(!coroutine.resume(x));
assert(!coroutine.resume(x, 1, 1, 1, 1, 1, 1, 1));
assert(_G.f() == 11);
assert(_G.f() == 12);
if !T {
(Message || print)('\a\n >>> testC not active: skipping yield/hook tests <<<\n\a');
} else {
local turn
global fn fact(t, x) {
assert(turn == t);
if x == 0 {
return 1
} else {
return x * fact(t, x - 1)
}
}
local A, B, a, b = 0, 0, 0, 0
local x = coroutine.create(fn () {
T.setyhook("", 2);
A = fact("A", 10)
})
local y = coroutine.create(fn () {
T.setyhook("", 3);
B = fact("B", 11)
})
while A == 0 || B == 0 {
if A == 0 {
turn = "A"
T.resume(x);
}
if B == 0 {
turn = "B"
T.resume(y);
}
}
assert(B / A == 11);
}
_X = coroutine.wrap(fn () {
local a = 10
local x = fn () {
a = a + 1
}
coroutine.yield();
})
_X();
co = coroutine.create(fn () {
coroutine.yield(getfenv(0));
return loadstring("return a")()
})
a = {
a = 15
}
debug.setfenv(co, a);
assert(debug.getfenv(co) == a);
assert(select(2, coroutine.resume(co)) == a);
assert(select(2, coroutine.resume(co)) == a.a);
print('OK');