if T == nil then (Message or print)('\a\n >>> testC not active: skipping opcode tests <<<\n\a') return end print "testing code generation and optimizations" -- this code gave an error for the code checker do local function f(a) for k, v, w in a do end end end function check(f, ...) local arg = { ... } local c = T.listcode(f) for i = 1, #arg do -- print(arg[i], c[i]) assert(string.find(c[i], '- ' .. arg[i] .. ' *%d')) end assert(c[#arg + 2] == nil) end function checkequal(a, b) a = T.listcode(a) b = T.listcode(b) for i = 1, #a do a[i] = string.gsub(a[i], '%b()', '') -- remove line number b[i] = string.gsub(b[i], '%b()', '') -- remove line number assert(a[i] == b[i]) end end -- some basic instructions check(function() (function() end) { f() } end, 'CLOSURE', 'NEWTABLE', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN') -- sequence of LOADNILs check(function() local a, b, c local d; local e; local f, g, h; d = nil; d = nil; b = nil; a = nil; c = nil; end, 'LOADNIL', 'RETURN') check(function() local a, b, c, d = 1, 1, 1, 1 d = nil; c = nil; b = nil; a = nil end, 'LOADK', 'LOADK', 'LOADK', 'LOADK', 'LOADNIL', 'RETURN') do local a, b, c, d = 1, 1, 1, 1 d = nil; c = nil; b = nil; a = nil assert(a == nil and b == nil and c == nil and d == nil) end -- single return check(function(a, b, c) return a end, 'RETURN') -- infinite loops check(function() while true do local a = -1 end end, 'LOADK', 'JMP', 'RETURN') check(function() while 1 do local a = -1 end end, 'LOADK', 'JMP', 'RETURN') check(function() repeat local x = 1 until true end, 'LOADK', 'RETURN') -- concat optimization check(function(a, b, c, d) return a .. b .. c .. d end, 'MOVE', 'MOVE', 'MOVE', 'MOVE', 'CONCAT', 'RETURN') -- not check(function() return not not nil end, 'LOADBOOL', 'RETURN') check(function() return not not false end, 'LOADBOOL', 'RETURN') check(function() return not not true end, 'LOADBOOL', 'RETURN') check(function() return not not 1 end, 'LOADBOOL', 'RETURN') -- direct access to locals check(function() local a, b, c, d a = b * 2 c[4], a[b] = -((a + d / -20.5 - a[b]) ^ a.x), b end, 'LOADNIL', 'MUL', 'DIV', 'ADD', 'GETTABLE', 'SUB', 'GETTABLE', 'POW', 'UNM', 'SETTABLE', 'SETTABLE', 'RETURN') -- direct access to constants check(function() local a, b a.x = 0 a.x = b a[b] = 'y' a = 1 - a b = 1 / a b = 5 + 4 a[true] = false end, 'LOADNIL', 'SETTABLE', 'SETTABLE', 'SETTABLE', 'SUB', 'DIV', 'LOADK', 'SETTABLE', 'RETURN') -- constant folding local function f() return -((2 ^ 8 + -(-1)) % 8) / 2 * 4 - 3 end check(f, 'LOADK', 'RETURN') assert(f() == -5) -- bug in constant folding for 5.1 check(function() return -nil end, 'LOADNIL', 'UNM', 'RETURN') check(function() local a, b, c b[c], a = c, b b[a], a = c, b a, b = c, a a = a end, 'LOADNIL', 'MOVE', 'MOVE', 'SETTABLE', 'MOVE', 'MOVE', 'MOVE', 'SETTABLE', 'MOVE', 'MOVE', 'MOVE', -- no code for a = a 'RETURN') -- x == nil , x ~= nil checkequal(function() if (a == nil) then a = 1 end ; if a ~= nil then a = 1 end end, function() if (a == 9) then a = 1 end ; if a ~= 9 then a = 1 end end) check(function() if a == nil then a = 1 end end, 'GETTABUP', 'EQ', 'JMP', 'SETTABUP', 'RETURN') -- de morgan checkequal(function() local a; if not (a or b) then b = a end end, function() local a; if (not a and not b) then b = a end end) checkequal(function(l) local a; return 0 <= a and a <= l end, function(l) local a; return not (not (a >= 0) or not (a <= l)) end) -- if- check(function(a) if a == 1 then elseif a == 2 then elseif a == 3 then else if a == 4 then else end end end, 'EQ', 'JMP', 'EQ', 'JMP', 'EQ', 'JMP', 'EQ', 'JMP', 'JMP', 'RETURN') checkequal( function(a) while a < 10 do a = a + 1 end end, function(a) if not (a < 10) then end ; a = a + 1; end ) checkequal( function(a) while a < 10 do a = a + 1 end end, function(a) while true do if not (a < 10) then break end ; a = a + 1; end end ) print 'OK'