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'