---
source: src/main.rs
expression: compiled
input_file: test-data/lua5.4-tests/nextvar.lua
---
print('testing tables, next, and for');
local fn checkerror(msg, f, ...) {
local s, err = pcall(f, ...)
assert(!s && string.find(err, msg));
}
local a = {}
for i = 1, 100 {
a[(i .. "+")] = true
}
for i = 1, 100 {
a[(i .. "+")] = undef
}
for i = 1, 100 {
a[(i)] = true
assert(#a == i);
}
local x = 0
for k, v with ipairs({
10,
20,
30,
x = 12
}) {
x = x + 1
assert(k == x && v == x * 10);
}
for _ with ipairs({
x = 12,
y = 24
}) {
assert(nil);
}
x = false
local i = 0
for k, v with ipairs({
true,
false,
true,
false
}) {
i = i + 1
x = !x
assert(x == v);
}
assert(i == 4);
assert(type(ipairs({})) == 'function' && ipairs({}) == ipairs({}));
{
local f = ipairs({})
local k, v = f({
math.mininteger = 10
}, math.maxinteger)
assert(k == math.mininteger && v == 10);
k, v = f({
math.mininteger = 10
}, k)
assert(k == nil);
}
if !T {
(Message || print)('\n >>> testC not active: skipping tests for table sizes <<<\n');
} else {
local fn mp2(n) {
local mp = 2 ^ math.ceil(math.log(n, 2))
assert(n == 0 || (mp / 2 < n && n <= mp));
return mp
}
local fn check(t, na, nh) {
local a, h = T.querytab(t)
if a != na || h != nh {
print(na, nh, a, h);
assert(nil);
}
}
{
local s = 0
for _ with pairs(math) {
s = s + 1
}
check(math, 0, mp2(s));
}
local sizes = {
0,
1,
2,
3,
4,
5,
7,
8,
9,
15,
16,
17,
30,
31,
32,
33,
34,
254,
255,
256,
500,
1000
}
for _, sa with ipairs(sizes) {
local arr = {
"return {"
}
for i = 1, sa {
arr[(1 + i)] = "1,"
}
for _, sh with ipairs(sizes) {
for j = 1, sh {
arr[(1 + sa + j)] = string.format('k%x=%d,', j, j)
}
arr[(1 + sa + sh + 1)] = "}"
local prog = table.concat(arr)
local f = assert(load(prog))
collectgarbage("stop");
f();
if sa == 0 || sh == 0 {
T.alloccount(2);
} else {
T.alloccount(3);
}
local t = f()
T.alloccount();
collectgarbage("restart");
assert(#t == sa);
check(t, sa, mp2(sh));
}
}
local a = {}
for i = 1, sizes[(#sizes)] {
a[(i)] = i
}
for k with ipairs(sizes) {
local t = {
table.unpack(a, 1, k)
}
assert(#t == k);
check(t, k, 0);
t = {
1,
2,
3,
table.unpack(a, 1, k)
}
check(t, k + 3, 0);
assert(#t == k + 3);
}
local lim = 130
local a = {}
a[(2)] = 1
check(a, 0, 1);
a = {}
a[(0)] = 1
check(a, 0, 1);
a[(2)] = 1
check(a, 0, 2);
a = {}
a[(0)] = 1
a[(1)] = 1
check(a, 1, 1);
a = {}
for i = 1, lim {
a[(i)] = 1
assert(#a == i);
check(a, mp2(i), 0);
}
a = {}
for i = 1, lim {
a[('a' .. i)] = 1
assert(#a == 0);
check(a, 0, mp2(i));
}
a = {}
for i = 1, 16 {
a[(i)] = i
}
check(a, 16, 0);
{
for i = 1, 11 {
a[(i)] = undef
}
for i = 30, 50 {
a[(i)] = true
a[(i)] = undef
}
check(a, 0, 8);
a[(10)] = 1
for i = 30, 50 {
a[(i)] = true
a[(i)] = undef
}
check(a, 0, 8);
for i = 1, 14 {
a[(i)] = true
a[(i)] = undef
}
for i = 18, 50 {
a[(i)] = true
a[(i)] = undef
}
check(a, 0, 4);
}
for i = 1, lim {
local a = {}
for i = i, 1, -1 {
a[(i)] = i
}
check(a, mp2(i), 0);
}
lim = 35
global fn foo(n, ...) {
local arg = {
...
}
check(arg, n, 0);
assert(select('#', ...) == n);
arg[(n + 1)] = true
check(arg, mp2(n + 1), 0);
arg.x = true
check(arg, mp2(n + 1), 1);
}
local a = {}
for i = 1, lim {
a[(i)] = true
foo(i, table.unpack(a));
}
local a = {}
for i = 1, 64 {
a[(i)] = true
}
for i = 1, 64 {
a[(i)] = nil
}
assert(T.querytab(a) == 64);
a[(32)] = true
a[(48)] = true
a[(51)] = true
assert(#a == 48);
assert(select(4, T.querytab(a)) == 48);
a[(50)] = true
assert(select(4, T.querytab(a)) == 50);
assert(#a == 51);
}
assert(#{} == 0);
assert(#{
nil
} == 0);
assert(#{
nil,
nil
} == 0);
assert(#{
nil,
nil,
nil
} == 0);
assert(#{
nil,
nil,
nil,
nil
} == 0);
assert(#{
1,
2,
3,
nil,
nil
} == 3);
print('+');
local nofind = {}
a, b, c = 1, 2, 3
a, b, c = nil
assert(next({}) == next({}));
local fn find(name) {
local n, v
while 1 {
n, v = next(_G, n)
if !n {
return nofind
}
assert(_G[(n)] != undef);
if n == name {
return v
}
}
}
local fn find1(name) {
for n, v with pairs(_G) {
if n == name {
return v
}
}
return nil
}
assert(print == find("print") && print == find1("print"));
assert(_G[("print")] == find("print"));
assert(assert == find1("assert"));
assert(nofind == find("return"));
assert(!find1("return"));
_G[("ret" .. "urn")] = undef
assert(nofind == find("return"));
_G[("xxx")] = 1
assert(xxx == find("xxx"));
checkerror("invalid key", next, {
10,
20
}, 3);
checkerror("bad argument", pairs);
checkerror("bad argument", ipairs);
print('+');
a = {}
for i = 0, 10000 {
if math.fmod(i, 10) != 0 {
a[('x' .. i)] = i
}
}
n = {
n = 0
}
for i, v with pairs(a) {
n.n = n.n + 1
assert(i && v && a[(i)] == v);
}
assert(n.n == 9000);
a = nil
{
local a = {}
for n, v with pairs(_G) {
a[(n)] = v
}
for n, v with pairs(a) {
if !package.loaded[(n)] && type(v) != "function" && !string.find(n, "^[%u_]") {
_G[(n)] = undef
}
collectgarbage();
}
}
local fn checknext(a) {
local b = {}
{
local k, v = next(a)
while k {
b[(k)] = v
k, v = next(a, k)
}
}
for k, v with pairs(b) {
assert(a[(k)] == v);
}
for k, v with pairs(a) {
assert(b[(k)] == v);
}
}
checknext({
1,
x = 1,
y = 2,
z = 3
});
checknext({
1,
2,
x = 1,
y = 2,
z = 3
});
checknext({
1,
2,
3,
x = 1,
y = 2,
z = 3
});
checknext({
1,
2,
3,
4,
x = 1,
y = 2,
z = 3
});
checknext({
1,
2,
3,
4,
5,
x = 1,
y = 2,
z = 3
});
assert(#{} == 0);
assert(#{
-1 = 2
} == 0);
for i = 0, 40 {
local a = {}
for j = 1, i {
a[(j)] = j
}
assert(#a == i);
}
method table.maxn(t) {
local max = 0
for k with pairs(t) {
max = (type(k) == 'number') && math.max(max, k) || max
}
return max
}
assert(table.maxn({}) == 0);
assert(table.maxn({
"1000" = true
}) == 0);
assert(table.maxn({
"1000" = true,
24.5 = 3
}) == 24.5);
assert(table.maxn({
1000 = true
}) == 1000);
assert(table.maxn({
10 = true,
100 * math.pi = print
}) == 100 * math.pi);
table.maxn = nil
a = {}
for i = 0, 50 {
a[(2 ^ i)] = true
}
assert(a[(#a)]);
print('+');
{
local a = {
1 = 1,
1.1 = 2,
'x' = 3,
string.rep('x', 1000) = 4,
print = 5,
checkerror = 6,
coroutine.running() = 7,
true = 8,
io.stdin = 9,
{} = 10
}
local b = {}
for i = 1, 10 {
b[(i)] = true
}
for k, v with pairs(a) {
assert(b[(v)]);
b[(v)] = undef
}
assert(next(b) == nil);
}
local t = {
{
1
} = 1,
{
2
} = 2,
string.rep("x ", 4) = 3,
100.3 = 4,
4 = 5
}
local n = 0
for k, v with pairs(t) {
n = n + 1
assert(t[(k)] == v);
t[(k)] = undef
collectgarbage();
assert(t[(k)] == undef);
}
assert(n == 5);
{
print("testing next x GC of deleted keys");
local co = coroutine.wrap(fn (t) {
for k, v with pairs(t) {
local k1 = next(t)
assert(k == k1);
t[(k)] = nil
local expected = (type(k) == "table" && k[(1)] || type(k) == "function" && k() || string.sub(k, 1, 1))
assert(expected == v);
coroutine.yield(v);
}
})
local t = {}
t[({
1
})] = 1
t[({
2
})] = 2
t[(string.rep("a", 50))] = "a"
t[(string.rep("b", 50))] = "b"
t[({
3
})] = 3
t[(string.rep("c", 10))] = "c"
t[(fn () {
return 10
})] = 10
local count = 7
while co(t) {
collectgarbage("collect");
count = count - 1
}
assert(count == 0 && next(t) == nil);
}
local fn test(a) {
assert(!pcall(table.insert, a, 2, 20));
table.insert(a, 10);
table.insert(a, 2, 20);
table.insert(a, 1, -1);
table.insert(a, 40);
table.insert(a, #a + 1, 50);
table.insert(a, 2, -2);
assert(a[(2)] != undef);
assert(a[("2")] == undef);
assert(!pcall(table.insert, a, 0, 20));
assert(!pcall(table.insert, a, #a + 2, 20));
assert(table.remove(a, 1) == -1);
assert(table.remove(a, 1) == -2);
assert(table.remove(a, 1) == 10);
assert(table.remove(a, 1) == 20);
assert(table.remove(a, 1) == 40);
assert(table.remove(a, 1) == 50);
assert(table.remove(a, 1) == nil);
assert(table.remove(a) == nil);
assert(table.remove(a, #a) == nil);
}
a = {
n = 0,
-7 = "ban"
}
test(a);
assert(a.n == 0 && a[(-7)] == "ban");
a = {
-7 = "ban"
}
test(a);
assert(a.n == nil && #a == 0 && a[(-7)] == "ban");
a = {
-1 = "ban"
}
test(a);
assert(#a == 0 && table.remove(a) == nil && a[(-1)] == "ban");
a = {
0 = "ban"
}
assert(#a == 0 && table.remove(a) == "ban" && a[(0)] == undef);
table.insert(a, 1, 10);
table.insert(a, 1, 20);
table.insert(a, 1, -1);
assert(table.remove(a) == 10);
assert(table.remove(a) == 20);
assert(table.remove(a) == -1);
assert(table.remove(a) == nil);
a = {
'c',
'd'
}
table.insert(a, 3, 'a');
table.insert(a, 'b');
assert(table.remove(a, 1) == 'c');
assert(table.remove(a, 1) == 'd');
assert(table.remove(a, 1) == 'a');
assert(table.remove(a, 1) == 'b');
assert(table.remove(a, 1) == nil);
assert(#a == 0 && a.n == nil);
a = {
10,
20,
30,
40
}
assert(table.remove(a, #a + 1) == nil);
assert(!pcall(table.remove, a, 0));
assert(a[(#a)] == 40);
assert(table.remove(a, #a) == 40);
assert(a[(#a)] == 30);
assert(table.remove(a, 2) == 20);
assert(a[(#a)] == 30 && #a == 2);
{
local fn test(proxy, t) {
for i = 1, 10 {
table.insert(proxy, 1, i);
}
assert(#proxy == 10 && #t == 10 && proxy[(1)] != undef);
for i = 1, 10 {
assert(t[(i)] == 11 - i);
}
table.sort(proxy);
for i = 1, 10 {
assert(t[(i)] == i && proxy[(i)] == i);
}
assert(table.concat(proxy, ",") == "1,2,3,4,5,6,7,8,9,10");
for i = 1, 8 {
assert(table.remove(proxy, 1) == i);
}
assert(#proxy == 2 && #t == 2);
local a, b, c = table.unpack(proxy)
assert(a == 9 && b == 10 && c == nil);
}
local t = {}
local proxy = setmetatable({}, {
__len = fn () {
return #t
},
__index = t,
__newindex = t
})
test(proxy, t);
local count = 0
t = setmetatable({}, {
__newindex = fn (t, k, v) {
count = count + 1
rawset(t, k, v);
}
})
test(t, t);
assert(count == 10);
t = setmetatable({}, {
__index = fn (_, k) {
return k + 1
},
__len = fn (_) {
return 5
}
})
assert(table.concat(t, ";") == "2;3;4;5;6");
}
{
local t = setmetatable({}, {
__len = fn () {
return math.maxinteger
}
})
table.insert(t, 20);
local k, v = next(t)
assert(k == math.mininteger && v == 20);
}
if !T {
(Message || print)('\n >>> testC not active: skipping tests for table library on non-tables <<<\n');
} else {
local debug = require('debug')
local tab = {
10,
20,
30
}
local mt = {}
local u = T.newuserdata(0)
checkerror("table expected", table.insert, u, 40);
checkerror("table expected", table.remove, u);
debug.setmetatable(u, mt);
checkerror("table expected", table.insert, u, 40);
checkerror("table expected", table.remove, u);
mt.__index = tab
checkerror("table expected", table.insert, u, 40);
checkerror("table expected", table.remove, u);
mt.__newindex = tab
checkerror("table expected", table.insert, u, 40);
checkerror("table expected", table.remove, u);
mt.__len = fn () {
return #tab
}
table.insert(u, 40);
assert(#u == 4 && #tab == 4 && u[(4)] == 40 && tab[(4)] == 40);
assert(table.remove(u) == 40);
table.insert(u, 1, 50);
assert(#u == 4 && #tab == 4 && u[(4)] == 30 && tab[(1)] == 50);
mt.__newindex = nil
mt.__len = nil
local tab2 = {}
local u2 = T.newuserdata(0)
debug.setmetatable(u2, {
__newindex = fn (_, k, v) {
tab2[(k)] = v
}
});
table.move(u, 1, 4, 1, u2);
assert(#tab2 == 4 && tab2[(1)] == tab[(1)] && tab2[(4)] == tab[(4)]);
}
print('+');
a = {}
for i = 1, 1000 {
a[(i)] = i
a[(i - 1)] = undef
}
assert(next(a, nil) == 1000 && next(a, 1000) == nil);
assert(next({}) == nil);
assert(next({}, nil) == nil);
for a, b with pairs({}) {
error("not here");
}
for i = 1, 0 {
error('not here');
}
for i = 0, 1, -1 {
error('not here');
}
a = nil
for i = 1, 1 {
assert(!a);
a = 1
}
assert(a);
a = nil
for i = 1, 1, -1 {
assert(!a);
a = 1
}
assert(a);
{
print("testing floats in numeric for");
local a
a = 0
for i = 1, 1, 1 {
a = a + 1
}
assert(a == 1);
a = 0
for i = 10000, 1e4, -1 {
a = a + 1
}
assert(a == 1);
a = 0
for i = 1, 0.99999, 1 {
a = a + 1
}
assert(a == 0);
a = 0
for i = 9999, 1e4, -1 {
a = a + 1
}
assert(a == 0);
a = 0
for i = 1, 0.99999, -1 {
a = a + 1
}
assert(a == 1);
a = 0
for i = 0, 0.999999999, 0.1 {
a = a + 1
}
assert(a == 10);
a = 0
for i = 1.0, 1, 1 {
a = a + 1
}
assert(a == 1);
a = 0
for i = -1.5, -1.5, 1 {
a = a + 1
}
assert(a == 1);
a = 0
for i = 1e6, 1e6, -1 {
a = a + 1
}
assert(a == 1);
a = 0
for i = 1.0, 0.99999, 1 {
a = a + 1
}
assert(a == 0);
a = 0
for i = 99999, 1e5, -1.0 {
a = a + 1
}
assert(a == 0);
a = 0
for i = 1.0, 0.99999, -1 {
a = a + 1
}
assert(a == 1);
}
{
local a
a = 0
for i = 1, 10 {
a = a + 1
i = "x"
}
assert(a == 10);
a = 0
for i = 10.0, 1, -1 {
a = a + 1
i = "x"
}
assert(a == 10);
}
a = 0
for i = "10", "1", "-2" {
a = a + 1
}
assert(a == 5);
{
local c
local fn checkfloat(i) {
assert(math.type(i) == "float");
c = c + 1
}
c = 0
for i = 1.0, 10 {
checkfloat(i);
}
assert(c == 10);
c = 0
for i = -1, -10, -1.0 {
checkfloat(i);
}
assert(c == 10);
local fn checkint(i) {
assert(math.type(i) == "integer");
c = c + 1
}
local m = math.maxinteger
c = 0
for i = m, m - 10, -1 {
checkint(i);
}
assert(c == 11);
c = 0
for i = 1, 10.9 {
checkint(i);
}
assert(c == 10);
c = 0
for i = 10, 0.001, -1 {
checkint(i);
}
assert(c == 10);
c = 0
for i = 1, "10.8" {
checkint(i);
}
assert(c == 10);
c = 0
for i = 9, "3.4", -1 {
checkint(i);
}
assert(c == 6);
c = 0
for i = 0, " -3.4 ", -1 {
checkint(i);
}
assert(c == 4);
c = 0
for i = 100, "96.3", -2 {
checkint(i);
}
assert(c == 2);
c = 0
for i = 1, math.huge {
if i > 10 {
break
}
checkint(i);
}
assert(c == 10);
c = 0
for i = -1, -math.huge, -1 {
if i < -10 {
break
}
checkint(i);
}
assert(c == 10);
for i = math.mininteger, -10e100 {
assert(false);
}
for i = math.maxinteger, 10e100, -1 {
assert(false);
}
}
{
local fn checkfor(from, to, step, t) {
local c = 0
for i = from, to, step {
c = c + 1
assert(i == t[(c)]);
}
assert(c == #t);
}
local maxi = math.maxinteger
local mini = math.mininteger
checkfor(mini, maxi, maxi, {
mini,
-1,
maxi - 1
});
checkfor(mini, math.huge, maxi, {
mini,
-1,
maxi - 1
});
checkfor(maxi, mini, mini, {
maxi,
-1
});
checkfor(maxi, mini, -maxi, {
maxi,
0,
-maxi
});
checkfor(maxi, -math.huge, mini, {
maxi,
-1
});
checkfor(maxi, mini, 1, {});
checkfor(mini, maxi, -1, {});
checkfor(maxi - 6, maxi, 3, {
maxi - 6,
maxi - 3,
maxi
});
checkfor(mini + 4, mini, -2, {
mini + 4,
mini + 2,
mini
});
local step = maxi /_ 10
local c = mini
for i = mini, maxi, step {
assert(i == c);
c = c + step
}
c = maxi
for i = maxi, mini, -step {
assert(i == c);
c = c - step
}
checkfor(maxi, maxi, maxi, {
maxi
});
checkfor(maxi, maxi, mini, {
maxi
});
checkfor(mini, mini, maxi, {
mini
});
checkfor(mini, mini, mini, {
mini
});
}
checkerror("'for' step is zero", fn () {
for i = 1, 10, 0 {
}
});
checkerror("'for' step is zero", fn () {
for i = 1, -10, 0 {
}
});
checkerror("'for' step is zero", fn () {
for i = 1.0, -10, 0.0 {
}
});
collectgarbage();
local fn f(n, p) {
local t = {}
for i = 1, p {
t[(i)] = i * 10
}
return fn (_, n, ...) {
assert(select("#", ...) == 0);
if n > 0 {
n = n - 1
return n, table.unpack(t)
}
}, nil, n
}
local x = 0
for n, a, b, c, d with f(5, 3) {
x = x + 1
assert(a == 10 && b == 20 && c == 30 && d == nil);
}
assert(x == 5);
a = {}
{
local x, y, z = pairs(a)
assert(type(x) == 'function' && y == a && z == nil);
}
local fn foo(e, i) {
assert(e == a);
if i <= 10 {
return i + 1, i + 2
}
}
local fn foo1(e, i) {
i = i + 1
assert(e == a);
if i <= e.n {
return i, a[(i)]
}
}
setmetatable(a, {
__pairs = fn (x) {
return foo, x, 0
}
});
local i = 0
for k, v with pairs(a) {
i = i + 1
assert(k == i && v == k + 1);
}
a.n = 5
a[(3)] = 30
a = {
n = 10
}
setmetatable(a, {
__index = fn (t, k) {
if k <= t.n {
return k * 10
}
}
});
i = 0
for k, v with ipairs(a) {
i = i + 1
assert(k == i && v == i * 10);
}
assert(i == a.n);
{
local t = setmetatable({
10,
20,
30
}, {
__pairs = fn (t) {
local inc = coroutine.yield()
return fn (t, i) {
if i > 1 {
return i - inc, t[(i - inc)]
} else {
return nil
}
}, t, #t + 1
}
})
local res = {}
local co = coroutine.wrap(fn () {
for i, p with pairs(t) {
res[(#res + 1)] = p
}
})
co();
co(1);
assert(res[(1)] == 30 && res[(2)] == 20 && res[(3)] == 10 && #res == 3);
}
print("OK");