lua

A copy of the Lua development repository
Log | Files | Refs | README

goto.lua (5982B)


      1 -- $Id: testes/goto.lua $
      2 -- See Copyright Notice in file all.lua
      3 
      4 collectgarbage()
      5 
      6 local function errmsg (code, m)
      7   local st, msg = load(code)
      8   assert(not st and string.find(msg, m))
      9 end
     10 
     11 -- cannot see label inside block
     12 errmsg([[ goto l1; do ::l1:: end ]], "label 'l1'")
     13 errmsg([[ do ::l1:: end goto l1; ]], "label 'l1'")
     14 
     15 -- repeated label
     16 errmsg([[ ::l1:: ::l1:: ]], "label 'l1'")
     17 errmsg([[ ::l1:: do ::l1:: end]], "label 'l1'")
     18 
     19 
     20 -- undefined label
     21 errmsg([[ goto l1; local aa ::l1:: ::l2:: print(3) ]], "local 'aa'")
     22 
     23 -- jumping over variable definition
     24 errmsg([[
     25 do local bb, cc; goto l1; end
     26 local aa
     27 ::l1:: print(3)
     28 ]], "local 'aa'")
     29 
     30 -- jumping into a block
     31 errmsg([[ do ::l1:: end goto l1 ]], "label 'l1'")
     32 errmsg([[ goto l1 do ::l1:: end ]], "label 'l1'")
     33 
     34 -- cannot continue a repeat-until with variables
     35 errmsg([[
     36   repeat
     37     if x then goto cont end
     38     local xuxu = 10
     39     ::cont::
     40   until xuxu < x
     41 ]], "local 'xuxu'")
     42 
     43 -- simple gotos
     44 local x
     45 do
     46   local y = 12
     47   goto l1
     48   ::l2:: x = x + 1; goto l3
     49   ::l1:: x = y; goto l2
     50 end
     51 ::l3:: ::l3_1:: assert(x == 13)
     52 
     53 
     54 -- long labels
     55 do
     56   local prog = [[
     57   do
     58     local a = 1
     59     goto l%sa; a = a + 1
     60    ::l%sa:: a = a + 10
     61     goto l%sb; a = a + 2
     62    ::l%sb:: a = a + 20
     63     return a
     64   end
     65   ]]
     66   local label = string.rep("0123456789", 40)
     67   prog = string.format(prog, label, label, label, label)
     68   assert(assert(load(prog))() == 31)
     69 end
     70 
     71 
     72 -- ok to jump over local dec. to end of block
     73 do
     74   goto l1
     75   local a = 23
     76   x = a
     77   ::l1::;
     78 end
     79 
     80 while true do
     81   goto l4
     82   goto l1  -- ok to jump over local dec. to end of block
     83   goto l1  -- multiple uses of same label
     84   local x = 45
     85   ::l1:: ;;;
     86 end
     87 ::l4:: assert(x == 13)
     88 
     89 if print then
     90   goto l1   -- ok to jump over local dec. to end of block
     91   error("should not be here")
     92   goto l2   -- ok to jump over local dec. to end of block
     93   local x
     94   ::l1:: ; ::l2:: ;;
     95 else end
     96 
     97 -- to repeat a label in a different function is OK
     98 local function foo ()
     99   local a = {}
    100   goto l3
    101   ::l1:: a[#a + 1] = 1; goto l2;
    102   ::l2:: a[#a + 1] = 2; goto l5;
    103   ::l3::
    104   ::l3a:: a[#a + 1] = 3; goto l1;
    105   ::l4:: a[#a + 1] = 4; goto l6;
    106   ::l5:: a[#a + 1] = 5; goto l4;
    107   ::l6:: assert(a[1] == 3 and a[2] == 1 and a[3] == 2 and
    108               a[4] == 5 and a[5] == 4)
    109   if not a[6] then a[6] = true; goto l3a end   -- do it twice
    110 end
    111 
    112 ::l6:: foo()
    113 
    114 
    115 do   -- bug in 5.2 -> 5.3.2
    116   local x
    117   ::L1::
    118   local y             -- cannot join this SETNIL with previous one
    119   assert(y == nil)
    120   y = true
    121   if x == nil then
    122     x = 1
    123     goto L1
    124   else
    125     x = x + 1
    126   end
    127   assert(x == 2 and y == true)
    128 end
    129 
    130 -- bug in 5.3
    131 do
    132   local first = true
    133   local a = false
    134   if true then
    135     goto LBL
    136     ::loop::
    137     a = true
    138     ::LBL::
    139     if first then
    140       first = false
    141       goto loop
    142     end
    143   end
    144   assert(a)
    145 end
    146 
    147 do   -- compiling infinite loops
    148   goto escape   -- do not run the infinite loops
    149   ::a:: goto a
    150   ::b:: goto c
    151   ::c:: goto b
    152 end
    153 ::escape::
    154 --------------------------------------------------------------------------------
    155 -- testing closing of upvalues
    156 
    157 local debug = require 'debug'
    158 
    159 local function foo ()
    160   local t = {}
    161   do
    162   local i = 1
    163   local a, b, c, d
    164   t[1] = function () return a, b, c, d end
    165   ::l1::
    166   local b
    167   do
    168     local c
    169     t[#t + 1] = function () return a, b, c, d end    -- t[2], t[4], t[6]
    170     if i > 2 then goto l2 end
    171     do
    172       local d
    173       t[#t + 1] = function () return a, b, c, d end   -- t[3], t[5]
    174       i = i + 1
    175       local a
    176       goto l1
    177     end
    178   end
    179   end
    180   ::l2:: return t
    181 end
    182 
    183 local a = foo()
    184 assert(#a == 6)
    185 
    186 -- all functions share same 'a'
    187 for i = 2, 6 do
    188   assert(debug.upvalueid(a[1], 1) == debug.upvalueid(a[i], 1))
    189 end
    190 
    191 -- 'b' and 'c' are shared among some of them
    192 for i = 2, 6 do
    193   -- only a[1] uses external 'b'/'b'
    194   assert(debug.upvalueid(a[1], 2) ~= debug.upvalueid(a[i], 2))
    195   assert(debug.upvalueid(a[1], 3) ~= debug.upvalueid(a[i], 3))
    196 end
    197 
    198 for i = 3, 5, 2 do
    199   -- inner functions share 'b'/'c' with previous ones
    200   assert(debug.upvalueid(a[i], 2) == debug.upvalueid(a[i - 1], 2))
    201   assert(debug.upvalueid(a[i], 3) == debug.upvalueid(a[i - 1], 3))
    202   -- but not with next ones
    203   assert(debug.upvalueid(a[i], 2) ~= debug.upvalueid(a[i + 1], 2))
    204   assert(debug.upvalueid(a[i], 3) ~= debug.upvalueid(a[i + 1], 3))
    205 end
    206 
    207 -- only external 'd' is shared
    208 for i = 2, 6, 2 do
    209   assert(debug.upvalueid(a[1], 4) == debug.upvalueid(a[i], 4))
    210 end
    211 
    212 -- internal 'd's are all different
    213 for i = 3, 5, 2 do
    214   for j = 1, 6 do
    215     assert((debug.upvalueid(a[i], 4) == debug.upvalueid(a[j], 4))
    216       == (i == j))
    217   end
    218 end
    219 
    220 --------------------------------------------------------------------------------
    221 -- testing if x goto optimizations
    222 
    223 local function testG (a)
    224   if a == 1 then
    225     goto l1
    226     error("should never be here!")
    227   elseif a == 2 then goto l2
    228   elseif a == 3 then goto l3
    229   elseif a == 4 then
    230     goto l1  -- go to inside the block
    231     error("should never be here!")
    232     ::l1:: a = a + 1   -- must go to 'if' end
    233   else
    234     goto l4
    235     ::l4a:: a = a * 2; goto l4b
    236     error("should never be here!")
    237     ::l4:: goto l4a
    238     error("should never be here!")
    239     ::l4b::
    240   end
    241   do return a end
    242   ::l2:: do return "2" end
    243   ::l3:: do return "3" end
    244   ::l1:: return "1"
    245 end
    246 
    247 assert(testG(1) == "1")
    248 assert(testG(2) == "2")
    249 assert(testG(3) == "3")
    250 assert(testG(4) == 5)
    251 assert(testG(5) == 10)
    252 
    253 do   -- test goto's around to-be-closed variable
    254 
    255   -- set 'var' and return an object that will reset 'var' when
    256   -- it goes out of scope
    257   local function newobj (var)
    258     _ENV[var] = true
    259     return setmetatable({}, {__close = function ()
    260       _ENV[var] = nil
    261     end})
    262   end
    263 
    264   goto L1
    265 
    266   ::L4:: assert(not X); goto L5   -- varX dead here
    267 
    268   ::L1::
    269   local varX <close> = newobj("X")
    270   assert(X); goto L2   -- varX alive here
    271 
    272   ::L3::
    273   assert(X); goto L4   -- varX alive here
    274 
    275   ::L2:: assert(X); goto L3  -- varX alive here
    276 
    277   ::L5::   -- return
    278 end
    279 
    280 
    281 
    282 foo()
    283 --------------------------------------------------------------------------------
    284 
    285 
    286 print'OK'