--- source: src/main.rs assertion_line: 136 expression: compiled input_file: test-data/lua5.3-tests/code.lua --- if T == nil { (Message || print)('\n >>> testC not active: skipping opcode tests <<<\n'); return } print("testing code generation and optimizations"); { 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 = 3 a = 0 a = 0.0 a = -7 + 7 a = 3.78 / 4 a = 3.78 / 4 a = -3.78 / 4 a = 3.78 / 4 a = -3.78 / 4 a = -3.79 / 4 a = 0.0 a = -0 a = 3 a = 3.0 a = 3 a = 3.0 } checkKlist(foo, { 3, 0, 0.0, 3.78 / 4, -3.78 / 4, -3.79 / 4, 3.0 }); global fn check(f, ...) { local arg = { ... } local c = T.listcode(f) for i = 1, #arg { assert(string.find(c[(i)], '- ' .. arg[(i)] .. ' *%d')); } assert(c[(#arg + 2)] == nil); } global fn checkequal(a, b) { a = T.listcode(a) b = T.listcode(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', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN'); check(fn () { local a, b, c local d local e local f, g, h d = nil d = nil b = nil a = nil c = nil }, 'LOADNIL', 'RETURN'); check(fn () { local a, b, c, d = 1, 1, 1, 1 d = nil c = nil b = nil a = nil }, 'LOADK', 'LOADK', 'LOADK', 'LOADK', 'LOADNIL', 'RETURN'); { 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 }, 'RETURN'); check(fn () { while true { local a = -1 } }, 'LOADK', 'JMP', 'RETURN'); check(fn () { while 1 { local a = -1 } }, 'LOADK', 'JMP', 'RETURN'); check(fn () { loop { local x = 1 } until true }, 'LOADK', 'RETURN'); check(fn (a, b, c, d) { return a .. b .. c .. d }, 'MOVE', 'MOVE', 'MOVE', 'MOVE', 'CONCAT', 'RETURN'); check(fn () { return !!nil }, 'LOADBOOL', 'RETURN'); check(fn () { return !!false }, 'LOADBOOL', 'RETURN'); check(fn () { return !!true }, 'LOADBOOL', 'RETURN'); check(fn () { return !!1 }, 'LOADBOOL', 'RETURN'); check(fn () { local a, b, c, d a = b * 2 c[(2)], a[(b)] = -((a + d / 2 - a[(b)]) ^ a.x), b }, 'LOADNIL', 'MUL', 'DIV', 'ADD', 'GETTABLE', 'SUB', 'GETTABLE', 'POW', 'UNM', 'SETTABLE', 'SETTABLE', 'RETURN'); check(fn () { local a, b a.x = 3.2 a.x = b a[(b)] = 'x' }, 'LOADNIL', 'SETTABLE', 'SETTABLE', 'SETTABLE', 'RETURN'); check(fn () { local a, b a = 1 - a b = 1 / a b = 5 - 4 }, 'LOADNIL', 'SUB', 'DIV', 'LOADK', 'RETURN'); check(fn () { local a, b a[(true)] = false }, 'LOADNIL', 'SETTABLE', 'RETURN'); local fn checkK(func, val) { check(func, 'LOADK', 'RETURN'); local k = T.listk(func) assert(#k == 1 && k[(1)] == val && math.type(k[(1)]) == math.type(val)); assert(func() == val); } checkK(fn () { return 0.0 }, 0.0); checkK(fn () { return 0 }, 0); checkK(fn () { return -0 /_ 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); checkK(fn () { return (-3 ^ 0 + 5) /_ 3.0 }, 1.0); checkK(fn () { return -3 % 5 }, 2); checkK(fn () { return -((2.0 ^ 8 + -(-1)) % 8) / 2 * 4 - 3 }, -5.0); checkK(fn () { return -((2 ^ 8 + -(-1)) % 8) /_ 2 * 4 - 3 }, -7.0); checkK(fn () { return 240 | 204 ^^ 0xAA & 0xFD }, 0xF4); checkK(fn () { return ~(~0xFF0 | 0xFF0) }, 0); checkK(fn () { return ~ ^^ -100024.0 }, -100024); checkK(fn () { return ((100 << 6) << -4) >> 2 }, 100); check(fn () { return -0.0 }, 'LOADK', 'UNM', 'RETURN'); check(fn () { return 3 / 0 }, 'DIV', 'RETURN'); check(fn () { return 0 % 0 }, 'MOD', 'RETURN'); check(fn () { return -4 /_ 0 }, 'IDIV', 'RETURN'); check(fn () { return -nil }, 'LOADNIL', 'UNM', 'RETURN'); 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', 'RETURN'); checkequal(fn () { if (a == nil) { a = 1 } if a != nil { a = 1 } }, fn () { if (a == 9) { a = 1 } if a != 9 { a = 1 } }); check(fn () { if a == nil { a = 'a' } }, 'GETTABUP', 'EQ', 'JMP', 'SETTABUP', 'RETURN'); 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, c, d, e) { if a == b { } elseif if a == c { } elseif if a == d { } else { if a == e { } else { } } }, 'EQ', 'JMP', 'EQ', 'JMP', 'EQ', 'JMP', 'EQ', 'JMP', 'JMP', 'RETURN'); checkequal(fn (a) { while a < 10 { a = a + 1 } }, fn (a) { if !(a < 10) { } a = a + 1 }); checkequal(fn (a) { while a < 10 { a = a + 1 } }, fn (a) { while true { if !(a < 10) { break } a = a + 1 } }); print('OK');