1-- $Id: testes/goto.lua $
  2-- See Copyright Notice in file all.lua
  3
  4collectgarbage()
  5
  6local function errmsg (code, m)
  7  local st, msg = load(code)
  8  assert(not st and string.find(msg, m))
  9end
 10
 11-- cannot see label inside block
 12errmsg([[ goto l1; do ::l1:: end ]], "label 'l1'")
 13errmsg([[ do ::l1:: end goto l1; ]], "label 'l1'")
 14
 15-- repeated label
 16errmsg([[ ::l1:: ::l1:: ]], "label 'l1'")
 17errmsg([[ ::l1:: do ::l1:: end]], "label 'l1'")
 18
 19
 20-- undefined label
 21errmsg([[ goto l1; local aa ::l1:: ::l2:: print(3) ]], "local 'aa'")
 22
 23-- jumping over variable definition
 24errmsg([[
 25do local bb, cc; goto l1; end
 26local aa
 27::l1:: print(3)
 28]], "local 'aa'")
 29
 30-- jumping into a block
 31errmsg([[ do ::l1:: end goto l1 ]], "label 'l1'")
 32errmsg([[ goto l1 do ::l1:: end ]], "label 'l1'")
 33
 34-- cannot continue a repeat-until with variables
 35errmsg([[
 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
 44local x
 45do
 46  local y = 12
 47  goto l1
 48  ::l2:: x = x + 1; goto l3
 49  ::l1:: x = y; goto l2
 50end
 51::l3:: ::l3_1:: assert(x == 13)
 52
 53
 54-- long labels
 55do
 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)
 69end
 70
 71
 72-- ok to jump over local dec. to end of block
 73do
 74  goto l1
 75  local a = 23
 76  x = a
 77  ::l1::;
 78end
 79
 80while 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:: ;;;
 86end
 87::l4:: assert(x == 13)
 88
 89if 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:: ;;
 95else end
 96
 97-- to repeat a label in a different function is OK
 98local 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
110end
111
112::l6:: foo()
113
114
115do   -- 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)
128end
129
130-- bug in 5.3
131do
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)
145end
146
147do   -- compiling infinite loops
148  goto escape   -- do not run the infinite loops
149  ::a:: goto a
150  ::b:: goto c
151  ::c:: goto b
152end
153::escape::
154--------------------------------------------------------------------------------
155-- testing closing of upvalues
156
157local debug = require 'debug'
158
159local 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
181end
182
183local a = foo()
184assert(#a == 6)
185
186-- all functions share same 'a'
187for i = 2, 6 do
188  assert(debug.upvalueid(a[1], 1) == debug.upvalueid(a[i], 1))
189end
190
191-- 'b' and 'c' are shared among some of them
192for 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))
196end
197
198for 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))
205end
206
207-- only external 'd' is shared
208for i = 2, 6, 2 do
209  assert(debug.upvalueid(a[1], 4) == debug.upvalueid(a[i], 4))
210end
211
212-- internal 'd's are all different
213for 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
218end
219
220--------------------------------------------------------------------------------
221-- testing if x goto optimizations
222
223local 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"
245end
246
247assert(testG(1) == "1")
248assert(testG(2) == "2")
249assert(testG(3) == "3")
250assert(testG(4) == 5)
251assert(testG(5) == 10)
252
253do
254  -- if x back goto out of scope of upvalue
255  local X
256  goto L1
257
258  ::L2:: goto L3
259
260  ::L1:: do
261    local a <close> = setmetatable({}, {__close = function () X = true end})
262    assert(X == nil)
263    if a then goto L2 end   -- jumping back out of scope of 'a'
264  end
265
266  ::L3:: assert(X == true)   -- checks that 'a' was correctly closed
267end
268--------------------------------------------------------------------------------
269
270
271print'OK'