github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/testdata/lua-5.3.3-tests/goto.lua (about)

     1  -- $Id: goto.lua,v 1.12 2016/03/07 19:26:18 roberto Exp $
     2  
     3  collectgarbage()
     4  
     5  local function errmsg (code, m)
     6    local st, msg = load(code)
     7    assert(not st and string.find(msg, m))
     8  end
     9  
    10  -- cannot see label inside block
    11  errmsg([[ goto l1; do ::l1:: end ]], "label 'l1'")
    12  errmsg([[ do ::l1:: end goto l1; ]], "label 'l1'")
    13  
    14  -- repeated label
    15  errmsg([[ ::l1:: ::l1:: ]], "label 'l1'")
    16  
    17  -- undefined label
    18  errmsg([[ goto l1; local aa ::l1:: ::l2:: print(3) ]], "local 'aa'")
    19  
    20  -- jumping over variable definition
    21  errmsg([[
    22  do local bb, cc; goto l1; end
    23  local aa
    24  ::l1:: print(3)
    25  ]], "local 'aa'")
    26  
    27  -- jumping into a block
    28  errmsg([[ do ::l1:: end goto l1 ]], "label 'l1'")
    29  errmsg([[ goto l1 do ::l1:: end ]], "label 'l1'")
    30  
    31  -- cannot continue a repeat-until with variables
    32  errmsg([[
    33    repeat
    34      if x then goto cont end
    35      local xuxu = 10
    36      ::cont::
    37    until xuxu < x
    38  ]], "local 'xuxu'")
    39  
    40  -- simple gotos
    41  local x
    42  do
    43    local y = 12
    44    goto l1
    45    ::l2:: x = x + 1; goto l3
    46    ::l1:: x = y; goto l2
    47  end
    48  ::l3:: ::l3_1:: assert(x == 13)
    49  
    50  -- long labels
    51  do
    52    local prog = [[
    53    do
    54      local a = 1
    55      goto l%sa; a = a + 1
    56     ::l%sa:: a = a + 10
    57      goto l%sb; a = a + 2
    58     ::l%sb:: a = a + 20
    59      return a
    60    end
    61    ]]
    62    local label = string.rep("0123456789", 40)
    63    prog = string.format(prog, label, label, label, label)
    64    assert(assert(load(prog))() == 31)
    65  end
    66  
    67  -- goto to correct label when nested
    68  do goto l3; ::l3:: end   -- does not loop jumping to previous label 'l3'
    69  
    70  -- ok to jump over local dec. to end of block
    71  do
    72    goto l1
    73    local a = 23
    74    x = a
    75    ::l1::;
    76  end
    77  
    78  while true do
    79    goto l4
    80    goto l1  -- ok to jump over local dec. to end of block
    81    goto l1  -- multiple uses of same label
    82    local x = 45
    83    ::l1:: ;;;
    84  end
    85  ::l4:: assert(x == 13)
    86  
    87  if print then
    88    goto l1   -- ok to jump over local dec. to end of block
    89    error("should not be here")
    90    goto l2   -- ok to jump over local dec. to end of block
    91    local x
    92    ::l1:: ; ::l2:: ;;
    93  else end
    94  
    95  -- to repeat a label in a different function is OK
    96  local function foo ()
    97    local a = {}
    98    goto l3
    99    ::l1:: a[#a + 1] = 1; goto l2;
   100    ::l2:: a[#a + 1] = 2; goto l5;
   101    ::l3::
   102    ::l3a:: a[#a + 1] = 3; goto l1;
   103    ::l4:: a[#a + 1] = 4; goto l6;
   104    ::l5:: a[#a + 1] = 5; goto l4;
   105    ::l6:: assert(a[1] == 3 and a[2] == 1 and a[3] == 2 and
   106                a[4] == 5 and a[5] == 4)
   107    if not a[6] then a[6] = true; goto l3a end   -- do it twice
   108  end
   109  
   110  ::l6:: foo()
   111  
   112  
   113  do   -- bug in 5.2 -> 5.3.2
   114    local x
   115    ::L1::
   116    local y             -- cannot join this SETNIL with previous one
   117    assert(y == nil)
   118    y = true
   119    if x == nil then
   120      x = 1
   121      goto L1
   122    else
   123      x = x + 1
   124    end
   125    assert(x == 2 and y == true)
   126  end
   127  
   128  --------------------------------------------------------------------------------
   129  -- testing closing of upvalues
   130  
   131  local debug = require 'debug'
   132  
   133  local function foo ()
   134    local t = {}
   135    do
   136    local i = 1
   137    local a, b, c, d
   138    t[1] = function () return a, b, c, d end
   139    ::l1::
   140    local b
   141    do
   142      local c
   143      t[#t + 1] = function () return a, b, c, d end    -- t[2], t[4], t[6]
   144      if i > 2 then goto l2 end
   145      do
   146        local d
   147        t[#t + 1] = function () return a, b, c, d end   -- t[3], t[5]
   148        i = i + 1
   149        local a
   150        goto l1
   151      end
   152    end
   153    end
   154    ::l2:: return t
   155  end
   156  
   157  local a = foo()
   158  assert(#a == 6)
   159  
   160  -- all functions share same 'a'
   161  for i = 2, 6 do
   162    assert(debug.upvalueid(a[1], 1) == debug.upvalueid(a[i], 1))
   163  end
   164  
   165  -- 'b' and 'c' are shared among some of them
   166  for i = 2, 6 do
   167    -- only a[1] uses external 'b'/'b'
   168    assert(debug.upvalueid(a[1], 2) ~= debug.upvalueid(a[i], 2))
   169    assert(debug.upvalueid(a[1], 3) ~= debug.upvalueid(a[i], 3))
   170  end
   171  
   172  for i = 3, 5, 2 do
   173    -- inner functions share 'b'/'c' with previous ones
   174    assert(debug.upvalueid(a[i], 2) == debug.upvalueid(a[i - 1], 2))
   175    assert(debug.upvalueid(a[i], 3) == debug.upvalueid(a[i - 1], 3))
   176    -- but not with next ones
   177    assert(debug.upvalueid(a[i], 2) ~= debug.upvalueid(a[i + 1], 2))
   178    assert(debug.upvalueid(a[i], 3) ~= debug.upvalueid(a[i + 1], 3))
   179  end
   180  
   181  -- only external 'd' is shared
   182  for i = 2, 6, 2 do
   183    assert(debug.upvalueid(a[1], 4) == debug.upvalueid(a[i], 4))
   184  end
   185  
   186  -- internal 'd's are all different
   187  for i = 3, 5, 2 do
   188    for j = 1, 6 do
   189      assert((debug.upvalueid(a[i], 4) == debug.upvalueid(a[j], 4))
   190        == (i == j))
   191    end
   192  end
   193  
   194  --------------------------------------------------------------------------------
   195  -- testing if x goto optimizations
   196  
   197  local function testG (a)
   198    if a == 1 then
   199      goto l1
   200      error("should never be here!")
   201    elseif a == 2 then goto l2
   202    elseif a == 3 then goto l3
   203    elseif a == 4 then
   204      goto l1  -- go to inside the block
   205      error("should never be here!")
   206      ::l1:: a = a + 1   -- must go to 'if' end
   207    else
   208      goto l4
   209      ::l4a:: a = a * 2; goto l4b
   210      error("should never be here!")
   211      ::l4:: goto l4a
   212      error("should never be here!")
   213      ::l4b::
   214    end
   215    do return a end
   216    ::l2:: do return "2" end
   217    ::l3:: do return "3" end
   218    ::l1:: return "1"
   219  end
   220  
   221  assert(testG(1) == "1")
   222  assert(testG(2) == "2")
   223  assert(testG(3) == "3")
   224  assert(testG(4) == 5)
   225  assert(testG(5) == 10)
   226  --------------------------------------------------------------------------------
   227  
   228  
   229  print'OK'