diff options
-rw-r--r-- | makefile | 2 | ||||
-rw-r--r-- | spec/inputs/goto.yue | 4 | ||||
-rw-r--r-- | spec/inputs/loops.yue | 8 | ||||
-rw-r--r-- | spec/inputs/test/loops_spec.yue | 6 | ||||
-rw-r--r-- | spec/outputs/5.1/loops.lua | 381 | ||||
-rw-r--r-- | spec/outputs/5.1/test/loops_spec.lua | 69 | ||||
-rw-r--r-- | spec/outputs/goto.lua | 4 | ||||
-rw-r--r-- | spec/outputs/loops.lua | 204 | ||||
-rw-r--r-- | spec/outputs/test/loops_spec.lua | 51 | ||||
-rw-r--r-- | src/3rdParty/lua/lauxlib.c | 8 | ||||
-rw-r--r-- | src/3rdParty/lua/lobject.c | 2 | ||||
-rw-r--r-- | src/3rdParty/lua/loslib.c | 4 | ||||
-rw-r--r-- | src/3rdParty/lua/ltablib.c | 2 | ||||
-rw-r--r-- | src/3rdParty/lua/luaconf.h | 5 | ||||
-rw-r--r-- | src/3rdParty/lua/lutf8lib.c | 27 | ||||
-rw-r--r-- | src/3rdParty/lua/lvm.c | 4 | ||||
-rw-r--r-- | src/3rdParty/lua/lvm.h | 5 | ||||
-rwxr-xr-x | src/yuescript/yue_ast.h | 1 | ||||
-rw-r--r--[-rwxr-xr-x] | src/yuescript/yue_compiler.cpp | 348 |
19 files changed, 811 insertions, 324 deletions
@@ -282,6 +282,8 @@ gen: release | |||
282 | @$(START_TIME) | 282 | @$(START_TIME) |
283 | @./$(BIN_NAME) $(TEST_INPUT) -t $(GEN_OUTPUT) --tl_enabled | 283 | @./$(BIN_NAME) $(TEST_INPUT) -t $(GEN_OUTPUT) --tl_enabled |
284 | @./$(BIN_NAME) $(TEST_INPUT)/teal-lang.yue -o $(GEN_OUTPUT)/teal-lang.lua | 284 | @./$(BIN_NAME) $(TEST_INPUT)/teal-lang.yue -o $(GEN_OUTPUT)/teal-lang.lua |
285 | @./$(BIN_NAME) $(TEST_INPUT)/loops.yue -o $(GEN_OUTPUT)/5.1/loops.lua --target=5.1 | ||
286 | @./$(BIN_NAME) $(TEST_INPUT)/test/loops_spec.yue -o $(GEN_OUTPUT)/5.1/test/loops_spec.lua --target=5.1 | ||
285 | @echo -en "Compile time: " | 287 | @echo -en "Compile time: " |
286 | @$(END_TIME) | 288 | @$(END_TIME) |
287 | 289 | ||
diff --git a/spec/inputs/goto.yue b/spec/inputs/goto.yue index 1197251..61584ca 100644 --- a/spec/inputs/goto.yue +++ b/spec/inputs/goto.yue | |||
@@ -10,8 +10,8 @@ do | |||
10 | for z = 1, 10 do for y = 1, 10 do for x = 1, 10 | 10 | for z = 1, 10 do for y = 1, 10 do for x = 1, 10 |
11 | if x^2 + y^2 == z^2 | 11 | if x^2 + y^2 == z^2 |
12 | print 'found a Pythagorean triple:', x, y, z | 12 | print 'found a Pythagorean triple:', x, y, z |
13 | goto done | 13 | goto ok |
14 | ::done:: | 14 | ::ok:: |
15 | 15 | ||
16 | do | 16 | do |
17 | for z = 1, 10 | 17 | for z = 1, 10 |
diff --git a/spec/inputs/loops.yue b/spec/inputs/loops.yue index d03e661..d997c65 100644 --- a/spec/inputs/loops.yue +++ b/spec/inputs/loops.yue | |||
@@ -111,10 +111,10 @@ until a == 10 | |||
111 | 111 | ||
112 | x = 0 | 112 | x = 0 |
113 | repeat | 113 | repeat |
114 | x += 1 | 114 | x += 1 |
115 | y = x | 115 | y = x |
116 | continue if x < 5 | 116 | continue if x < 5 |
117 | print y | 117 | print y |
118 | until y == 10 | 118 | until y == 10 |
119 | 119 | ||
120 | a = 3 | 120 | a = 3 |
diff --git a/spec/inputs/test/loops_spec.yue b/spec/inputs/test/loops_spec.yue index 817919f..a115581 100644 --- a/spec/inputs/test/loops_spec.yue +++ b/spec/inputs/test/loops_spec.yue | |||
@@ -5,8 +5,8 @@ describe "loops", -> | |||
5 | continue if x % 2 == 1 | 5 | continue if x % 2 == 1 |
6 | x | 6 | x |
7 | 7 | ||
8 | assert.same output, { 2,4,6 } | 8 | assert.same { 2,4,6 }, output |
9 | 9 | ||
10 | it "continue in repeat", -> | 10 | it "continue in repeat", -> |
11 | output = {} | 11 | output = {} |
12 | a = 0 | 12 | a = 0 |
@@ -19,5 +19,5 @@ describe "loops", -> | |||
19 | output[] = a | 19 | output[] = a |
20 | until a == 8 | 20 | until a == 8 |
21 | 21 | ||
22 | assert.same output, { 1,2,4 } | 22 | assert.same { 1,2,4 }, output |
23 | 23 | ||
diff --git a/spec/outputs/5.1/loops.lua b/spec/outputs/5.1/loops.lua new file mode 100644 index 0000000..a3b9548 --- /dev/null +++ b/spec/outputs/5.1/loops.lua | |||
@@ -0,0 +1,381 @@ | |||
1 | for x = 1, 10 do | ||
2 | print("yeah") | ||
3 | end | ||
4 | for x = 1, #something do | ||
5 | print("yeah") | ||
6 | end | ||
7 | for y = 100, 60, -3 do | ||
8 | print("count down", y) | ||
9 | end | ||
10 | for a = 1, 10 do | ||
11 | print("okay") | ||
12 | end | ||
13 | for a = 1, 10 do | ||
14 | for b = 2, 43 do | ||
15 | print(a, b) | ||
16 | end | ||
17 | end | ||
18 | for i in iter do | ||
19 | for j in yeah do | ||
20 | local x = 343 + i + j | ||
21 | print(i, j) | ||
22 | end | ||
23 | end | ||
24 | local _list_0 = something | ||
25 | for _index_0 = 1, #_list_0 do | ||
26 | local x = _list_0[_index_0] | ||
27 | print(x) | ||
28 | end | ||
29 | for k, v in pairs(hello) do | ||
30 | print(k, v) | ||
31 | end | ||
32 | for x in y, z do | ||
33 | print(x) | ||
34 | end | ||
35 | for x in y, z, k do | ||
36 | print(x) | ||
37 | end | ||
38 | local _list_1 = modules | ||
39 | for _index_0 = 1, #_list_1 do | ||
40 | local name, members = _list_1[_index_0] | ||
41 | print(name, member) | ||
42 | end | ||
43 | local x | ||
44 | x = function() | ||
45 | for x in y do | ||
46 | local _ = y | ||
47 | end | ||
48 | end | ||
49 | local hello = { | ||
50 | 1, | ||
51 | 2, | ||
52 | 3, | ||
53 | 4, | ||
54 | 5 | ||
55 | } | ||
56 | do | ||
57 | local _accum_0 = { } | ||
58 | local _len_0 = 1 | ||
59 | for _index_0 = 1, #hello do | ||
60 | local y = hello[_index_0] | ||
61 | if y % 2 == 0 then | ||
62 | _accum_0[_len_0] = y | ||
63 | end | ||
64 | _len_0 = _len_0 + 1 | ||
65 | end | ||
66 | x = _accum_0 | ||
67 | end | ||
68 | x = function() | ||
69 | for _index_0 = 1, #hello do | ||
70 | local x = hello[_index_0] | ||
71 | local _ = y | ||
72 | end | ||
73 | end | ||
74 | local t | ||
75 | do | ||
76 | local _accum_0 = { } | ||
77 | local _len_0 = 1 | ||
78 | for i = 10, 20 do | ||
79 | _accum_0[_len_0] = i * 2 | ||
80 | _len_0 = _len_0 + 1 | ||
81 | end | ||
82 | t = _accum_0 | ||
83 | end | ||
84 | local hmm = 0 | ||
85 | local y | ||
86 | do | ||
87 | local _accum_0 = { } | ||
88 | local _len_0 = 1 | ||
89 | for j = 3, 30, 8 do | ||
90 | hmm = hmm + 1 | ||
91 | _accum_0[_len_0] = j * hmm | ||
92 | _len_0 = _len_0 + 1 | ||
93 | end | ||
94 | y = _accum_0 | ||
95 | end | ||
96 | local _ | ||
97 | _ = function() | ||
98 | for k = 10, 40 do | ||
99 | _ = "okay" | ||
100 | end | ||
101 | end | ||
102 | _ = function() | ||
103 | local _accum_0 = { } | ||
104 | local _len_0 = 1 | ||
105 | for k = 10, 40 do | ||
106 | _accum_0[_len_0] = "okay" | ||
107 | _len_0 = _len_0 + 1 | ||
108 | end | ||
109 | return _accum_0 | ||
110 | end | ||
111 | while true do | ||
112 | print("name") | ||
113 | end | ||
114 | while 5 + 5 do | ||
115 | print("okay world") | ||
116 | working(man) | ||
117 | end | ||
118 | while also do | ||
119 | i(work(too)) | ||
120 | _ = "okay" | ||
121 | end | ||
122 | local i = 0 | ||
123 | do | ||
124 | local _accum_0 = { } | ||
125 | local _len_0 = 1 | ||
126 | while i < 10 do | ||
127 | i = i + 1 | ||
128 | _len_0 = _len_0 + 1 | ||
129 | end | ||
130 | x = _accum_0 | ||
131 | end | ||
132 | do | ||
133 | local _accum_0 = { } | ||
134 | local _len_0 = 1 | ||
135 | local _list_2 = 3 | ||
136 | for _index_0 = 1, #_list_2 do | ||
137 | local thing = _list_2[_index_0] | ||
138 | y = "hello" | ||
139 | _len_0 = _len_0 + 1 | ||
140 | end | ||
141 | x = _accum_0 | ||
142 | end | ||
143 | do | ||
144 | local _accum_0 = { } | ||
145 | local _len_0 = 1 | ||
146 | for x = 1, 2 do | ||
147 | y = "hello" | ||
148 | _len_0 = _len_0 + 1 | ||
149 | end | ||
150 | x = _accum_0 | ||
151 | end | ||
152 | while true do | ||
153 | local _continue_0 = false | ||
154 | repeat | ||
155 | if false then | ||
156 | _continue_0 = true | ||
157 | break | ||
158 | end | ||
159 | print("yes") | ||
160 | if true then | ||
161 | break | ||
162 | end | ||
163 | print("no") | ||
164 | _continue_0 = true | ||
165 | until true | ||
166 | if not _continue_0 then | ||
167 | break | ||
168 | end | ||
169 | end | ||
170 | for i = 1, 10 do | ||
171 | while true do | ||
172 | local _continue_0 = false | ||
173 | repeat | ||
174 | do | ||
175 | if not true then | ||
176 | _continue_0 = true | ||
177 | break | ||
178 | end | ||
179 | break | ||
180 | end | ||
181 | _continue_0 = true | ||
182 | until true | ||
183 | if not _continue_0 then | ||
184 | break | ||
185 | end | ||
186 | end | ||
187 | end | ||
188 | local a = 1 | ||
189 | repeat | ||
190 | local _cond_0 = false | ||
191 | local _continue_0 = false | ||
192 | repeat | ||
193 | a = a + 1 | ||
194 | if a == 5 then | ||
195 | _cond_0 = a == 10 | ||
196 | _continue_0 = true | ||
197 | break | ||
198 | end | ||
199 | if a == 6 then | ||
200 | break | ||
201 | end | ||
202 | print(a) | ||
203 | _cond_0 = a == 10 | ||
204 | _continue_0 = true | ||
205 | until true | ||
206 | if not _continue_0 then | ||
207 | break | ||
208 | end | ||
209 | until _cond_0 | ||
210 | x = 0 | ||
211 | repeat | ||
212 | local _cond_0 = false | ||
213 | local _continue_0 = false | ||
214 | repeat | ||
215 | x = x + 1 | ||
216 | y = x | ||
217 | if x < 5 then | ||
218 | _cond_0 = y == 10 | ||
219 | _continue_0 = true | ||
220 | break | ||
221 | end | ||
222 | print(y) | ||
223 | _cond_0 = y == 10 | ||
224 | _continue_0 = true | ||
225 | until true | ||
226 | if not _continue_0 then | ||
227 | break | ||
228 | end | ||
229 | until _cond_0 | ||
230 | a = 3 | ||
231 | while not (a == 0) do | ||
232 | a = a - 1 | ||
233 | end | ||
234 | local done = false | ||
235 | while not done do | ||
236 | done = true | ||
237 | end | ||
238 | repeat | ||
239 | print("hello") | ||
240 | until true | ||
241 | while not done do | ||
242 | x = 10 | ||
243 | repeat | ||
244 | x = x - 1 | ||
245 | until x == 0 | ||
246 | end | ||
247 | while not cond do | ||
248 | print("okay") | ||
249 | end | ||
250 | for x = 1, 10 do | ||
251 | local _continue_0 = false | ||
252 | repeat | ||
253 | if x > 3 and x < 7 then | ||
254 | _continue_0 = true | ||
255 | break | ||
256 | end | ||
257 | print(x) | ||
258 | _continue_0 = true | ||
259 | until true | ||
260 | if not _continue_0 then | ||
261 | break | ||
262 | end | ||
263 | end | ||
264 | local list | ||
265 | do | ||
266 | local _accum_0 = { } | ||
267 | local _len_0 = 1 | ||
268 | for x = 1, 10 do | ||
269 | local _continue_0 = false | ||
270 | repeat | ||
271 | if x > 3 and x < 7 then | ||
272 | _continue_0 = true | ||
273 | break | ||
274 | end | ||
275 | _accum_0[_len_0] = x | ||
276 | _len_0 = _len_0 + 1 | ||
277 | _continue_0 = true | ||
278 | until true | ||
279 | if not _continue_0 then | ||
280 | break | ||
281 | end | ||
282 | end | ||
283 | list = _accum_0 | ||
284 | end | ||
285 | local _list_2 = { | ||
286 | 1, | ||
287 | 2, | ||
288 | 3, | ||
289 | 4, | ||
290 | 5, | ||
291 | 6 | ||
292 | } | ||
293 | for _index_0 = 1, #_list_2 do | ||
294 | local a = _list_2[_index_0] | ||
295 | local _continue_0 = false | ||
296 | repeat | ||
297 | if a == 1 then | ||
298 | _continue_0 = true | ||
299 | break | ||
300 | end | ||
301 | if a == 3 then | ||
302 | _continue_0 = true | ||
303 | break | ||
304 | end | ||
305 | print(a) | ||
306 | _continue_0 = true | ||
307 | until true | ||
308 | if not _continue_0 then | ||
309 | break | ||
310 | end | ||
311 | end | ||
312 | for x = 1, 10 do | ||
313 | local _continue_0 = false | ||
314 | repeat | ||
315 | if x % 2 == 0 then | ||
316 | _continue_0 = true | ||
317 | break | ||
318 | end | ||
319 | for y = 2, 12 do | ||
320 | local _continue_1 = false | ||
321 | repeat | ||
322 | if y % 3 == 0 then | ||
323 | _continue_1 = true | ||
324 | break | ||
325 | end | ||
326 | _continue_1 = true | ||
327 | until true | ||
328 | if not _continue_1 then | ||
329 | break | ||
330 | end | ||
331 | end | ||
332 | _continue_0 = true | ||
333 | until true | ||
334 | if not _continue_0 then | ||
335 | break | ||
336 | end | ||
337 | end | ||
338 | while true do | ||
339 | local _continue_0 = false | ||
340 | repeat | ||
341 | do | ||
342 | if false then | ||
343 | _continue_0 = true | ||
344 | break | ||
345 | end | ||
346 | break | ||
347 | end | ||
348 | _continue_0 = true | ||
349 | until true | ||
350 | if not _continue_0 then | ||
351 | break | ||
352 | end | ||
353 | end | ||
354 | while true do | ||
355 | local _continue_0 = false | ||
356 | repeat | ||
357 | if false then | ||
358 | _continue_0 = true | ||
359 | break | ||
360 | end | ||
361 | do | ||
362 | return 22 | ||
363 | end | ||
364 | _continue_0 = true | ||
365 | until true | ||
366 | if not _continue_0 then | ||
367 | break | ||
368 | end | ||
369 | end | ||
370 | do | ||
371 | local xxx = { | ||
372 | 1, | ||
373 | 2, | ||
374 | 3, | ||
375 | 4 | ||
376 | } | ||
377 | for _index_0 = 1, #xxx do | ||
378 | local thing = xxx[_index_0] | ||
379 | print(thing) | ||
380 | end | ||
381 | end | ||
diff --git a/spec/outputs/5.1/test/loops_spec.lua b/spec/outputs/5.1/test/loops_spec.lua new file mode 100644 index 0000000..bad17a6 --- /dev/null +++ b/spec/outputs/5.1/test/loops_spec.lua | |||
@@ -0,0 +1,69 @@ | |||
1 | return describe("loops", function() | ||
2 | it("should continue", function() | ||
3 | local input = { | ||
4 | 1, | ||
5 | 2, | ||
6 | 3, | ||
7 | 4, | ||
8 | 5, | ||
9 | 6 | ||
10 | } | ||
11 | local output | ||
12 | do | ||
13 | local _accum_0 = { } | ||
14 | local _len_0 = 1 | ||
15 | for _index_0 = 1, #input do | ||
16 | local x = input[_index_0] | ||
17 | local _continue_0 = false | ||
18 | repeat | ||
19 | if x % 2 == 1 then | ||
20 | _continue_0 = true | ||
21 | break | ||
22 | end | ||
23 | _accum_0[_len_0] = x | ||
24 | _len_0 = _len_0 + 1 | ||
25 | _continue_0 = true | ||
26 | until true | ||
27 | if not _continue_0 then | ||
28 | break | ||
29 | end | ||
30 | end | ||
31 | output = _accum_0 | ||
32 | end | ||
33 | return assert.same({ | ||
34 | 2, | ||
35 | 4, | ||
36 | 6 | ||
37 | }, output) | ||
38 | end) | ||
39 | return it("continue in repeat", function() | ||
40 | local output = { } | ||
41 | local a = 0 | ||
42 | repeat | ||
43 | local _cond_0 = false | ||
44 | local _continue_0 = false | ||
45 | repeat | ||
46 | a = a + 1 | ||
47 | if a == 3 then | ||
48 | _cond_0 = a == 8 | ||
49 | _continue_0 = true | ||
50 | break | ||
51 | end | ||
52 | if a == 5 then | ||
53 | break | ||
54 | end | ||
55 | output[#output + 1] = a | ||
56 | _cond_0 = a == 8 | ||
57 | _continue_0 = true | ||
58 | until true | ||
59 | if not _continue_0 then | ||
60 | break | ||
61 | end | ||
62 | until _cond_0 | ||
63 | return assert.same({ | ||
64 | 1, | ||
65 | 2, | ||
66 | 4 | ||
67 | }, output) | ||
68 | end) | ||
69 | end) | ||
diff --git a/spec/outputs/goto.lua b/spec/outputs/goto.lua index d1f7b77..421508a 100644 --- a/spec/outputs/goto.lua +++ b/spec/outputs/goto.lua | |||
@@ -14,12 +14,12 @@ do | |||
14 | for x = 1, 10 do | 14 | for x = 1, 10 do |
15 | if x ^ 2 + y ^ 2 == z ^ 2 then | 15 | if x ^ 2 + y ^ 2 == z ^ 2 then |
16 | print('found a Pythagorean triple:', x, y, z) | 16 | print('found a Pythagorean triple:', x, y, z) |
17 | goto done | 17 | goto ok |
18 | end | 18 | end |
19 | end | 19 | end |
20 | end | 20 | end |
21 | end | 21 | end |
22 | ::done:: | 22 | ::ok:: |
23 | end | 23 | end |
24 | do | 24 | do |
25 | for z = 1, 10 do | 25 | for z = 1, 10 do |
diff --git a/spec/outputs/loops.lua b/spec/outputs/loops.lua index e5c189e..9c16ee4 100644 --- a/spec/outputs/loops.lua +++ b/spec/outputs/loops.lua | |||
@@ -150,83 +150,47 @@ do | |||
150 | x = _accum_0 | 150 | x = _accum_0 |
151 | end | 151 | end |
152 | while true do | 152 | while true do |
153 | local _continue_0 = false | 153 | if false then |
154 | repeat | 154 | goto _continue_0 |
155 | if false then | 155 | end |
156 | _continue_0 = true | 156 | print("yes") |
157 | break | 157 | if true then |
158 | end | ||
159 | print("yes") | ||
160 | if true then | ||
161 | break | ||
162 | end | ||
163 | print("no") | ||
164 | _continue_0 = true | ||
165 | until true | ||
166 | if not _continue_0 then | ||
167 | break | 158 | break |
168 | end | 159 | end |
160 | print("no") | ||
161 | ::_continue_0:: | ||
169 | end | 162 | end |
170 | for i = 1, 10 do | 163 | for i = 1, 10 do |
171 | while true do | 164 | while true do |
172 | local _continue_0 = false | 165 | if not true then |
173 | repeat | 166 | goto _continue_1 |
174 | do | ||
175 | if not true then | ||
176 | _continue_0 = true | ||
177 | break | ||
178 | end | ||
179 | break | ||
180 | end | ||
181 | _continue_0 = true | ||
182 | until true | ||
183 | if not _continue_0 then | ||
184 | break | ||
185 | end | 167 | end |
168 | break | ||
169 | ::_continue_1:: | ||
186 | end | 170 | end |
187 | end | 171 | end |
188 | local a = 1 | 172 | local a = 1 |
189 | repeat | 173 | repeat |
190 | local _cond_0 = false | 174 | a = a + 1 |
191 | local _continue_0 = false | 175 | if a == 5 then |
192 | repeat | 176 | goto _continue_2 |
193 | a = a + 1 | 177 | end |
194 | if a == 5 then | 178 | if a == 6 then |
195 | _cond_0 = a == 10 | ||
196 | _continue_0 = true | ||
197 | break | ||
198 | end | ||
199 | if a == 6 then | ||
200 | break | ||
201 | end | ||
202 | print(a) | ||
203 | _cond_0 = a == 10 | ||
204 | _continue_0 = true | ||
205 | until true | ||
206 | if not _continue_0 then | ||
207 | break | 179 | break |
208 | end | 180 | end |
209 | until _cond_0 | 181 | print(a) |
182 | ::_continue_2:: | ||
183 | until a == 10 | ||
210 | x = 0 | 184 | x = 0 |
211 | repeat | 185 | repeat |
212 | local _cond_0 = false | 186 | x = x + 1 |
213 | local _continue_0 = false | 187 | y = x |
214 | repeat | 188 | if x < 5 then |
215 | x = x + 1 | 189 | goto _continue_3 |
216 | y = x | ||
217 | if x < 5 then | ||
218 | _cond_0 = y == 10 | ||
219 | _continue_0 = true | ||
220 | break | ||
221 | end | ||
222 | print(y) | ||
223 | _cond_0 = y == 10 | ||
224 | _continue_0 = true | ||
225 | until true | ||
226 | if not _continue_0 then | ||
227 | break | ||
228 | end | 190 | end |
229 | until _cond_0 | 191 | print(y) |
192 | ::_continue_3:: | ||
193 | until y == 10 | ||
230 | a = 3 | 194 | a = 3 |
231 | while not (a == 0) do | 195 | while not (a == 0) do |
232 | a = a - 1 | 196 | a = a - 1 |
@@ -248,37 +212,23 @@ while not cond do | |||
248 | print("okay") | 212 | print("okay") |
249 | end | 213 | end |
250 | for x = 1, 10 do | 214 | for x = 1, 10 do |
251 | local _continue_0 = false | 215 | if x > 3 and x < 7 then |
252 | repeat | 216 | goto _continue_4 |
253 | if x > 3 and x < 7 then | ||
254 | _continue_0 = true | ||
255 | break | ||
256 | end | ||
257 | print(x) | ||
258 | _continue_0 = true | ||
259 | until true | ||
260 | if not _continue_0 then | ||
261 | break | ||
262 | end | 217 | end |
218 | print(x) | ||
219 | ::_continue_4:: | ||
263 | end | 220 | end |
264 | local list | 221 | local list |
265 | do | 222 | do |
266 | local _accum_0 = { } | 223 | local _accum_0 = { } |
267 | local _len_0 = 1 | 224 | local _len_0 = 1 |
268 | for x = 1, 10 do | 225 | for x = 1, 10 do |
269 | local _continue_0 = false | 226 | if x > 3 and x < 7 then |
270 | repeat | 227 | goto _continue_5 |
271 | if x > 3 and x < 7 then | ||
272 | _continue_0 = true | ||
273 | break | ||
274 | end | ||
275 | _accum_0[_len_0] = x | ||
276 | _len_0 = _len_0 + 1 | ||
277 | _continue_0 = true | ||
278 | until true | ||
279 | if not _continue_0 then | ||
280 | break | ||
281 | end | 228 | end |
229 | _accum_0[_len_0] = x | ||
230 | _len_0 = _len_0 + 1 | ||
231 | ::_continue_5:: | ||
282 | end | 232 | end |
283 | list = _accum_0 | 233 | list = _accum_0 |
284 | end | 234 | end |
@@ -292,78 +242,42 @@ local _list_2 = { | |||
292 | } | 242 | } |
293 | for _index_0 = 1, #_list_2 do | 243 | for _index_0 = 1, #_list_2 do |
294 | local a = _list_2[_index_0] | 244 | local a = _list_2[_index_0] |
295 | local _continue_0 = false | 245 | if a == 1 then |
296 | repeat | 246 | goto _continue_6 |
297 | if a == 1 then | ||
298 | _continue_0 = true | ||
299 | break | ||
300 | end | ||
301 | if a == 3 then | ||
302 | _continue_0 = true | ||
303 | break | ||
304 | end | ||
305 | print(a) | ||
306 | _continue_0 = true | ||
307 | until true | ||
308 | if not _continue_0 then | ||
309 | break | ||
310 | end | 247 | end |
248 | if a == 3 then | ||
249 | goto _continue_6 | ||
250 | end | ||
251 | print(a) | ||
252 | ::_continue_6:: | ||
311 | end | 253 | end |
312 | for x = 1, 10 do | 254 | for x = 1, 10 do |
313 | local _continue_0 = false | 255 | if x % 2 == 0 then |
314 | repeat | 256 | goto _continue_7 |
315 | if x % 2 == 0 then | 257 | end |
316 | _continue_0 = true | 258 | for y = 2, 12 do |
317 | break | 259 | if y % 3 == 0 then |
318 | end | 260 | goto _continue_8 |
319 | for y = 2, 12 do | ||
320 | local _continue_1 = false | ||
321 | repeat | ||
322 | if y % 3 == 0 then | ||
323 | _continue_1 = true | ||
324 | break | ||
325 | end | ||
326 | _continue_1 = true | ||
327 | until true | ||
328 | if not _continue_1 then | ||
329 | break | ||
330 | end | ||
331 | end | 261 | end |
332 | _continue_0 = true | 262 | ::_continue_8:: |
333 | until true | ||
334 | if not _continue_0 then | ||
335 | break | ||
336 | end | 263 | end |
264 | ::_continue_7:: | ||
337 | end | 265 | end |
338 | while true do | 266 | while true do |
339 | local _continue_0 = false | 267 | if false then |
340 | repeat | 268 | goto _continue_9 |
341 | do | ||
342 | if false then | ||
343 | _continue_0 = true | ||
344 | break | ||
345 | end | ||
346 | break | ||
347 | end | ||
348 | _continue_0 = true | ||
349 | until true | ||
350 | if not _continue_0 then | ||
351 | break | ||
352 | end | 269 | end |
270 | break | ||
271 | ::_continue_9:: | ||
353 | end | 272 | end |
354 | while true do | 273 | while true do |
355 | local _continue_0 = false | 274 | if false then |
356 | repeat | 275 | goto _continue_10 |
357 | if false then | 276 | end |
358 | _continue_0 = true | 277 | do |
359 | break | ||
360 | end | ||
361 | return 22 | 278 | return 22 |
362 | _continue_0 = true | ||
363 | until true | ||
364 | if not _continue_0 then | ||
365 | break | ||
366 | end | 279 | end |
280 | ::_continue_10:: | ||
367 | end | 281 | end |
368 | do | 282 | do |
369 | local xxx = { | 283 | local xxx = { |
diff --git a/spec/outputs/test/loops_spec.lua b/spec/outputs/test/loops_spec.lua index 34f2e9c..9c85e1a 100644 --- a/spec/outputs/test/loops_spec.lua +++ b/spec/outputs/test/loops_spec.lua | |||
@@ -14,56 +14,39 @@ return describe("loops", function() | |||
14 | local _len_0 = 1 | 14 | local _len_0 = 1 |
15 | for _index_0 = 1, #input do | 15 | for _index_0 = 1, #input do |
16 | local x = input[_index_0] | 16 | local x = input[_index_0] |
17 | local _continue_0 = false | 17 | if x % 2 == 1 then |
18 | repeat | 18 | goto _continue_0 |
19 | if x % 2 == 1 then | ||
20 | _continue_0 = true | ||
21 | break | ||
22 | end | ||
23 | _accum_0[_len_0] = x | ||
24 | _len_0 = _len_0 + 1 | ||
25 | _continue_0 = true | ||
26 | until true | ||
27 | if not _continue_0 then | ||
28 | break | ||
29 | end | 19 | end |
20 | _accum_0[_len_0] = x | ||
21 | _len_0 = _len_0 + 1 | ||
22 | ::_continue_0:: | ||
30 | end | 23 | end |
31 | output = _accum_0 | 24 | output = _accum_0 |
32 | end | 25 | end |
33 | return assert.same(output, { | 26 | return assert.same({ |
34 | 2, | 27 | 2, |
35 | 4, | 28 | 4, |
36 | 6 | 29 | 6 |
37 | }) | 30 | }, output) |
38 | end) | 31 | end) |
39 | return it("continue in repeat", function() | 32 | return it("continue in repeat", function() |
40 | local output = { } | 33 | local output = { } |
41 | local a = 0 | 34 | local a = 0 |
42 | repeat | 35 | repeat |
43 | local _cond_0 = false | 36 | a = a + 1 |
44 | local _continue_0 = false | 37 | if a == 3 then |
45 | repeat | 38 | goto _continue_0 |
46 | a = a + 1 | 39 | end |
47 | if a == 3 then | 40 | if a == 5 then |
48 | _cond_0 = a == 8 | ||
49 | _continue_0 = true | ||
50 | break | ||
51 | end | ||
52 | if a == 5 then | ||
53 | break | ||
54 | end | ||
55 | output[#output + 1] = a | ||
56 | _cond_0 = a == 8 | ||
57 | _continue_0 = true | ||
58 | until true | ||
59 | if not _continue_0 then | ||
60 | break | 41 | break |
61 | end | 42 | end |
62 | until _cond_0 | 43 | output[#output + 1] = a |
63 | return assert.same(output, { | 44 | ::_continue_0:: |
45 | until a == 8 | ||
46 | return assert.same({ | ||
64 | 1, | 47 | 1, |
65 | 2, | 48 | 2, |
66 | 4 | 49 | 4 |
67 | }) | 50 | }, output) |
68 | end) | 51 | end) |
69 | end) | 52 | end) |
diff --git a/src/3rdParty/lua/lauxlib.c b/src/3rdParty/lua/lauxlib.c index cba5df9..4ca6c65 100644 --- a/src/3rdParty/lua/lauxlib.c +++ b/src/3rdParty/lua/lauxlib.c | |||
@@ -526,14 +526,14 @@ static void newbox (lua_State *L) { | |||
526 | 526 | ||
527 | /* | 527 | /* |
528 | ** Compute new size for buffer 'B', enough to accommodate extra 'sz' | 528 | ** Compute new size for buffer 'B', enough to accommodate extra 'sz' |
529 | ** bytes. (The test for "double is not big enough" also gets the | 529 | ** bytes. (The test for "not big enough" also gets the case when the |
530 | ** case when the multiplication by 2 overflows.) | 530 | ** computation of 'newsize' overflows.) |
531 | */ | 531 | */ |
532 | static size_t newbuffsize (luaL_Buffer *B, size_t sz) { | 532 | static size_t newbuffsize (luaL_Buffer *B, size_t sz) { |
533 | size_t newsize = B->size * 2; /* double buffer size */ | 533 | size_t newsize = (B->size / 2) * 3; /* buffer size * 1.5 */ |
534 | if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */ | 534 | if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */ |
535 | return luaL_error(B->L, "buffer too large"); | 535 | return luaL_error(B->L, "buffer too large"); |
536 | if (newsize < B->n + sz) /* double is not big enough? */ | 536 | if (newsize < B->n + sz) /* not big enough? */ |
537 | newsize = B->n + sz; | 537 | newsize = B->n + sz; |
538 | return newsize; | 538 | return newsize; |
539 | } | 539 | } |
diff --git a/src/3rdParty/lua/lobject.c b/src/3rdParty/lua/lobject.c index a2c0060..03e2798 100644 --- a/src/3rdParty/lua/lobject.c +++ b/src/3rdParty/lua/lobject.c | |||
@@ -62,7 +62,7 @@ static lua_Integer intarith (lua_State *L, int op, lua_Integer v1, | |||
62 | case LUA_OPBOR: return intop(|, v1, v2); | 62 | case LUA_OPBOR: return intop(|, v1, v2); |
63 | case LUA_OPBXOR: return intop(^, v1, v2); | 63 | case LUA_OPBXOR: return intop(^, v1, v2); |
64 | case LUA_OPSHL: return luaV_shiftl(v1, v2); | 64 | case LUA_OPSHL: return luaV_shiftl(v1, v2); |
65 | case LUA_OPSHR: return luaV_shiftl(v1, -v2); | 65 | case LUA_OPSHR: return luaV_shiftr(v1, v2); |
66 | case LUA_OPUNM: return intop(-, 0, v1); | 66 | case LUA_OPUNM: return intop(-, 0, v1); |
67 | case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1); | 67 | case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1); |
68 | default: lua_assert(0); return 0; | 68 | default: lua_assert(0); return 0; |
diff --git a/src/3rdParty/lua/loslib.c b/src/3rdParty/lua/loslib.c index 3e20d62..854dcf6 100644 --- a/src/3rdParty/lua/loslib.c +++ b/src/3rdParty/lua/loslib.c | |||
@@ -260,9 +260,7 @@ static int getfield (lua_State *L, const char *key, int d, int delta) { | |||
260 | res = d; | 260 | res = d; |
261 | } | 261 | } |
262 | else { | 262 | else { |
263 | /* unsigned avoids overflow when lua_Integer has 32 bits */ | 263 | if (!(res >= 0 ? res - delta <= INT_MAX : INT_MIN + delta <= res)) |
264 | if (!(res >= 0 ? (lua_Unsigned)res <= (lua_Unsigned)INT_MAX + delta | ||
265 | : (lua_Integer)INT_MIN + delta <= res)) | ||
266 | return luaL_error(L, "field '%s' is out-of-bound", key); | 264 | return luaL_error(L, "field '%s' is out-of-bound", key); |
267 | res -= delta; | 265 | res -= delta; |
268 | } | 266 | } |
diff --git a/src/3rdParty/lua/ltablib.c b/src/3rdParty/lua/ltablib.c index 868d78f..e6bc4d0 100644 --- a/src/3rdParty/lua/ltablib.c +++ b/src/3rdParty/lua/ltablib.c | |||
@@ -93,7 +93,7 @@ static int tremove (lua_State *L) { | |||
93 | lua_Integer pos = luaL_optinteger(L, 2, size); | 93 | lua_Integer pos = luaL_optinteger(L, 2, size); |
94 | if (pos != size) /* validate 'pos' if given */ | 94 | if (pos != size) /* validate 'pos' if given */ |
95 | /* check whether 'pos' is in [1, size + 1] */ | 95 | /* check whether 'pos' is in [1, size + 1] */ |
96 | luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 1, | 96 | luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 2, |
97 | "position out of bounds"); | 97 | "position out of bounds"); |
98 | lua_geti(L, 1, pos); /* result = t[pos] */ | 98 | lua_geti(L, 1, pos); /* result = t[pos] */ |
99 | for ( ; pos < size; pos++) { | 99 | for ( ; pos < size; pos++) { |
diff --git a/src/3rdParty/lua/luaconf.h b/src/3rdParty/lua/luaconf.h index fcc0018..e4650fb 100644 --- a/src/3rdParty/lua/luaconf.h +++ b/src/3rdParty/lua/luaconf.h | |||
@@ -747,14 +747,15 @@ | |||
747 | 747 | ||
748 | /* | 748 | /* |
749 | @@ LUA_IDSIZE gives the maximum size for the description of the source | 749 | @@ LUA_IDSIZE gives the maximum size for the description of the source |
750 | @@ of a function in debug information. | 750 | ** of a function in debug information. |
751 | ** CHANGE it if you want a different size. | 751 | ** CHANGE it if you want a different size. |
752 | */ | 752 | */ |
753 | #define LUA_IDSIZE 60 | 753 | #define LUA_IDSIZE 60 |
754 | 754 | ||
755 | 755 | ||
756 | /* | 756 | /* |
757 | @@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. | 757 | @@ LUAL_BUFFERSIZE is the initial buffer size used by the lauxlib |
758 | ** buffer system. | ||
758 | */ | 759 | */ |
759 | #define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number))) | 760 | #define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number))) |
760 | 761 | ||
diff --git a/src/3rdParty/lua/lutf8lib.c b/src/3rdParty/lua/lutf8lib.c index e7bf098..3a5b9bc 100644 --- a/src/3rdParty/lua/lutf8lib.c +++ b/src/3rdParty/lua/lutf8lib.c | |||
@@ -25,6 +25,9 @@ | |||
25 | 25 | ||
26 | #define MAXUTF 0x7FFFFFFFu | 26 | #define MAXUTF 0x7FFFFFFFu |
27 | 27 | ||
28 | |||
29 | #define MSGInvalid "invalid UTF-8 code" | ||
30 | |||
28 | /* | 31 | /* |
29 | ** Integer type for decoded UTF-8 values; MAXUTF needs 31 bits. | 32 | ** Integer type for decoded UTF-8 values; MAXUTF needs 31 bits. |
30 | */ | 33 | */ |
@@ -35,7 +38,8 @@ typedef unsigned long utfint; | |||
35 | #endif | 38 | #endif |
36 | 39 | ||
37 | 40 | ||
38 | #define iscont(p) ((*(p) & 0xC0) == 0x80) | 41 | #define iscont(c) (((c) & 0xC0) == 0x80) |
42 | #define iscontp(p) iscont(*(p)) | ||
39 | 43 | ||
40 | 44 | ||
41 | /* from strlib */ | 45 | /* from strlib */ |
@@ -65,7 +69,7 @@ static const char *utf8_decode (const char *s, utfint *val, int strict) { | |||
65 | int count = 0; /* to count number of continuation bytes */ | 69 | int count = 0; /* to count number of continuation bytes */ |
66 | for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */ | 70 | for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */ |
67 | unsigned int cc = (unsigned char)s[++count]; /* read next byte */ | 71 | unsigned int cc = (unsigned char)s[++count]; /* read next byte */ |
68 | if ((cc & 0xC0) != 0x80) /* not a continuation byte? */ | 72 | if (!iscont(cc)) /* not a continuation byte? */ |
69 | return NULL; /* invalid byte sequence */ | 73 | return NULL; /* invalid byte sequence */ |
70 | res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ | 74 | res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ |
71 | } | 75 | } |
@@ -140,7 +144,7 @@ static int codepoint (lua_State *L) { | |||
140 | utfint code; | 144 | utfint code; |
141 | s = utf8_decode(s, &code, !lax); | 145 | s = utf8_decode(s, &code, !lax); |
142 | if (s == NULL) | 146 | if (s == NULL) |
143 | return luaL_error(L, "invalid UTF-8 code"); | 147 | return luaL_error(L, MSGInvalid); |
144 | lua_pushinteger(L, code); | 148 | lua_pushinteger(L, code); |
145 | n++; | 149 | n++; |
146 | } | 150 | } |
@@ -190,16 +194,16 @@ static int byteoffset (lua_State *L) { | |||
190 | "position out of bounds"); | 194 | "position out of bounds"); |
191 | if (n == 0) { | 195 | if (n == 0) { |
192 | /* find beginning of current byte sequence */ | 196 | /* find beginning of current byte sequence */ |
193 | while (posi > 0 && iscont(s + posi)) posi--; | 197 | while (posi > 0 && iscontp(s + posi)) posi--; |
194 | } | 198 | } |
195 | else { | 199 | else { |
196 | if (iscont(s + posi)) | 200 | if (iscontp(s + posi)) |
197 | return luaL_error(L, "initial position is a continuation byte"); | 201 | return luaL_error(L, "initial position is a continuation byte"); |
198 | if (n < 0) { | 202 | if (n < 0) { |
199 | while (n < 0 && posi > 0) { /* move back */ | 203 | while (n < 0 && posi > 0) { /* move back */ |
200 | do { /* find beginning of previous character */ | 204 | do { /* find beginning of previous character */ |
201 | posi--; | 205 | posi--; |
202 | } while (posi > 0 && iscont(s + posi)); | 206 | } while (posi > 0 && iscontp(s + posi)); |
203 | n++; | 207 | n++; |
204 | } | 208 | } |
205 | } | 209 | } |
@@ -208,7 +212,7 @@ static int byteoffset (lua_State *L) { | |||
208 | while (n > 0 && posi < (lua_Integer)len) { | 212 | while (n > 0 && posi < (lua_Integer)len) { |
209 | do { /* find beginning of next character */ | 213 | do { /* find beginning of next character */ |
210 | posi++; | 214 | posi++; |
211 | } while (iscont(s + posi)); /* (cannot pass final '\0') */ | 215 | } while (iscontp(s + posi)); /* (cannot pass final '\0') */ |
212 | n--; | 216 | n--; |
213 | } | 217 | } |
214 | } | 218 | } |
@@ -226,15 +230,15 @@ static int iter_aux (lua_State *L, int strict) { | |||
226 | const char *s = luaL_checklstring(L, 1, &len); | 230 | const char *s = luaL_checklstring(L, 1, &len); |
227 | lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2); | 231 | lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2); |
228 | if (n < len) { | 232 | if (n < len) { |
229 | while (iscont(s + n)) n++; /* skip continuation bytes */ | 233 | while (iscontp(s + n)) n++; /* go to next character */ |
230 | } | 234 | } |
231 | if (n >= len) /* (also handles original 'n' being negative) */ | 235 | if (n >= len) /* (also handles original 'n' being negative) */ |
232 | return 0; /* no more codepoints */ | 236 | return 0; /* no more codepoints */ |
233 | else { | 237 | else { |
234 | utfint code; | 238 | utfint code; |
235 | const char *next = utf8_decode(s + n, &code, strict); | 239 | const char *next = utf8_decode(s + n, &code, strict); |
236 | if (next == NULL) | 240 | if (next == NULL || iscontp(next)) |
237 | return luaL_error(L, "invalid UTF-8 code"); | 241 | return luaL_error(L, MSGInvalid); |
238 | lua_pushinteger(L, n + 1); | 242 | lua_pushinteger(L, n + 1); |
239 | lua_pushinteger(L, code); | 243 | lua_pushinteger(L, code); |
240 | return 2; | 244 | return 2; |
@@ -253,7 +257,8 @@ static int iter_auxlax (lua_State *L) { | |||
253 | 257 | ||
254 | static int iter_codes (lua_State *L) { | 258 | static int iter_codes (lua_State *L) { |
255 | int lax = lua_toboolean(L, 2); | 259 | int lax = lua_toboolean(L, 2); |
256 | luaL_checkstring(L, 1); | 260 | const char *s = luaL_checkstring(L, 1); |
261 | luaL_argcheck(L, !iscontp(s), 1, MSGInvalid); | ||
257 | lua_pushcfunction(L, lax ? iter_auxlax : iter_auxstrict); | 262 | lua_pushcfunction(L, lax ? iter_auxlax : iter_auxstrict); |
258 | lua_pushvalue(L, 1); | 263 | lua_pushvalue(L, 1); |
259 | lua_pushinteger(L, 0); | 264 | lua_pushinteger(L, 0); |
diff --git a/src/3rdParty/lua/lvm.c b/src/3rdParty/lua/lvm.c index 614df05..73a19ba 100644 --- a/src/3rdParty/lua/lvm.c +++ b/src/3rdParty/lua/lvm.c | |||
@@ -765,12 +765,10 @@ lua_Number luaV_modf (lua_State *L, lua_Number m, lua_Number n) { | |||
765 | /* number of bits in an integer */ | 765 | /* number of bits in an integer */ |
766 | #define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT) | 766 | #define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT) |
767 | 767 | ||
768 | |||
768 | /* | 769 | /* |
769 | ** Shift left operation. (Shift right just negates 'y'.) | 770 | ** Shift left operation. (Shift right just negates 'y'.) |
770 | */ | 771 | */ |
771 | #define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y)) | ||
772 | |||
773 | |||
774 | lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) { | 772 | lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) { |
775 | if (y < 0) { /* shift right? */ | 773 | if (y < 0) { /* shift right? */ |
776 | if (y <= -NBITS) return 0; | 774 | if (y <= -NBITS) return 0; |
diff --git a/src/3rdParty/lua/lvm.h b/src/3rdParty/lua/lvm.h index 1bc16f3..dba1ad2 100644 --- a/src/3rdParty/lua/lvm.h +++ b/src/3rdParty/lua/lvm.h | |||
@@ -110,6 +110,11 @@ typedef enum { | |||
110 | luaC_barrierback(L, gcvalue(t), v); } | 110 | luaC_barrierback(L, gcvalue(t), v); } |
111 | 111 | ||
112 | 112 | ||
113 | /* | ||
114 | ** Shift right is the same as shift left with a negative 'y' | ||
115 | */ | ||
116 | #define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y)) | ||
117 | |||
113 | 118 | ||
114 | 119 | ||
115 | LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2); | 120 | LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2); |
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index 1712e8a..ed963be 100755 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h | |||
@@ -828,7 +828,6 @@ AST_NODE(Statement) | |||
828 | Import_t, While_t, Repeat_t, For_t, ForEach_t, | 828 | Import_t, While_t, Repeat_t, For_t, ForEach_t, |
829 | Return_t, Local_t, Global_t, Export_t, Macro_t, MacroInPlace_t, | 829 | Return_t, Local_t, Global_t, Export_t, Macro_t, MacroInPlace_t, |
830 | BreakLoop_t, Label_t, Goto_t, ShortTabAppending_t, | 830 | BreakLoop_t, Label_t, Goto_t, ShortTabAppending_t, |
831 | BreakLoop_t, Label_t, Goto_t, ShortTabAppending_t, | ||
832 | Backcall_t, LocalAttrib_t, PipeBody_t, ExpListAssign_t | 831 | Backcall_t, LocalAttrib_t, PipeBody_t, ExpListAssign_t |
833 | > content; | 832 | > content; |
834 | ast_ptr<false, statement_appendix_t> appendix; | 833 | ast_ptr<false, statement_appendix_t> appendix; |
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 1d949fe..672f2d4 100755..100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
@@ -14,6 +14,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI | |||
14 | #include <unordered_map> | 14 | #include <unordered_map> |
15 | #include <unordered_set> | 15 | #include <unordered_set> |
16 | #include <vector> | 16 | #include <vector> |
17 | #include <optional> | ||
17 | 18 | ||
18 | #include "yuescript/yue_compiler.h" | 19 | #include "yuescript/yue_compiler.h" |
19 | #include "yuescript/yue_parser.h" | 20 | #include "yuescript/yue_parser.h" |
@@ -59,7 +60,7 @@ namespace yue { | |||
59 | 60 | ||
60 | typedef std::list<std::string> str_list; | 61 | typedef std::list<std::string> str_list; |
61 | 62 | ||
62 | const std::string_view version = "0.15.3"sv; | 63 | const std::string_view version = "0.15.4"sv; |
63 | const std::string_view extension = "yue"sv; | 64 | const std::string_view extension = "yue"sv; |
64 | 65 | ||
65 | class YueCompilerImpl { | 66 | class YueCompilerImpl { |
@@ -146,11 +147,30 @@ public: | |||
146 | str_list out; | 147 | str_list out; |
147 | pushScope(); | 148 | pushScope(); |
148 | _enableReturn.push(_info.moduleName.empty()); | 149 | _enableReturn.push(_info.moduleName.empty()); |
150 | _gotoScopes.push(0); | ||
151 | _gotoScope = 1; | ||
149 | _varArgs.push({true, false}); | 152 | _varArgs.push({true, false}); |
150 | transformBlock(block, out, | 153 | transformBlock(block, out, |
151 | config.implicitReturnRoot ? ExpUsage::Return : ExpUsage::Common, | 154 | config.implicitReturnRoot ? ExpUsage::Return : ExpUsage::Common, |
152 | nullptr, true); | 155 | nullptr, true); |
153 | popScope(); | 156 | popScope(); |
157 | if (!gotos.empty()) { | ||
158 | for (const auto& gotoNode : gotos) { | ||
159 | bool noLabel = true; | ||
160 | BLOCK_START | ||
161 | BREAK_IF(static_cast<int>(_labels.size()) <= gotoNode.scope); | ||
162 | BREAK_IF(_labels[gotoNode.scope] == std::nullopt); | ||
163 | const auto& scope = _labels[gotoNode.scope].value(); | ||
164 | auto it = scope.find(gotoNode.label); | ||
165 | BREAK_IF(it == scope.end()); | ||
166 | BREAK_IF(gotoNode.level < it->second.level); | ||
167 | noLabel = false; | ||
168 | BLOCK_END | ||
169 | if (noLabel) { | ||
170 | throw std::logic_error(_info.errorMessage("no visible label '"s + gotoNode.label + "' for <goto>"s, gotoNode.ptr->label)); | ||
171 | } | ||
172 | } | ||
173 | } | ||
154 | if (config.lintGlobalVariable) { | 174 | if (config.lintGlobalVariable) { |
155 | globals = std::make_unique<GlobalVars>(); | 175 | globals = std::make_unique<GlobalVars>(); |
156 | for (const auto& var : _globals) { | 176 | for (const auto& var : _globals) { |
@@ -256,6 +276,20 @@ private: | |||
256 | std::ostringstream _buf; | 276 | std::ostringstream _buf; |
257 | std::ostringstream _joinBuf; | 277 | std::ostringstream _joinBuf; |
258 | const std::string _newLine = "\n"; | 278 | const std::string _newLine = "\n"; |
279 | int _gotoScope = 0; | ||
280 | std::stack<int> _gotoScopes; | ||
281 | struct LabelNode { | ||
282 | int line; | ||
283 | int level; | ||
284 | }; | ||
285 | std::vector<std::optional<std::unordered_map<std::string, LabelNode>>> _labels; | ||
286 | struct GotoNode { | ||
287 | ast_ptr<true, Goto_t> ptr; | ||
288 | std::string label; | ||
289 | int scope; | ||
290 | int level; | ||
291 | }; | ||
292 | std::list<GotoNode> gotos; | ||
259 | 293 | ||
260 | enum class LocalMode { | 294 | enum class LocalMode { |
261 | None = 0, | 295 | None = 0, |
@@ -457,13 +491,30 @@ private: | |||
457 | std::string getUnusedName(std::string_view name) const { | 491 | std::string getUnusedName(std::string_view name) const { |
458 | int index = 0; | 492 | int index = 0; |
459 | std::string newName; | 493 | std::string newName; |
494 | std::string nameStr(name); | ||
460 | do { | 495 | do { |
461 | newName = std::string(name) + std::to_string(index); | 496 | newName = nameStr + std::to_string(index); |
462 | index++; | 497 | index++; |
463 | } while (isLocal(newName)); | 498 | } while (isLocal(newName)); |
464 | return newName; | 499 | return newName; |
465 | } | 500 | } |
466 | 501 | ||
502 | std::string getUnusedLabel(std::string_view label) const { | ||
503 | int scopeIndex = _gotoScopes.top(); | ||
504 | if (static_cast<int>(_labels.size()) <= scopeIndex || _labels[scopeIndex] == std::nullopt) { | ||
505 | return std::string(label) + '0'; | ||
506 | } | ||
507 | auto& scope = _labels[scopeIndex].value(); | ||
508 | int index = 0; | ||
509 | std::string newLabel; | ||
510 | std::string labelStr(label); | ||
511 | do { | ||
512 | newLabel = labelStr + std::to_string(index); | ||
513 | index++; | ||
514 | } while (scope.find(newLabel) != scope.end()); | ||
515 | return newLabel; | ||
516 | } | ||
517 | |||
467 | std::string transformCondExp(Exp_t* cond, bool unless) { | 518 | std::string transformCondExp(Exp_t* cond, bool unless) { |
468 | str_list tmp; | 519 | str_list tmp; |
469 | if (unless) { | 520 | if (unless) { |
@@ -975,6 +1026,17 @@ private: | |||
975 | return false; | 1026 | return false; |
976 | } | 1027 | } |
977 | 1028 | ||
1029 | void pushFunctionScope() { | ||
1030 | _enableReturn.push(true); | ||
1031 | _gotoScopes.push(_gotoScope); | ||
1032 | _gotoScope++; | ||
1033 | } | ||
1034 | |||
1035 | void popFunctionScope() { | ||
1036 | _enableReturn.pop(); | ||
1037 | _gotoScopes.pop(); | ||
1038 | } | ||
1039 | |||
978 | void pushAnonVarArg() { | 1040 | void pushAnonVarArg() { |
979 | if (!_varArgs.empty() && _varArgs.top().hasVar) { | 1041 | if (!_varArgs.empty() && _varArgs.top().hasVar) { |
980 | _varArgs.push({true, false}); | 1042 | _varArgs.push({true, false}); |
@@ -2642,7 +2704,7 @@ private: | |||
2642 | str_list temp; | 2704 | str_list temp; |
2643 | std::string* funcStart = nullptr; | 2705 | std::string* funcStart = nullptr; |
2644 | if (usage == ExpUsage::Closure) { | 2706 | if (usage == ExpUsage::Closure) { |
2645 | _enableReturn.push(true); | 2707 | pushFunctionScope(); |
2646 | pushAnonVarArg(); | 2708 | pushAnonVarArg(); |
2647 | funcStart = &temp.emplace_back(); | 2709 | funcStart = &temp.emplace_back(); |
2648 | pushScope(); | 2710 | pushScope(); |
@@ -2765,7 +2827,7 @@ private: | |||
2765 | *funcStart = anonFuncStart() + nll(nodes.front()); | 2827 | *funcStart = anonFuncStart() + nll(nodes.front()); |
2766 | temp.push_back(indent() + anonFuncEnd()); | 2828 | temp.push_back(indent() + anonFuncEnd()); |
2767 | popAnonVarArg(); | 2829 | popAnonVarArg(); |
2768 | _enableReturn.pop(); | 2830 | popFunctionScope(); |
2769 | } | 2831 | } |
2770 | out.push_back(join(temp)); | 2832 | out.push_back(join(temp)); |
2771 | } | 2833 | } |
@@ -2928,7 +2990,7 @@ private: | |||
2928 | } | 2990 | } |
2929 | std::string* funcStart = nullptr; | 2991 | std::string* funcStart = nullptr; |
2930 | if (usage == ExpUsage::Closure) { | 2992 | if (usage == ExpUsage::Closure) { |
2931 | _enableReturn.push(true); | 2993 | pushFunctionScope(); |
2932 | pushAnonVarArg(); | 2994 | pushAnonVarArg(); |
2933 | funcStart = &temp.emplace_back(); | 2995 | funcStart = &temp.emplace_back(); |
2934 | pushScope(); | 2996 | pushScope(); |
@@ -2974,7 +3036,7 @@ private: | |||
2974 | *funcStart = anonFuncStart() + nll(x); | 3036 | *funcStart = anonFuncStart() + nll(x); |
2975 | temp.push_back(indent() + anonFuncEnd()); | 3037 | temp.push_back(indent() + anonFuncEnd()); |
2976 | popAnonVarArg(); | 3038 | popAnonVarArg(); |
2977 | _enableReturn.pop(); | 3039 | popFunctionScope(); |
2978 | } | 3040 | } |
2979 | break; | 3041 | break; |
2980 | } | 3042 | } |
@@ -3091,7 +3153,7 @@ private: | |||
3091 | } | 3153 | } |
3092 | 3154 | ||
3093 | void transformFunLit(FunLit_t* funLit, str_list& out) { | 3155 | void transformFunLit(FunLit_t* funLit, str_list& out) { |
3094 | _enableReturn.push(true); | 3156 | pushFunctionScope(); |
3095 | _varArgs.push({false, false}); | 3157 | _varArgs.push({false, false}); |
3096 | bool isFatArrow = _parser.toString(funLit->arrow) == "=>"sv; | 3158 | bool isFatArrow = _parser.toString(funLit->arrow) == "=>"sv; |
3097 | pushScope(); | 3159 | pushScope(); |
@@ -3142,7 +3204,7 @@ private: | |||
3142 | } | 3204 | } |
3143 | } | 3205 | } |
3144 | out.push_back(clearBuf()); | 3206 | out.push_back(clearBuf()); |
3145 | _enableReturn.pop(); | 3207 | popFunctionScope(); |
3146 | _varArgs.pop(); | 3208 | _varArgs.pop(); |
3147 | } | 3209 | } |
3148 | 3210 | ||
@@ -3979,7 +4041,7 @@ private: | |||
3979 | str_list temp; | 4041 | str_list temp; |
3980 | std::string* funcStart = nullptr; | 4042 | std::string* funcStart = nullptr; |
3981 | if (usage == ExpUsage::Closure) { | 4043 | if (usage == ExpUsage::Closure) { |
3982 | _enableReturn.push(true); | 4044 | pushFunctionScope(); |
3983 | pushAnonVarArg(); | 4045 | pushAnonVarArg(); |
3984 | funcStart = &temp.emplace_back(); | 4046 | funcStart = &temp.emplace_back(); |
3985 | pushScope(); | 4047 | pushScope(); |
@@ -4122,7 +4184,7 @@ private: | |||
4122 | *funcStart = anonFuncStart() + nll(x); | 4184 | *funcStart = anonFuncStart() + nll(x); |
4123 | temp.push_back(indent() + anonFuncEnd()); | 4185 | temp.push_back(indent() + anonFuncEnd()); |
4124 | popAnonVarArg(); | 4186 | popAnonVarArg(); |
4125 | _enableReturn.pop(); | 4187 | popFunctionScope(); |
4126 | break; | 4188 | break; |
4127 | default: | 4189 | default: |
4128 | break; | 4190 | break; |
@@ -4148,7 +4210,7 @@ private: | |||
4148 | pushScope(); | 4210 | pushScope(); |
4149 | break; | 4211 | break; |
4150 | case ExpUsage::Closure: | 4212 | case ExpUsage::Closure: |
4151 | _enableReturn.push(true); | 4213 | pushFunctionScope(); |
4152 | pushAnonVarArg(); | 4214 | pushAnonVarArg(); |
4153 | funcStart = &temp.emplace_back(); | 4215 | funcStart = &temp.emplace_back(); |
4154 | pushScope(); | 4216 | pushScope(); |
@@ -4226,7 +4288,7 @@ private: | |||
4226 | *funcStart = anonFuncStart() + nll(x); | 4288 | *funcStart = anonFuncStart() + nll(x); |
4227 | temp.push_back(indent() + anonFuncEnd()); | 4289 | temp.push_back(indent() + anonFuncEnd()); |
4228 | popAnonVarArg(); | 4290 | popAnonVarArg(); |
4229 | _enableReturn.pop(); | 4291 | popFunctionScope(); |
4230 | break; | 4292 | break; |
4231 | default: | 4293 | default: |
4232 | break; | 4294 | break; |
@@ -4283,7 +4345,7 @@ private: | |||
4283 | str_list temp; | 4345 | str_list temp; |
4284 | std::string* funcStart = nullptr; | 4346 | std::string* funcStart = nullptr; |
4285 | if (usage == ExpUsage::Closure) { | 4347 | if (usage == ExpUsage::Closure) { |
4286 | _enableReturn.push(true); | 4348 | pushFunctionScope(); |
4287 | pushAnonVarArg(); | 4349 | pushAnonVarArg(); |
4288 | funcStart = &temp.emplace_back(); | 4350 | funcStart = &temp.emplace_back(); |
4289 | pushScope(); | 4351 | pushScope(); |
@@ -4326,7 +4388,7 @@ private: | |||
4326 | *funcStart = anonFuncStart() + nll(x); | 4388 | *funcStart = anonFuncStart() + nll(x); |
4327 | temp.push_back(indent() + anonFuncEnd()); | 4389 | temp.push_back(indent() + anonFuncEnd()); |
4328 | popAnonVarArg(); | 4390 | popAnonVarArg(); |
4329 | _enableReturn.pop(); | 4391 | popFunctionScope(); |
4330 | break; | 4392 | break; |
4331 | } | 4393 | } |
4332 | case ExpUsage::Return: { | 4394 | case ExpUsage::Return: { |
@@ -5052,7 +5114,7 @@ private: | |||
5052 | auto x = values.front(); | 5114 | auto x = values.front(); |
5053 | switch (usage) { | 5115 | switch (usage) { |
5054 | case ExpUsage::Closure: | 5116 | case ExpUsage::Closure: |
5055 | _enableReturn.push(true); | 5117 | pushFunctionScope(); |
5056 | pushAnonVarArg(); | 5118 | pushAnonVarArg(); |
5057 | pushScope(); | 5119 | pushScope(); |
5058 | break; | 5120 | break; |
@@ -5255,7 +5317,7 @@ private: | |||
5255 | out.back().insert(0, anonFuncStart() + nll(x)); | 5317 | out.back().insert(0, anonFuncStart() + nll(x)); |
5256 | out.back().append(indent() + anonFuncEnd()); | 5318 | out.back().append(indent() + anonFuncEnd()); |
5257 | popAnonVarArg(); | 5319 | popAnonVarArg(); |
5258 | _enableReturn.pop(); | 5320 | popFunctionScope(); |
5259 | break; | 5321 | break; |
5260 | } | 5322 | } |
5261 | case ExpUsage::Assignment: { | 5323 | case ExpUsage::Assignment: { |
@@ -5447,7 +5509,7 @@ private: | |||
5447 | auto x = comp; | 5509 | auto x = comp; |
5448 | switch (usage) { | 5510 | switch (usage) { |
5449 | case ExpUsage::Closure: | 5511 | case ExpUsage::Closure: |
5450 | _enableReturn.push(true); | 5512 | pushFunctionScope(); |
5451 | pushAnonVarArg(); | 5513 | pushAnonVarArg(); |
5452 | pushScope(); | 5514 | pushScope(); |
5453 | break; | 5515 | break; |
@@ -5511,7 +5573,7 @@ private: | |||
5511 | out.back().insert(0, anonFuncStart() + nll(comp)); | 5573 | out.back().insert(0, anonFuncStart() + nll(comp)); |
5512 | out.back().append(indent() + anonFuncEnd()); | 5574 | out.back().append(indent() + anonFuncEnd()); |
5513 | popAnonVarArg(); | 5575 | popAnonVarArg(); |
5514 | _enableReturn.pop(); | 5576 | popFunctionScope(); |
5515 | break; | 5577 | break; |
5516 | } | 5578 | } |
5517 | case ExpUsage::Assignment: { | 5579 | case ExpUsage::Assignment: { |
@@ -5804,44 +5866,80 @@ private: | |||
5804 | str_list temp; | 5866 | str_list temp; |
5805 | bool extraDo = false; | 5867 | bool extraDo = false; |
5806 | bool withContinue = hasContinueStatement(body); | 5868 | bool withContinue = hasContinueStatement(body); |
5869 | int target = getLuaTarget(body); | ||
5870 | std::string extraLabel; | ||
5807 | if (withContinue) { | 5871 | if (withContinue) { |
5808 | if (auto block = ast_cast<Block_t>(body)) { | 5872 | if (target < 502) { |
5809 | if (!block->statements.empty()) { | 5873 | if (auto block = ast_cast<Block_t>(body)) { |
5810 | auto stmt = static_cast<Statement_t*>(block->statements.back()); | 5874 | if (!block->statements.empty()) { |
5811 | if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { | 5875 | auto stmt = static_cast<Statement_t*>(block->statements.back()); |
5812 | extraDo = _parser.toString(breakLoop) == "break"sv; | 5876 | if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { |
5877 | extraDo = _parser.toString(breakLoop) == "break"sv; | ||
5878 | } | ||
5813 | } | 5879 | } |
5814 | } | 5880 | } |
5815 | } | 5881 | auto continueVar = getUnusedName("_continue_"sv); |
5816 | auto continueVar = getUnusedName("_continue_"sv); | 5882 | addToScope(continueVar); |
5817 | addToScope(continueVar); | 5883 | _continueVars.push({continueVar, nullptr}); |
5818 | _continueVars.push({continueVar, nullptr}); | 5884 | _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body); |
5819 | _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body); | 5885 | _buf << indent() << "repeat"sv << nll(body); |
5820 | _buf << indent() << "repeat"sv << nll(body); | ||
5821 | pushScope(); | ||
5822 | if (extraDo) { | ||
5823 | _buf << indent() << "do"sv << nll(body); | ||
5824 | pushScope(); | 5886 | pushScope(); |
5887 | if (extraDo) { | ||
5888 | _buf << indent() << "do"sv << nll(body); | ||
5889 | pushScope(); | ||
5890 | } | ||
5891 | temp.push_back(clearBuf()); | ||
5892 | } else { | ||
5893 | auto continueLabel = getUnusedLabel("_continue_"sv); | ||
5894 | _continueVars.push({continueLabel, nullptr}); | ||
5895 | transformLabel(toAst<Label_t>("::"s + _continueVars.top().var + "::"s, body), temp); | ||
5896 | extraLabel = temp.back(); | ||
5897 | temp.pop_back(); | ||
5898 | } | ||
5899 | if (auto block = ast_cast<Block_t>(body); body && !block->statements.empty()) { | ||
5900 | auto last = static_cast<Statement_t*>(block->statements.back()); | ||
5901 | if (last->content.is<Return_t>()) { | ||
5902 | auto doNode = last->new_ptr<Do_t>(); | ||
5903 | auto newBody = last->new_ptr<Body_t>(); | ||
5904 | auto newStmt = last->new_ptr<Statement_t>(); | ||
5905 | newStmt->content.set(last->content); | ||
5906 | newBody->content.set(newStmt); | ||
5907 | doNode->body.set(newBody); | ||
5908 | auto simpleValue = last->new_ptr<SimpleValue_t>(); | ||
5909 | simpleValue->value.set(doNode); | ||
5910 | auto expList = last->new_ptr<ExpList_t>(); | ||
5911 | expList->exprs.push_back(newExp(simpleValue, last)); | ||
5912 | auto expListAssign = last->new_ptr<ExpListAssign_t>(); | ||
5913 | expListAssign->expList.set(expList); | ||
5914 | last->content.set(expListAssign); | ||
5915 | } | ||
5825 | } | 5916 | } |
5826 | temp.push_back(clearBuf()); | ||
5827 | } | 5917 | } |
5828 | transform_plain_body(body, temp, usage, assignList); | 5918 | transform_plain_body(body, temp, usage, assignList); |
5829 | if (withContinue) { | 5919 | if (withContinue) { |
5830 | if (extraDo) { | 5920 | if (target < 502) { |
5921 | if (extraDo) { | ||
5922 | popScope(); | ||
5923 | _buf << indent() << "end"sv << nll(body); | ||
5924 | } | ||
5925 | if (!appendContent.empty()) { | ||
5926 | _buf << indent() << appendContent; | ||
5927 | } | ||
5928 | _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); | ||
5831 | popScope(); | 5929 | popScope(); |
5832 | _buf << indent() << "end"sv << nll(body); | 5930 | _buf << indent() << "until true"sv << nlr(body); |
5833 | } | 5931 | _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nlr(body); |
5834 | if (!appendContent.empty()) { | 5932 | _buf << indent(1) << "break"sv << nlr(body); |
5835 | _buf << indent() << appendContent; | 5933 | _buf << indent() << "end"sv << nlr(body); |
5934 | temp.push_back(clearBuf()); | ||
5935 | _continueVars.pop(); | ||
5936 | } else { | ||
5937 | if (!appendContent.empty()) { | ||
5938 | temp.push_back(indent() + appendContent); | ||
5939 | } | ||
5940 | temp.push_back(extraLabel); | ||
5941 | _continueVars.pop(); | ||
5836 | } | 5942 | } |
5837 | _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); | ||
5838 | popScope(); | ||
5839 | _buf << indent() << "until true"sv << nlr(body); | ||
5840 | _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nlr(body); | ||
5841 | _buf << indent(1) << "break"sv << nlr(body); | ||
5842 | _buf << indent() << "end"sv << nlr(body); | ||
5843 | temp.push_back(clearBuf()); | ||
5844 | _continueVars.pop(); | ||
5845 | } else if (!appendContent.empty()) { | 5943 | } else if (!appendContent.empty()) { |
5846 | temp.back().append(indent() + appendContent); | 5944 | temp.back().append(indent() + appendContent); |
5847 | } | 5945 | } |
@@ -5854,56 +5952,67 @@ private: | |||
5854 | auto body = repeatNode->body->content.get(); | 5952 | auto body = repeatNode->body->content.get(); |
5855 | bool withContinue = hasContinueStatement(body); | 5953 | bool withContinue = hasContinueStatement(body); |
5856 | std::string conditionVar; | 5954 | std::string conditionVar; |
5955 | std::string extraLabel; | ||
5956 | ast_ptr<false, ExpListAssign_t> condAssign; | ||
5957 | int target = getLuaTarget(repeatNode); | ||
5857 | if (withContinue) { | 5958 | if (withContinue) { |
5858 | if (auto block = ast_cast<Block_t>(body)) { | 5959 | if (target < 502) { |
5859 | if (!block->statements.empty()) { | 5960 | if (auto block = ast_cast<Block_t>(body)) { |
5860 | auto stmt = static_cast<Statement_t*>(block->statements.back()); | 5961 | if (!block->statements.empty()) { |
5861 | if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { | 5962 | auto stmt = static_cast<Statement_t*>(block->statements.back()); |
5862 | extraDo = _parser.toString(breakLoop) == "break"sv; | 5963 | if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { |
5964 | extraDo = _parser.toString(breakLoop) == "break"sv; | ||
5965 | } | ||
5863 | } | 5966 | } |
5864 | } | 5967 | } |
5865 | } | 5968 | conditionVar = getUnusedName("_cond_"); |
5866 | conditionVar = getUnusedName("_cond_"); | 5969 | forceAddToScope(conditionVar); |
5867 | forceAddToScope(conditionVar); | 5970 | auto continueVar = getUnusedName("_continue_"sv); |
5868 | auto continueVar = getUnusedName("_continue_"sv); | 5971 | forceAddToScope(continueVar); |
5869 | forceAddToScope(continueVar); | 5972 | { |
5870 | { | 5973 | auto assignment = toAst<ExpListAssign_t>(conditionVar + "=nil"s, repeatNode->condition); |
5871 | auto assignment = toAst<ExpListAssign_t>(conditionVar + "=nil"s, repeatNode->condition); | 5974 | auto assign = assignment->action.to<Assign_t>(); |
5872 | auto assign = assignment->action.to<Assign_t>(); | 5975 | assign->values.clear(); |
5873 | assign->values.clear(); | 5976 | assign->values.push_back(repeatNode->condition); |
5874 | assign->values.push_back(repeatNode->condition); | 5977 | _continueVars.push({continueVar, assignment.get()}); |
5875 | _continueVars.push({continueVar, assignment.get()}); | 5978 | } |
5876 | } | 5979 | _buf << indent() << "local "sv << conditionVar << " = false"sv << nll(body); |
5877 | _buf << indent() << "local "sv << conditionVar << " = false"sv << nll(body); | 5980 | _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body); |
5878 | _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body); | 5981 | _buf << indent() << "repeat"sv << nll(body); |
5879 | _buf << indent() << "repeat"sv << nll(body); | ||
5880 | pushScope(); | ||
5881 | if (extraDo) { | ||
5882 | _buf << indent() << "do"sv << nll(body); | ||
5883 | pushScope(); | 5982 | pushScope(); |
5983 | if (extraDo) { | ||
5984 | _buf << indent() << "do"sv << nll(body); | ||
5985 | pushScope(); | ||
5986 | } | ||
5987 | temp.push_back(clearBuf()); | ||
5988 | } else { | ||
5989 | auto continueLabel = getUnusedLabel("_continue_"sv); | ||
5990 | _continueVars.push({continueLabel, nullptr}); | ||
5991 | transformLabel(toAst<Label_t>("::"s + _continueVars.top().var + "::"s, body), temp); | ||
5992 | extraLabel = temp.back(); | ||
5993 | temp.pop_back(); | ||
5884 | } | 5994 | } |
5885 | temp.push_back(clearBuf()); | ||
5886 | } | 5995 | } |
5887 | transform_plain_body(body, temp, ExpUsage::Common); | 5996 | transform_plain_body(body, temp, ExpUsage::Common); |
5888 | if (withContinue) { | 5997 | if (withContinue) { |
5889 | { | 5998 | if (target < 502) { |
5890 | transformAssignment(_continueVars.top().condAssign, temp); | 5999 | transformAssignment(_continueVars.top().condAssign, temp); |
5891 | auto assignCond = std::move(temp.back()); | 6000 | if (extraDo) { |
5892 | temp.pop_back(); | 6001 | popScope(); |
5893 | temp.back().append(assignCond); | 6002 | _buf << indent() << "end"sv << nll(body); |
5894 | } | 6003 | } |
5895 | if (extraDo) { | 6004 | _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); |
5896 | popScope(); | 6005 | popScope(); |
5897 | _buf << indent() << "end"sv << nll(body); | 6006 | _buf << indent() << "until true"sv << nlr(body); |
6007 | _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nlr(body); | ||
6008 | _buf << indent(1) << "break"sv << nlr(body); | ||
6009 | _buf << indent() << "end"sv << nlr(body); | ||
6010 | temp.push_back(clearBuf()); | ||
6011 | _continueVars.pop(); | ||
6012 | } else { | ||
6013 | temp.push_back(extraLabel); | ||
6014 | _continueVars.pop(); | ||
5898 | } | 6015 | } |
5899 | _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); | ||
5900 | popScope(); | ||
5901 | _buf << indent() << "until true"sv << nlr(body); | ||
5902 | _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nlr(body); | ||
5903 | _buf << indent(1) << "break"sv << nlr(body); | ||
5904 | _buf << indent() << "end"sv << nlr(body); | ||
5905 | temp.push_back(clearBuf()); | ||
5906 | _continueVars.pop(); | ||
5907 | } | 6016 | } |
5908 | out.push_back(join(temp)); | 6017 | out.push_back(join(temp)); |
5909 | return conditionVar; | 6018 | return conditionVar; |
@@ -5937,7 +6046,7 @@ private: | |||
5937 | 6046 | ||
5938 | void transformForClosure(For_t* forNode, str_list& out) { | 6047 | void transformForClosure(For_t* forNode, str_list& out) { |
5939 | str_list temp; | 6048 | str_list temp; |
5940 | _enableReturn.push(true); | 6049 | pushFunctionScope(); |
5941 | pushAnonVarArg(); | 6050 | pushAnonVarArg(); |
5942 | std::string& funcStart = temp.emplace_back(); | 6051 | std::string& funcStart = temp.emplace_back(); |
5943 | pushScope(); | 6052 | pushScope(); |
@@ -5947,7 +6056,7 @@ private: | |||
5947 | funcStart = anonFuncStart() + nll(forNode); | 6056 | funcStart = anonFuncStart() + nll(forNode); |
5948 | temp.push_back(indent() + anonFuncEnd()); | 6057 | temp.push_back(indent() + anonFuncEnd()); |
5949 | popAnonVarArg(); | 6058 | popAnonVarArg(); |
5950 | _enableReturn.pop(); | 6059 | popFunctionScope(); |
5951 | out.push_back(join(temp)); | 6060 | out.push_back(join(temp)); |
5952 | } | 6061 | } |
5953 | 6062 | ||
@@ -6026,7 +6135,7 @@ private: | |||
6026 | 6135 | ||
6027 | void transformForEachClosure(ForEach_t* forEach, str_list& out) { | 6136 | void transformForEachClosure(ForEach_t* forEach, str_list& out) { |
6028 | str_list temp; | 6137 | str_list temp; |
6029 | _enableReturn.push(true); | 6138 | pushFunctionScope(); |
6030 | pushAnonVarArg(); | 6139 | pushAnonVarArg(); |
6031 | std::string& funcStart = temp.emplace_back(); | 6140 | std::string& funcStart = temp.emplace_back(); |
6032 | pushScope(); | 6141 | pushScope(); |
@@ -6036,7 +6145,7 @@ private: | |||
6036 | funcStart = anonFuncStart() + nll(forEach); | 6145 | funcStart = anonFuncStart() + nll(forEach); |
6037 | temp.push_back(indent() + anonFuncEnd()); | 6146 | temp.push_back(indent() + anonFuncEnd()); |
6038 | popAnonVarArg(); | 6147 | popAnonVarArg(); |
6039 | _enableReturn.pop(); | 6148 | popFunctionScope(); |
6040 | out.push_back(join(temp)); | 6149 | out.push_back(join(temp)); |
6041 | } | 6150 | } |
6042 | 6151 | ||
@@ -6202,7 +6311,7 @@ private: | |||
6202 | 6311 | ||
6203 | void transformClassDeclClosure(ClassDecl_t* classDecl, str_list& out) { | 6312 | void transformClassDeclClosure(ClassDecl_t* classDecl, str_list& out) { |
6204 | str_list temp; | 6313 | str_list temp; |
6205 | _enableReturn.push(true); | 6314 | pushFunctionScope(); |
6206 | pushAnonVarArg(); | 6315 | pushAnonVarArg(); |
6207 | std::string& funcStart = temp.emplace_back(); | 6316 | std::string& funcStart = temp.emplace_back(); |
6208 | pushScope(); | 6317 | pushScope(); |
@@ -6211,7 +6320,7 @@ private: | |||
6211 | funcStart = anonFuncStart() + nll(classDecl); | 6320 | funcStart = anonFuncStart() + nll(classDecl); |
6212 | temp.push_back(indent() + anonFuncEnd()); | 6321 | temp.push_back(indent() + anonFuncEnd()); |
6213 | popAnonVarArg(); | 6322 | popAnonVarArg(); |
6214 | _enableReturn.pop(); | 6323 | popFunctionScope(); |
6215 | out.push_back(join(temp)); | 6324 | out.push_back(join(temp)); |
6216 | } | 6325 | } |
6217 | 6326 | ||
@@ -6611,7 +6720,7 @@ private: | |||
6611 | 6720 | ||
6612 | void transformWithClosure(With_t* with, str_list& out) { | 6721 | void transformWithClosure(With_t* with, str_list& out) { |
6613 | str_list temp; | 6722 | str_list temp; |
6614 | _enableReturn.push(true); | 6723 | pushFunctionScope(); |
6615 | pushAnonVarArg(); | 6724 | pushAnonVarArg(); |
6616 | std::string& funcStart = temp.emplace_back(); | 6725 | std::string& funcStart = temp.emplace_back(); |
6617 | pushScope(); | 6726 | pushScope(); |
@@ -6620,7 +6729,7 @@ private: | |||
6620 | funcStart = anonFuncStart() + nll(with); | 6729 | funcStart = anonFuncStart() + nll(with); |
6621 | temp.push_back(indent() + anonFuncEnd()); | 6730 | temp.push_back(indent() + anonFuncEnd()); |
6622 | popAnonVarArg(); | 6731 | popAnonVarArg(); |
6623 | _enableReturn.pop(); | 6732 | popFunctionScope(); |
6624 | out.push_back(join(temp)); | 6733 | out.push_back(join(temp)); |
6625 | } | 6734 | } |
6626 | 6735 | ||
@@ -6918,7 +7027,7 @@ private: | |||
6918 | void transformTblComprehension(TblComprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { | 7027 | void transformTblComprehension(TblComprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { |
6919 | switch (usage) { | 7028 | switch (usage) { |
6920 | case ExpUsage::Closure: | 7029 | case ExpUsage::Closure: |
6921 | _enableReturn.push(true); | 7030 | pushFunctionScope(); |
6922 | pushAnonVarArg(); | 7031 | pushAnonVarArg(); |
6923 | pushScope(); | 7032 | pushScope(); |
6924 | break; | 7033 | break; |
@@ -6980,7 +7089,7 @@ private: | |||
6980 | out.back().insert(0, anonFuncStart() + nll(comp)); | 7089 | out.back().insert(0, anonFuncStart() + nll(comp)); |
6981 | out.back().append(indent() + anonFuncEnd()); | 7090 | out.back().append(indent() + anonFuncEnd()); |
6982 | popAnonVarArg(); | 7091 | popAnonVarArg(); |
6983 | _enableReturn.pop(); | 7092 | popFunctionScope(); |
6984 | break; | 7093 | break; |
6985 | case ExpUsage::Assignment: { | 7094 | case ExpUsage::Assignment: { |
6986 | out.push_back(clearBuf()); | 7095 | out.push_back(clearBuf()); |
@@ -7025,7 +7134,7 @@ private: | |||
7025 | str_list temp; | 7134 | str_list temp; |
7026 | std::string* funcStart = nullptr; | 7135 | std::string* funcStart = nullptr; |
7027 | if (usage == ExpUsage::Closure) { | 7136 | if (usage == ExpUsage::Closure) { |
7028 | _enableReturn.push(true); | 7137 | pushFunctionScope(); |
7029 | pushAnonVarArg(); | 7138 | pushAnonVarArg(); |
7030 | funcStart = &temp.emplace_back(); | 7139 | funcStart = &temp.emplace_back(); |
7031 | } else { | 7140 | } else { |
@@ -7038,7 +7147,7 @@ private: | |||
7038 | *funcStart = anonFuncStart() + nll(doNode); | 7147 | *funcStart = anonFuncStart() + nll(doNode); |
7039 | temp.push_back(indent() + anonFuncEnd()); | 7148 | temp.push_back(indent() + anonFuncEnd()); |
7040 | popAnonVarArg(); | 7149 | popAnonVarArg(); |
7041 | _enableReturn.pop(); | 7150 | popFunctionScope(); |
7042 | } else { | 7151 | } else { |
7043 | temp.push_back(indent() + "end"s + nlr(doNode)); | 7152 | temp.push_back(indent() + "end"s + nlr(doNode)); |
7044 | } | 7153 | } |
@@ -7445,7 +7554,7 @@ private: | |||
7445 | void transformWhileClosure(While_t* whileNode, str_list& out) { | 7554 | void transformWhileClosure(While_t* whileNode, str_list& out) { |
7446 | auto x = whileNode; | 7555 | auto x = whileNode; |
7447 | str_list temp; | 7556 | str_list temp; |
7448 | _enableReturn.push(true); | 7557 | pushFunctionScope(); |
7449 | pushAnonVarArg(); | 7558 | pushAnonVarArg(); |
7450 | std::string& funcStart = temp.emplace_back(); | 7559 | std::string& funcStart = temp.emplace_back(); |
7451 | pushScope(); | 7560 | pushScope(); |
@@ -7469,7 +7578,7 @@ private: | |||
7469 | funcStart = anonFuncStart() + nll(whileNode); | 7578 | funcStart = anonFuncStart() + nll(whileNode); |
7470 | temp.push_back(indent() + anonFuncEnd()); | 7579 | temp.push_back(indent() + anonFuncEnd()); |
7471 | popAnonVarArg(); | 7580 | popAnonVarArg(); |
7472 | _enableReturn.pop(); | 7581 | popFunctionScope(); |
7473 | out.push_back(join(temp)); | 7582 | out.push_back(join(temp)); |
7474 | } | 7583 | } |
7475 | 7584 | ||
@@ -7507,7 +7616,7 @@ private: | |||
7507 | str_list temp; | 7616 | str_list temp; |
7508 | std::string* funcStart = nullptr; | 7617 | std::string* funcStart = nullptr; |
7509 | if (usage == ExpUsage::Closure) { | 7618 | if (usage == ExpUsage::Closure) { |
7510 | _enableReturn.push(true); | 7619 | pushFunctionScope(); |
7511 | pushAnonVarArg(); | 7620 | pushAnonVarArg(); |
7512 | funcStart = &temp.emplace_back(); | 7621 | funcStart = &temp.emplace_back(); |
7513 | pushScope(); | 7622 | pushScope(); |
@@ -7631,7 +7740,7 @@ private: | |||
7631 | } | 7740 | } |
7632 | temp.push_back(indent() + "end"s + nlr(switchNode)); | 7741 | temp.push_back(indent() + "end"s + nlr(switchNode)); |
7633 | if (usage == ExpUsage::Closure) { | 7742 | if (usage == ExpUsage::Closure) { |
7634 | _enableReturn.pop(); | 7743 | popFunctionScope(); |
7635 | popScope(); | 7744 | popScope(); |
7636 | *funcStart = anonFuncStart() + nll(switchNode); | 7745 | *funcStart = anonFuncStart() + nll(switchNode); |
7637 | temp.push_back(indent() + anonFuncEnd()); | 7746 | temp.push_back(indent() + anonFuncEnd()); |
@@ -7798,29 +7907,52 @@ private: | |||
7798 | return; | 7907 | return; |
7799 | } | 7908 | } |
7800 | if (_continueVars.empty()) throw std::logic_error(_info.errorMessage("continue is not inside a loop"sv, breakLoop)); | 7909 | if (_continueVars.empty()) throw std::logic_error(_info.errorMessage("continue is not inside a loop"sv, breakLoop)); |
7910 | str_list temp; | ||
7801 | auto& item = _continueVars.top(); | 7911 | auto& item = _continueVars.top(); |
7802 | if (item.condAssign) { | 7912 | if (item.condAssign) { |
7803 | str_list temp; | ||
7804 | transformAssignment(item.condAssign, temp); | 7913 | transformAssignment(item.condAssign, temp); |
7805 | _buf << temp.back(); | ||
7806 | } | 7914 | } |
7807 | _buf << indent() << item.var << " = true"sv << nll(breakLoop); | 7915 | if (getLuaTarget(breakLoop) < 502) { |
7808 | _buf << indent() << "break"sv << nll(breakLoop); | 7916 | if (!temp.empty()) { |
7809 | out.push_back(clearBuf()); | 7917 | _buf << temp.back(); |
7918 | } | ||
7919 | _buf << indent() << item.var << " = true"sv << nll(breakLoop); | ||
7920 | _buf << indent() << "break"sv << nll(breakLoop); | ||
7921 | out.push_back(clearBuf()); | ||
7922 | } else { | ||
7923 | transformGoto(toAst<Goto_t>("goto "s + item.var, breakLoop), temp); | ||
7924 | out.push_back(join(temp)); | ||
7925 | } | ||
7810 | } | 7926 | } |
7811 | 7927 | ||
7812 | void transformLabel(Label_t* label, str_list& out) { | 7928 | void transformLabel(Label_t* label, str_list& out) { |
7813 | if (getLuaTarget(label) < 502) { | 7929 | if (getLuaTarget(label) < 502) { |
7814 | throw std::logic_error(_info.errorMessage("label statement is not available when not targeting Lua version 5.2 or higher"sv, label)); | 7930 | throw std::logic_error(_info.errorMessage("label statement is not available when not targeting Lua version 5.2 or higher"sv, label)); |
7815 | } | 7931 | } |
7816 | out.push_back(indent() + "::"s + _parser.toString(label->label) + "::"s + nll(label)); | 7932 | auto labelStr = _parser.toString(label->label); |
7933 | int currentScope = _gotoScopes.top(); | ||
7934 | if (static_cast<int>(_labels.size()) <= currentScope) { | ||
7935 | _labels.resize(currentScope + 1, std::nullopt); | ||
7936 | _labels[currentScope] = std::unordered_map<std::string, LabelNode>(); | ||
7937 | } | ||
7938 | if (!_labels[currentScope]) { | ||
7939 | _labels[currentScope] = std::unordered_map<std::string, LabelNode>(); | ||
7940 | } | ||
7941 | auto& scope = _labels[currentScope].value(); | ||
7942 | if (auto it = scope.find(labelStr); it != scope.end()) { | ||
7943 | throw std::logic_error(_info.errorMessage("label '"s + labelStr + "' already defined at line "s + std::to_string(it->second.line), label)); | ||
7944 | } | ||
7945 | scope[labelStr] = {label->m_begin.m_line, static_cast<int>(_scopes.size())}; | ||
7946 | out.push_back(indent() + "::"s + labelStr + "::"s + nll(label)); | ||
7817 | } | 7947 | } |
7818 | 7948 | ||
7819 | void transformGoto(Goto_t* gotoNode, str_list& out) { | 7949 | void transformGoto(Goto_t* gotoNode, str_list& out) { |
7820 | if (getLuaTarget(gotoNode) < 502) { | 7950 | if (getLuaTarget(gotoNode) < 502) { |
7821 | throw std::logic_error(_info.errorMessage("goto statement is not available when not targeting Lua version 5.2 or higher"sv, gotoNode)); | 7951 | throw std::logic_error(_info.errorMessage("goto statement is not available when not targeting Lua version 5.2 or higher"sv, gotoNode)); |
7822 | } | 7952 | } |
7823 | out.push_back(indent() + "goto "s + _parser.toString(gotoNode->label) + nll(gotoNode)); | 7953 | auto labelStr = _parser.toString(gotoNode->label); |
7954 | gotos.push_back({gotoNode, labelStr, _gotoScopes.top(), static_cast<int>(_scopes.size())}); | ||
7955 | out.push_back(indent() + "goto "s + labelStr + nll(gotoNode)); | ||
7824 | } | 7956 | } |
7825 | 7957 | ||
7826 | void transformShortTabAppending(ShortTabAppending_t* tab, str_list& out) { | 7958 | void transformShortTabAppending(ShortTabAppending_t* tab, str_list& out) { |