diff options
Diffstat (limited to '')
-rw-r--r-- | testes/goto.lua | 170 |
1 files changed, 160 insertions, 10 deletions
diff --git a/testes/goto.lua b/testes/goto.lua index eca68516..3310314d 100644 --- a/testes/goto.lua +++ b/testes/goto.lua | |||
@@ -1,6 +1,12 @@ | |||
1 | -- $Id: testes/goto.lua $ | 1 | -- $Id: testes/goto.lua $ |
2 | -- See Copyright Notice in file lua.h | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | global<const> require | ||
5 | global<const> print, load, assert, string, setmetatable | ||
6 | global<const> collectgarbage, error | ||
7 | |||
8 | print("testing goto and global declarations") | ||
9 | |||
4 | collectgarbage() | 10 | collectgarbage() |
5 | 11 | ||
6 | local function errmsg (code, m) | 12 | local function errmsg (code, m) |
@@ -17,15 +23,18 @@ errmsg([[ ::l1:: ::l1:: ]], "label 'l1'") | |||
17 | errmsg([[ ::l1:: do ::l1:: end]], "label 'l1'") | 23 | errmsg([[ ::l1:: do ::l1:: end]], "label 'l1'") |
18 | 24 | ||
19 | 25 | ||
20 | -- undefined label | ||
21 | errmsg([[ goto l1; local aa ::l1:: ::l2:: print(3) ]], "local 'aa'") | ||
22 | 26 | ||
23 | -- jumping over variable definition | 27 | -- jumping over variable declaration |
28 | errmsg([[ goto l1; local aa ::l1:: ::l2:: print(3) ]], "scope of 'aa'") | ||
29 | |||
30 | errmsg([[ goto l2; global *; ::l1:: ::l2:: print(3) ]], "scope of '*'") | ||
31 | |||
24 | errmsg([[ | 32 | errmsg([[ |
25 | do local bb, cc; goto l1; end | 33 | do local bb, cc; goto l1; end |
26 | local aa | 34 | local aa |
27 | ::l1:: print(3) | 35 | ::l1:: print(3) |
28 | ]], "local 'aa'") | 36 | ]], "scope of 'aa'") |
37 | |||
29 | 38 | ||
30 | -- jumping into a block | 39 | -- jumping into a block |
31 | errmsg([[ do ::l1:: end goto l1 ]], "label 'l1'") | 40 | errmsg([[ do ::l1:: end goto l1 ]], "label 'l1'") |
@@ -38,7 +47,7 @@ errmsg([[ | |||
38 | local xuxu = 10 | 47 | local xuxu = 10 |
39 | ::cont:: | 48 | ::cont:: |
40 | until xuxu < x | 49 | until xuxu < x |
41 | ]], "local 'xuxu'") | 50 | ]], "scope of 'xuxu'") |
42 | 51 | ||
43 | -- simple gotos | 52 | -- simple gotos |
44 | local x | 53 | local x |
@@ -252,6 +261,8 @@ assert(testG(5) == 10) | |||
252 | 261 | ||
253 | do -- test goto's around to-be-closed variable | 262 | do -- test goto's around to-be-closed variable |
254 | 263 | ||
264 | global * | ||
265 | |||
255 | -- set 'var' and return an object that will reset 'var' when | 266 | -- set 'var' and return an object that will reset 'var' when |
256 | -- it goes out of scope | 267 | -- it goes out of scope |
257 | local function newobj (var) | 268 | local function newobj (var) |
@@ -263,16 +274,16 @@ do -- test goto's around to-be-closed variable | |||
263 | 274 | ||
264 | goto L1 | 275 | goto L1 |
265 | 276 | ||
266 | ::L4:: assert(not X); goto L5 -- varX dead here | 277 | ::L4:: assert(not varX); goto L5 -- varX dead here |
267 | 278 | ||
268 | ::L1:: | 279 | ::L1:: |
269 | local varX <close> = newobj("X") | 280 | local varX <close> = newobj("X") |
270 | assert(X); goto L2 -- varX alive here | 281 | assert(varX); goto L2 -- varX alive here |
271 | 282 | ||
272 | ::L3:: | 283 | ::L3:: |
273 | assert(X); goto L4 -- varX alive here | 284 | assert(varX); goto L4 -- varX alive here |
274 | 285 | ||
275 | ::L2:: assert(X); goto L3 -- varX alive here | 286 | ::L2:: assert(varX); goto L3 -- varX alive here |
276 | 287 | ||
277 | ::L5:: -- return | 288 | ::L5:: -- return |
278 | end | 289 | end |
@@ -280,7 +291,146 @@ end | |||
280 | 291 | ||
281 | 292 | ||
282 | foo() | 293 | foo() |
283 | -------------------------------------------------------------------------------- | 294 | -------------------------------------------------------------------------- |
295 | |||
296 | local function checkerr (code, err) | ||
297 | local st, msg = load(code) | ||
298 | assert(not st and string.find(msg, err)) | ||
299 | end | ||
300 | |||
301 | do | ||
302 | global T<const> | ||
303 | |||
304 | -- globals must be declared, after a global declaration | ||
305 | checkerr("global none; X = 1", "variable 'X'") | ||
306 | checkerr("global none; function XX() end", "variable 'XX'") | ||
284 | 307 | ||
308 | -- global variables cannot be to-be-closed | ||
309 | checkerr("global X<close>", "cannot be") | ||
310 | checkerr("global <close> *", "cannot be") | ||
311 | |||
312 | do | ||
313 | local X = 10 | ||
314 | do global X; X = 20 end | ||
315 | assert(X == 10) -- local X | ||
316 | end | ||
317 | assert(_ENV.X == 20) -- global X | ||
318 | |||
319 | -- '_ENV' cannot be global | ||
320 | checkerr("global _ENV, a; a = 10", "variable 'a'") | ||
321 | |||
322 | -- global declarations inside functions | ||
323 | checkerr([[ | ||
324 | global none | ||
325 | local function foo () XXX = 1 end --< ERROR]], "variable 'XXX'") | ||
326 | |||
327 | if not T then -- when not in "test mode", "global" isn't reserved | ||
328 | assert(load("global = 1; return global")() == 1) | ||
329 | print " ('global' is not a reserved word)" | ||
330 | else | ||
331 | -- "global" reserved, cannot be used as a variable | ||
332 | assert(not load("global = 1; return global")) | ||
333 | end | ||
334 | |||
335 | local foo = 20 | ||
336 | do | ||
337 | global function foo (x) | ||
338 | if x == 0 then return 1 else return 2 * foo(x - 1) end | ||
339 | end | ||
340 | assert(foo == _ENV.foo and foo(4) == 16) | ||
341 | end | ||
342 | assert(_ENV.foo(4) == 16) | ||
343 | assert(foo == 20) -- local one is in context here | ||
344 | |||
345 | do | ||
346 | global foo; | ||
347 | function foo (x) return end -- Ok after declaration | ||
348 | end | ||
349 | |||
350 | checkerr([[ | ||
351 | global<const> foo; | ||
352 | function foo (x) return end -- ERROR: foo is read-only | ||
353 | ]], "assign to const variable 'foo'") | ||
354 | |||
355 | checkerr([[ | ||
356 | global foo <const>; | ||
357 | function foo (x) -- ERROR: foo is read-only | ||
358 | return | ||
359 | end | ||
360 | ]], "%:2%:") -- correct line in error message | ||
361 | |||
362 | checkerr([[ | ||
363 | global<const> *; | ||
364 | print(X) -- Ok to use | ||
365 | Y = 1 -- ERROR | ||
366 | ]], "assign to const variable 'Y'") | ||
367 | |||
368 | checkerr([[ | ||
369 | global *; | ||
370 | Y = X -- Ok to use | ||
371 | global<const> *; | ||
372 | Y = 1 -- ERROR | ||
373 | ]], "assign to const variable 'Y'") | ||
374 | |||
375 | global * | ||
376 | Y = 10 | ||
377 | assert(_ENV.Y == 10) | ||
378 | global<const> * | ||
379 | local x = Y | ||
380 | global * | ||
381 | Y = x + Y | ||
382 | assert(_ENV.Y == 20) | ||
383 | Y = nil | ||
384 | end | ||
385 | |||
386 | |||
387 | do -- Ok to declare hundreds of globals | ||
388 | global table | ||
389 | local code = {} | ||
390 | for i = 1, 1000 do | ||
391 | code[#code + 1] = ";global x" .. i | ||
392 | end | ||
393 | code[#code + 1] = "; return x990" | ||
394 | code = table.concat(code) | ||
395 | _ENV.x990 = 11 | ||
396 | assert(load(code)() == 11) | ||
397 | _ENV.x990 = nil | ||
398 | end | ||
399 | |||
400 | do -- mixing lots of global/local declarations | ||
401 | global table | ||
402 | local code = {} | ||
403 | for i = 1, 200 do | ||
404 | code[#code + 1] = ";global x" .. i | ||
405 | code[#code + 1] = ";local y" .. i .. "=" .. (2*i) | ||
406 | end | ||
407 | code[#code + 1] = "; return x200 + y200" | ||
408 | code = table.concat(code) | ||
409 | _ENV.x200 = 11 | ||
410 | assert(assert(load(code))() == 2*200 + 11) | ||
411 | _ENV.x200 = nil | ||
412 | end | ||
413 | |||
414 | do print "testing initialization in global declarations" | ||
415 | global<const> a, b, c = 10, 20, 30 | ||
416 | assert(_ENV.a == 10 and b == 20 and c == 30) | ||
417 | |||
418 | global<const> a, b, c = 10 | ||
419 | assert(_ENV.a == 10 and b == nil and c == nil) | ||
420 | |||
421 | global table | ||
422 | global a, b, c, d = table.unpack{1, 2, 3, 6, 5} | ||
423 | assert(_ENV.a == 1 and b == 2 and c == 3 and d == 6) | ||
424 | |||
425 | local a, b = 100, 200 | ||
426 | do | ||
427 | global a, b = a, b | ||
428 | end | ||
429 | assert(_ENV.a == 100 and _ENV.b == 200) | ||
430 | |||
431 | |||
432 | _ENV.a, _ENV.b, _ENV.c, _ENV.d = nil -- erase these globals | ||
433 | end | ||
285 | 434 | ||
286 | print'OK' | 435 | print'OK' |
436 | |||