You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1196 lines
25 KiB
1196 lines
25 KiB
ravi.auto(true)
|
|
|
|
print "testing code generation and optimizations"
|
|
T = ravi
|
|
|
|
local opcodes_coverage = {}
|
|
opcodes_coverage.MOVE = 0
|
|
opcodes_coverage.LOADK = 0
|
|
opcodes_coverage.LOADKX = 0
|
|
opcodes_coverage.LOADBOOL = 0
|
|
opcodes_coverage.LOADNIL = 0
|
|
opcodes_coverage.GETUPVAL = 0
|
|
opcodes_coverage.GETTABUP = 0
|
|
opcodes_coverage.GETTABLE = 0
|
|
opcodes_coverage.SETTABUP = 0
|
|
opcodes_coverage.SETUPVAL = 0
|
|
opcodes_coverage.SETTABLE = 0
|
|
opcodes_coverage.NEWTABLE = 0
|
|
opcodes_coverage.SELF = 0
|
|
opcodes_coverage.ADD = 0
|
|
opcodes_coverage.SUB = 0
|
|
opcodes_coverage.MUL = 0
|
|
opcodes_coverage.MOD = 0
|
|
opcodes_coverage.POW = 0
|
|
opcodes_coverage.DIV = 0
|
|
opcodes_coverage.IDIV = 0
|
|
opcodes_coverage.BAND = 0
|
|
opcodes_coverage.BOR = 0
|
|
opcodes_coverage.BXOR = 0
|
|
opcodes_coverage.SHL = 0
|
|
opcodes_coverage.SHR = 0
|
|
opcodes_coverage.UNM = 0
|
|
opcodes_coverage.BNOT = 0
|
|
opcodes_coverage.NOT = 0
|
|
opcodes_coverage.LEN = 0
|
|
opcodes_coverage.CONCAT = 0
|
|
opcodes_coverage.JMP = 0
|
|
opcodes_coverage.EQ = 0
|
|
opcodes_coverage.LT = 0
|
|
opcodes_coverage.LE = 0
|
|
opcodes_coverage.TEST = 0
|
|
opcodes_coverage.TESTSET = 0
|
|
opcodes_coverage.CALL = 0
|
|
opcodes_coverage.TAILCALL = 0
|
|
opcodes_coverage.RETURN = 0
|
|
opcodes_coverage.FORLOOP = 0
|
|
opcodes_coverage.FORPREP = 0
|
|
opcodes_coverage.TFORCALL = 0
|
|
opcodes_coverage.TFORLOOP = 0
|
|
opcodes_coverage.SETLIST = 0
|
|
opcodes_coverage.CLOSURE = 0
|
|
opcodes_coverage.VARARG = 0
|
|
opcodes_coverage.EXTRAARG = 0
|
|
opcodes_coverage.NEWARRAYI = 0
|
|
opcodes_coverage.NEWARRAYF = 0
|
|
opcodes_coverage.LOADIZ = 0
|
|
opcodes_coverage.LOADFZ = 0
|
|
opcodes_coverage.UNMF = 0
|
|
opcodes_coverage.UNMI = 0
|
|
opcodes_coverage.ADDFF = 0
|
|
opcodes_coverage.ADDFI = 0
|
|
opcodes_coverage.ADDII = 0
|
|
opcodes_coverage.SUBFF = 0
|
|
opcodes_coverage.SUBFI = 0
|
|
opcodes_coverage.SUBIF = 0
|
|
opcodes_coverage.SUBII = 0
|
|
opcodes_coverage.MULFF = 0
|
|
opcodes_coverage.MULFI = 0
|
|
opcodes_coverage.MULII = 0
|
|
opcodes_coverage.DIVFF = 0
|
|
opcodes_coverage.DIVFI = 0
|
|
opcodes_coverage.DIVIF = 0
|
|
opcodes_coverage.DIVII = 0
|
|
opcodes_coverage.TOINT = 0
|
|
opcodes_coverage.TOFLT = 0
|
|
opcodes_coverage.TOARRAYI = 0
|
|
opcodes_coverage.TOARRAYF = 0
|
|
opcodes_coverage.MOVEI = 0
|
|
opcodes_coverage.MOVEF = 0
|
|
opcodes_coverage.MOVEAI = 0
|
|
opcodes_coverage.MOVEAF = 0
|
|
opcodes_coverage.GETTABLE_AI = 0
|
|
opcodes_coverage.GETTABLE_AF = 0
|
|
opcodes_coverage.SETTABLE_AI = 0
|
|
opcodes_coverage.SETTABLE_AF = 0
|
|
opcodes_coverage.FORLOOP_IP = 0
|
|
opcodes_coverage.FORLOOP_I1 = 0
|
|
opcodes_coverage.FORPREP_IP = 0
|
|
opcodes_coverage.FORPREP_I1 = 0
|
|
opcodes_coverage.SETUPVALI = 0
|
|
opcodes_coverage.SETUPVALF = 0
|
|
opcodes_coverage.SETUPVALAI = 0
|
|
opcodes_coverage.SETUPVALAF = 0
|
|
opcodes_coverage.SETTABLE_AII = 0
|
|
opcodes_coverage.SETTABLE_AFF = 0
|
|
opcodes_coverage.BAND_II = 0
|
|
opcodes_coverage.BOR_II = 0
|
|
opcodes_coverage.BXOR_II = 0
|
|
opcodes_coverage.SHL_II = 0
|
|
opcodes_coverage.SHR_II = 0
|
|
opcodes_coverage.BNOT_I = 0
|
|
opcodes_coverage.EQ_II = 0
|
|
opcodes_coverage.EQ_FF = 0
|
|
opcodes_coverage.LT_II = 0
|
|
opcodes_coverage.LT_FF = 0
|
|
opcodes_coverage.LE_II = 0
|
|
opcodes_coverage.LE_FF = 0
|
|
opcodes_coverage.GETTABLE_I = 0
|
|
opcodes_coverage.GETTABLE_S = 0
|
|
opcodes_coverage.SETTABLE_I = 0
|
|
opcodes_coverage.SETTABLE_S = 0
|
|
opcodes_coverage.TOTAB = 0
|
|
opcodes_coverage.MOVETAB = 0
|
|
opcodes_coverage.SETUPVALT = 0
|
|
opcodes_coverage.SELF_S = 0
|
|
|
|
|
|
local compile = function(f)
|
|
if ravi.jit() then
|
|
assert(ravi.compile(f))
|
|
end
|
|
return true
|
|
end
|
|
|
|
-- ================================================================
|
|
-- Following section is an extract from the code.lua test
|
|
-- These functions test bytecode generation, and also provide
|
|
-- helper routines that we use later on in other test cases
|
|
|
|
-- testing opcodes
|
|
function check (f, ...)
|
|
local arg = {...}
|
|
local c = T.listcode(f)
|
|
for i=1, #arg do
|
|
--print(arg[i], c[i])
|
|
opcodes_coverage[arg[i]] = opcodes_coverage[arg[i]]+1
|
|
assert(string.find(c[i], '- '..arg[i]..' *[AB][xs]?=%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')
|
|
|
|
|
|
-- no foldings
|
|
check(function () return -0.0 end, 'LOADK', 'UNM', 'RETURN')--
|
|
--check(function () return 3/0 end, 'DIV', 'RETURN')
|
|
check(function () return 0%0 end, 'MOD', 'RETURN')
|
|
check(function () return -4//0 end, 'IDIV', 'RETURN')
|
|
|
|
-- 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-goto optimizations
|
|
check(function (a)
|
|
if a == 1 then goto l1
|
|
elseif a == 2 then goto l2
|
|
elseif a == 3 then goto l2
|
|
else if a == 4 then goto l3
|
|
else goto l3
|
|
end
|
|
end
|
|
::l1:: ::l2:: ::l3:: ::l4::
|
|
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) ::L2:: if not(a < 10) then goto L1 end; a = a + 1;
|
|
goto L2; ::L1:: 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 'Lua bytecode tests OK'
|
|
-- ================================================================
|
|
|
|
|
|
local z,x,y,tryme
|
|
|
|
-- test 1
|
|
z = function(a)
|
|
return a+1
|
|
end
|
|
x = function(f)
|
|
local j = 5
|
|
j = f(j)
|
|
return j
|
|
end
|
|
check(x, 'LOADK', 'MOVE', 'MOVE', 'CALL',
|
|
'MOVE', 'RETURN', 'RETURN')
|
|
check(z, 'ADD', 'RETURN', 'RETURN')
|
|
y = x(z)
|
|
compile(z)
|
|
compile(x)
|
|
assert(x(z) == 6 and y == 6)
|
|
print("test 1 OK")
|
|
|
|
-- test 2
|
|
x = function ()
|
|
local i, j:integer
|
|
j=0
|
|
for i=1,1000000000 do
|
|
j = j+1
|
|
end
|
|
return j
|
|
end
|
|
check(x, 'LOADNIL', 'LOADIZ', 'LOADK', 'LOADK',
|
|
'LOADK', 'LOADK', 'FORPREP_I1', 'ADDII', 'FORLOOP_I1',
|
|
'RETURN', 'RETURN')
|
|
compile(x)
|
|
assert(x() == 1000000000)
|
|
print("test 2 OK")
|
|
|
|
-- test 3
|
|
x = function ()
|
|
local j:number
|
|
for i=1,1000000000 do
|
|
j = j+1
|
|
end
|
|
return j
|
|
end
|
|
check(x, 'LOADNIL', 'LOADFZ', 'LOADK', 'LOADK',
|
|
'LOADK', 'FORPREP_I1', 'ADDFI', 'FORLOOP_I1',
|
|
'RETURN', 'RETURN')
|
|
compile(x)
|
|
assert(x() == 1000000000.0)
|
|
print("test 3 OK")
|
|
|
|
-- test 4
|
|
x = function ()
|
|
local j = 0
|
|
for i=2,6,3 do
|
|
j = i
|
|
end
|
|
return j
|
|
end
|
|
check(x, 'LOADK', 'LOADK',
|
|
'LOADK', 'LOADK', 'FORPREP_IP', 'MOVE', 'FORLOOP_IP',
|
|
'RETURN', 'RETURN')
|
|
compile(x)
|
|
assert(x() == 5)
|
|
print("test 4 OK")
|
|
|
|
-- test 5
|
|
x = function ()
|
|
if 1 == 2 then
|
|
return 5.0
|
|
end
|
|
return 1.0
|
|
end
|
|
check(x, 'EQ_II', 'JMP', 'LOADK',
|
|
'RETURN', 'LOADK', 'RETURN', 'RETURN')
|
|
compile(x)
|
|
assert(x() == 1.0)
|
|
print("test 5 OK")
|
|
|
|
-- test 6
|
|
x = function (a: integer, b: integer)
|
|
if a == b then
|
|
return 5.0
|
|
end
|
|
return 1.0
|
|
end
|
|
check(x, 'TOINT', 'TOINT', 'EQ_II', 'JMP', 'LOADK',
|
|
'RETURN', 'LOADK', 'RETURN', 'RETURN')
|
|
compile(x)
|
|
assert(x(1,2) == 1.0)
|
|
print("test 6 OK")
|
|
|
|
-- test 7
|
|
x = function (y: integer)
|
|
if y < 1 then
|
|
return 1.0
|
|
elseif y >= 5 then
|
|
return 2.0
|
|
else
|
|
return 3.0
|
|
end
|
|
end
|
|
check(x, 'TOINT', 'LT_II', 'JMP', 'LOADK',
|
|
'RETURN', 'JMP', 'LE_II', 'JMP', 'LOADK',
|
|
'RETURN', 'JMP', 'LOADK', 'RETURN', 'RETURN')
|
|
compile(x)
|
|
assert(x(5) == 2.0)
|
|
assert(x(4) == 3.0)
|
|
print("test 7 OK")
|
|
|
|
-- test 8
|
|
x = function (y: number)
|
|
if y < 1.0 then
|
|
return 1.0
|
|
elseif y >= 5.0 then
|
|
return 2.0
|
|
else
|
|
return 3.0
|
|
end
|
|
end
|
|
check(x, 'TOFLT', 'LT_FF', 'JMP', 'LOADK',
|
|
'RETURN', 'JMP', 'LE_FF', 'JMP', 'LOADK',
|
|
'RETURN', 'JMP', 'LOADK', 'RETURN', 'RETURN')
|
|
compile(x)
|
|
assert(x(5.1) == 2.0)
|
|
assert(x(4.0) == 3.0)
|
|
print("test 8 OK")
|
|
|
|
-- test 10
|
|
x = function (y: integer, z)
|
|
if y == 1 then
|
|
if z == 1 then
|
|
return 99.0
|
|
else
|
|
return z
|
|
end
|
|
elseif y >= 5 then
|
|
return 2.0
|
|
else
|
|
return 3.0
|
|
end
|
|
end
|
|
check(x, 'TOINT', 'EQ_II', 'JMP', 'EQ',
|
|
'JMP', 'LOADK', 'RETURN', 'JMP', 'RETURN', 'JMP',
|
|
'LE_II', 'JMP', 'LOADK',
|
|
'RETURN', 'JMP', 'LOADK', 'RETURN', 'RETURN')
|
|
assert(compile(x))
|
|
assert(x(1,1) == 99.0)
|
|
assert(x(1,2) == 2)
|
|
assert(x(1,5.3) == 5.3)
|
|
assert(x(5) == 2.0)
|
|
assert(x(4) == 3.0)
|
|
print("test 9 OK")
|
|
|
|
-- test 11
|
|
x = function()
|
|
local function tryme()
|
|
local i,j = 5,6
|
|
return i,j
|
|
end
|
|
assert(compile(tryme))
|
|
local i:integer, j:integer = tryme()
|
|
assert(i+j == 11)
|
|
end
|
|
compile(x)
|
|
check(x, 'CLOSURE', 'GETTABUP', 'GETUPVAL',
|
|
'MOVE', 'CALL', 'CALL', 'MOVE', 'CALL', 'TOINT', 'TOINT',
|
|
'GETTABUP', 'ADDII', 'EQ_II', 'JMP', 'LOADBOOL', 'LOADBOOL',
|
|
'CALL', 'RETURN')
|
|
x()
|
|
print("test 10 OK")
|
|
|
|
-- test 12
|
|
function x()
|
|
local a : number[], j:number = {}
|
|
for i=1,10 do
|
|
a[i] = i
|
|
j = j + a[i]
|
|
end
|
|
return j
|
|
end
|
|
assert(x() == 55.0)
|
|
check(x, 'NEWARRAYF', 'LOADNIL', 'LOADFZ',
|
|
'LOADK', 'LOADK', 'LOADK', 'FORPREP_I1',
|
|
'SETTABLE_AF', 'GETTABLE_AF', 'ADDFF',
|
|
'FORLOOP_I1', 'RETURN', 'RETURN')
|
|
compile(x)
|
|
assert(x() == 55.0)
|
|
print("test 11 OK")
|
|
|
|
-- test 13
|
|
function pisum()
|
|
local sum : number
|
|
for j = 1,500 do
|
|
sum = 0.0
|
|
for k = 1,10000 do
|
|
sum = sum + 1.0/(k*k)
|
|
end
|
|
end
|
|
return sum
|
|
end
|
|
assert(math.abs(pisum()-1.644834071848065) < 1e-12)
|
|
check(pisum, 'LOADNIL', 'LOADFZ', 'LOADK', 'LOADK',
|
|
'LOADK', 'FORPREP_I1', 'LOADK', 'LOADK',
|
|
'LOADK', 'LOADK', 'FORPREP_I1', 'MULII',
|
|
'DIVFI', 'ADDFF', 'FORLOOP_I1', 'FORLOOP_I1',
|
|
'RETURN', 'RETURN')
|
|
assert(compile(pisum))
|
|
assert(math.abs(pisum()-1.644834071848065) < 1e-12)
|
|
print("test 12 OK")
|
|
|
|
-- test 15
|
|
function y()
|
|
local i,j = 5.1,"6.2"
|
|
return i,j
|
|
end
|
|
function x(f)
|
|
local i:number, j:number = f()
|
|
return i+j
|
|
end
|
|
assert(x(y) == 11.3)
|
|
check(x, 'MOVE', 'CALL', 'TOFLT',
|
|
'TOFLT', 'ADDFF', 'RETURN', 'RETURN')
|
|
assert(compile(y))
|
|
assert(compile(x))
|
|
assert(x(y) == 11.3)
|
|
print("test 13 OK")
|
|
|
|
-- test 16
|
|
function tryme(x,y)
|
|
if x < y then
|
|
return 1
|
|
else
|
|
return 0
|
|
end
|
|
end
|
|
check(tryme, 'LT', 'JMP', 'LOADK',
|
|
'RETURN', 'JMP', 'LOADK', 'RETURN',
|
|
'RETURN')
|
|
assert(tryme(1,2) == 1)
|
|
assert(tryme(2,1) == 0)
|
|
compile(tryme)
|
|
assert(tryme(1,2) == 1)
|
|
assert(tryme(2,1) == 0)
|
|
print("test 14 OK")
|
|
|
|
-- test 17
|
|
function tryme(x,y)
|
|
return x < y
|
|
end
|
|
check(tryme, 'LT', 'JMP', 'LOADBOOL',
|
|
'LOADBOOL', 'RETURN', 'RETURN')
|
|
assert(tryme(1,2))
|
|
compile(tryme)
|
|
assert(tryme(1,2))
|
|
assert(not tryme(2,1))
|
|
print("test 15 OK")
|
|
|
|
-- test 18
|
|
function tabtest(x)
|
|
x[1] = 5
|
|
return x[1]
|
|
end
|
|
assert(tabtest({}) == 5)
|
|
check(tabtest, 'SETTABLE', 'GETTABLE', 'RETURN', 'RETURN')
|
|
compile(tabtest)
|
|
assert(tabtest({}) == 5)
|
|
print("test 16 OK")
|
|
|
|
-- test 19
|
|
function optest()
|
|
local a,b,c = 1, 5
|
|
c = a and b
|
|
return c
|
|
end
|
|
check(optest, 'LOADK', 'LOADK', 'LOADNIL',
|
|
'TESTSET', 'JMP', 'MOVE', 'RETURN', 'RETURN')
|
|
assert(optest() == 5)
|
|
compile(optest)
|
|
assert(optest() == 5)
|
|
print("test 17 OK")
|
|
|
|
-- test 20
|
|
function optest()
|
|
local a,b,c = 1, 5
|
|
c = a or b
|
|
return c
|
|
end
|
|
check(optest, 'LOADK', 'LOADK', 'LOADNIL',
|
|
'TESTSET', 'JMP', 'MOVE', 'RETURN', 'RETURN')
|
|
assert(optest() == 1)
|
|
compile(optest)
|
|
assert(optest() == 1)
|
|
print("test 18 OK")
|
|
|
|
-- test 21
|
|
function optest()
|
|
local a,b = 1, 5
|
|
if a and b then
|
|
return b
|
|
end
|
|
return a
|
|
end
|
|
check(optest, 'LOADK', 'LOADK', 'TEST', 'JMP',
|
|
'TEST', 'JMP', 'RETURN', 'RETURN', 'RETURN')
|
|
assert(optest() == 5)
|
|
compile(optest)
|
|
assert(optest() == 5)
|
|
print("test 19 OK")
|
|
|
|
-- test 22
|
|
function optest()
|
|
local a,b = nil, 5
|
|
if a or b then
|
|
return b
|
|
end
|
|
return a
|
|
end
|
|
check(optest, 'LOADNIL', 'LOADK', 'TEST', 'JMP',
|
|
'TEST', 'JMP', 'RETURN', 'RETURN', 'RETURN')
|
|
assert(optest() == 5)
|
|
compile(optest)
|
|
assert(optest() == 5)
|
|
print("test 20 OK")
|
|
|
|
-- test 29
|
|
z = function()
|
|
local x=function()
|
|
local j:number[] = {}
|
|
return j
|
|
end
|
|
compile(x)
|
|
y=x()
|
|
y[1] = 99.67
|
|
assert(y[1], 99.67)
|
|
assert(#y == 1)
|
|
end
|
|
check(z, 'CLOSURE', 'GETUPVAL', 'MOVE', 'CALL',
|
|
'MOVE', 'CALL', 'SETUPVAL', 'SETTABUP', 'GETTABUP', 'GETTABUP',
|
|
'LOADK', 'CALL', 'GETTABUP', 'GETUPVAL', 'LEN', 'EQ_II',
|
|
'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL', 'RETURN')
|
|
z()
|
|
compile(z)
|
|
z()
|
|
print("test 21 OK")
|
|
|
|
-- test 30
|
|
z = function()
|
|
local days: table = {"Sunday", "Monday", "Tuesday", "Wednesday",
|
|
"Thursday", "Friday", "Saturda"}
|
|
assert(days[1] == 'Sunday')
|
|
assert(#days == 7)
|
|
assert(days[3] == 'Tuesday')
|
|
days[7] = days[7] .. 'y'
|
|
x = function()
|
|
local t = ''
|
|
for k,v in pairs(days) do
|
|
t = t .. v
|
|
end
|
|
return t
|
|
end
|
|
assert(compile(x))
|
|
assert(x() == "SundayMondayTuesdayWednesdayThursdayFridaySaturday")
|
|
end
|
|
check(z, 'NEWTABLE', 'LOADK', 'LOADK', 'LOADK', 'LOADK',
|
|
'LOADK', 'LOADK', 'LOADK', 'SETLIST', 'GETTABUP', 'GETTABLE_I',
|
|
'EQ', 'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL', 'GETTABUP', 'LEN',
|
|
'EQ_II', 'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL', 'GETTABUP', 'GETTABLE_I',
|
|
'EQ', 'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL', 'GETTABLE_I', 'LOADK',
|
|
'CONCAT', 'SETTABLE_I', 'CLOSURE', 'SETUPVAL', 'GETTABUP', 'GETUPVAL',
|
|
'GETUPVAL', 'CALL', 'CALL', 'GETTABUP', 'GETUPVAL', 'CALL', 'EQ',
|
|
'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL', 'RETURN')
|
|
z()
|
|
compile(z)
|
|
z()
|
|
print("test 22 OK")
|
|
|
|
-- test 31
|
|
x = function(a)
|
|
return not a
|
|
end
|
|
y = function(a)
|
|
return a
|
|
end
|
|
assert(compile(x))
|
|
assert(compile(y))
|
|
assert(y(x()))
|
|
assert(y(x(false)))
|
|
assert(not y(x(true)))
|
|
print("test 23 OK")
|
|
|
|
-- test 36
|
|
t = { name_ = "ravi" }
|
|
function t:name()
|
|
return self.name_
|
|
end
|
|
function z(t)
|
|
return t:name()
|
|
end
|
|
assert(compile(t.name))
|
|
assert(compile(z))
|
|
assert(z(t) == "ravi")
|
|
print("test 25 OK")
|
|
|
|
-- test 38
|
|
-- test ravi integer array
|
|
function f()
|
|
local x: integer[] = { 1, 5 }
|
|
local y: integer
|
|
|
|
x[3] = x[1] + x[2]
|
|
y = x[3]
|
|
|
|
return y
|
|
end
|
|
assert(compile(f))
|
|
assert(f() == 6)
|
|
print("test 26 OK")
|
|
|
|
-- test 39
|
|
function f()
|
|
local x: number[] = { 5.0, 6.1 }
|
|
x[3] = x[1] + x[2]
|
|
return x[3]
|
|
end
|
|
--ravi.dumplua(f)
|
|
assert(compile(f))
|
|
assert(math.abs(f()-11.1) < 1e-12)
|
|
print("test 27 OK")
|
|
|
|
-- test 41
|
|
-- Ravi arrays support for ipairs()
|
|
-- Plus special slot at [0]
|
|
x = function()
|
|
local nums: integer[] = {1, 2, 3, 4, 5, 6, 7}
|
|
local t = 0
|
|
assert(#nums == 7)
|
|
nums[0] = 558
|
|
for k,v in ipairs(nums) do
|
|
t = t + v
|
|
end
|
|
assert(nums[0] == 558)
|
|
return t
|
|
end
|
|
assert(compile(x))
|
|
assert(x() == 28)
|
|
print("test 28 OK")
|
|
|
|
-- test 42
|
|
-- Ravi arrays support for pairs()
|
|
-- Plus special slot at [0]
|
|
x = function()
|
|
local nums: integer[] = {1, 2, 3, 4, 5, 6, 7}
|
|
local t = 0
|
|
assert(#nums == 7)
|
|
nums[0] = 558
|
|
for k,v in pairs(nums) do
|
|
t = t + v
|
|
end
|
|
assert(nums[0] == 558)
|
|
return t
|
|
end
|
|
assert(compile(x))
|
|
assert(x() == 28)
|
|
print("test 29 OK")
|
|
|
|
-- test 43
|
|
-- test creation of arrays and slice
|
|
x = function()
|
|
local zeros: integer[] = table.intarray(10, 0)
|
|
local ones: integer[] = table.intarray(10, 1)
|
|
|
|
local a : integer[] = table.slice(ones, 1, 10)
|
|
assert(#zeros == 10)
|
|
assert(#ones == 10)
|
|
assert(#a == 10)
|
|
|
|
local i = 0
|
|
for k,v in ipairs(a) do
|
|
i = i + v
|
|
end
|
|
assert(i == 10)
|
|
local y = table.slice(ones, 10, 1)
|
|
y[1] = 115
|
|
return ones[10] == 115
|
|
end
|
|
assert(compile(x))
|
|
assert(x() == true)
|
|
print("test 30 OK")
|
|
|
|
-- test 44
|
|
matrix = {}
|
|
matrix.new = function (m, n)
|
|
local t = {m, n, table.numarray(m*n, 0)}
|
|
return t
|
|
end
|
|
|
|
matrix.getcol = function(m, col)
|
|
local rows = m[1]
|
|
local cols = m[2]
|
|
local data = m[3]
|
|
assert(col > 0 and col <= cols)
|
|
return table.slice(data, (col-1)*rows+1, rows)
|
|
end
|
|
|
|
matrix.getdata = function(m)
|
|
return m[3]
|
|
end
|
|
|
|
matrix.datalen = function(data)
|
|
return #data
|
|
end
|
|
|
|
x = function()
|
|
local m = matrix.new(5,5)
|
|
local data: number[] = matrix.getdata(m)
|
|
local data_len: integer = matrix.datalen(data)
|
|
for i = 1,data_len do
|
|
data[i] = i
|
|
end
|
|
-- get third col
|
|
local col3 = matrix.getcol(m, 3)
|
|
-- should be 11,12,13,14,15
|
|
local n = 0
|
|
for k,v in ipairs(col3) do
|
|
n = n + v
|
|
end
|
|
-- should be 65
|
|
return n
|
|
end
|
|
|
|
assert(compile(matrix.new))
|
|
assert(compile(matrix.getcol))
|
|
assert(compile(matrix.getdata))
|
|
assert(compile(x))
|
|
assert(x() == 65)
|
|
print("test 31 OK")
|
|
|
|
-- test 23
|
|
function testadd(a,b)
|
|
return a+b
|
|
end
|
|
assert(compile(testadd))
|
|
assert(testadd(1,1) == 2)
|
|
assert(testadd(1.5,1.6) == 3.1)
|
|
assert(testadd("1.5",1.6) == 3.1)
|
|
assert(testadd("1.5","1.6") == 3.1)
|
|
print("test 32 OK")
|
|
|
|
-- test 24
|
|
function testsub(a,b)
|
|
return a-b
|
|
end
|
|
assert(compile(testsub))
|
|
assert(testsub(1,1) == 0)
|
|
assert(math.abs(testsub(1.5,1.6)-(-0.1)) < 1e-12)
|
|
assert(math.abs(testsub("1.5",1.6)-(-0.1)) < 1e-12)
|
|
assert(math.abs(testsub("1.5","1.6")-(-0.1)) < 1e-12)
|
|
print("test 33 OK")
|
|
|
|
-- test 25
|
|
function testmul(a,b)
|
|
return a*b
|
|
end
|
|
assert(compile(testmul))
|
|
assert(testmul(2,2) == 4)
|
|
assert(math.abs(testmul(1.5,1.6)-2.4) < 1e-12)
|
|
assert(math.abs(testmul("1.5",1.6)-2.4) < 1e-12)
|
|
assert(math.abs(testmul("1.5","1.6")-2.4) < 1e-12)
|
|
print("test 34 OK")
|
|
|
|
|
|
-- test 26
|
|
function testdiv(a,b)
|
|
return a/b
|
|
end
|
|
assert(compile(testdiv))
|
|
assert(testdiv(2,2) == 1.0)
|
|
assert(math.abs(testdiv(1.5,1.6)-0.9375) < 1e-12)
|
|
assert(math.abs(testdiv("1.5",1.6)-0.9375) < 1e-12)
|
|
assert(math.abs(testdiv("1.5","1.6")-0.9375) < 1e-12)
|
|
print("test 35 OK")
|
|
|
|
|
|
-- test 37
|
|
-- this tests that within the for loop
|
|
-- the locals get mapped correctly to upvalues
|
|
function f()
|
|
local a={}
|
|
for i=1,2 do
|
|
local y:integer = 0
|
|
a[i] = function()
|
|
y = y + 10
|
|
return y;
|
|
end
|
|
end
|
|
return a
|
|
end
|
|
assert(compile(f))
|
|
t = f()
|
|
assert(#t == 2)
|
|
assert(compile(t[1]))
|
|
assert(compile(t[2]))
|
|
assert(t[1]() == 10)
|
|
assert(t[2]() == 10)
|
|
assert(t[1]() == 20)
|
|
assert(t[2]() == 20)
|
|
print("test 36 OK")
|
|
|
|
|
|
|
|
-- test 27
|
|
-- upvalues
|
|
local x = 1
|
|
local y=function()
|
|
local f = function()
|
|
return x
|
|
end
|
|
compile(f)
|
|
return f
|
|
end
|
|
compile(y)
|
|
local f = y()
|
|
assert(f() == 1)
|
|
x=5
|
|
assert(f() == 5)
|
|
print("test 37 OK")
|
|
|
|
-- test 28
|
|
-- upvalues
|
|
x1 = 3
|
|
local y=function()
|
|
local f = function()
|
|
return x1
|
|
end
|
|
compile(f)
|
|
return f
|
|
end
|
|
--ravi.dumplua(y)
|
|
compile(y)
|
|
local f = y()
|
|
--assert(ravi.iscompiled(f))
|
|
--ravi.dumplua(f)
|
|
--ravi.dumpllvm(f)
|
|
assert(f() == 3)
|
|
x1=5
|
|
assert(f() == 5)
|
|
print("test 38 OK")
|
|
|
|
-- test 35
|
|
function x()
|
|
local x = 1
|
|
local f = function()
|
|
x=x+1
|
|
return x
|
|
end
|
|
return f
|
|
end
|
|
f=x()
|
|
assert(compile(f))
|
|
assert(f() == 2)
|
|
assert(f() == 3)
|
|
print("test 39 OK")
|
|
|
|
-- test setupval, getupval
|
|
function x()
|
|
local a = 0
|
|
return function(x) a=a+x; return a; end
|
|
end
|
|
-- ravi.dumplua(x)
|
|
compile(x)
|
|
y=x()
|
|
compile(y)
|
|
assert(y(2) == 2)
|
|
assert(y(2) == 4)
|
|
assert(y(3) == 7)
|
|
print('test 40 Ok')
|
|
|
|
-- test 32
|
|
x=function(a,b)
|
|
return a%b
|
|
end
|
|
assert(compile(x))
|
|
assert(x(5,2) == 1)
|
|
assert(math.abs(x(5.1,2.1)-0.9) < 1e-12)
|
|
print("test 41 OK")
|
|
|
|
-- test 33
|
|
x=function(a,b)
|
|
return a//b
|
|
end
|
|
assert(compile(x))
|
|
assert(x(5,2) == 2)
|
|
assert(math.abs(x(5.5,2.1)-2.0) < 1e-12)
|
|
print("test 42 OK")
|
|
|
|
-- test 6
|
|
x = function ()
|
|
local j = 0
|
|
for i=2.0,6.0,3.1 do
|
|
j = i
|
|
end
|
|
return j
|
|
end
|
|
|
|
if (not compile(x)) then
|
|
print("test 6 FAILED to compile")
|
|
end
|
|
assert(x() == 5.1)
|
|
print("test 43 OK")
|
|
|
|
-- test parameter types
|
|
x = function (a: integer, b: number)
|
|
local i: integer = a
|
|
local j: number = b
|
|
return i+j
|
|
end
|
|
--ravi.dumplua(x)
|
|
assert(x(1,5.5) == 6.5)
|
|
compile(x)
|
|
assert(x(1,5.5) == 6.5)
|
|
print'test 44 OK'
|
|
|
|
x=function (a:number[], b:integer)
|
|
local j: number = a[b]
|
|
return j
|
|
end
|
|
function y()
|
|
local t: number[] = { 4.2 }
|
|
return x(t, 1)
|
|
end
|
|
|
|
assert(y() == 4.2)
|
|
compile(x)
|
|
compile(y)
|
|
assert(y() == 4.2)
|
|
print'test 45 OK'
|
|
|
|
-- test 40
|
|
function x(t) return t; end
|
|
function f()
|
|
local tt: integer[] = {1}
|
|
local ss: number[] = { 55.5 }
|
|
tt = x(tt)
|
|
ss = x(ss)
|
|
end
|
|
assert(compile(x))
|
|
assert(compile(f))
|
|
assert(pcall(f))
|
|
function f()
|
|
local tt: integer[] = {1}
|
|
tt = x({})
|
|
end
|
|
--ravi.dumplua(f)
|
|
print'+'
|
|
assert(compile(f))
|
|
assert(not pcall(f))
|
|
print'+'
|
|
function f()
|
|
local tt: integer[] = {1}
|
|
local ss: number[] = { 55.5 }
|
|
ss = x(tt)
|
|
end
|
|
print'+'
|
|
assert(compile(f))
|
|
assert(not pcall(f))
|
|
|
|
print("test 46 OK")
|
|
|
|
|
|
-- test 41
|
|
function test_idiv()
|
|
local t = {}
|
|
t.__idiv = function(...) return 'idiv' end
|
|
local t1=setmetatable({1,2,3}, t)
|
|
local t2=setmetatable({4,5,6}, t)
|
|
local x= function() return t1//t2 end
|
|
check(x, 'GETUPVAL', 'GETUPVAL', 'IDIV', 'RETURN', 'RETURN')
|
|
local s1=x()
|
|
assert(s1 == 'idiv')
|
|
assert(compile(t.__idiv))
|
|
assert(compile(x))
|
|
local s2=x()
|
|
assert(s1 == s2)
|
|
local x= function(t1: number, t2: number) return t1//t2 end
|
|
check(x, 'TOFLT', 'TOFLT', 'IDIV', 'RETURN', 'RETURN')
|
|
local s1=x(4.1,2.0)
|
|
assert(s1 == 2)
|
|
assert(compile(x))
|
|
local s2=x(4.1,2.0)
|
|
assert(s1 == s2)
|
|
end
|
|
compile(test_idiv)
|
|
test_idiv()
|
|
print'test 47 (IDIV) OK'
|
|
|
|
function test_tableaccess()
|
|
-- Test specialised version of GETTABLE and SETTABLE
|
|
-- when local variable is known to be of table type
|
|
-- and key is a string
|
|
local f = function()
|
|
local t : table = {}
|
|
t.name = 'dibyendu'
|
|
t.data = {}
|
|
t.data.city = 'london'
|
|
return t.name, t.data.city
|
|
end
|
|
check(f, 'NEWTABLE', 'SETTABLE_S', 'NEWTABLE',
|
|
'SETTABLE_S', 'GETTABLE_S', 'SETTABLE',
|
|
'GETTABLE_S', 'GETTABLE_S' , 'GETTABLE',
|
|
'RETURN', 'RETURN')
|
|
local a,b = f()
|
|
assert(a == 'dibyendu')
|
|
assert(b == 'london')
|
|
assert(compile(f))
|
|
a,b = f()
|
|
assert(a == 'dibyendu')
|
|
assert(b == 'london')
|
|
|
|
-- Test specialised version of GETTABLE and SETTABLE
|
|
-- when local variable is known to be of table type
|
|
-- and key is a integer
|
|
f = function()
|
|
local t : table = {}
|
|
t[1] = 'dibyendu'
|
|
t[2] = {}
|
|
t[2][1] = 'london'
|
|
return t[1], t[2][1]
|
|
end
|
|
check(f, 'NEWTABLE', 'SETTABLE_I', 'NEWTABLE',
|
|
'SETTABLE_I', 'GETTABLE_I', 'SETTABLE',
|
|
'GETTABLE_I', 'GETTABLE_I' , 'GETTABLE',
|
|
'RETURN', 'RETURN')
|
|
local a,b = f()
|
|
assert(a == 'dibyendu')
|
|
assert(b == 'london')
|
|
assert(compile(f))
|
|
a,b = f()
|
|
assert(a == 'dibyendu')
|
|
assert(b == 'london')
|
|
end
|
|
test_tableaccess()
|
|
print 'Test 48 OK'
|
|
|
|
function test_self_s()
|
|
local t : table = {}
|
|
t.name_ = 'dibyendu majumdar'
|
|
t.name = function (t:table) return t.name_ end
|
|
print(t:name())
|
|
return t:name()
|
|
end
|
|
check(test_self_s, 'NEWTABLE', 'SETTABLE_S', 'CLOSURE',
|
|
'SETTABLE_S', 'GETTABUP', 'SELF_S', 'CALL', 'CALL', 'SELF_S', 'TAILCALL',
|
|
'RETURN')
|
|
assert(test_self_s() == 'dibyendu majumdar')
|
|
compile(test_self_s)
|
|
assert(test_self_s() == 'dibyendu majumdar')
|
|
print 'Test 49 OK'
|
|
|
|
-- issue #73
|
|
function bug_index_event()
|
|
local t1 = { name='dibyendu' }
|
|
local t2 = { surname='majumdar' }
|
|
t2.__index = t2
|
|
setmetatable(t1, t2)
|
|
assert(t1.name == 'dibyendu')
|
|
assert(t1.surname == 'majumdar') -- index event
|
|
assert(t1.surname == 'majumdar') -- index event
|
|
|
|
local t3: table = { name='dibyendu' }
|
|
setmetatable(t3, t2)
|
|
assert(t3.name == 'dibyendu')
|
|
assert(t3.surname == 'majumdar') -- index event
|
|
assert(t3.surname == 'majumdar') -- index event
|
|
|
|
t1 = { [1]='dibyendu' }
|
|
t2 = { [2]='majumdar' }
|
|
t2.__index = t2
|
|
setmetatable(t1, t2)
|
|
assert(t1[1] == 'dibyendu')
|
|
assert(t1[2] == 'majumdar') -- index event
|
|
assert(t1[2] == 'majumdar') -- index event
|
|
|
|
local t3: table = { [1]='dibyendu' }
|
|
setmetatable(t3, t2)
|
|
assert(t3[1] == 'dibyendu')
|
|
assert(t3[2] == 'majumdar') -- index event
|
|
assert(t3[2] == 'majumdar') -- index event
|
|
end
|
|
bug_index_event()
|
|
compile(bug_index_event)
|
|
bug_index_event()
|
|
print 'Test 50 OK'
|
|
|
|
|
|
for k,v in pairs(opcodes_coverage)
|
|
do
|
|
print(k, v)
|
|
end
|
|
|