| -- $Id: testes/goto.lua $ |
| -- See Copyright Notice in file all.lua |
| |
| collectgarbage() |
| |
| local function errmsg (code, m) |
| local st, msg = load(code) |
| assert(not st and string.find(msg, m)) |
| end |
| |
| -- cannot see label inside block |
| errmsg([[ goto l1; do ::l1:: end ]], "label 'l1'") |
| errmsg([[ do ::l1:: end goto l1; ]], "label 'l1'") |
| |
| -- repeated label |
| errmsg([[ ::l1:: ::l1:: ]], "label 'l1'") |
| errmsg([[ ::l1:: do ::l1:: end]], "label 'l1'") |
| |
| |
| -- undefined label |
| errmsg([[ goto l1; local aa ::l1:: ::l2:: print(3) ]], "local 'aa'") |
| |
| -- jumping over variable definition |
| errmsg([[ |
| do local bb, cc; goto l1; end |
| local aa |
| ::l1:: print(3) |
| ]], "local 'aa'") |
| |
| -- jumping into a block |
| errmsg([[ do ::l1:: end goto l1 ]], "label 'l1'") |
| errmsg([[ goto l1 do ::l1:: end ]], "label 'l1'") |
| |
| -- cannot continue a repeat-until with variables |
| errmsg([[ |
| repeat |
| if x then goto cont end |
| local xuxu = 10 |
| ::cont:: |
| until xuxu < x |
| ]], "local 'xuxu'") |
| |
| -- simple gotos |
| local x |
| do |
| local y = 12 |
| goto l1 |
| ::l2:: x = x + 1; goto l3 |
| ::l1:: x = y; goto l2 |
| end |
| ::l3:: ::l3_1:: assert(x == 13) |
| |
| |
| -- long labels |
| do |
| local prog = [[ |
| do |
| local a = 1 |
| goto l%sa; a = a + 1 |
| ::l%sa:: a = a + 10 |
| goto l%sb; a = a + 2 |
| ::l%sb:: a = a + 20 |
| return a |
| end |
| ]] |
| local label = string.rep("0123456789", 40) |
| prog = string.format(prog, label, label, label, label) |
| assert(assert(load(prog))() == 31) |
| end |
| |
| |
| -- ok to jump over local dec. to end of block |
| do |
| goto l1 |
| local a = 23 |
| x = a |
| ::l1::; |
| end |
| |
| while true do |
| goto l4 |
| goto l1 -- ok to jump over local dec. to end of block |
| goto l1 -- multiple uses of same label |
| local x = 45 |
| ::l1:: ;;; |
| end |
| ::l4:: assert(x == 13) |
| |
| if print then |
| goto l1 -- ok to jump over local dec. to end of block |
| error("should not be here") |
| goto l2 -- ok to jump over local dec. to end of block |
| local x |
| ::l1:: ; ::l2:: ;; |
| else end |
| |
| -- to repeat a label in a different function is OK |
| local function foo () |
| local a = {} |
| goto l3 |
| ::l1:: a[#a + 1] = 1; goto l2; |
| ::l2:: a[#a + 1] = 2; goto l5; |
| ::l3:: |
| ::l3a:: a[#a + 1] = 3; goto l1; |
| ::l4:: a[#a + 1] = 4; goto l6; |
| ::l5:: a[#a + 1] = 5; goto l4; |
| ::l6:: assert(a[1] == 3 and a[2] == 1 and a[3] == 2 and |
| a[4] == 5 and a[5] == 4) |
| if not a[6] then a[6] = true; goto l3a end -- do it twice |
| end |
| |
| ::l6:: foo() |
| |
| |
| do -- bug in 5.2 -> 5.3.2 |
| local x |
| ::L1:: |
| local y -- cannot join this SETNIL with previous one |
| assert(y == nil) |
| y = true |
| if x == nil then |
| x = 1 |
| goto L1 |
| else |
| x = x + 1 |
| end |
| assert(x == 2 and y == true) |
| end |
| |
| -- bug in 5.3 |
| do |
| local first = true |
| local a = false |
| if true then |
| goto LBL |
| ::loop:: |
| a = true |
| ::LBL:: |
| if first then |
| first = false |
| goto loop |
| end |
| end |
| assert(a) |
| end |
| |
| do -- compiling infinite loops |
| goto escape -- do not run the infinite loops |
| ::a:: goto a |
| ::b:: goto c |
| ::c:: goto b |
| end |
| ::escape:: |
| -------------------------------------------------------------------------------- |
| -- testing closing of upvalues |
| |
| local debug = require 'debug' |
| |
| local function foo () |
| local t = {} |
| do |
| local i = 1 |
| local a, b, c, d |
| t[1] = function () return a, b, c, d end |
| ::l1:: |
| local b |
| do |
| local c |
| t[#t + 1] = function () return a, b, c, d end -- t[2], t[4], t[6] |
| if i > 2 then goto l2 end |
| do |
| local d |
| t[#t + 1] = function () return a, b, c, d end -- t[3], t[5] |
| i = i + 1 |
| local a |
| goto l1 |
| end |
| end |
| end |
| ::l2:: return t |
| end |
| |
| local a = foo() |
| assert(#a == 6) |
| |
| -- all functions share same 'a' |
| for i = 2, 6 do |
| assert(debug.upvalueid(a[1], 1) == debug.upvalueid(a[i], 1)) |
| end |
| |
| -- 'b' and 'c' are shared among some of them |
| for i = 2, 6 do |
| -- only a[1] uses external 'b'/'b' |
| assert(debug.upvalueid(a[1], 2) ~= debug.upvalueid(a[i], 2)) |
| assert(debug.upvalueid(a[1], 3) ~= debug.upvalueid(a[i], 3)) |
| end |
| |
| for i = 3, 5, 2 do |
| -- inner functions share 'b'/'c' with previous ones |
| assert(debug.upvalueid(a[i], 2) == debug.upvalueid(a[i - 1], 2)) |
| assert(debug.upvalueid(a[i], 3) == debug.upvalueid(a[i - 1], 3)) |
| -- but not with next ones |
| assert(debug.upvalueid(a[i], 2) ~= debug.upvalueid(a[i + 1], 2)) |
| assert(debug.upvalueid(a[i], 3) ~= debug.upvalueid(a[i + 1], 3)) |
| end |
| |
| -- only external 'd' is shared |
| for i = 2, 6, 2 do |
| assert(debug.upvalueid(a[1], 4) == debug.upvalueid(a[i], 4)) |
| end |
| |
| -- internal 'd's are all different |
| for i = 3, 5, 2 do |
| for j = 1, 6 do |
| assert((debug.upvalueid(a[i], 4) == debug.upvalueid(a[j], 4)) |
| == (i == j)) |
| end |
| end |
| |
| -------------------------------------------------------------------------------- |
| -- testing if x goto optimizations |
| |
| local function testG (a) |
| if a == 1 then |
| goto l1 |
| error("should never be here!") |
| elseif a == 2 then goto l2 |
| elseif a == 3 then goto l3 |
| elseif a == 4 then |
| goto l1 -- go to inside the block |
| error("should never be here!") |
| ::l1:: a = a + 1 -- must go to 'if' end |
| else |
| goto l4 |
| ::l4a:: a = a * 2; goto l4b |
| error("should never be here!") |
| ::l4:: goto l4a |
| error("should never be here!") |
| ::l4b:: |
| end |
| do return a end |
| ::l2:: do return "2" end |
| ::l3:: do return "3" end |
| ::l1:: return "1" |
| end |
| |
| assert(testG(1) == "1") |
| assert(testG(2) == "2") |
| assert(testG(3) == "3") |
| assert(testG(4) == 5) |
| assert(testG(5) == 10) |
| |
| do |
| -- if x back goto out of scope of upvalue |
| local X |
| goto L1 |
| |
| ::L2:: goto L3 |
| |
| ::L1:: do |
| local a <close> = setmetatable({}, {__close = function () X = true end}) |
| assert(X == nil) |
| if a then goto L2 end -- jumping back out of scope of 'a' |
| end |
| |
| ::L3:: assert(X == true) -- checks that 'a' was correctly closed |
| end |
| -------------------------------------------------------------------------------- |
| |
| |
| print'OK' |