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