aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--spec/outputs/5.1/loops.lua36
-rw-r--r--spec/outputs/codes_from_doc_de.lua8
-rw-r--r--spec/outputs/codes_from_doc_en.lua8
-rw-r--r--spec/outputs/codes_from_doc_id-id.lua8
-rw-r--r--spec/outputs/codes_from_doc_pt-br.lua8
-rw-r--r--spec/outputs/codes_from_doc_zh.lua8
-rw-r--r--spec/outputs/loops.lua36
-rw-r--r--spec/outputs/test/config_spec.lua12
-rw-r--r--spec/outputs/test/do_statement_spec.lua4
-rw-r--r--spec/outputs/test/with_statement_spec.lua98
-rw-r--r--spec/outputs/with.lua50
-rw-r--r--src/yuescript/yue_ast.cpp4
-rw-r--r--src/yuescript/yue_ast.h6
-rw-r--r--src/yuescript/yue_compiler.cpp413
-rw-r--r--src/yuescript/yue_parser.cpp2
15 files changed, 406 insertions, 295 deletions
diff --git a/spec/outputs/5.1/loops.lua b/spec/outputs/5.1/loops.lua
index e4f2871..019cd60 100644
--- a/spec/outputs/5.1/loops.lua
+++ b/spec/outputs/5.1/loops.lua
@@ -499,25 +499,21 @@ local _anon_func_0 = function(i, tb)
499end 499end
500do 500do
501 local index 501 local index
502 do 502 for i = 1, #tb do
503 local _accum_0 503 if tb[i] then
504 for i = 1, #tb do 504 index = i
505 if tb[i] then 505 break
506 _accum_0 = i
507 break
508 end
509 end 506 end
510 index = _accum_0
511 end 507 end
512 f((function() 508 f((function()
513 local _accum_0 509 local _val_0
514 for i = 1, #tb do 510 for i = 1, #tb do
515 if tb[i] then 511 if tb[i] then
516 _accum_0 = i 512 _val_0 = i
517 break 513 break
518 end 514 end
519 end 515 end
520 return _accum_0 516 return _val_0
521 end)()) 517 end)())
522 f((function() 518 f((function()
523 local _accum_0 = { } 519 local _accum_0 = { }
@@ -545,13 +541,13 @@ do
545 i = 1 541 i = 1
546 local idx 542 local idx
547 do 543 do
548 local _accum_0 544 local _val_0
549 while tb[i] do 545 while tb[i] do
550 i = i + 1 546 i = i + 1
551 _accum_0 = i - 1 547 _val_0 = i - 1
552 break 548 break
553 end 549 end
554 idx = _accum_0 550 idx = _val_0
555 end 551 end
556 local f1 552 local f1
557 f1 = function() 553 f1 = function()
@@ -560,13 +556,13 @@ do
560 end 556 end
561 i = 1 557 i = 1
562 f((function() 558 f((function()
563 local _accum_0 559 local _val_0
564 while tb[i] do 560 while tb[i] do
565 i = i + 1 561 i = i + 1
566 _accum_0 = i - 1 562 _val_0 = i - 1
567 break 563 break
568 end 564 end
569 return _accum_0 565 return _val_0
570 end)()) 566 end)())
571 local _accum_0 = { } 567 local _accum_0 = { }
572 local _len_0 = 1 568 local _len_0 = 1
@@ -592,13 +588,13 @@ do
592 print(1) 588 print(1)
593 until true 589 until true
594 do 590 do
595 local _accum_0 591 local _val_0
596 repeat 592 repeat
597 a = func() 593 a = func()
598 _accum_0 = a.x 594 _val_0 = a.x
599 break 595 break
600 until a.v 596 until a.v
601 x = _accum_0 597 x = _val_0
602 end 598 end
603 local items 599 local items
604 local _accum_0 = { } 600 local _accum_0 = { }
diff --git a/spec/outputs/codes_from_doc_de.lua b/spec/outputs/codes_from_doc_de.lua
index 44fc28a..7de1a35 100644
--- a/spec/outputs/codes_from_doc_de.lua
+++ b/spec/outputs/codes_from_doc_de.lua
@@ -3260,16 +3260,14 @@ for i = 1, 20 do
3260end 3260end
3261doubled_evens = _accum_0 3261doubled_evens = _accum_0
3262local first_large 3262local first_large
3263local _accum_0
3264local _list_0 = numbers 3263local _list_0 = numbers
3265for _index_0 = 1, #_list_0 do 3264for _index_0 = 1, #_list_0 do
3266 local n = _list_0[_index_0] 3265 local n = _list_0[_index_0]
3267 if n > 10 then 3266 if n > 10 then
3268 _accum_0 = n 3267 first_large = n
3269 break 3268 break
3270 end 3269 end
3271end 3270end
3272first_large = _accum_0
3273local func_a 3271local func_a
3274func_a = function() 3272func_a = function()
3275 for i = 1, 10 do 3273 for i = 1, 10 do
@@ -3324,16 +3322,14 @@ for i = 1, 20 do
3324end 3322end
3325doubled_evens = _accum_0 3323doubled_evens = _accum_0
3326local first_large 3324local first_large
3327local _accum_0
3328local _list_0 = numbers 3325local _list_0 = numbers
3329for _index_0 = 1, #_list_0 do 3326for _index_0 = 1, #_list_0 do
3330 local n = _list_0[_index_0] 3327 local n = _list_0[_index_0]
3331 if n > 10 then 3328 if n > 10 then
3332 _accum_0 = n 3329 first_large = n
3333 break 3330 break
3334 end 3331 end
3335end 3332end
3336first_large = _accum_0
3337local func_a 3333local func_a
3338func_a = function() 3334func_a = function()
3339 for i = 1, 10 do 3335 for i = 1, 10 do
diff --git a/spec/outputs/codes_from_doc_en.lua b/spec/outputs/codes_from_doc_en.lua
index 5320961..cd83bbf 100644
--- a/spec/outputs/codes_from_doc_en.lua
+++ b/spec/outputs/codes_from_doc_en.lua
@@ -3260,16 +3260,14 @@ for i = 1, 20 do
3260end 3260end
3261doubled_evens = _accum_0 3261doubled_evens = _accum_0
3262local first_large 3262local first_large
3263local _accum_0
3264local _list_0 = numbers 3263local _list_0 = numbers
3265for _index_0 = 1, #_list_0 do 3264for _index_0 = 1, #_list_0 do
3266 local n = _list_0[_index_0] 3265 local n = _list_0[_index_0]
3267 if n > 10 then 3266 if n > 10 then
3268 _accum_0 = n 3267 first_large = n
3269 break 3268 break
3270 end 3269 end
3271end 3270end
3272first_large = _accum_0
3273local func_a 3271local func_a
3274func_a = function() 3272func_a = function()
3275 for i = 1, 10 do 3273 for i = 1, 10 do
@@ -3324,16 +3322,14 @@ for i = 1, 20 do
3324end 3322end
3325doubled_evens = _accum_0 3323doubled_evens = _accum_0
3326local first_large 3324local first_large
3327local _accum_0
3328local _list_0 = numbers 3325local _list_0 = numbers
3329for _index_0 = 1, #_list_0 do 3326for _index_0 = 1, #_list_0 do
3330 local n = _list_0[_index_0] 3327 local n = _list_0[_index_0]
3331 if n > 10 then 3328 if n > 10 then
3332 _accum_0 = n 3329 first_large = n
3333 break 3330 break
3334 end 3331 end
3335end 3332end
3336first_large = _accum_0
3337local func_a 3333local func_a
3338func_a = function() 3334func_a = function()
3339 for i = 1, 10 do 3335 for i = 1, 10 do
diff --git a/spec/outputs/codes_from_doc_id-id.lua b/spec/outputs/codes_from_doc_id-id.lua
index e952434..b024989 100644
--- a/spec/outputs/codes_from_doc_id-id.lua
+++ b/spec/outputs/codes_from_doc_id-id.lua
@@ -3260,16 +3260,14 @@ for i = 1, 20 do
3260end 3260end
3261doubled_evens = _accum_0 3261doubled_evens = _accum_0
3262local first_large 3262local first_large
3263local _accum_0
3264local _list_0 = numbers 3263local _list_0 = numbers
3265for _index_0 = 1, #_list_0 do 3264for _index_0 = 1, #_list_0 do
3266 local n = _list_0[_index_0] 3265 local n = _list_0[_index_0]
3267 if n > 10 then 3266 if n > 10 then
3268 _accum_0 = n 3267 first_large = n
3269 break 3268 break
3270 end 3269 end
3271end 3270end
3272first_large = _accum_0
3273local func_a 3271local func_a
3274func_a = function() 3272func_a = function()
3275 for i = 1, 10 do 3273 for i = 1, 10 do
@@ -3324,16 +3322,14 @@ for i = 1, 20 do
3324end 3322end
3325doubled_evens = _accum_0 3323doubled_evens = _accum_0
3326local first_large 3324local first_large
3327local _accum_0
3328local _list_0 = numbers 3325local _list_0 = numbers
3329for _index_0 = 1, #_list_0 do 3326for _index_0 = 1, #_list_0 do
3330 local n = _list_0[_index_0] 3327 local n = _list_0[_index_0]
3331 if n > 10 then 3328 if n > 10 then
3332 _accum_0 = n 3329 first_large = n
3333 break 3330 break
3334 end 3331 end
3335end 3332end
3336first_large = _accum_0
3337local func_a 3333local func_a
3338func_a = function() 3334func_a = function()
3339 for i = 1, 10 do 3335 for i = 1, 10 do
diff --git a/spec/outputs/codes_from_doc_pt-br.lua b/spec/outputs/codes_from_doc_pt-br.lua
index 0c9affb..f5643c8 100644
--- a/spec/outputs/codes_from_doc_pt-br.lua
+++ b/spec/outputs/codes_from_doc_pt-br.lua
@@ -3260,16 +3260,14 @@ for i = 1, 20 do
3260end 3260end
3261doubled_evens = _accum_0 3261doubled_evens = _accum_0
3262local first_large 3262local first_large
3263local _accum_0
3264local _list_0 = numbers 3263local _list_0 = numbers
3265for _index_0 = 1, #_list_0 do 3264for _index_0 = 1, #_list_0 do
3266 local n = _list_0[_index_0] 3265 local n = _list_0[_index_0]
3267 if n > 10 then 3266 if n > 10 then
3268 _accum_0 = n 3267 first_large = n
3269 break 3268 break
3270 end 3269 end
3271end 3270end
3272first_large = _accum_0
3273local func_a 3271local func_a
3274func_a = function() 3272func_a = function()
3275 for i = 1, 10 do 3273 for i = 1, 10 do
@@ -3324,16 +3322,14 @@ for i = 1, 20 do
3324end 3322end
3325doubled_evens = _accum_0 3323doubled_evens = _accum_0
3326local first_large 3324local first_large
3327local _accum_0
3328local _list_0 = numbers 3325local _list_0 = numbers
3329for _index_0 = 1, #_list_0 do 3326for _index_0 = 1, #_list_0 do
3330 local n = _list_0[_index_0] 3327 local n = _list_0[_index_0]
3331 if n > 10 then 3328 if n > 10 then
3332 _accum_0 = n 3329 first_large = n
3333 break 3330 break
3334 end 3331 end
3335end 3332end
3336first_large = _accum_0
3337local func_a 3333local func_a
3338func_a = function() 3334func_a = function()
3339 for i = 1, 10 do 3335 for i = 1, 10 do
diff --git a/spec/outputs/codes_from_doc_zh.lua b/spec/outputs/codes_from_doc_zh.lua
index fa985e2..087782e 100644
--- a/spec/outputs/codes_from_doc_zh.lua
+++ b/spec/outputs/codes_from_doc_zh.lua
@@ -3260,16 +3260,14 @@ for i = 1, 20 do
3260end 3260end
3261doubled_evens = _accum_0 3261doubled_evens = _accum_0
3262local first_large 3262local first_large
3263local _accum_0
3264local _list_0 = numbers 3263local _list_0 = numbers
3265for _index_0 = 1, #_list_0 do 3264for _index_0 = 1, #_list_0 do
3266 local n = _list_0[_index_0] 3265 local n = _list_0[_index_0]
3267 if n > 10 then 3266 if n > 10 then
3268 _accum_0 = n 3267 first_large = n
3269 break 3268 break
3270 end 3269 end
3271end 3270end
3272first_large = _accum_0
3273local func_a 3271local func_a
3274func_a = function() 3272func_a = function()
3275 for i = 1, 10 do 3273 for i = 1, 10 do
@@ -3324,16 +3322,14 @@ for i = 1, 20 do
3324end 3322end
3325doubled_evens = _accum_0 3323doubled_evens = _accum_0
3326local first_large 3324local first_large
3327local _accum_0
3328local _list_0 = numbers 3325local _list_0 = numbers
3329for _index_0 = 1, #_list_0 do 3326for _index_0 = 1, #_list_0 do
3330 local n = _list_0[_index_0] 3327 local n = _list_0[_index_0]
3331 if n > 10 then 3328 if n > 10 then
3332 _accum_0 = n 3329 first_large = n
3333 break 3330 break
3334 end 3331 end
3335end 3332end
3336first_large = _accum_0
3337local func_a 3333local func_a
3338func_a = function() 3334func_a = function()
3339 for i = 1, 10 do 3335 for i = 1, 10 do
diff --git a/spec/outputs/loops.lua b/spec/outputs/loops.lua
index 6ab4bbb..4fb4187 100644
--- a/spec/outputs/loops.lua
+++ b/spec/outputs/loops.lua
@@ -380,25 +380,21 @@ local _anon_func_0 = function(i, tb)
380end 380end
381do 381do
382 local index 382 local index
383 do 383 for i = 1, #tb do
384 local _accum_0 384 if tb[i] then
385 for i = 1, #tb do 385 index = i
386 if tb[i] then 386 break
387 _accum_0 = i
388 break
389 end
390 end 387 end
391 index = _accum_0
392 end 388 end
393 f((function() 389 f((function()
394 local _accum_0 390 local _val_0
395 for i = 1, #tb do 391 for i = 1, #tb do
396 if tb[i] then 392 if tb[i] then
397 _accum_0 = i 393 _val_0 = i
398 break 394 break
399 end 395 end
400 end 396 end
401 return _accum_0 397 return _val_0
402 end)()) 398 end)())
403 f((function() 399 f((function()
404 local _accum_0 = { } 400 local _accum_0 = { }
@@ -426,13 +422,13 @@ do
426 i = 1 422 i = 1
427 local idx 423 local idx
428 do 424 do
429 local _accum_0 425 local _val_0
430 while tb[i] do 426 while tb[i] do
431 i = i + 1 427 i = i + 1
432 _accum_0 = i - 1 428 _val_0 = i - 1
433 break 429 break
434 end 430 end
435 idx = _accum_0 431 idx = _val_0
436 end 432 end
437 local f1 433 local f1
438 f1 = function() 434 f1 = function()
@@ -441,13 +437,13 @@ do
441 end 437 end
442 i = 1 438 i = 1
443 f((function() 439 f((function()
444 local _accum_0 440 local _val_0
445 while tb[i] do 441 while tb[i] do
446 i = i + 1 442 i = i + 1
447 _accum_0 = i - 1 443 _val_0 = i - 1
448 break 444 break
449 end 445 end
450 return _accum_0 446 return _val_0
451 end)()) 447 end)())
452 local _accum_0 = { } 448 local _accum_0 = { }
453 local _len_0 = 1 449 local _len_0 = 1
@@ -473,13 +469,13 @@ do
473 print(1) 469 print(1)
474 until true 470 until true
475 do 471 do
476 local _accum_0 472 local _val_0
477 repeat 473 repeat
478 a = func() 474 a = func()
479 _accum_0 = a.x 475 _val_0 = a.x
480 break 476 break
481 until a.v 477 until a.v
482 x = _accum_0 478 x = _val_0
483 end 479 end
484 local items 480 local items
485 local _accum_0 = { } 481 local _accum_0 = { }
diff --git a/spec/outputs/test/config_spec.lua b/spec/outputs/test/config_spec.lua
index 410bacc..dc98760 100644
--- a/spec/outputs/test/config_spec.lua
+++ b/spec/outputs/test/config_spec.lua
@@ -114,14 +114,10 @@ return describe("config", function()
114 y = 20 114 y = 20
115 } 115 }
116 local result 116 local result
117 do 117 repeat
118 local _accum_0 118 result = obj.x + obj.y
119 repeat 119 break
120 _accum_0 = obj.x + obj.y 120 until true
121 break
122 until true
123 result = _accum_0
124 end
125 return assert.same(result, 30) 121 return assert.same(result, 30)
126 end) 122 end)
127 it("should handle existential operators", function() 123 it("should handle existential operators", function()
diff --git a/spec/outputs/test/do_statement_spec.lua b/spec/outputs/test/do_statement_spec.lua
index fb93fa0..7c491a0 100644
--- a/spec/outputs/test/do_statement_spec.lua
+++ b/spec/outputs/test/do_statement_spec.lua
@@ -104,12 +104,10 @@ return describe("do statement", function()
104 } 104 }
105 local result 105 local result
106 do 106 do
107 local _accum_0
108 repeat 107 repeat
109 _accum_0 = obj:double() 108 result = obj:double()
110 break 109 break
111 until true 110 until true
112 result = _accum_0
113 end 111 end
114 return assert.same(result, 20) 112 return assert.same(result, 20)
115 end) 113 end)
diff --git a/spec/outputs/test/with_statement_spec.lua b/spec/outputs/test/with_statement_spec.lua
index dcd2aa1..e6f64e8 100644
--- a/spec/outputs/test/with_statement_spec.lua
+++ b/spec/outputs/test/with_statement_spec.lua
@@ -53,14 +53,10 @@ return describe("with statement", function()
53 value = 5 53 value = 5
54 } 54 }
55 local result 55 local result
56 do 56 repeat
57 local _accum_0 57 result = obj.value * 2
58 repeat 58 break
59 _accum_0 = obj.value * 2 59 until true
60 break
61 until true
62 result = _accum_0
63 end
64 return assert.same(result, 10) 60 return assert.same(result, 10)
65 end) 61 end)
66 it("should support multiple statements", function() 62 it("should support multiple statements", function()
@@ -125,27 +121,19 @@ return describe("with statement", function()
125 y = 10 121 y = 10
126 } 122 }
127 local result 123 local result
128 do 124 repeat
129 local _accum_0 125 result = obj.x + obj.y
130 repeat 126 break
131 _accum_0 = obj.x + obj.y 127 until true
132 break
133 until true
134 result = _accum_0
135 end
136 return assert.same(result, 15) 128 return assert.same(result, 15)
137 end) 129 end)
138 it("should work with string methods", function() 130 it("should work with string methods", function()
139 local s = "hello" 131 local s = "hello"
140 local result 132 local result
141 do 133 repeat
142 local _accum_0 134 result = s:upper()
143 repeat 135 break
144 _accum_0 = s:upper() 136 until true
145 break
146 until true
147 result = _accum_0
148 end
149 return assert.same(result, "HELLO") 137 return assert.same(result, "HELLO")
150 end) 138 end)
151 it("should handle metatable access", function() 139 it("should handle metatable access", function()
@@ -169,12 +157,10 @@ return describe("with statement", function()
169 x = 10 157 x = 10
170 } 158 }
171 local _val_0 159 local _val_0
172 local _accum_0
173 repeat 160 repeat
174 _accum_0 = obj.x * 2 161 _val_0 = obj.x * 2
175 break 162 break
176 until true 163 until true
177 _val_0 = _accum_0
178 return _val_0 164 return _val_0
179 end 165 end
180 local result = fn() 166 local result = fn()
@@ -187,12 +173,10 @@ return describe("with statement", function()
187 value = 42 173 value = 42
188 } 174 }
189 local _val_0 175 local _val_0
190 local _accum_0
191 repeat 176 repeat
192 _accum_0 = obj.value 177 _val_0 = obj.value
193 break 178 break
194 until true 179 until true
195 _val_0 = _accum_0
196 return _val_0 180 return _val_0
197 end 181 end
198 return assert.same(get_value(), 42) 182 return assert.same(get_value(), 42)
@@ -202,19 +186,15 @@ return describe("with statement", function()
202 value = 10 186 value = 10
203 } 187 }
204 local result 188 local result
205 do 189 repeat
206 local _accum_0 190 local _exp_0 = obj.value
207 repeat 191 if _exp_0 ~= nil then
208 local _exp_0 = obj.value 192 result = _exp_0
209 if _exp_0 ~= nil then 193 else
210 _accum_0 = _exp_0 194 result = 0
211 else 195 end
212 _accum_0 = 0 196 break
213 end 197 until true
214 break
215 until true
216 result = _accum_0
217 end
218 return assert.same(result, 10) 198 return assert.same(result, 10)
219 end) 199 end)
220 it("should handle nil object safely", function() 200 it("should handle nil object safely", function()
@@ -222,10 +202,10 @@ return describe("with statement", function()
222 do 202 do
223 local _with_0 = nil 203 local _with_0 = nil
224 do 204 do
225 local _accum_0 205 local _accum_0 = { }
226 repeat 206 repeat
227 if _with_0 ~= nil then 207 if _with_0 ~= nil then
228 _accum_0 = _with_0.value 208 result = _with_0.value
229 break 209 break
230 end 210 end
231 until true 211 until true
@@ -245,16 +225,12 @@ return describe("with statement", function()
245 end 225 end
246 } 226 }
247 local result 227 local result
248 do 228 repeat
249 local _accum_0 229 obj:add(10)
250 repeat 230 obj:add(5)
251 obj:add(10) 231 result = obj:get()
252 obj:add(5) 232 break
253 _accum_0 = obj:get() 233 until true
254 break
255 until true
256 result = _accum_0
257 end
258 return assert.same(result, 20) 234 return assert.same(result, 20)
259 end) 235 end)
260 return it("should support nested property access", function() 236 return it("should support nested property access", function()
@@ -266,14 +242,10 @@ return describe("with statement", function()
266 } 242 }
267 } 243 }
268 local result 244 local result
269 do 245 repeat
270 local _accum_0 246 result = obj.level1.level2.level3
271 repeat 247 break
272 _accum_0 = obj.level1.level2.level3 248 until true
273 break
274 until true
275 result = _accum_0
276 end
277 return assert.same(result, "deep") 249 return assert.same(result, "deep")
278 end) 250 end)
279end) 251end)
diff --git a/spec/outputs/with.lua b/spec/outputs/with.lua
index 3cd8aab..ce0e495 100644
--- a/spec/outputs/with.lua
+++ b/spec/outputs/with.lua
@@ -191,62 +191,52 @@ do
191 f((function() 191 f((function()
192 local _with_0 = item 192 local _with_0 = item
193 local _val_0 193 local _val_0
194 do 194 repeat
195 local _accum_0 195 if _with_0.id > 0 then
196 repeat 196 _val_0 = _with_0.content
197 if _with_0.id > 0 then 197 break
198 _accum_0 = _with_0.content 198 end
199 break 199 until true
200 end
201 until true
202 _val_0 = _accum_0
203 end
204 return _val_0 200 return _val_0
205 end)()) 201 end)())
206 local a 202 local a
207 do 203 do
208 local _with_0 = tb 204 local _with_0 = tb
209 do 205 repeat
210 local _accum_0 206 if _with_0.v then
211 repeat 207 a = _with_0.a
212 if _with_0.v then 208 break
213 _accum_0 = _with_0.a 209 end
214 break 210 until true
215 end
216 until true
217 a = _accum_0
218 end
219 end 211 end
220 local _accum_0 212 local _val_0
221 while true do 213 while true do
222 local _with_0 = tb 214 local _with_0 = tb
223 local _accum_1 215 local _accum_0 = { }
224 repeat 216 repeat
225 if _with_0 ~= nil then 217 if _with_0 ~= nil then
226 _accum_1 = 1 218 _val_0 = 1
227 break 219 break
228 end 220 end
229 until true 221 until true
230 _accum_0 = _accum_1 222 _val_0 = _accum_0
231 break 223 break
232 end 224 end
233 a = _accum_0 225 a = _val_0
234end 226end
235do 227do
236 local a 228 local a
237 local _accum_0
238 for i = 1, 100 do 229 for i = 1, 100 do
239 local x = tb[i] 230 local x = tb[i]
240 if x ~= nil then 231 if x ~= nil then
241 local _des_0 = 1 232 local _des_0 = 1
242 if _des_0 then 233 if _des_0 then
243 x.id = _des_0 234 x.id = _des_0
244 _accum_0 = x 235 a = x
245 break 236 break
246 end 237 end
247 end 238 end
248 end 239 end
249 a = _accum_0
250end 240end
251do 241do
252 local tb = { 242 local tb = {
@@ -254,11 +244,9 @@ do
254 y = 2 244 y = 2
255 } 245 }
256 local a 246 local a
257 local _accum_0
258 repeat 247 repeat
259 _accum_0 = tb.x + tb.y 248 a = tb.x + tb.y
260 break 249 break
261 until true 250 until true
262 a = _accum_0
263end 251end
264return nil 252return nil
diff --git a/src/yuescript/yue_ast.cpp b/src/yuescript/yue_ast.cpp
index 2fccd35..9c398c8 100644
--- a/src/yuescript/yue_ast.cpp
+++ b/src/yuescript/yue_ast.cpp
@@ -201,8 +201,8 @@ std::string Continue_t::to_string(void*) const {
201 return "continue"s; 201 return "continue"s;
202} 202}
203std::string BreakLoop_t::to_string(void* ud) const { 203std::string BreakLoop_t::to_string(void* ud) const {
204 if (value) { 204 if (valueList) {
205 return type->to_string(ud) + ' ' + value->to_string(ud); 205 return type->to_string(ud) + ' ' + valueList->to_string(ud);
206 } 206 }
207 return type->to_string(ud); 207 return type->to_string(ud);
208} 208}
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h
index 98f9014..91800b0 100644
--- a/src/yuescript/yue_ast.h
+++ b/src/yuescript/yue_ast.h
@@ -914,9 +914,9 @@ AST_END(Continue)
914 914
915AST_NODE(BreakLoop) 915AST_NODE(BreakLoop)
916 ast_sel<true, Break_t, Continue_t> type; 916 ast_sel<true, Break_t, Continue_t> type;
917 ast_ptr<false, Exp_t> value; 917 ast_ptr<false, ExpList_t> valueList;
918 AST_MEMBER(BreakLoop, &type, &value) 918 AST_MEMBER(BreakLoop, &type, &valueList)
919 std::string varBWV; 919 std::list<std::string> vars;
920AST_END(BreakLoop) 920AST_END(BreakLoop)
921 921
922AST_NODE(PipeBody) 922AST_NODE(PipeBody)
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index eb31ab5..bd52d33 100644
--- a/src/yuescript/yue_compiler.cpp
+++ b/src/yuescript/yue_compiler.cpp
@@ -78,7 +78,7 @@ static std::unordered_set<std::string> Metamethods = {
78 "close"s // Lua 5.4 78 "close"s // Lua 5.4
79}; 79};
80 80
81const std::string_view version = "0.32.9"sv; 81const std::string_view version = "0.33.0"sv;
82const std::string_view extension = "yue"sv; 82const std::string_view extension = "yue"sv;
83 83
84class CompileError : public std::logic_error { 84class CompileError : public std::logic_error {
@@ -1996,6 +1996,18 @@ private:
1996 } 1996 }
1997 } 1997 }
1998 1998
1999 str_list getAssignVars(ExpList_t* assignList) {
2000 str_list vars;
2001 bool lintGlobal = _config.lintGlobalVariable;
2002 _config.lintGlobalVariable = false;
2003 for (auto exp : assignList->exprs.objects()) {
2004 auto var = singleVariableFrom(exp, AccessType::None);
2005 vars.push_back(var.empty() ? Empty : var);
2006 }
2007 _config.lintGlobalVariable = lintGlobal;
2008 return vars;
2009 }
2010
1999 str_list getAssignVars(ExpListAssign_t* assignment) { 2011 str_list getAssignVars(ExpListAssign_t* assignment) {
2000 str_list vars; 2012 str_list vars;
2001 bool lintGlobal = _config.lintGlobalVariable; 2013 bool lintGlobal = _config.lintGlobalVariable;
@@ -2211,9 +2223,9 @@ private:
2211 if (exprs.size() < values.size()) { 2223 if (exprs.size() < values.size()) {
2212 auto num = exprs.size(); 2224 auto num = exprs.size();
2213 if (num > 1) { 2225 if (num > 1) {
2214 _buf << "no more than "sv << num << " right values expected, got "sv << values.size(); 2226 _buf << "expected no more than "sv << num << " right values, got "sv << values.size();
2215 } else { 2227 } else {
2216 _buf << "only one right value expected, got "sv << values.size(); 2228 _buf << "expected only one right value, got "sv << values.size();
2217 } 2229 }
2218 throw CompileError(clearBuf(), values.front()); 2230 throw CompileError(clearBuf(), values.front());
2219 } 2231 }
@@ -2234,6 +2246,9 @@ private:
2234 case id<Switch_t>(): 2246 case id<Switch_t>():
2235 case id<Do_t>(): 2247 case id<Do_t>():
2236 case id<Try_t>(): 2248 case id<Try_t>():
2249 case id<For_t>():
2250 case id<While_t>():
2251 case id<Repeat_t>():
2237 needHoldValues = true; 2252 needHoldValues = true;
2238 break; 2253 break;
2239 } 2254 }
@@ -2245,7 +2260,7 @@ private:
2245 } 2260 }
2246 } 2261 }
2247 if (!needHoldValues) { 2262 if (!needHoldValues) {
2248 _buf << exprs.size() << " right values expected, got "sv << values.size(); 2263 _buf << "expected "sv << exprs.size() << " right values, got "sv << values.size();
2249 throw CompileError(clearBuf(), values.front()); 2264 throw CompileError(clearBuf(), values.front());
2250 } 2265 }
2251 auto newAssign = assign->new_ptr<Assign_t>(); 2266 auto newAssign = assign->new_ptr<Assign_t>();
@@ -8911,7 +8926,7 @@ private:
8911 return (breakLoopType & int(BreakLoopType::Continue)) != 0; 8926 return (breakLoopType & int(BreakLoopType::Continue)) != 0;
8912 } 8927 }
8913 8928
8914 uint32_t getBreakLoopType(ast_node* body, const std::string& varBWV) { 8929 uint32_t getBreakLoopType(ast_node* body, bool allowBreakWithValues, str_list& breakWithValues) {
8915 uint32_t type = 0; 8930 uint32_t type = 0;
8916 body->traverse([&](ast_node* node) { 8931 body->traverse([&](ast_node* node) {
8917 if (auto stmt = ast_cast<Statement_t>(node)) { 8932 if (auto stmt = ast_cast<Statement_t>(node)) {
@@ -8920,12 +8935,25 @@ private:
8920 type |= int(BreakLoopType::Continue); 8935 type |= int(BreakLoopType::Continue);
8921 return traversal::Return; 8936 return traversal::Return;
8922 } else { 8937 } else {
8923 if (breakLoop->value) { 8938 if (breakLoop->valueList && breakLoop->vars.empty()) {
8924 if (varBWV.empty()) { 8939 if (!allowBreakWithValues) {
8925 throw CompileError("break with a value is not allowed here"sv, breakLoop->value); 8940 throw CompileError("break with values is not allowed here"sv, breakLoop->valueList->exprs.front());
8926 } 8941 }
8927 type |= int(BreakLoopType::BreakWithValue); 8942 type |= int(BreakLoopType::BreakWithValue);
8928 breakLoop->varBWV = varBWV; 8943 if (breakWithValues.empty()) {
8944 pushScope();
8945 for (size_t i = 0; i < breakLoop->valueList->exprs.size(); i++) {
8946 auto var = getUnusedName("_val_"sv);
8947 breakWithValues.push_back(var);
8948 addToScope(var);
8949 }
8950 popScope();
8951 } else {
8952 if (breakLoop->valueList->exprs.size() != breakWithValues.size()) {
8953 throw CompileError("expecting "s + std::to_string(breakWithValues.size()) + " break values, got "s + std::to_string(breakLoop->valueList->exprs.size()), breakLoop->valueList->exprs.front());
8954 }
8955 }
8956 breakLoop->vars = breakWithValues;
8929 } else { 8957 } else {
8930 type |= int(BreakLoopType::Break); 8958 type |= int(BreakLoopType::Break);
8931 } 8959 }
@@ -8940,28 +8968,28 @@ private:
8940 switch (sVal->get_id()) { 8968 switch (sVal->get_id()) {
8941 case id<With_t>(): { 8969 case id<With_t>(): {
8942 auto withNode = static_cast<With_t*>(sVal); 8970 auto withNode = static_cast<With_t*>(sVal);
8943 type |= getBreakLoopType(withNode->body, varBWV); 8971 type |= getBreakLoopType(withNode->body, allowBreakWithValues, breakWithValues);
8944 return traversal::Return; 8972 return traversal::Return;
8945 } 8973 }
8946 case id<Do_t>(): { 8974 case id<Do_t>(): {
8947 auto doNode = static_cast<Do_t*>(sVal); 8975 auto doNode = static_cast<Do_t*>(sVal);
8948 type |= getBreakLoopType(doNode->body, varBWV); 8976 type |= getBreakLoopType(doNode->body, allowBreakWithValues, breakWithValues);
8949 return traversal::Return; 8977 return traversal::Return;
8950 } 8978 }
8951 case id<If_t>(): { 8979 case id<If_t>(): {
8952 auto ifNode = static_cast<If_t*>(sVal); 8980 auto ifNode = static_cast<If_t*>(sVal);
8953 for (auto n : ifNode->nodes.objects()) { 8981 for (auto n : ifNode->nodes.objects()) {
8954 type |= getBreakLoopType(n, varBWV); 8982 type |= getBreakLoopType(n, allowBreakWithValues, breakWithValues);
8955 } 8983 }
8956 return traversal::Return; 8984 return traversal::Return;
8957 } 8985 }
8958 case id<Switch_t>(): { 8986 case id<Switch_t>(): {
8959 auto switchNode = static_cast<Switch_t*>(sVal); 8987 auto switchNode = static_cast<Switch_t*>(sVal);
8960 for (auto branch : switchNode->branches.objects()) { 8988 for (auto branch : switchNode->branches.objects()) {
8961 type |= getBreakLoopType(static_cast<SwitchCase_t*>(branch)->body, varBWV); 8989 type |= getBreakLoopType(static_cast<SwitchCase_t*>(branch)->body, allowBreakWithValues, breakWithValues);
8962 } 8990 }
8963 if (switchNode->lastBranch) { 8991 if (switchNode->lastBranch) {
8964 type |= getBreakLoopType(switchNode->lastBranch, varBWV); 8992 type |= getBreakLoopType(switchNode->lastBranch, allowBreakWithValues, breakWithValues);
8965 } 8993 }
8966 return traversal::Return; 8994 return traversal::Return;
8967 } 8995 }
@@ -8980,6 +9008,17 @@ private:
8980 return type; 9008 return type;
8981 } 9009 }
8982 9010
9011 uint32_t getBreakLoopTypeNoValues(ast_node* body) {
9012 str_list values;
9013 return getBreakLoopType(body, false, values);
9014 }
9015
9016 std::pair<uint32_t, str_list> getBreakLoopTypeAllowValues(ast_node* body) {
9017 str_list values;
9018 auto breakLoopType = getBreakLoopType(body, true, values);
9019 return {breakLoopType, std::move(values)};
9020 }
9021
8983 void addDoToLastLineReturn(ast_node* body) { 9022 void addDoToLastLineReturn(ast_node* body) {
8984 if (auto block = ast_cast<Block_t>(body); block && !block->statementOrComments.empty()) { 9023 if (auto block = ast_cast<Block_t>(body); block && !block->statementOrComments.empty()) {
8985 auto last = lastStatementFrom(block); 9024 auto last = lastStatementFrom(block);
@@ -9066,7 +9105,7 @@ private:
9066 str_list temp; 9105 str_list temp;
9067 bool extraDo = false; 9106 bool extraDo = false;
9068 auto body = repeatNode->body.get(); 9107 auto body = repeatNode->body.get();
9069 auto breakLoopType = getBreakLoopType(body, Empty); 9108 auto breakLoopType = getBreakLoopTypeNoValues(body);
9070 bool withContinue = hasContinue(breakLoopType); 9109 bool withContinue = hasContinue(breakLoopType);
9071 std::string conditionVar; 9110 std::string conditionVar;
9072 std::string extraLabel; 9111 std::string extraLabel;
@@ -9141,28 +9180,42 @@ private:
9141 void transformForNum(ForNum_t* forNum, str_list& out) { 9180 void transformForNum(ForNum_t* forNum, str_list& out) {
9142 str_list temp; 9181 str_list temp;
9143 transformForNumHead(forNum, temp); 9182 transformForNumHead(forNum, temp);
9144 auto breakLoopType = getBreakLoopType(forNum->body, Empty); 9183 auto breakLoopType = getBreakLoopTypeNoValues(forNum->body);
9145 transformLoopBody(forNum->body, temp, breakLoopType, ExpUsage::Common); 9184 transformLoopBody(forNum->body, temp, breakLoopType, ExpUsage::Common);
9146 popScope(); 9185 popScope();
9147 out.push_back(join(temp) + indent() + "end"s + nl(forNum)); 9186 out.push_back(join(temp) + indent() + "end"s + nl(forNum));
9148 } 9187 }
9149 9188
9150 std::string transformForNumInner(ForNum_t* forNum, str_list& out) { 9189 str_list transformForNumInner(ForNum_t* forNum, str_list& out, uint32_t breakLoopType, str_list&& vars) {
9151 auto x = forNum; 9190 auto x = forNum;
9152 std::string accum = getUnusedName("_accum_"sv); 9191 std::string accum;
9153 addToScope(accum); 9192 if (hasBreakWithValue(breakLoopType)) {
9154 std::string len = getUnusedName("_len_"sv); 9193 str_list vs;
9155 addToScope(len); 9194 for (const auto& var : vars) {
9156 auto breakLoopType = getBreakLoopType(forNum->body, accum); 9195 if (!isDefined(var)) {
9157 _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(forNum); 9196 addToScope(var);
9197 vs.push_back(var);
9198 }
9199 }
9200 if (!vs.empty()) {
9201 _buf << indent() << "local "sv << join(vs, ", "sv) << nl(forNum);
9202 }
9203 } else {
9204 accum = getUnusedName("_accum_"sv);
9205 addToScope(accum);
9206 vars = {accum};
9207 _buf << indent() << "local "sv << accum << " = { }"sv << nl(forNum);
9208 }
9158 out.emplace_back(clearBuf()); 9209 out.emplace_back(clearBuf());
9159 _buf << indent() << "local "sv << len << " = 1"sv << nl(forNum);
9160 auto& lenAssign = out.emplace_back(clearBuf());
9161 transformForNumHead(forNum, out);
9162 if (hasBreakWithValue(breakLoopType)) { 9210 if (hasBreakWithValue(breakLoopType)) {
9163 lenAssign.clear(); 9211 transformForNumHead(forNum, out);
9164 transformLoopBody(forNum->body, out, breakLoopType, ExpUsage::Common); 9212 transformLoopBody(forNum->body, out, breakLoopType, ExpUsage::Common);
9165 } else { 9213 } else {
9214 std::string len = getUnusedName("_len_"sv);
9215 addToScope(len);
9216 _buf << indent() << "local "sv << len << " = 1"sv << nl(forNum);
9217 auto& lenAssign = out.emplace_back(clearBuf());
9218 transformForNumHead(forNum, out);
9166 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); 9219 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x);
9167 auto followStmt = toAst<Statement_t>(len + "+=1"s, forNum->body); 9220 auto followStmt = toAst<Statement_t>(len + "+=1"s, forNum->body);
9168 expList->followStmt = followStmt.get(); 9221 expList->followStmt = followStmt.get();
@@ -9173,7 +9226,7 @@ private:
9173 } 9226 }
9174 popScope(); 9227 popScope();
9175 out.push_back(indent() + "end"s + nl(forNum)); 9228 out.push_back(indent() + "end"s + nl(forNum));
9176 return accum; 9229 return vars;
9177 } 9230 }
9178 9231
9179 void transformForNumClosure(ForNum_t* forNum, str_list& out) { 9232 void transformForNumClosure(ForNum_t* forNum, str_list& out) {
@@ -9189,8 +9242,10 @@ private:
9189 pushAnonVarArg(); 9242 pushAnonVarArg();
9190 std::string& funcStart = temp.emplace_back(); 9243 std::string& funcStart = temp.emplace_back();
9191 pushScope(); 9244 pushScope();
9192 auto accum = transformForNumInner(forNum, temp); 9245 str_list vars;
9193 temp.push_back(indent() + "return "s + accum + nl(forNum)); 9246 auto breakLoopType = getBreakLoopType(forNum->body, true, vars);
9247 vars = transformForNumInner(forNum, temp, breakLoopType, std::move(vars));
9248 temp.push_back(indent() + "return "s + join(vars, ", "sv) + nl(forNum));
9194 popScope(); 9249 popScope();
9195 funcStart = anonFuncStart() + nl(forNum); 9250 funcStart = anonFuncStart() + nl(forNum);
9196 temp.push_back(indent() + anonFuncEnd()); 9251 temp.push_back(indent() + anonFuncEnd());
@@ -9200,29 +9255,45 @@ private:
9200 } 9255 }
9201 9256
9202 void transformForNumInPlace(ForNum_t* forNum, str_list& out, ExpList_t* assignExpList) { 9257 void transformForNumInPlace(ForNum_t* forNum, str_list& out, ExpList_t* assignExpList) {
9203 auto x = forNum;
9204 str_list temp; 9258 str_list temp;
9205 bool isScoped = !currentScope().lastStatement;
9206 if (assignExpList) { 9259 if (assignExpList) {
9260 auto vars = getAssignVars(assignExpList);
9261 bool extraVar = false;
9262 for (const auto& var : vars) {
9263 if (var.empty()) {
9264 vars.clear();
9265 extraVar = true;
9266 break;
9267 }
9268 }
9269 auto breakLoopType = getBreakLoopType(forNum->body, true, vars);
9270 bool isScoped = true;
9271 if (currentScope().lastStatement) {
9272 isScoped = false;
9273 } else if (!extraVar && hasBreakWithValue(breakLoopType)) {
9274 isScoped = false;
9275 }
9207 if (isScoped) { 9276 if (isScoped) {
9208 _buf << indent() << "do"sv << nl(forNum); 9277 _buf << indent() << "do"sv << nl(forNum);
9209 pushScope(); 9278 pushScope();
9210 } 9279 }
9211 auto accum = transformForNumInner(forNum, temp); 9280 vars = transformForNumInner(forNum, temp, breakLoopType, std::move(vars));
9212 auto assign = x->new_ptr<Assign_t>(); 9281 if (extraVar || !hasBreakWithValue(breakLoopType)) {
9213 assign->values.push_back(toAst<Exp_t>(accum, x)); 9282 auto assign = toAst<Assign_t>('=' + join(vars, ","sv), assignExpList);
9214 auto assignment = x->new_ptr<ExpListAssign_t>(); 9283 auto assignment = assignExpList->new_ptr<ExpListAssign_t>();
9215 assignment->expList.set(assignExpList); 9284 assignment->expList.set(assignExpList);
9216 assignment->action.set(assign); 9285 assignment->action.set(assign);
9217 transformAssignment(assignment, temp); 9286 transformAssignment(assignment, temp);
9287 }
9218 if (isScoped) { 9288 if (isScoped) {
9219 popScope(); 9289 popScope();
9220 temp.push_back(indent() + "end"s + nl(forNum)); 9290 temp.push_back(indent() + "end"s + nl(forNum));
9221 } 9291 }
9222 } else { 9292 } else {
9223 auto accum = transformForNumInner(forNum, temp); 9293 str_list vars;
9224 auto returnNode = newReturn(toAst<Exp_t>(accum, forNum)); 9294 auto breakLoopType = getBreakLoopType(forNum->body, true, vars);
9225 transformReturn(returnNode, temp); 9295 vars = transformForNumInner(forNum, temp, breakLoopType, std::move(vars));
9296 temp.push_back(indent() + "return "s + join(vars, ", "sv) + nl(forNum));
9226 } 9297 }
9227 out.push_back(join(temp)); 9298 out.push_back(join(temp));
9228 } 9299 }
@@ -9248,7 +9319,7 @@ private:
9248 void transformForEach(ForEach_t* forEach, str_list& out) { 9319 void transformForEach(ForEach_t* forEach, str_list& out) {
9249 str_list temp; 9320 str_list temp;
9250 bool extraScoped = transformForEachHead(forEach->nameList, forEach->loopValue, temp, false); 9321 bool extraScoped = transformForEachHead(forEach->nameList, forEach->loopValue, temp, false);
9251 auto breakLoopType = getBreakLoopType(forEach->body, Empty); 9322 auto breakLoopType = getBreakLoopTypeNoValues(forEach->body);
9252 transformLoopBody(forEach->body, temp, breakLoopType, ExpUsage::Common); 9323 transformLoopBody(forEach->body, temp, breakLoopType, ExpUsage::Common);
9253 popScope(); 9324 popScope();
9254 out.push_back(temp.front() + temp.back() + indent() + "end"s + nl(forEach)); 9325 out.push_back(temp.front() + temp.back() + indent() + "end"s + nl(forEach));
@@ -9258,22 +9329,36 @@ private:
9258 } 9329 }
9259 } 9330 }
9260 9331
9261 std::string transformForEachInner(ForEach_t* forEach, str_list& out) { 9332 str_list transformForEachInner(ForEach_t* forEach, str_list& out, uint32_t breakLoopType, str_list&& vars) {
9262 auto x = forEach; 9333 auto x = forEach;
9263 std::string accum = getUnusedName("_accum_"sv); 9334 std::string accum;
9264 addToScope(accum); 9335 if (hasBreakWithValue(breakLoopType)) {
9265 std::string len = getUnusedName("_len_"sv); 9336 str_list vs;
9266 addToScope(len); 9337 for (const auto& var : vars) {
9267 auto breakLoopType = getBreakLoopType(forEach->body, accum); 9338 if (!isDefined(var)) {
9268 _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(forEach); 9339 addToScope(var);
9340 vs.push_back(var);
9341 }
9342 }
9343 if (!vs.empty()) {
9344 _buf << indent() << "local "sv << join(vs, ", "sv) << nl(forEach);
9345 }
9346 } else {
9347 accum = getUnusedName("_accum_"sv);
9348 addToScope(accum);
9349 vars = {accum};
9350 _buf << indent() << "local "sv << accum << " = { }"sv << nl(forEach);
9351 }
9269 out.emplace_back(clearBuf()); 9352 out.emplace_back(clearBuf());
9270 _buf << indent() << "local "sv << len << " = 1"sv << nl(forEach);
9271 auto& lenAssign = out.emplace_back(clearBuf());
9272 transformForEachHead(forEach->nameList, forEach->loopValue, out, true);
9273 if (hasBreakWithValue(breakLoopType)) { 9353 if (hasBreakWithValue(breakLoopType)) {
9274 lenAssign.clear(); 9354 transformForEachHead(forEach->nameList, forEach->loopValue, out, true);
9275 transformLoopBody(forEach->body, out, breakLoopType, ExpUsage::Common); 9355 transformLoopBody(forEach->body, out, breakLoopType, ExpUsage::Common);
9276 } else { 9356 } else {
9357 std::string len = getUnusedName("_len_"sv);
9358 addToScope(len);
9359 _buf << indent() << "local "sv << len << " = 1"sv << nl(forEach);
9360 auto& lenAssign = out.emplace_back(clearBuf());
9361 transformForEachHead(forEach->nameList, forEach->loopValue, out, true);
9277 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); 9362 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x);
9278 auto followStmt = toAst<Statement_t>(len + "+=1"s, forEach->body); 9363 auto followStmt = toAst<Statement_t>(len + "+=1"s, forEach->body);
9279 expList->followStmt = followStmt.get(); 9364 expList->followStmt = followStmt.get();
@@ -9284,7 +9369,7 @@ private:
9284 } 9369 }
9285 popScope(); 9370 popScope();
9286 out.push_back(indent() + "end"s + nl(forEach)); 9371 out.push_back(indent() + "end"s + nl(forEach));
9287 return accum; 9372 return vars;
9288 } 9373 }
9289 9374
9290 void transformForEachClosure(ForEach_t* forEach, str_list& out) { 9375 void transformForEachClosure(ForEach_t* forEach, str_list& out) {
@@ -9300,8 +9385,10 @@ private:
9300 pushAnonVarArg(); 9385 pushAnonVarArg();
9301 std::string& funcStart = temp.emplace_back(); 9386 std::string& funcStart = temp.emplace_back();
9302 pushScope(); 9387 pushScope();
9303 auto accum = transformForEachInner(forEach, temp); 9388 str_list vars;
9304 temp.push_back(indent() + "return "s + accum + nl(forEach)); 9389 auto breakLoopType = getBreakLoopType(forEach->body, true, vars);
9390 vars = transformForEachInner(forEach, temp, breakLoopType, std::move(vars));
9391 temp.push_back(indent() + "return "s + join(vars, ", "sv) + nl(forEach));
9305 popScope(); 9392 popScope();
9306 funcStart = anonFuncStart() + nl(forEach); 9393 funcStart = anonFuncStart() + nl(forEach);
9307 temp.push_back(indent() + anonFuncEnd()); 9394 temp.push_back(indent() + anonFuncEnd());
@@ -9311,29 +9398,45 @@ private:
9311 } 9398 }
9312 9399
9313 void transformForEachInPlace(ForEach_t* forEach, str_list& out, ExpList_t* assignExpList) { 9400 void transformForEachInPlace(ForEach_t* forEach, str_list& out, ExpList_t* assignExpList) {
9314 auto x = forEach;
9315 str_list temp; 9401 str_list temp;
9316 bool isScoped = !currentScope().lastStatement;
9317 if (assignExpList) { 9402 if (assignExpList) {
9403 auto vars = getAssignVars(assignExpList);
9404 bool extraVar = false;
9405 for (const auto& var : vars) {
9406 if (var.empty()) {
9407 vars.clear();
9408 extraVar = true;
9409 break;
9410 }
9411 }
9412 auto breakLoopType = getBreakLoopType(forEach->body, true, vars);
9413 bool isScoped = true;
9414 if (currentScope().lastStatement) {
9415 isScoped = false;
9416 } else if (!extraVar && hasBreakWithValue(breakLoopType)) {
9417 isScoped = false;
9418 }
9318 if (isScoped) { 9419 if (isScoped) {
9319 _buf << indent() << "do"sv << nl(forEach); 9420 _buf << indent() << "do"sv << nl(forEach);
9320 pushScope(); 9421 pushScope();
9321 } 9422 }
9322 auto accum = transformForEachInner(forEach, temp); 9423 vars = transformForEachInner(forEach, temp, breakLoopType, std::move(vars));
9323 auto assign = x->new_ptr<Assign_t>(); 9424 if (extraVar || !hasBreakWithValue(breakLoopType)) {
9324 assign->values.push_back(toAst<Exp_t>(accum, x)); 9425 auto assign = toAst<Assign_t>('=' + join(vars, ","sv), assignExpList);
9325 auto assignment = x->new_ptr<ExpListAssign_t>(); 9426 auto assignment = assignExpList->new_ptr<ExpListAssign_t>();
9326 assignment->expList.set(assignExpList); 9427 assignment->expList.set(assignExpList);
9327 assignment->action.set(assign); 9428 assignment->action.set(assign);
9328 transformAssignment(assignment, temp); 9429 transformAssignment(assignment, temp);
9430 }
9329 if (isScoped) { 9431 if (isScoped) {
9330 popScope(); 9432 popScope();
9331 temp.push_back(indent() + "end"s + nl(forEach)); 9433 temp.push_back(indent() + "end"s + nl(forEach));
9332 } 9434 }
9333 } else { 9435 } else {
9334 auto accum = transformForEachInner(forEach, temp); 9436 str_list vars;
9335 auto returnNode = newReturn(toAst<Exp_t>(accum, forEach)); 9437 auto breakLoopType = getBreakLoopType(forEach->body, true, vars);
9336 transformReturn(returnNode, temp); 9438 vars = transformForEachInner(forEach, temp, breakLoopType, std::move(vars));
9439 temp.push_back(indent() + "return "s + join(vars, ", "sv) + nl(forEach));
9337 } 9440 }
9338 out.push_back(join(temp)); 9441 out.push_back(join(temp));
9339 } 9442 }
@@ -10274,7 +10377,8 @@ private:
10274 breakWithVar = getUnusedName("_val_"sv); 10377 breakWithVar = getUnusedName("_val_"sv);
10275 extraBreakVar = true; 10378 extraBreakVar = true;
10276 } 10379 }
10277 auto breakLoopType = getBreakLoopType(with->body, breakWithVar); 10380 str_list vars{breakWithVar};
10381 auto breakLoopType = getBreakLoopType(with->body, true, vars);
10278 if (!hasBreakWithValue(breakLoopType)) { 10382 if (!hasBreakWithValue(breakLoopType)) {
10279 breakWithVar.clear(); 10383 breakWithVar.clear();
10280 } 10384 }
@@ -10308,6 +10412,10 @@ private:
10308 } else { 10412 } else {
10309 bool transformed = false; 10413 bool transformed = false;
10310 if (!breakWithVar.empty()) { 10414 if (!breakWithVar.empty()) {
10415 if (extraBreakVar) {
10416 addToScope(breakWithVar);
10417 temp.push_back(indent() + "local "s + breakWithVar + nl(with));
10418 }
10311 auto repeatNode = toAst<Repeat_t>("repeat\n\t--\nuntil true"s, x); 10419 auto repeatNode = toAst<Repeat_t>("repeat\n\t--\nuntil true"s, x);
10312 auto block = x->new_ptr<Block_t>(); 10420 auto block = x->new_ptr<Block_t>();
10313 if (auto blk = with->body.as<Block_t>()) { 10421 if (auto blk = with->body.as<Block_t>()) {
@@ -10317,10 +10425,7 @@ private:
10317 block->statementOrComments.push_back(stmt); 10425 block->statementOrComments.push_back(stmt);
10318 } 10426 }
10319 repeatNode->body.set(block); 10427 repeatNode->body.set(block);
10320 auto sVal = x->new_ptr<SimpleValue_t>(); 10428 transformRepeat(repeatNode, temp);
10321 sVal->value.set(repeatNode);
10322 auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x);
10323 transformAssignment(asmt, temp);
10324 transformed = true; 10429 transformed = true;
10325 } else if (!extraScope && assignList) { 10430 } else if (!extraScope && assignList) {
10326 if (auto block = with->body.as<Block_t>()) { 10431 if (auto block = with->body.as<Block_t>()) {
@@ -10784,7 +10889,57 @@ private:
10784 temp.push_back(indent() + "do"s + nl(doNode)); 10889 temp.push_back(indent() + "do"s + nl(doNode));
10785 pushScope(); 10890 pushScope();
10786 } 10891 }
10787 transformBody(doNode->body, temp, usage, assignList); 10892 str_list breakVars;
10893 bool extraVar = false;
10894 switch (usage) {
10895 case ExpUsage::Closure:
10896 case ExpUsage::Return: {
10897 uint32_t breakLoopType = 0;
10898 std::tie(breakLoopType, breakVars) = getBreakLoopTypeAllowValues(doNode->body);
10899 if (hasBreakWithValue(breakLoopType)) {
10900 for (const auto& var : breakVars) addToScope(var);
10901 temp.push_back(indent() + "local "s + join(breakVars, ", "sv) + nl(doNode));
10902 extraVar = true;
10903 }
10904 break;
10905 }
10906 case ExpUsage::Assignment: {
10907 auto vars = getAssignVars(assignList);
10908 for (const auto& var : vars) {
10909 if (var.empty()) {
10910 vars.clear();
10911 extraVar = true;
10912 break;
10913 }
10914 }
10915 auto breakLoopType = getBreakLoopType(doNode->body, true, vars);
10916 if (hasBreakWithValue(breakLoopType)) {
10917 breakVars = std::move(vars);
10918 }
10919 break;
10920 }
10921 case ExpUsage::Common: {
10922 getBreakLoopTypeNoValues(doNode->body);
10923 break;
10924 }
10925 }
10926 if (breakVars.empty()) {
10927 transformBody(doNode->body, temp, usage, assignList);
10928 } else {
10929 auto x = doNode;
10930 auto repeatNode = toAst<Repeat_t>("repeat\n\t--\nuntil true"s, x);
10931 repeatNode->body.set(doNode->body->content);
10932 transformRepeat(repeatNode, temp);
10933 if (assignList && extraVar) {
10934 auto assignment = x->new_ptr<ExpListAssign_t>();
10935 assignment->expList.set(assignList);
10936 auto assign = toAst<Assign_t>('=' + join(breakVars, ","sv), x);
10937 assignment->action.set(assign);
10938 transformAssignment(assignment, temp);
10939 } else if (usage == ExpUsage::Closure || usage == ExpUsage::Return) {
10940 temp.push_back(indent() + "return "s + join(breakVars, ", "sv) + nl(doNode));
10941 }
10942 }
10788 if (usage == ExpUsage::Closure) { 10943 if (usage == ExpUsage::Closure) {
10789 popScope(); 10944 popScope();
10790 *funcStart = anonFuncStart() + nl(doNode); 10945 *funcStart = anonFuncStart() + nl(doNode);
@@ -11438,13 +11593,20 @@ private:
11438 pushScope(); 11593 pushScope();
11439 } 11594 }
11440 } 11595 }
11441 auto accumVar = getUnusedName("_accum_"sv); 11596 std::string accumVar;
11442 addToScope(accumVar); 11597 auto [breakLoopType, vars] = getBreakLoopTypeAllowValues(whileNode->body);
11598 if (hasBreakWithValue(breakLoopType)) {
11599 for (const auto& var : vars) addToScope(var);
11600 _buf << indent() << "local "sv << join(vars, ", "sv) << nl(whileNode);
11601 } else {
11602 accumVar = getUnusedName("_accum_"sv);
11603 addToScope(accumVar);
11604 vars.push_back(accumVar);
11605 _buf << indent() << "local "sv << accumVar << " = { }"sv << nl(whileNode);
11606 }
11607 temp.emplace_back(clearBuf());
11443 auto lenVar = getUnusedName("_len_"sv); 11608 auto lenVar = getUnusedName("_len_"sv);
11444 addToScope(lenVar); 11609 addToScope(lenVar);
11445 auto breakLoopType = getBreakLoopType(whileNode->body, accumVar);
11446 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(whileNode);
11447 temp.emplace_back(clearBuf());
11448 _buf << indent() << "local "s << lenVar << " = 1"s << nl(whileNode); 11610 _buf << indent() << "local "s << lenVar << " = 1"s << nl(whileNode);
11449 auto& lenAssign = temp.emplace_back(clearBuf()); 11611 auto& lenAssign = temp.emplace_back(clearBuf());
11450 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 11612 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
@@ -11466,15 +11628,14 @@ private:
11466 popScope(); 11628 popScope();
11467 temp.push_back(indent() + "end"s + nl(whileNode)); 11629 temp.push_back(indent() + "end"s + nl(whileNode));
11468 if (expList) { 11630 if (expList) {
11469 auto assign = x->new_ptr<Assign_t>(); 11631 auto assign = toAst<Assign_t>('=' + join(vars, ","sv), expList);
11470 assign->values.push_back(toAst<Exp_t>(accumVar, x)); 11632 auto assignment = expList->new_ptr<ExpListAssign_t>();
11471 auto assignment = x->new_ptr<ExpListAssign_t>();
11472 assignment->expList.set(expList); 11633 assignment->expList.set(expList);
11473 assignment->action.set(assign); 11634 assignment->action.set(assign);
11474 transformAssignment(assignment, temp); 11635 transformAssignment(assignment, temp);
11475 if (extraScope) popScope(); 11636 if (extraScope) popScope();
11476 } else { 11637 } else {
11477 temp.push_back(indent() + "return "s + accumVar + nl(whileNode)); 11638 temp.push_back(indent() + "return "s + join(vars, ", "sv) + nl(whileNode));
11478 } 11639 }
11479 if (expList && extraScope) { 11640 if (expList && extraScope) {
11480 temp.push_back(indent() + "end"s + nl(whileNode)); 11641 temp.push_back(indent() + "end"s + nl(whileNode));
@@ -11494,13 +11655,20 @@ private:
11494 pushAnonVarArg(); 11655 pushAnonVarArg();
11495 std::string& funcStart = temp.emplace_back(); 11656 std::string& funcStart = temp.emplace_back();
11496 pushScope(); 11657 pushScope();
11497 auto accumVar = getUnusedName("_accum_"sv); 11658 std::string accumVar;
11498 addToScope(accumVar); 11659 auto [breakLoopType, vars] = getBreakLoopTypeAllowValues(whileNode->body);
11660 if (hasBreakWithValue(breakLoopType)) {
11661 for (const auto& var : vars) addToScope(var);
11662 _buf << indent() << "local "sv << join(vars, ", "sv) << nl(whileNode);
11663 } else {
11664 accumVar = getUnusedName("_accum_"sv);
11665 addToScope(accumVar);
11666 vars.push_back(accumVar);
11667 _buf << indent() << "local "sv << accumVar << " = { }"sv << nl(whileNode);
11668 }
11669 temp.emplace_back(clearBuf());
11499 auto lenVar = getUnusedName("_len_"sv); 11670 auto lenVar = getUnusedName("_len_"sv);
11500 addToScope(lenVar); 11671 addToScope(lenVar);
11501 auto breakLoopType = getBreakLoopType(whileNode->body, accumVar);
11502 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(whileNode);
11503 temp.emplace_back(clearBuf());
11504 auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nl(whileNode)); 11672 auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nl(whileNode));
11505 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 11673 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
11506 auto condStr = transformCondExp(whileNode->condition, isUntil); 11674 auto condStr = transformCondExp(whileNode->condition, isUntil);
@@ -11520,7 +11688,7 @@ private:
11520 } 11688 }
11521 popScope(); 11689 popScope();
11522 temp.push_back(indent() + "end"s + nl(whileNode)); 11690 temp.push_back(indent() + "end"s + nl(whileNode));
11523 temp.push_back(indent() + "return "s + accumVar + nl(whileNode)); 11691 temp.push_back(indent() + "return "s + join(vars, ", "sv) + nl(whileNode));
11524 popScope(); 11692 popScope();
11525 funcStart = anonFuncStart() + nl(whileNode); 11693 funcStart = anonFuncStart() + nl(whileNode);
11526 temp.push_back(indent() + anonFuncEnd()); 11694 temp.push_back(indent() + anonFuncEnd());
@@ -11560,7 +11728,7 @@ private:
11560 pushScope(); 11728 pushScope();
11561 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 11729 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
11562 auto condStr = transformCondExp(whileNode->condition, isUntil); 11730 auto condStr = transformCondExp(whileNode->condition, isUntil);
11563 auto breakLoopType = getBreakLoopType(whileNode->body, Empty); 11731 auto breakLoopType = getBreakLoopTypeNoValues(whileNode->body);
11564 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common); 11732 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common);
11565 popScope(); 11733 popScope();
11566 _buf << indent() << "while "sv << condStr << " do"sv << nl(whileNode); 11734 _buf << indent() << "while "sv << condStr << " do"sv << nl(whileNode);
@@ -11580,13 +11748,20 @@ private:
11580 pushScope(); 11748 pushScope();
11581 } 11749 }
11582 } 11750 }
11583 auto accumVar = getUnusedName("_accum_"sv); 11751 std::string accumVar;
11584 addToScope(accumVar); 11752 auto [breakLoopType, vars] = getBreakLoopTypeAllowValues(repeatNode->body);
11753 if (hasBreakWithValue(breakLoopType)) {
11754 for (const auto& var : vars) addToScope(var);
11755 _buf << indent() << "local "sv << join(vars, ", "sv) << nl(repeatNode);
11756 } else {
11757 accumVar = getUnusedName("_accum_"sv);
11758 addToScope(accumVar);
11759 vars.push_back(accumVar);
11760 _buf << indent() << "local "sv << accumVar << " = { }"sv << nl(repeatNode);
11761 }
11762 temp.emplace_back(clearBuf());
11585 auto lenVar = getUnusedName("_len_"sv); 11763 auto lenVar = getUnusedName("_len_"sv);
11586 addToScope(lenVar); 11764 addToScope(lenVar);
11587 auto breakLoopType = getBreakLoopType(repeatNode->body, accumVar);
11588 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(repeatNode);
11589 temp.emplace_back(clearBuf());
11590 _buf << indent() << "local "s << lenVar << " = 1"s << nl(repeatNode); 11765 _buf << indent() << "local "s << lenVar << " = 1"s << nl(repeatNode);
11591 auto& lenAssign = temp.emplace_back(clearBuf()); 11766 auto& lenAssign = temp.emplace_back(clearBuf());
11592 auto condStr = transformCondExp(repeatNode->condition, false); 11767 auto condStr = transformCondExp(repeatNode->condition, false);
@@ -11607,15 +11782,14 @@ private:
11607 popScope(); 11782 popScope();
11608 temp.push_back(indent() + "until "s + condStr + nl(repeatNode)); 11783 temp.push_back(indent() + "until "s + condStr + nl(repeatNode));
11609 if (expList) { 11784 if (expList) {
11610 auto assign = x->new_ptr<Assign_t>(); 11785 auto assign = toAst<Assign_t>('=' + join(vars, ","sv), expList);
11611 assign->values.push_back(toAst<Exp_t>(accumVar, x)); 11786 auto assignment = expList->new_ptr<ExpListAssign_t>();
11612 auto assignment = x->new_ptr<ExpListAssign_t>();
11613 assignment->expList.set(expList); 11787 assignment->expList.set(expList);
11614 assignment->action.set(assign); 11788 assignment->action.set(assign);
11615 transformAssignment(assignment, temp); 11789 transformAssignment(assignment, temp);
11616 if (extraScope) popScope(); 11790 if (extraScope) popScope();
11617 } else { 11791 } else {
11618 temp.push_back(indent() + "return "s + accumVar + nl(repeatNode)); 11792 temp.push_back(indent() + "return "s + join(vars, ", "sv) + nl(repeatNode));
11619 } 11793 }
11620 if (expList && extraScope) { 11794 if (expList && extraScope) {
11621 temp.push_back(indent() + "end"s + nl(repeatNode)); 11795 temp.push_back(indent() + "end"s + nl(repeatNode));
@@ -11635,13 +11809,20 @@ private:
11635 pushAnonVarArg(); 11809 pushAnonVarArg();
11636 std::string& funcStart = temp.emplace_back(); 11810 std::string& funcStart = temp.emplace_back();
11637 pushScope(); 11811 pushScope();
11638 auto accumVar = getUnusedName("_accum_"sv); 11812 std::string accumVar;
11639 addToScope(accumVar); 11813 auto [breakLoopType, vars] = getBreakLoopTypeAllowValues(repeatNode->body);
11814 if (hasBreakWithValue(breakLoopType)) {
11815 for (const auto& var : vars) addToScope(var);
11816 _buf << indent() << "local "sv << join(vars, ", "sv) << nl(repeatNode);
11817 } else {
11818 accumVar = getUnusedName("_accum_"sv);
11819 addToScope(accumVar);
11820 vars.push_back(accumVar);
11821 _buf << indent() << "local "sv << accumVar << " = { }"sv << nl(repeatNode);
11822 }
11823 temp.emplace_back(clearBuf());
11640 auto lenVar = getUnusedName("_len_"sv); 11824 auto lenVar = getUnusedName("_len_"sv);
11641 addToScope(lenVar); 11825 addToScope(lenVar);
11642 auto breakLoopType = getBreakLoopType(repeatNode->body, accumVar);
11643 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(repeatNode);
11644 temp.emplace_back(clearBuf());
11645 auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nl(repeatNode)); 11826 auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nl(repeatNode));
11646 auto condStr = transformCondExp(repeatNode->condition, false); 11827 auto condStr = transformCondExp(repeatNode->condition, false);
11647 temp.push_back(indent() + "repeat"s + nl(repeatNode)); 11828 temp.push_back(indent() + "repeat"s + nl(repeatNode));
@@ -11660,7 +11841,7 @@ private:
11660 } 11841 }
11661 popScope(); 11842 popScope();
11662 temp.push_back(indent() + "until "s + condStr + nl(repeatNode)); 11843 temp.push_back(indent() + "until "s + condStr + nl(repeatNode));
11663 temp.push_back(indent() + "return "s + accumVar + nl(repeatNode)); 11844 temp.push_back(indent() + "return "s + join(vars, ", "sv) + nl(repeatNode));
11664 popScope(); 11845 popScope();
11665 funcStart = anonFuncStart() + nl(repeatNode); 11846 funcStart = anonFuncStart() + nl(repeatNode);
11666 temp.push_back(indent() + anonFuncEnd()); 11847 temp.push_back(indent() + anonFuncEnd());
@@ -11975,9 +12156,9 @@ private:
11975 if (x->leftList.size() < x->assign->values.size()) { 12156 if (x->leftList.size() < x->assign->values.size()) {
11976 auto num = x->leftList.size(); 12157 auto num = x->leftList.size();
11977 if (num > 1) { 12158 if (num > 1) {
11978 _buf << "no more than "sv << num << " right values expected, got "sv << x->assign->values.size(); 12159 _buf << "expected no more than "sv << num << " right values, got "sv << x->assign->values.size();
11979 } else { 12160 } else {
11980 _buf << "only one right value expected, got "sv << x->assign->values.size(); 12161 _buf << "expected only one right value, got "sv << x->assign->values.size();
11981 } 12162 }
11982 throw CompileError(clearBuf(), x->assign->values.front()); 12163 throw CompileError(clearBuf(), x->assign->values.front());
11983 } 12164 }
@@ -12044,7 +12225,7 @@ private:
12044 auto value = singleValueFrom(assignA->values.back()); 12225 auto value = singleValueFrom(assignA->values.back());
12045 if (!value) { 12226 if (!value) {
12046 if (listA->names.size() > assignA->values.size()) { 12227 if (listA->names.size() > assignA->values.size()) {
12047 _buf << listA->names.size() << " right values expected, got "sv << assignA->values.size(); 12228 _buf << "expected "sv << listA->names.size() << " right values, got "sv << assignA->values.size();
12048 throw CompileError(clearBuf(), assignA->values.front()); 12229 throw CompileError(clearBuf(), assignA->values.front());
12049 } else { 12230 } else {
12050 break; 12231 break;
@@ -12067,7 +12248,7 @@ private:
12067 if (listA->names.size() > assignA->values.size()) { 12248 if (listA->names.size() > assignA->values.size()) {
12068 auto chainValue = value->item.as<ChainValue_t>(); 12249 auto chainValue = value->item.as<ChainValue_t>();
12069 if (!chainValue || !ast_is<Invoke_t, InvokeArgs_t>(chainValue->items.back())) { 12250 if (!chainValue || !ast_is<Invoke_t, InvokeArgs_t>(chainValue->items.back())) {
12070 _buf << listA->names.size() << " right values expected, got "sv << assignA->values.size(); 12251 _buf << "expected "sv << listA->names.size() << " right values, got "sv << assignA->values.size();
12071 throw CompileError(clearBuf(), assignA->values.front()); 12252 throw CompileError(clearBuf(), assignA->values.front());
12072 } 12253 }
12073 } 12254 }
@@ -12223,9 +12404,13 @@ private:
12223 throw CompileError(keyword + " is not inside a loop"s, breakLoop); 12404 throw CompileError(keyword + " is not inside a loop"s, breakLoop);
12224 } 12405 }
12225 if (isBreak) { 12406 if (isBreak) {
12226 if (breakLoop->value) { 12407 if (breakLoop->valueList) {
12227 auto exp = toAst<Exp_t>(breakLoop->varBWV, breakLoop->value); 12408 auto expList = toAst<ExpList_t>(join(breakLoop->vars, ","sv), breakLoop);
12228 auto assignment = assignmentFrom(exp, breakLoop->value, breakLoop); 12409 auto assignment = breakLoop->new_ptr<ExpListAssign_t>();
12410 assignment->expList.set(expList);
12411 auto assign = breakLoop->new_ptr<Assign_t>();
12412 assign->values.dup(breakLoop->valueList->exprs);
12413 assignment->action.set(assign);
12229 transformAssignment(assignment, out); 12414 transformAssignment(assignment, out);
12230 } 12415 }
12231 out.push_back(indent() + keyword + nl(breakLoop)); 12416 out.push_back(indent() + keyword + nl(breakLoop));
@@ -12293,7 +12478,7 @@ private:
12293 auto x = chainAssign; 12478 auto x = chainAssign;
12294 auto value = chainAssign->assign->values.front(); 12479 auto value = chainAssign->assign->values.front();
12295 if (chainAssign->assign->values.size() != 1) { 12480 if (chainAssign->assign->values.size() != 1) {
12296 throw CompileError("only one right value expected"sv, value); 12481 throw CompileError("expected only one right value"sv, value);
12297 } 12482 }
12298 str_list temp; 12483 str_list temp;
12299 bool constVal = false; 12484 bool constVal = false;
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp
index 3d8e315..b52a452 100644
--- a/src/yuescript/yue_parser.cpp
+++ b/src/yuescript/yue_parser.cpp
@@ -476,7 +476,7 @@ YueParser::YueParser() {
476 476
477 Break = key("break"); 477 Break = key("break");
478 Continue = key("continue"); 478 Continue = key("continue");
479 BreakLoop = (Break >> -(space >> Exp) | Continue) >> not_alpha_num; 479 BreakLoop = (Break >> -(space >> ExpList) | Continue) >> not_alpha_num;
480 480
481 Return = key("return") >> -(space >> (TableBlock | ExpList)); 481 Return = key("return") >> -(space >> (TableBlock | ExpList));
482 482