---
source: src/main.rs
assertion_line: 136
expression: compiled
input_file: test-data/lua5.4-tests/code.lua
---
if T == nil {
(Message || print)('\n >>> testC not active: skipping opcode tests <<<\n');
return
}
print("testing code generation and optimizations");
local k0aux = 0
local k0 = k0aux
local k1 = 1
local k3 = 3
local k6 = k3 + (k3 << k0)
local kFF0 = 0xFF0
local k3_78 = 3.78
local x, k3_78_4 = 10, k3_78 / 4
assert(x == 10);
local kx = "x"
local kTrue = true
local kFalse = false
local kNil = nil
{
local fn f(a) {
for k, v, w with a {
}
}
}
local fn checkKlist(func, list) {
local k = T.listk(func)
assert(#k == #list);
for i = 1, #k {
assert(k[(i)] == list[(i)] && math.type(k[(i)]) == math.type(list[(i)]));
}
}
local fn foo() {
local a
a = k3
a = 0
a = 0.0
a = -7 + 7
a = k3_78 / 4
a = k3_78_4
a = -k3_78 / 4
a = k3_78 / 4
a = -3.78 / 4
a = -3.79 / 4
a = 0.0
a = -0
a = k3
a = 3.0
a = 3
a = 3.0
}
checkKlist(foo, {
3.78 / 4,
-3.78 / 4,
-3.79 / 4
});
foo = fn (f, a) {
f(100 * 1000);
f(100.0 * 1000);
f(-100 * 1000);
f(-100 * 1000.0);
f(100000);
f(100000.0);
f(-100000);
f(-100000.0);
}
checkKlist(foo, {
100000,
100000.0,
-100000,
-100000.0
});
foo = fn (t, a) {
t[(a)] = 1
t[(a)] = 1.0
t[(a)] = 1
t[(a)] = 1.0
t[(a)] = 2
t[(a)] = 2.0
t[(a)] = 0
t[(a)] = 0.0
t[(a)] = 1
t[(a)] = 1.0
t[(a)] = 2
t[(a)] = 2.0
t[(a)] = 0
t[(a)] = 0.0
}
checkKlist(foo, {
1,
1.0,
2,
2.0,
0,
0.0
});
global fn check(f, ...) {
local arg = {
...
}
local c = T.listcode(f)
for i = 1, #arg {
local opcode = string.match(c[(i)], "%u%w+")
assert(arg[(i)] == opcode);
}
assert(c[(#arg + 2)] == undef);
}
global fn checkR(f, p, r, ...) {
local r1 = f(p)
assert(r == r1 && math.type(r) == math.type(r1));
check(f, ...);
}
global fn checkequal(a, b) {
a = T.listcode(a)
b = T.listcode(b)
assert(#a == #b);
for i = 1, #a {
a[(i)] = string.gsub(a[(i)], '%b()', '')
b[(i)] = string.gsub(b[(i)], '%b()', '')
assert(a[(i)] == b[(i)]);
}
}
check(fn () {
(fn () {
})({
f()
});
}, 'CLOSURE', 'NEWTABLE', 'EXTRAARG', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN0');
check(fn (x) {
(fn () {
return x
})({
f()
});
}, 'CLOSURE', 'NEWTABLE', 'EXTRAARG', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN');
check(fn () {
local kNil = nil
local a, b, c
local d
local e
local f, g, h
d = nil
d = nil
b = nil
a = kNil
c = nil
}, 'LOADNIL', 'RETURN0');
check(fn () {
local a, b, c, d = 1, 1, 1, 1
d = nil
c = nil
b = nil
a = nil
}, 'LOADI', 'LOADI', 'LOADI', 'LOADI', 'LOADNIL', 'RETURN0');
{
local a, b, c, d = 1, 1, 1, 1
d = nil
c = nil
b = nil
a = nil
assert(a == nil && b == nil && c == nil && d == nil);
}
check(fn (a, b, c) {
return a
}, 'RETURN1');
check(fn () {
while kTrue {
local a = -1
}
}, 'LOADI', 'JMP', 'RETURN0');
check(fn () {
while 1 {
local a = -1
}
}, 'LOADI', 'JMP', 'RETURN0');
check(fn () {
loop {
local x = 1
} until true
}, 'LOADI', 'RETURN0');
check(fn (a, b, c, d) {
return a .. b .. c .. d
}, 'MOVE', 'MOVE', 'MOVE', 'MOVE', 'CONCAT', 'RETURN1');
check(fn () {
return !!nil
}, 'LOADFALSE', 'RETURN1');
check(fn () {
return !!kFalse
}, 'LOADFALSE', 'RETURN1');
check(fn () {
return !!true
}, 'LOADTRUE', 'RETURN1');
check(fn () {
return !!k3
}, 'LOADTRUE', 'RETURN1');
check(fn () {
local a, b, c, d
a = b * a
c.x, a[(b)] = -((a + d / b - a[(b)]) ^ a.x), b
}, 'LOADNIL', 'MUL', 'MMBIN', 'DIV', 'MMBIN', 'ADD', 'MMBIN', 'GETTABLE', 'SUB', 'MMBIN', 'GETFIELD', 'POW', 'MMBIN', 'UNM', 'SETTABLE', 'SETFIELD', 'RETURN0');
check(fn () {
local a, b
local c = kNil
a[(kx)] = 3.2
a.x = b
a[(b)] = 'x'
}, 'LOADNIL', 'SETFIELD', 'SETFIELD', 'SETTABLE', 'RETURN0');
check(fn (a) {
local k255 = 255
a[(1)] = a[(100)]
a[(k255)] = a[(256)]
a[(256)] = 5
}, 'GETI', 'SETI', 'LOADI', 'GETTABLE', 'SETI', 'LOADI', 'SETTABLE', 'RETURN0');
check(fn () {
local a, b
a = a - a
b = a / a
b = 5 - 4
}, 'LOADNIL', 'SUB', 'MMBIN', 'DIV', 'MMBIN', 'LOADI', 'RETURN0');
check(fn () {
local a, b
a[(kTrue)] = false
}, 'LOADNIL', 'LOADTRUE', 'SETTABLE', 'RETURN0');
checkR(fn (a) {
if a == 1 {
return 2
}
}, 1, 2, 'EQI', 'JMP', 'LOADI', 'RETURN1');
checkR(fn (a) {
if -4.0 == a {
return 2
}
}, -4, 2, 'EQI', 'JMP', 'LOADI', 'RETURN1');
checkR(fn (a) {
if a == "hi" {
return 2
}
}, 10, nil, 'EQK', 'JMP', 'LOADI', 'RETURN1');
checkR(fn (a) {
if a == 10000 {
return 2
}
}, 1, nil, 'EQK', 'JMP', 'LOADI', 'RETURN1');
checkR(fn (a) {
if -10000 == a {
return 2
}
}, -10000, 2, 'EQK', 'JMP', 'LOADI', 'RETURN1');
checkR(fn (a) {
if -10 <= a {
return 2
}
}, -10, 2, 'GEI', 'JMP', 'LOADI', 'RETURN1');
checkR(fn (a) {
if 128.0 > a {
return 2
}
}, 129, nil, 'LTI', 'JMP', 'LOADI', 'RETURN1');
checkR(fn (a) {
if -127.0 < a {
return 2
}
}, -127, nil, 'GTI', 'JMP', 'LOADI', 'RETURN1');
checkR(fn (a) {
if 10 < a {
return 2
}
}, 11, 2, 'GTI', 'JMP', 'LOADI', 'RETURN1');
checkR(fn (a) {
if 129 < a {
return 2
}
}, 130, 2, 'LOADI', 'LT', 'JMP', 'LOADI', 'RETURN1');
checkR(fn (a) {
if a >= 23.0 {
return 2
}
}, 25, 2, 'GEI', 'JMP', 'LOADI', 'RETURN1');
checkR(fn (a) {
if a >= 23.1 {
return 2
}
}, 0, nil, 'LOADK', 'LE', 'JMP', 'LOADI', 'RETURN1');
checkR(fn (a) {
if a > 2300.0 {
return 2
}
}, 0, nil, 'LOADF', 'LT', 'JMP', 'LOADI', 'RETURN1');
local fn checkK(func, val) {
check(func, 'LOADK', 'RETURN1');
checkKlist(func, {
val
});
assert(func() == val);
}
local fn checkI(func, val) {
check(func, 'LOADI', 'RETURN1');
checkKlist(func, {});
assert(func() == val);
}
local fn checkF(func, val) {
check(func, 'LOADF', 'RETURN1');
checkKlist(func, {});
assert(func() == val);
}
checkF(fn () {
return 0.0
}, 0.0);
checkI(fn () {
return k0
}, 0);
checkI(fn () {
return -k0 /_ 1
}, 0);
checkK(fn () {
return 3 ^ -1
}, 1 / 3);
checkK(fn () {
return (1 + 1) ^ (50 + 50)
}, 2 ^ 100);
checkK(fn () {
return (-2) ^ (31 - 2)
}, -0x20000000 + 0.0);
checkF(fn () {
return (-k3 ^ 0 + 5) /_ 3.0
}, 1.0);
checkI(fn () {
return -k3 % 5
}, 2);
checkF(fn () {
return -((2.0 ^ 8 + -(-1)) % 8) / 2 * 4 - 3
}, -5.0);
checkF(fn () {
return -((2 ^ 8 + -(-1)) % 8) /_ 2 * 4 - 3
}, -7.0);
checkI(fn () {
return 240 | 204 ^^ 0xAA & 0xFD
}, 0xF4);
checkI(fn () {
return ~(~kFF0 | kFF0)
}, 0);
checkI(fn () {
return ~ ^^ -1024.0
}, -1024);
checkI(fn () {
return ((100 << k6) << -4) >> 2
}, 100);
local a = 17
local sbx = ((1 << a) - 1) >> 1
local border = 65535
checkI(fn () {
return border
}, sbx);
checkI(fn () {
return -border
}, -sbx);
checkI(fn () {
return border + 1
}, sbx + 1);
checkK(fn () {
return border + 2
}, sbx + 2);
checkK(fn () {
return -(border + 1)
}, -(sbx + 1));
local border = 65535.0
checkF(fn () {
return border
}, sbx + 0.0);
checkF(fn () {
return -border
}, -sbx + 0.0);
checkF(fn () {
return border + 1
}, (sbx + 1.0));
checkK(fn () {
return border + 2
}, (sbx + 2.0));
checkK(fn () {
return -(border + 1)
}, -(sbx + 1.0));
checkR(fn (x) {
return x + k1
}, 10, 11, 'ADDI', 'MMBINI', 'RETURN1');
checkR(fn (x) {
return x - 127
}, 10, -117, 'ADDI', 'MMBINI', 'RETURN1');
checkR(fn (x) {
return 128 + x
}, 0.0, 128.0, 'ADDI', 'MMBINI', 'RETURN1');
checkR(fn (x) {
return x * -127
}, -1.0, 127.0, 'MULK', 'MMBINK', 'RETURN1');
checkR(fn (x) {
return 20 * x
}, 2, 40, 'MULK', 'MMBINK', 'RETURN1');
checkR(fn (x) {
return x ^ -2
}, 2, 0.25, 'POWK', 'MMBINK', 'RETURN1');
checkR(fn (x) {
return x / 40
}, 40, 1.0, 'DIVK', 'MMBINK', 'RETURN1');
checkR(fn (x) {
return x /_ 1
}, 10.0, 10.0, 'IDIVK', 'MMBINK', 'RETURN1');
checkR(fn (x) {
return x % (100 - 10)
}, 91, 1, 'MODK', 'MMBINK', 'RETURN1');
checkR(fn (x) {
return k1 << x
}, 3, 8, 'SHLI', 'MMBINI', 'RETURN1');
checkR(fn (x) {
return x << 127
}, 10, 0, 'SHRI', 'MMBINI', 'RETURN1');
checkR(fn (x) {
return x << -127
}, 10, 0, 'SHRI', 'MMBINI', 'RETURN1');
checkR(fn (x) {
return x >> 128
}, 8, 0, 'SHRI', 'MMBINI', 'RETURN1');
checkR(fn (x) {
return x >> -127
}, 8, 0, 'SHRI', 'MMBINI', 'RETURN1');
checkR(fn (x) {
return x & 1
}, 9, 1, 'BANDK', 'MMBINK', 'RETURN1');
checkR(fn (x) {
return 10 | x
}, 1, 11, 'BORK', 'MMBINK', 'RETURN1');
checkR(fn (x) {
return -10 ^^ x
}, -1, 9, 'BXORK', 'MMBINK', 'RETURN1');
checkR(fn (x) {
return x + 0.0
}, 1, 1.0, 'ADDK', 'MMBINK', 'RETURN1');
checkR(fn (x) {
return x * -10000
}, 2, -20000, 'MULK', 'MMBINK', 'RETURN1');
checkR(fn (x) {
return x ^ 0.5
}, 4, 2.0, 'POWK', 'MMBINK', 'RETURN1');
checkR(fn (x) {
return x / 2.0
}, 4, 2.0, 'DIVK', 'MMBINK', 'RETURN1');
checkR(fn (x) {
return x /_ 10000
}, 10000, 1, 'IDIVK', 'MMBINK', 'RETURN1');
checkR(fn (x) {
return x % (100.0 - 10)
}, 91, 1.0, 'MODK', 'MMBINK', 'RETURN1');
check(fn () {
return -0.0
}, 'LOADF', 'UNM', 'RETURN1');
check(fn () {
return k3 / 0
}, 'LOADI', 'DIVK', 'MMBINK', 'RETURN1');
check(fn () {
return 0 % 0
}, 'LOADI', 'MODK', 'MMBINK', 'RETURN1');
check(fn () {
return -4 /_ 0
}, 'LOADI', 'IDIVK', 'MMBINK', 'RETURN1');
check(fn (x) {
return x >> 2.0
}, 'LOADF', 'SHR', 'MMBIN', 'RETURN1');
check(fn (x) {
return x << 128
}, 'LOADI', 'SHL', 'MMBIN', 'RETURN1');
check(fn (x) {
return x & 2.0
}, 'LOADF', 'BAND', 'MMBIN', 'RETURN1');
check(fn () {
for i = -10, 10.5 {
}
}, 'LOADI', 'LOADK', 'LOADI', 'FORPREP', 'FORLOOP', 'RETURN0');
check(fn () {
for i = 0xfffffff, 10.0, 1 {
}
}, 'LOADK', 'LOADF', 'LOADI', 'FORPREP', 'FORLOOP', 'RETURN0');
check(fn () {
return -nil
}, 'LOADNIL', 'UNM', 'RETURN1');
check(fn () {
local a, b, c
b[(c)], a = c, b
b[(a)], a = c, b
a, b = c, a
a = a
}, 'LOADNIL', 'MOVE', 'MOVE', 'SETTABLE', 'MOVE', 'MOVE', 'MOVE', 'SETTABLE', 'MOVE', 'MOVE', 'MOVE', 'RETURN0');
{
local t
check(fn () {
t[(kx)] = t.y
}, 'GETTABUP', 'SETTABUP');
check(fn (a) {
t[(a())] = t[(a())]
}, 'MOVE', 'CALL', 'GETUPVAL', 'MOVE', 'CALL', 'GETUPVAL', 'GETTABLE', 'SETTABLE');
}
checkequal(fn () {
local a
if !(a || b) {
b = a
}
}, fn () {
local a
if (!a && !b) {
b = a
}
});
checkequal(fn (l) {
local a
return 0 <= a && a <= l
}, fn (l) {
local a
return !(!(a >= 0) || !(a <= l))
});
check(fn (a, b) {
while a {
if b {
break
} else {
a = a + 1
}
}
}, 'TEST', 'JMP', 'TEST', 'JMP', 'ADDI', 'MMBINI', 'JMP', 'RETURN0');
checkequal(fn () {
return 6 || true || nil
}, fn () {
return k6 || kTrue || kNil
});
checkequal(fn () {
return 6 && true || nil
}, fn () {
return k6 && kTrue || kNil
});
{
local k0 = "00000000000000000000000000000000000000000000000000"
local fn f1() {
local k = k0
return fn () {
return fn () {
return k
}
}
}
local f2 = f1()
local f3 = f2()
assert(f3() == k0);
checkK(f3, k0);
assert(T.listk(f1)[(1)] == nil);
assert(T.listk(f2)[(1)] == nil);
}
print('OK');