From 9b37a4695ebf50b37b5b4fb279ae948f23b5b6a0 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Tue, 19 Mar 2019 10:53:18 -0300 Subject: New semantics for the integer 'for' loop The numerical 'for' loop over integers now uses a precomputed counter to control its number of iteractions. This change eliminates several weird cases caused by overflows (wrap-around) in the control variable. (It also ensures that every integer loop halts.) Also, the special opcodes for the usual case of step==1 were removed. (The new code is already somewhat complex for the usual case, but efficient.) --- testes/code.lua | 4 +-- testes/db.lua | 2 +- testes/nextvar.lua | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 71 insertions(+), 8 deletions(-) (limited to 'testes') diff --git a/testes/code.lua b/testes/code.lua index 834ff5e2..128ca2cb 100644 --- a/testes/code.lua +++ b/testes/code.lua @@ -303,9 +303,9 @@ check(function (x) return x & 2.0 end, 'LOADF', 'BAND', 'RETURN1') -- basic 'for' loops check(function () for i = -10, 10.5 do end end, -'LOADI', 'LOADK', 'LOADI', 'FORPREP1', 'FORLOOP1', 'RETURN0') +'LOADI', 'LOADK', 'LOADI', 'FORPREP', 'FORLOOP', 'RETURN0') check(function () for i = 0xfffffff, 10.0, 1 do end end, -'LOADK', 'LOADF', 'LOADI', 'FORPREP1', 'FORLOOP1', 'RETURN0') +'LOADK', 'LOADF', 'LOADI', 'FORPREP', 'FORLOOP', 'RETURN0') -- bug in constant folding for 5.1 check(function () return -nil end, 'LOADNIL', 'UNM', 'RETURN1') diff --git a/testes/db.lua b/testes/db.lua index 976962b0..0858dd20 100644 --- a/testes/db.lua +++ b/testes/db.lua @@ -162,7 +162,7 @@ test([[for i,v in pairs{'a','b'} do end ]], {1,2,1,2,1,3}) -test([[for i=1,4 do a=1 end]], {1,1,1,1,1}) +test([[for i=1,4 do a=1 end]], {1,1,1,1}, true) do -- testing line info/trace with large gaps in source diff --git a/testes/nextvar.lua b/testes/nextvar.lua index d2306ed1..e769ccdd 100644 --- a/testes/nextvar.lua +++ b/testes/nextvar.lua @@ -76,7 +76,7 @@ while a < lim do a = math.ceil(a*1.3) end - + local function check (t, na, nh) local a, h = T.querytab(t) if a ~= na or h ~= nh then @@ -100,7 +100,7 @@ local s = 'return {' for i=1,lim do s = s..i..',' local s = s - for k=0,lim do + for k=0,lim do local t = load(s..'}', '')() assert(#t == i) check(t, fb(i), mp2(k)) @@ -279,7 +279,7 @@ do -- clear global table end --- +-- local function checknext (a) local b = {} @@ -500,7 +500,7 @@ else --[ mt.__newindex = nil mt.__len = nil local tab2 = {} - local u2 = T.newuserdata(0) + local u2 = T.newuserdata(0) debug.setmetatable(u2, {__newindex = function (_, k, v) tab2[k] = v end}) table.move(u, 1, 4, 1, u2) assert(#tab2 == 4 and tab2[1] == tab[1] and tab2[4] == tab[4]) @@ -601,6 +601,69 @@ do -- checking types end + +do -- testing other strange cases for numeric 'for' + + local function checkfor (from, to, step, t) + local c = 0 + for i = from, to, step do + c = c + 1 + assert(i == t[c]) + end + assert(c == #t) + end + + 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 do + assert(i == c) + c = c + step + end + + c = maxi + for i = maxi, mini, -step do + assert(i == c) + c = c - step + end + + checkfor(maxi, maxi, maxi, {maxi}) + checkfor(maxi, maxi, mini, {maxi}) + checkfor(mini, mini, maxi, {mini}) + checkfor(mini, mini, mini, {mini}) +end + + +checkerror("'for' step is zero", function () + for i = 1, 10, 0 do end +end) + +checkerror("'for' step is zero", function () + for i = 1, -10, 0 do end +end) + +checkerror("'for' step is zero", function () + for i = 1.0, -10, 0.0 do end +end) + collectgarbage() @@ -657,7 +720,7 @@ a[3] = 30 -- testing ipairs with metamethods a = {n=10} setmetatable(a, { __index = function (t,k) - if k <= t.n then return k * 10 end + if k <= t.n then return k * 10 end end}) i = 0 for k,v in ipairs(a) do -- cgit v1.2.3-55-g6feb