diff options
| author | Li Jin <dragon-fly@qq.com> | 2025-05-21 11:44:54 +0800 |
|---|---|---|
| committer | Li Jin <dragon-fly@qq.com> | 2025-05-21 11:44:54 +0800 |
| commit | 0603800a4114ed8b4c9572a7d7852995c9b9f334 (patch) | |
| tree | 456524685562bcd0d874530e3ddc2a0fc0731525 | |
| parent | ff137ac73d999a5849f02706cfd52f4659b025ef (diff) | |
| download | yuescript-0603800a4114ed8b4c9572a7d7852995c9b9f334.tar.gz yuescript-0603800a4114ed8b4c9572a7d7852995c9b9f334.tar.bz2 yuescript-0603800a4114ed8b4c9572a7d7852995c9b9f334.zip | |
Added break with value syntax.
| -rwxr-xr-x | doc/docs/doc/README.md | 27 | ||||
| -rwxr-xr-x | doc/docs/zh/doc/README.md | 27 | ||||
| -rw-r--r-- | spec/inputs/loops.yue | 39 | ||||
| -rw-r--r-- | spec/outputs/5.1/loops.lua | 104 | ||||
| -rw-r--r-- | spec/outputs/codes_from_doc.lua | 60 | ||||
| -rw-r--r-- | spec/outputs/codes_from_doc_zh.lua | 60 | ||||
| -rw-r--r-- | spec/outputs/loops.lua | 104 | ||||
| -rw-r--r-- | spec/outputs/macro.lua | 2 | ||||
| -rw-r--r-- | spec/outputs/unicode/loops.lua | 4 | ||||
| -rw-r--r-- | spec/outputs/unicode/macro.lua | 2 | ||||
| -rw-r--r-- | src/yuescript/yue_ast.cpp | 12 | ||||
| -rw-r--r-- | src/yuescript/yue_ast.h | 14 | ||||
| -rw-r--r-- | src/yuescript/yue_compiler.cpp | 183 | ||||
| -rw-r--r-- | src/yuescript/yue_parser.cpp | 4 | ||||
| -rw-r--r-- | src/yuescript/yue_parser.h | 2 |
15 files changed, 561 insertions, 83 deletions
diff --git a/doc/docs/doc/README.md b/doc/docs/doc/README.md index c275c52..dac96ee 100755 --- a/doc/docs/doc/README.md +++ b/doc/docs/doc/README.md | |||
| @@ -29,6 +29,16 @@ inventory = | |||
| 29 | * name: "bread" | 29 | * name: "bread" |
| 30 | count: 3 | 30 | count: 3 |
| 31 | 31 | ||
| 32 | -- list comprehension | ||
| 33 | map = (arr, action) -> | ||
| 34 | [action item for item in *arr] | ||
| 35 | |||
| 36 | filter = (arr, cond) -> | ||
| 37 | [item for item in *arr when cond item] | ||
| 38 | |||
| 39 | reduce = (arr, init, action): init -> | ||
| 40 | init = action init, item for item in *arr | ||
| 41 | |||
| 32 | -- pipe operator | 42 | -- pipe operator |
| 33 | [1, 2, 3] | 43 | [1, 2, 3] |
| 34 | |> map (x) -> x * 2 | 44 | |> map (x) -> x * 2 |
| @@ -2324,6 +2334,23 @@ doubled_evens = for i = 1, 20 | |||
| 2324 | </pre> | 2334 | </pre> |
| 2325 | </YueDisplay> | 2335 | </YueDisplay> |
| 2326 | 2336 | ||
| 2337 | In addition, for loops support break with a return value, allowing the loop itself to be used as an expression that exits early with a meaningful result. | ||
| 2338 | |||
| 2339 | For example, to find the first number greater than 10: | ||
| 2340 | |||
| 2341 | ```moonscript | ||
| 2342 | first_large = for n in *numbers | ||
| 2343 | break n if n > 10 | ||
| 2344 | ``` | ||
| 2345 | <YueDisplay> | ||
| 2346 | <pre> | ||
| 2347 | first_large = for n in *numbers | ||
| 2348 | break n if n > 10 | ||
| 2349 | </pre> | ||
| 2350 | </YueDisplay> | ||
| 2351 | |||
| 2352 | This break-with-value syntax enables concise and expressive search or early-exit patterns directly within loop expressions. | ||
| 2353 | |||
| 2327 | You can also filter values by combining the for loop expression with the continue statement. | 2354 | You can also filter values by combining the for loop expression with the continue statement. |
| 2328 | 2355 | ||
| 2329 | For loops at the end of a function body are not accumulated into a table for a return value (Instead the function will return nil). Either an explicit return statement can be used, or the loop can be converted into a list comprehension. | 2356 | For loops at the end of a function body are not accumulated into a table for a return value (Instead the function will return nil). Either an explicit return statement can be used, or the loop can be converted into a list comprehension. |
diff --git a/doc/docs/zh/doc/README.md b/doc/docs/zh/doc/README.md index 11dc108..850afed 100755 --- a/doc/docs/zh/doc/README.md +++ b/doc/docs/zh/doc/README.md | |||
| @@ -29,6 +29,16 @@ inventory = | |||
| 29 | * name: "bread" | 29 | * name: "bread" |
| 30 | count: 3 | 30 | count: 3 |
| 31 | 31 | ||
| 32 | -- 列表推导 | ||
| 33 | map = (arr, action) -> | ||
| 34 | [action item for item in *arr] | ||
| 35 | |||
| 36 | filter = (arr, cond) -> | ||
| 37 | [item for item in *arr when cond item] | ||
| 38 | |||
| 39 | reduce = (arr, init, action): init -> | ||
| 40 | init = action init, item for item in *arr | ||
| 41 | |||
| 32 | -- 管道操作符 | 42 | -- 管道操作符 |
| 33 | [1, 2, 3] | 43 | [1, 2, 3] |
| 34 | |> map (x) -> x * 2 | 44 | |> map (x) -> x * 2 |
| @@ -2286,9 +2296,24 @@ doubled_evens = for i = 1, 20 | |||
| 2286 | </pre> | 2296 | </pre> |
| 2287 | </YueDisplay> | 2297 | </YueDisplay> |
| 2288 | 2298 | ||
| 2299 | 此外,for循环还支持带返回值的break语句,这样循环本身就可以作为一个表达式,在满足条件时提前退出并返回有意义的结果。 | ||
| 2300 | |||
| 2301 | 例如,查找第一个大于10的数字: | ||
| 2302 | |||
| 2303 | ```moonscript | ||
| 2304 | first_large = for n in *numbers | ||
| 2305 | break n if n > 10 | ||
| 2306 | ``` | ||
| 2307 | <YueDisplay> | ||
| 2308 | <pre> | ||
| 2309 | first_large = for n in *numbers | ||
| 2310 | break n if n > 10 | ||
| 2311 | </pre> | ||
| 2312 | </YueDisplay> | ||
| 2313 | |||
| 2289 | 你还可以结合for循环表达式与continue语句来过滤值。 | 2314 | 你还可以结合for循环表达式与continue语句来过滤值。 |
| 2290 | 2315 | ||
| 2291 | 注意出现在函数体末尾的for循环,不会被当作是一个表达式,并将循环结果累积到一个列表中作为返回值(相反,函数将返回nil)。如果要函数末尾的循环转换为列表表达式,可以使用返回语句加for循环表达式。 | 2316 | 注意出现在函数体末尾的for循环,不会被当作是一个表达式并将循环结果累积到一个列表中作为返回值(相反,函数将返回nil)。如果要函数末尾的循环转换为列表表达式,可以显式地使用返回语句加for循环表达式。 |
| 2292 | 2317 | ||
| 2293 | ```moonscript | 2318 | ```moonscript |
| 2294 | func_a = -> for i = 1, 10 do print i | 2319 | func_a = -> for i = 1, 10 do print i |
diff --git a/spec/inputs/loops.yue b/spec/inputs/loops.yue index c5b28b3..9a91b42 100644 --- a/spec/inputs/loops.yue +++ b/spec/inputs/loops.yue | |||
| @@ -213,3 +213,42 @@ do | |||
| 213 | do | 213 | do |
| 214 | until x := func 'a', b do | 214 | until x := func 'a', b do |
| 215 | print "false expected" | 215 | print "false expected" |
| 216 | |||
| 217 | do | ||
| 218 | index = for i = 1, #tb | ||
| 219 | break i if tb[i] | ||
| 220 | |||
| 221 | f for i = 1, #tb | ||
| 222 | break i if tb[i] | ||
| 223 | |||
| 224 | f for i = 1, #tb | ||
| 225 | i if tb[i] | ||
| 226 | |||
| 227 | i = 1 | ||
| 228 | ids = while tb[i] | ||
| 229 | i += 1 | ||
| 230 | i - 1 | ||
| 231 | |||
| 232 | i = 1 | ||
| 233 | idx = while tb[i] | ||
| 234 | i += 1 | ||
| 235 | break i - 1 | ||
| 236 | |||
| 237 | f1 = -> | ||
| 238 | i = 1 | ||
| 239 | f while tb[i] | ||
| 240 | i += 1 | ||
| 241 | i - 1 | ||
| 242 | |||
| 243 | i = 1 | ||
| 244 | f while tb[i] | ||
| 245 | i += 1 | ||
| 246 | break i - 1 | ||
| 247 | |||
| 248 | list = for item in *items | ||
| 249 | switch item | ||
| 250 | when type: "A", :value | ||
| 251 | if value > 5 | ||
| 252 | item | ||
| 253 | |||
| 254 | |||
diff --git a/spec/outputs/5.1/loops.lua b/spec/outputs/5.1/loops.lua index 57b19be..bc720f6 100644 --- a/spec/outputs/5.1/loops.lua +++ b/spec/outputs/5.1/loops.lua | |||
| @@ -60,8 +60,8 @@ do | |||
| 60 | local y = hello[_index_0] | 60 | local y = hello[_index_0] |
| 61 | if y % 2 == 0 then | 61 | if y % 2 == 0 then |
| 62 | _accum_0[_len_0] = y | 62 | _accum_0[_len_0] = y |
| 63 | _len_0 = _len_0 + 1 | ||
| 63 | end | 64 | end |
| 64 | _len_0 = _len_0 + 1 | ||
| 65 | end | 65 | end |
| 66 | x = _accum_0 | 66 | x = _accum_0 |
| 67 | end | 67 | end |
| @@ -132,13 +132,11 @@ do | |||
| 132 | end | 132 | end |
| 133 | do | 133 | do |
| 134 | local _accum_0 = { } | 134 | local _accum_0 = { } |
| 135 | local _len_0 = 1 | ||
| 136 | local _list_2 = 3 | 135 | local _list_2 = 3 |
| 137 | for _index_0 = 1, #_list_2 do | 136 | for _index_0 = 1, #_list_2 do |
| 138 | local thing = _list_2[_index_0] | 137 | local thing = _list_2[_index_0] |
| 139 | y = "hello" | 138 | y = "hello" |
| 140 | break | 139 | break |
| 141 | _len_0 = _len_0 + 1 | ||
| 142 | end | 140 | end |
| 143 | x = _accum_0 | 141 | x = _accum_0 |
| 144 | end | 142 | end |
| @@ -489,3 +487,103 @@ do | |||
| 489 | end | 487 | end |
| 490 | until false | 488 | until false |
| 491 | end | 489 | end |
| 490 | local _anon_func_0 = function(i, tb) | ||
| 491 | local _accum_0 = { } | ||
| 492 | local _len_0 = 1 | ||
| 493 | while tb[i] do | ||
| 494 | i = i + 1 | ||
| 495 | _accum_0[_len_0] = i - 1 | ||
| 496 | _len_0 = _len_0 + 1 | ||
| 497 | end | ||
| 498 | return _accum_0 | ||
| 499 | end | ||
| 500 | do | ||
| 501 | local index | ||
| 502 | do | ||
| 503 | local _accum_0 | ||
| 504 | for i = 1, #tb do | ||
| 505 | if tb[i] then | ||
| 506 | _accum_0 = i | ||
| 507 | break | ||
| 508 | end | ||
| 509 | end | ||
| 510 | index = _accum_0 | ||
| 511 | end | ||
| 512 | f((function() | ||
| 513 | local _accum_0 | ||
| 514 | for i = 1, #tb do | ||
| 515 | if tb[i] then | ||
| 516 | _accum_0 = i | ||
| 517 | break | ||
| 518 | end | ||
| 519 | end | ||
| 520 | return _accum_0 | ||
| 521 | end)()) | ||
| 522 | f((function() | ||
| 523 | local _accum_0 = { } | ||
| 524 | local _len_0 = 1 | ||
| 525 | for i = 1, #tb do | ||
| 526 | if tb[i] then | ||
| 527 | _accum_0[_len_0] = i | ||
| 528 | _len_0 = _len_0 + 1 | ||
| 529 | end | ||
| 530 | end | ||
| 531 | return _accum_0 | ||
| 532 | end)()) | ||
| 533 | i = 1 | ||
| 534 | local ids | ||
| 535 | do | ||
| 536 | local _accum_0 = { } | ||
| 537 | local _len_0 = 1 | ||
| 538 | while tb[i] do | ||
| 539 | i = i + 1 | ||
| 540 | _accum_0[_len_0] = i - 1 | ||
| 541 | _len_0 = _len_0 + 1 | ||
| 542 | end | ||
| 543 | ids = _accum_0 | ||
| 544 | end | ||
| 545 | i = 1 | ||
| 546 | local idx | ||
| 547 | do | ||
| 548 | local _accum_0 | ||
| 549 | while tb[i] do | ||
| 550 | i = i + 1 | ||
| 551 | _accum_0 = i - 1 | ||
| 552 | break | ||
| 553 | end | ||
| 554 | idx = _accum_0 | ||
| 555 | end | ||
| 556 | local f1 | ||
| 557 | f1 = function() | ||
| 558 | i = 1 | ||
| 559 | return f(_anon_func_0(i, tb)) | ||
| 560 | end | ||
| 561 | i = 1 | ||
| 562 | f((function() | ||
| 563 | local _accum_0 | ||
| 564 | while tb[i] do | ||
| 565 | i = i + 1 | ||
| 566 | _accum_0 = i - 1 | ||
| 567 | break | ||
| 568 | end | ||
| 569 | return _accum_0 | ||
| 570 | end)()) | ||
| 571 | local _accum_0 = { } | ||
| 572 | local _len_0 = 1 | ||
| 573 | local _list_3 = items | ||
| 574 | for _index_0 = 1, #_list_3 do | ||
| 575 | local item = _list_3[_index_0] | ||
| 576 | local _type_0 = type(item) | ||
| 577 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
| 578 | if _tab_0 then | ||
| 579 | local value = item.value | ||
| 580 | if "A" == item.type and value ~= nil then | ||
| 581 | if value > 5 then | ||
| 582 | _accum_0[_len_0] = item | ||
| 583 | _len_0 = _len_0 + 1 | ||
| 584 | end | ||
| 585 | end | ||
| 586 | end | ||
| 587 | end | ||
| 588 | list = _accum_0 | ||
| 589 | end | ||
diff --git a/spec/outputs/codes_from_doc.lua b/spec/outputs/codes_from_doc.lua index a5412ab..644b7c3 100644 --- a/spec/outputs/codes_from_doc.lua +++ b/spec/outputs/codes_from_doc.lua | |||
| @@ -20,6 +20,38 @@ local inventory = { | |||
| 20 | } | 20 | } |
| 21 | } | 21 | } |
| 22 | } | 22 | } |
| 23 | local map | ||
| 24 | map = function(arr, action) | ||
| 25 | local _accum_0 = { } | ||
| 26 | local _len_0 = 1 | ||
| 27 | for _index_0 = 1, #arr do | ||
| 28 | local item = arr[_index_0] | ||
| 29 | _accum_0[_len_0] = action(item) | ||
| 30 | _len_0 = _len_0 + 1 | ||
| 31 | end | ||
| 32 | return _accum_0 | ||
| 33 | end | ||
| 34 | local filter | ||
| 35 | filter = function(arr, cond) | ||
| 36 | local _accum_0 = { } | ||
| 37 | local _len_0 = 1 | ||
| 38 | for _index_0 = 1, #arr do | ||
| 39 | local item = arr[_index_0] | ||
| 40 | if cond(item) then | ||
| 41 | _accum_0[_len_0] = item | ||
| 42 | _len_0 = _len_0 + 1 | ||
| 43 | end | ||
| 44 | end | ||
| 45 | return _accum_0 | ||
| 46 | end | ||
| 47 | local reduce | ||
| 48 | reduce = function(arr, init, action) | ||
| 49 | for _index_0 = 1, #arr do | ||
| 50 | local item = arr[_index_0] | ||
| 51 | init = action(init, item) | ||
| 52 | end | ||
| 53 | return init | ||
| 54 | end | ||
| 23 | print(reduce(filter(map({ | 55 | print(reduce(filter(map({ |
| 24 | 1, | 56 | 1, |
| 25 | 2, | 57 | 2, |
| @@ -1026,12 +1058,24 @@ local _len_0 = 1 | |||
| 1026 | for i = 1, 20 do | 1058 | for i = 1, 20 do |
| 1027 | if i % 2 == 0 then | 1059 | if i % 2 == 0 then |
| 1028 | _accum_0[_len_0] = i * 2 | 1060 | _accum_0[_len_0] = i * 2 |
| 1061 | _len_0 = _len_0 + 1 | ||
| 1029 | else | 1062 | else |
| 1030 | _accum_0[_len_0] = i | 1063 | _accum_0[_len_0] = i |
| 1064 | _len_0 = _len_0 + 1 | ||
| 1031 | end | 1065 | end |
| 1032 | _len_0 = _len_0 + 1 | ||
| 1033 | end | 1066 | end |
| 1034 | doubled_evens = _accum_0 | 1067 | doubled_evens = _accum_0 |
| 1068 | local first_large | ||
| 1069 | local _accum_0 | ||
| 1070 | local _list_0 = numbers | ||
| 1071 | for _index_0 = 1, #_list_0 do | ||
| 1072 | local n = _list_0[_index_0] | ||
| 1073 | if n > 10 then | ||
| 1074 | _accum_0 = n | ||
| 1075 | break | ||
| 1076 | end | ||
| 1077 | end | ||
| 1078 | first_large = _accum_0 | ||
| 1035 | local func_a | 1079 | local func_a |
| 1036 | func_a = function() | 1080 | func_a = function() |
| 1037 | for i = 1, 10 do | 1081 | for i = 1, 10 do |
| @@ -3189,12 +3233,24 @@ local _len_0 = 1 | |||
| 3189 | for i = 1, 20 do | 3233 | for i = 1, 20 do |
| 3190 | if i % 2 == 0 then | 3234 | if i % 2 == 0 then |
| 3191 | _accum_0[_len_0] = i * 2 | 3235 | _accum_0[_len_0] = i * 2 |
| 3236 | _len_0 = _len_0 + 1 | ||
| 3192 | else | 3237 | else |
| 3193 | _accum_0[_len_0] = i | 3238 | _accum_0[_len_0] = i |
| 3239 | _len_0 = _len_0 + 1 | ||
| 3194 | end | 3240 | end |
| 3195 | _len_0 = _len_0 + 1 | ||
| 3196 | end | 3241 | end |
| 3197 | doubled_evens = _accum_0 | 3242 | doubled_evens = _accum_0 |
| 3243 | local first_large | ||
| 3244 | local _accum_0 | ||
| 3245 | local _list_0 = numbers | ||
| 3246 | for _index_0 = 1, #_list_0 do | ||
| 3247 | local n = _list_0[_index_0] | ||
| 3248 | if n > 10 then | ||
| 3249 | _accum_0 = n | ||
| 3250 | break | ||
| 3251 | end | ||
| 3252 | end | ||
| 3253 | first_large = _accum_0 | ||
| 3198 | local func_a | 3254 | local func_a |
| 3199 | func_a = function() | 3255 | func_a = function() |
| 3200 | for i = 1, 10 do | 3256 | for i = 1, 10 do |
diff --git a/spec/outputs/codes_from_doc_zh.lua b/spec/outputs/codes_from_doc_zh.lua index d9cc4dc..2457c52 100644 --- a/spec/outputs/codes_from_doc_zh.lua +++ b/spec/outputs/codes_from_doc_zh.lua | |||
| @@ -20,6 +20,38 @@ local inventory = { | |||
| 20 | } | 20 | } |
| 21 | } | 21 | } |
| 22 | } | 22 | } |
| 23 | local map | ||
| 24 | map = function(arr, action) | ||
| 25 | local _accum_0 = { } | ||
| 26 | local _len_0 = 1 | ||
| 27 | for _index_0 = 1, #arr do | ||
| 28 | local item = arr[_index_0] | ||
| 29 | _accum_0[_len_0] = action(item) | ||
| 30 | _len_0 = _len_0 + 1 | ||
| 31 | end | ||
| 32 | return _accum_0 | ||
| 33 | end | ||
| 34 | local filter | ||
| 35 | filter = function(arr, cond) | ||
| 36 | local _accum_0 = { } | ||
| 37 | local _len_0 = 1 | ||
| 38 | for _index_0 = 1, #arr do | ||
| 39 | local item = arr[_index_0] | ||
| 40 | if cond(item) then | ||
| 41 | _accum_0[_len_0] = item | ||
| 42 | _len_0 = _len_0 + 1 | ||
| 43 | end | ||
| 44 | end | ||
| 45 | return _accum_0 | ||
| 46 | end | ||
| 47 | local reduce | ||
| 48 | reduce = function(arr, init, action) | ||
| 49 | for _index_0 = 1, #arr do | ||
| 50 | local item = arr[_index_0] | ||
| 51 | init = action(init, item) | ||
| 52 | end | ||
| 53 | return init | ||
| 54 | end | ||
| 23 | print(reduce(filter(map({ | 55 | print(reduce(filter(map({ |
| 24 | 1, | 56 | 1, |
| 25 | 2, | 57 | 2, |
| @@ -1020,12 +1052,24 @@ local _len_0 = 1 | |||
| 1020 | for i = 1, 20 do | 1052 | for i = 1, 20 do |
| 1021 | if i % 2 == 0 then | 1053 | if i % 2 == 0 then |
| 1022 | _accum_0[_len_0] = i * 2 | 1054 | _accum_0[_len_0] = i * 2 |
| 1055 | _len_0 = _len_0 + 1 | ||
| 1023 | else | 1056 | else |
| 1024 | _accum_0[_len_0] = i | 1057 | _accum_0[_len_0] = i |
| 1058 | _len_0 = _len_0 + 1 | ||
| 1025 | end | 1059 | end |
| 1026 | _len_0 = _len_0 + 1 | ||
| 1027 | end | 1060 | end |
| 1028 | doubled_evens = _accum_0 | 1061 | doubled_evens = _accum_0 |
| 1062 | local first_large | ||
| 1063 | local _accum_0 | ||
| 1064 | local _list_0 = numbers | ||
| 1065 | for _index_0 = 1, #_list_0 do | ||
| 1066 | local n = _list_0[_index_0] | ||
| 1067 | if n > 10 then | ||
| 1068 | _accum_0 = n | ||
| 1069 | break | ||
| 1070 | end | ||
| 1071 | end | ||
| 1072 | first_large = _accum_0 | ||
| 1029 | local func_a | 1073 | local func_a |
| 1030 | func_a = function() | 1074 | func_a = function() |
| 1031 | for i = 1, 10 do | 1075 | for i = 1, 10 do |
| @@ -3177,12 +3221,24 @@ local _len_0 = 1 | |||
| 3177 | for i = 1, 20 do | 3221 | for i = 1, 20 do |
| 3178 | if i % 2 == 0 then | 3222 | if i % 2 == 0 then |
| 3179 | _accum_0[_len_0] = i * 2 | 3223 | _accum_0[_len_0] = i * 2 |
| 3224 | _len_0 = _len_0 + 1 | ||
| 3180 | else | 3225 | else |
| 3181 | _accum_0[_len_0] = i | 3226 | _accum_0[_len_0] = i |
| 3227 | _len_0 = _len_0 + 1 | ||
| 3182 | end | 3228 | end |
| 3183 | _len_0 = _len_0 + 1 | ||
| 3184 | end | 3229 | end |
| 3185 | doubled_evens = _accum_0 | 3230 | doubled_evens = _accum_0 |
| 3231 | local first_large | ||
| 3232 | local _accum_0 | ||
| 3233 | local _list_0 = numbers | ||
| 3234 | for _index_0 = 1, #_list_0 do | ||
| 3235 | local n = _list_0[_index_0] | ||
| 3236 | if n > 10 then | ||
| 3237 | _accum_0 = n | ||
| 3238 | break | ||
| 3239 | end | ||
| 3240 | end | ||
| 3241 | first_large = _accum_0 | ||
| 3186 | local func_a | 3242 | local func_a |
| 3187 | func_a = function() | 3243 | func_a = function() |
| 3188 | for i = 1, 10 do | 3244 | for i = 1, 10 do |
diff --git a/spec/outputs/loops.lua b/spec/outputs/loops.lua index 8624d49..9a47579 100644 --- a/spec/outputs/loops.lua +++ b/spec/outputs/loops.lua | |||
| @@ -60,8 +60,8 @@ do | |||
| 60 | local y = hello[_index_0] | 60 | local y = hello[_index_0] |
| 61 | if y % 2 == 0 then | 61 | if y % 2 == 0 then |
| 62 | _accum_0[_len_0] = y | 62 | _accum_0[_len_0] = y |
| 63 | _len_0 = _len_0 + 1 | ||
| 63 | end | 64 | end |
| 64 | _len_0 = _len_0 + 1 | ||
| 65 | end | 65 | end |
| 66 | x = _accum_0 | 66 | x = _accum_0 |
| 67 | end | 67 | end |
| @@ -132,13 +132,11 @@ do | |||
| 132 | end | 132 | end |
| 133 | do | 133 | do |
| 134 | local _accum_0 = { } | 134 | local _accum_0 = { } |
| 135 | local _len_0 = 1 | ||
| 136 | local _list_2 = 3 | 135 | local _list_2 = 3 |
| 137 | for _index_0 = 1, #_list_2 do | 136 | for _index_0 = 1, #_list_2 do |
| 138 | local thing = _list_2[_index_0] | 137 | local thing = _list_2[_index_0] |
| 139 | y = "hello" | 138 | y = "hello" |
| 140 | break | 139 | break |
| 141 | _len_0 = _len_0 + 1 | ||
| 142 | end | 140 | end |
| 143 | x = _accum_0 | 141 | x = _accum_0 |
| 144 | end | 142 | end |
| @@ -370,3 +368,103 @@ do | |||
| 370 | end | 368 | end |
| 371 | until false | 369 | until false |
| 372 | end | 370 | end |
| 371 | local _anon_func_0 = function(i, tb) | ||
| 372 | local _accum_0 = { } | ||
| 373 | local _len_0 = 1 | ||
| 374 | while tb[i] do | ||
| 375 | i = i + 1 | ||
| 376 | _accum_0[_len_0] = i - 1 | ||
| 377 | _len_0 = _len_0 + 1 | ||
| 378 | end | ||
| 379 | return _accum_0 | ||
| 380 | end | ||
| 381 | do | ||
| 382 | local index | ||
| 383 | do | ||
| 384 | local _accum_0 | ||
| 385 | for i = 1, #tb do | ||
| 386 | if tb[i] then | ||
| 387 | _accum_0 = i | ||
| 388 | break | ||
| 389 | end | ||
| 390 | end | ||
| 391 | index = _accum_0 | ||
| 392 | end | ||
| 393 | f((function() | ||
| 394 | local _accum_0 | ||
| 395 | for i = 1, #tb do | ||
| 396 | if tb[i] then | ||
| 397 | _accum_0 = i | ||
| 398 | break | ||
| 399 | end | ||
| 400 | end | ||
| 401 | return _accum_0 | ||
| 402 | end)()) | ||
| 403 | f((function() | ||
| 404 | local _accum_0 = { } | ||
| 405 | local _len_0 = 1 | ||
| 406 | for i = 1, #tb do | ||
| 407 | if tb[i] then | ||
| 408 | _accum_0[_len_0] = i | ||
| 409 | _len_0 = _len_0 + 1 | ||
| 410 | end | ||
| 411 | end | ||
| 412 | return _accum_0 | ||
| 413 | end)()) | ||
| 414 | i = 1 | ||
| 415 | local ids | ||
| 416 | do | ||
| 417 | local _accum_0 = { } | ||
| 418 | local _len_0 = 1 | ||
| 419 | while tb[i] do | ||
| 420 | i = i + 1 | ||
| 421 | _accum_0[_len_0] = i - 1 | ||
| 422 | _len_0 = _len_0 + 1 | ||
| 423 | end | ||
| 424 | ids = _accum_0 | ||
| 425 | end | ||
| 426 | i = 1 | ||
| 427 | local idx | ||
| 428 | do | ||
| 429 | local _accum_0 | ||
| 430 | while tb[i] do | ||
| 431 | i = i + 1 | ||
| 432 | _accum_0 = i - 1 | ||
| 433 | break | ||
| 434 | end | ||
| 435 | idx = _accum_0 | ||
| 436 | end | ||
| 437 | local f1 | ||
| 438 | f1 = function() | ||
| 439 | i = 1 | ||
| 440 | return f(_anon_func_0(i, tb)) | ||
| 441 | end | ||
| 442 | i = 1 | ||
| 443 | f((function() | ||
| 444 | local _accum_0 | ||
| 445 | while tb[i] do | ||
| 446 | i = i + 1 | ||
| 447 | _accum_0 = i - 1 | ||
| 448 | break | ||
| 449 | end | ||
| 450 | return _accum_0 | ||
| 451 | end)()) | ||
| 452 | local _accum_0 = { } | ||
| 453 | local _len_0 = 1 | ||
| 454 | local _list_3 = items | ||
| 455 | for _index_0 = 1, #_list_3 do | ||
| 456 | local item = _list_3[_index_0] | ||
| 457 | local _type_0 = type(item) | ||
| 458 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
| 459 | if _tab_0 then | ||
| 460 | local value = item.value | ||
| 461 | if "A" == item.type and value ~= nil then | ||
| 462 | if value > 5 then | ||
| 463 | _accum_0[_len_0] = item | ||
| 464 | _len_0 = _len_0 + 1 | ||
| 465 | end | ||
| 466 | end | ||
| 467 | end | ||
| 468 | end | ||
| 469 | list = _accum_0 | ||
| 470 | end | ||
diff --git a/spec/outputs/macro.lua b/spec/outputs/macro.lua index 4d31574..9f5507c 100644 --- a/spec/outputs/macro.lua +++ b/spec/outputs/macro.lua | |||
| @@ -330,10 +330,8 @@ local _1 | |||
| 330 | _1 = function() | 330 | _1 = function() |
| 331 | print(1) | 331 | print(1) |
| 332 | local _accum_0 = { } | 332 | local _accum_0 = { } |
| 333 | local _len_0 = 1 | ||
| 334 | while false do | 333 | while false do |
| 335 | break | 334 | break |
| 336 | _len_0 = _len_0 + 1 | ||
| 337 | end | 335 | end |
| 338 | return _accum_0 | 336 | return _accum_0 |
| 339 | end | 337 | end |
diff --git a/spec/outputs/unicode/loops.lua b/spec/outputs/unicode/loops.lua index 8379993..27bbe2e 100644 --- a/spec/outputs/unicode/loops.lua +++ b/spec/outputs/unicode/loops.lua | |||
| @@ -60,8 +60,8 @@ do | |||
| 60 | local _u53d8_u91cfy = _u4f60_u597d[_index_0] | 60 | local _u53d8_u91cfy = _u4f60_u597d[_index_0] |
| 61 | if _u53d8_u91cfy % 2 == 0 then | 61 | if _u53d8_u91cfy % 2 == 0 then |
| 62 | _accum_0[_len_0] = _u53d8_u91cfy | 62 | _accum_0[_len_0] = _u53d8_u91cfy |
| 63 | _len_0 = _len_0 + 1 | ||
| 63 | end | 64 | end |
| 64 | _len_0 = _len_0 + 1 | ||
| 65 | end | 65 | end |
| 66 | _u53d8_u91cfx = _accum_0 | 66 | _u53d8_u91cfx = _accum_0 |
| 67 | end | 67 | end |
| @@ -132,13 +132,11 @@ do | |||
| 132 | end | 132 | end |
| 133 | do | 133 | do |
| 134 | local _accum_0 = { } | 134 | local _accum_0 = { } |
| 135 | local _len_0 = 1 | ||
| 136 | local _list_2 = 3 | 135 | local _list_2 = 3 |
| 137 | for _index_0 = 1, #_list_2 do | 136 | for _index_0 = 1, #_list_2 do |
| 138 | local _u4e1c_u897f = _list_2[_index_0] | 137 | local _u4e1c_u897f = _list_2[_index_0] |
| 139 | _u53d8_u91cfy = "你好" | 138 | _u53d8_u91cfy = "你好" |
| 140 | break | 139 | break |
| 141 | _len_0 = _len_0 + 1 | ||
| 142 | end | 140 | end |
| 143 | _u53d8_u91cfx = _accum_0 | 141 | _u53d8_u91cfx = _accum_0 |
| 144 | end | 142 | end |
diff --git a/spec/outputs/unicode/macro.lua b/spec/outputs/unicode/macro.lua index b14f571..3b9327a 100644 --- a/spec/outputs/unicode/macro.lua +++ b/spec/outputs/unicode/macro.lua | |||
| @@ -365,10 +365,8 @@ local _1 | |||
| 365 | _1 = function() | 365 | _1 = function() |
| 366 | _u6253_u5370(1) | 366 | _u6253_u5370(1) |
| 367 | local _accum_0 = { } | 367 | local _accum_0 = { } |
| 368 | local _len_0 = 1 | ||
| 369 | while false do | 368 | while false do |
| 370 | break | 369 | break |
| 371 | _len_0 = _len_0 + 1 | ||
| 372 | end | 370 | end |
| 373 | return _accum_0 | 371 | return _accum_0 |
| 374 | end | 372 | end |
diff --git a/src/yuescript/yue_ast.cpp b/src/yuescript/yue_ast.cpp index fe6e726..612bdcd 100644 --- a/src/yuescript/yue_ast.cpp +++ b/src/yuescript/yue_ast.cpp | |||
| @@ -188,9 +188,17 @@ std::string ConstValue_t::to_string(void* ud) const { | |||
| 188 | std::string NotIn_t::to_string(void*) const { | 188 | std::string NotIn_t::to_string(void*) const { |
| 189 | return {}; | 189 | return {}; |
| 190 | } | 190 | } |
| 191 | std::string Break_t::to_string(void*) const { | ||
| 192 | return "break"s; | ||
| 193 | } | ||
| 194 | std::string Continue_t::to_string(void*) const { | ||
| 195 | return "continue"s; | ||
| 196 | } | ||
| 191 | std::string BreakLoop_t::to_string(void* ud) const { | 197 | std::string BreakLoop_t::to_string(void* ud) const { |
| 192 | auto info = reinterpret_cast<YueFormat*>(ud); | 198 | if (value) { |
| 193 | return info->convert(this); | 199 | return type->to_string(ud) + ' ' + value->to_string(ud); |
| 200 | } | ||
| 201 | return type->to_string(ud); | ||
| 194 | } | 202 | } |
| 195 | std::string YueLineComment_t::to_string(void* ud) const { | 203 | std::string YueLineComment_t::to_string(void* ud) const { |
| 196 | auto info = reinterpret_cast<YueFormat*>(ud); | 204 | auto info = reinterpret_cast<YueFormat*>(ud); |
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index 5e70645..782db5a 100644 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h | |||
| @@ -273,6 +273,8 @@ AST_NODE(ExpList) | |||
| 273 | ast_ptr<true, Seperator_t> sep; | 273 | ast_ptr<true, Seperator_t> sep; |
| 274 | ast_list<true, Exp_t> exprs; | 274 | ast_list<true, Exp_t> exprs; |
| 275 | AST_MEMBER(ExpList, &sep, &exprs) | 275 | AST_MEMBER(ExpList, &sep, &exprs) |
| 276 | bool followStmtProcessed = false; | ||
| 277 | Statement_t* followStmt = nullptr; | ||
| 276 | AST_END(ExpList) | 278 | AST_END(ExpList) |
| 277 | 279 | ||
| 278 | AST_NODE(Return) | 280 | AST_NODE(Return) |
| @@ -856,7 +858,17 @@ AST_NODE(WhileLine) | |||
| 856 | AST_MEMBER(WhileLine, &type, &condition) | 858 | AST_MEMBER(WhileLine, &type, &condition) |
| 857 | AST_END(WhileLine) | 859 | AST_END(WhileLine) |
| 858 | 860 | ||
| 859 | AST_LEAF(BreakLoop) | 861 | AST_LEAF(Break) |
| 862 | AST_END(Break) | ||
| 863 | |||
| 864 | AST_LEAF(Continue) | ||
| 865 | AST_END(Continue) | ||
| 866 | |||
| 867 | AST_NODE(BreakLoop) | ||
| 868 | ast_sel<true, Break_t, Continue_t> type; | ||
| 869 | ast_ptr<false, Exp_t> value; | ||
| 870 | AST_MEMBER(BreakLoop, &type, &value) | ||
| 871 | std::string varBWV; | ||
| 860 | AST_END(BreakLoop) | 872 | AST_END(BreakLoop) |
| 861 | 873 | ||
| 862 | AST_NODE(PipeBody) | 874 | AST_NODE(PipeBody) |
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index bc4574b..1a9387b 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 | ||
| 81 | const std::string_view version = "0.27.6"sv; | 81 | const std::string_view version = "0.28.0"sv; |
| 82 | const std::string_view extension = "yue"sv; | 82 | const std::string_view extension = "yue"sv; |
| 83 | 83 | ||
| 84 | class CompileError : public std::logic_error { | 84 | class CompileError : public std::logic_error { |
| @@ -2464,6 +2464,10 @@ private: | |||
| 2464 | auto info = extractDestructureInfo(assignment, false, optionalDestruct); | 2464 | auto info = extractDestructureInfo(assignment, false, optionalDestruct); |
| 2465 | if (info.destructures.empty()) { | 2465 | if (info.destructures.empty()) { |
| 2466 | transformAssignmentCommon(assignment, out); | 2466 | transformAssignmentCommon(assignment, out); |
| 2467 | if (assignment->expList->followStmt) { | ||
| 2468 | transformStatement(assignment->expList->followStmt, out); | ||
| 2469 | assignment->expList->followStmtProcessed = true; | ||
| 2470 | } | ||
| 2467 | return true; | 2471 | return true; |
| 2468 | } else { | 2472 | } else { |
| 2469 | auto x = assignment; | 2473 | auto x = assignment; |
| @@ -2729,8 +2733,12 @@ private: | |||
| 2729 | temp.push_back(indent() + "end"s + nlr(x)); | 2733 | temp.push_back(indent() + "end"s + nlr(x)); |
| 2730 | } | 2734 | } |
| 2731 | out.push_back(join(temp)); | 2735 | out.push_back(join(temp)); |
| 2736 | if (assignment->expList->followStmt) { | ||
| 2737 | transformStatement(assignment->expList->followStmt, out); | ||
| 2738 | assignment->expList->followStmtProcessed = true; | ||
| 2739 | } | ||
| 2740 | return false; | ||
| 2732 | } | 2741 | } |
| 2733 | return false; | ||
| 2734 | } | 2742 | } |
| 2735 | 2743 | ||
| 2736 | void transformAssignItem(ast_node* value, str_list& out) { | 2744 | void transformAssignItem(ast_node* value, str_list& out) { |
| @@ -4329,7 +4337,9 @@ private: | |||
| 4329 | return false; | 4337 | return false; |
| 4330 | }; | 4338 | }; |
| 4331 | switch (usage) { | 4339 | switch (usage) { |
| 4332 | case ExpUsage::Common: YUEE("AST node mismatch", x); return; | 4340 | case ExpUsage::Common: |
| 4341 | YUEE("AST node mismatch", x); | ||
| 4342 | return; | ||
| 4333 | case ExpUsage::Return: | 4343 | case ExpUsage::Return: |
| 4334 | case ExpUsage::Closure: { | 4344 | case ExpUsage::Closure: { |
| 4335 | prepareValue(); | 4345 | prepareValue(); |
| @@ -7195,7 +7205,7 @@ private: | |||
| 7195 | try { | 7205 | try { |
| 7196 | unsigned long long value = std::stoull(binaryPart, nullptr, 2); | 7206 | unsigned long long value = std::stoull(binaryPart, nullptr, 2); |
| 7197 | numStr = std::to_string(value); | 7207 | numStr = std::to_string(value); |
| 7198 | } catch (const std::exception& e) { | 7208 | } catch (const std::exception&) { |
| 7199 | throw CompileError("invalid binary literal"sv, num); | 7209 | throw CompileError("invalid binary literal"sv, num); |
| 7200 | } | 7210 | } |
| 7201 | } else if (getLuaTarget(num) < 502) { | 7211 | } else if (getLuaTarget(num) < 502) { |
| @@ -8162,11 +8172,44 @@ private: | |||
| 8162 | } | 8172 | } |
| 8163 | } | 8173 | } |
| 8164 | 8174 | ||
| 8165 | bool hasContinueStatement(ast_node* body) { | 8175 | enum class BreakLoopType { |
| 8166 | return traversal::Stop == body->traverse([&](ast_node* node) { | 8176 | None = 0, |
| 8177 | Break = 1, | ||
| 8178 | BreakWithValue = 1 << 1, | ||
| 8179 | Continue = 1 << 2 | ||
| 8180 | }; | ||
| 8181 | |||
| 8182 | bool hasBreak(uint32_t breakLoopType) const { | ||
| 8183 | return (breakLoopType & int(BreakLoopType::Break)) != 0; | ||
| 8184 | } | ||
| 8185 | |||
| 8186 | bool hasBreakWithValue(uint32_t breakLoopType) const { | ||
| 8187 | return (breakLoopType & int(BreakLoopType::BreakWithValue)) != 0; | ||
| 8188 | } | ||
| 8189 | |||
| 8190 | bool hasContinue(uint32_t breakLoopType) const { | ||
| 8191 | return (breakLoopType & int(BreakLoopType::Continue)) != 0; | ||
| 8192 | } | ||
| 8193 | |||
| 8194 | uint32_t getBreakLoopType(ast_node* body, const std::string& varBWV) { | ||
| 8195 | uint32_t type = 0; | ||
| 8196 | body->traverse([&](ast_node* node) { | ||
| 8167 | if (auto stmt = ast_cast<Statement_t>(node)) { | 8197 | if (auto stmt = ast_cast<Statement_t>(node)) { |
| 8168 | if (stmt->content.is<BreakLoop_t>()) { | 8198 | if (auto breakLoop = stmt->content.as<BreakLoop_t>()) { |
| 8169 | return _parser.toString(stmt->content) == "continue"sv ? traversal::Stop : traversal::Return; | 8199 | if (breakLoop->type.is<Continue_t>()) { |
| 8200 | type |= int(BreakLoopType::Continue); | ||
| 8201 | return traversal::Return; | ||
| 8202 | } else { | ||
| 8203 | if (breakLoop->value) { | ||
| 8204 | if (varBWV.empty()) { | ||
| 8205 | throw CompileError("break with a value is not allowed here"sv, breakLoop->value); | ||
| 8206 | } | ||
| 8207 | type |= int(BreakLoopType::BreakWithValue); | ||
| 8208 | breakLoop->varBWV = varBWV; | ||
| 8209 | } else { | ||
| 8210 | type |= int(BreakLoopType::Break); | ||
| 8211 | } | ||
| 8212 | } | ||
| 8170 | } else if (auto expList = expListFrom(stmt)) { | 8213 | } else if (auto expList = expListFrom(stmt)) { |
| 8171 | BLOCK_START | 8214 | BLOCK_START |
| 8172 | auto value = singleValueFrom(expList); | 8215 | auto value = singleValueFrom(expList); |
| @@ -8177,40 +8220,30 @@ private: | |||
| 8177 | switch (sVal->get_id()) { | 8220 | switch (sVal->get_id()) { |
| 8178 | case id<With_t>(): { | 8221 | case id<With_t>(): { |
| 8179 | auto withNode = static_cast<With_t*>(sVal); | 8222 | auto withNode = static_cast<With_t*>(sVal); |
| 8180 | if (hasContinueStatement(withNode->body)) { | 8223 | type |= getBreakLoopType(withNode->body, varBWV); |
| 8181 | return traversal::Stop; | 8224 | return traversal::Return; |
| 8182 | } | ||
| 8183 | break; | ||
| 8184 | } | 8225 | } |
| 8185 | case id<Do_t>(): { | 8226 | case id<Do_t>(): { |
| 8186 | auto doNode = static_cast<Do_t*>(sVal); | 8227 | auto doNode = static_cast<Do_t*>(sVal); |
| 8187 | if (hasContinueStatement(doNode->body)) { | 8228 | type |= getBreakLoopType(doNode->body, varBWV); |
| 8188 | return traversal::Stop; | 8229 | return traversal::Return; |
| 8189 | } | ||
| 8190 | break; | ||
| 8191 | } | 8230 | } |
| 8192 | case id<If_t>(): { | 8231 | case id<If_t>(): { |
| 8193 | auto ifNode = static_cast<If_t*>(sVal); | 8232 | auto ifNode = static_cast<If_t*>(sVal); |
| 8194 | for (auto n : ifNode->nodes.objects()) { | 8233 | for (auto n : ifNode->nodes.objects()) { |
| 8195 | if (hasContinueStatement(n)) { | 8234 | type |= getBreakLoopType(n, varBWV); |
| 8196 | return traversal::Stop; | ||
| 8197 | } | ||
| 8198 | } | 8235 | } |
| 8199 | break; | 8236 | return traversal::Return; |
| 8200 | } | 8237 | } |
| 8201 | case id<Switch_t>(): { | 8238 | case id<Switch_t>(): { |
| 8202 | auto switchNode = static_cast<Switch_t*>(sVal); | 8239 | auto switchNode = static_cast<Switch_t*>(sVal); |
| 8203 | for (auto branch : switchNode->branches.objects()) { | 8240 | for (auto branch : switchNode->branches.objects()) { |
| 8204 | if (hasContinueStatement(static_cast<SwitchCase_t*>(branch)->body)) { | 8241 | type |= getBreakLoopType(static_cast<SwitchCase_t*>(branch)->body, varBWV); |
| 8205 | return traversal::Stop; | ||
| 8206 | } | ||
| 8207 | } | 8242 | } |
| 8208 | if (switchNode->lastBranch) { | 8243 | if (switchNode->lastBranch) { |
| 8209 | if (hasContinueStatement(switchNode->lastBranch)) { | 8244 | type |= getBreakLoopType(switchNode->lastBranch, varBWV); |
| 8210 | return traversal::Stop; | ||
| 8211 | } | ||
| 8212 | } | 8245 | } |
| 8213 | break; | 8246 | return traversal::Return; |
| 8214 | } | 8247 | } |
| 8215 | } | 8248 | } |
| 8216 | BLOCK_END | 8249 | BLOCK_END |
| @@ -8224,6 +8257,7 @@ private: | |||
| 8224 | } | 8257 | } |
| 8225 | return traversal::Return; | 8258 | return traversal::Return; |
| 8226 | }); | 8259 | }); |
| 8260 | return type; | ||
| 8227 | } | 8261 | } |
| 8228 | 8262 | ||
| 8229 | void addDoToLastLineReturn(ast_node* body) { | 8263 | void addDoToLastLineReturn(ast_node* body) { |
| @@ -8247,10 +8281,10 @@ private: | |||
| 8247 | } | 8281 | } |
| 8248 | } | 8282 | } |
| 8249 | 8283 | ||
| 8250 | void transformLoopBody(ast_node* body, str_list& out, const std::string& appendContent, ExpUsage usage, ExpList_t* assignList = nullptr) { | 8284 | void transformLoopBody(ast_node* body, str_list& out, uint32_t breakLoopType, ExpUsage usage, ExpList_t* assignList = nullptr) { |
| 8251 | str_list temp; | 8285 | str_list temp; |
| 8252 | bool extraDo = false; | 8286 | bool extraDo = false; |
| 8253 | bool withContinue = hasContinueStatement(body); | 8287 | bool withContinue = hasContinue(breakLoopType); |
| 8254 | int target = getLuaTarget(body); | 8288 | int target = getLuaTarget(body); |
| 8255 | std::string extraLabel; | 8289 | std::string extraLabel; |
| 8256 | if (withContinue) { | 8290 | if (withContinue) { |
| @@ -8259,7 +8293,7 @@ private: | |||
| 8259 | if (!block->statements.empty()) { | 8293 | if (!block->statements.empty()) { |
| 8260 | auto stmt = static_cast<Statement_t*>(block->statements.back()); | 8294 | auto stmt = static_cast<Statement_t*>(block->statements.back()); |
| 8261 | if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { | 8295 | if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { |
| 8262 | extraDo = _parser.toString(breakLoop) == "break"sv; | 8296 | extraDo = breakLoop->type.is<Break_t>(); |
| 8263 | } | 8297 | } |
| 8264 | } | 8298 | } |
| 8265 | } | 8299 | } |
| @@ -8292,9 +8326,6 @@ private: | |||
| 8292 | popScope(); | 8326 | popScope(); |
| 8293 | _buf << indent() << "end"sv << nll(body); | 8327 | _buf << indent() << "end"sv << nll(body); |
| 8294 | } | 8328 | } |
| 8295 | if (!appendContent.empty()) { | ||
| 8296 | _buf << indent() << appendContent; | ||
| 8297 | } | ||
| 8298 | _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); | 8329 | _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); |
| 8299 | popScope(); | 8330 | popScope(); |
| 8300 | _buf << indent() << "until true"sv << nlr(body); | 8331 | _buf << indent() << "until true"sv << nlr(body); |
| @@ -8304,14 +8335,9 @@ private: | |||
| 8304 | temp.push_back(clearBuf()); | 8335 | temp.push_back(clearBuf()); |
| 8305 | _continueVars.pop(); | 8336 | _continueVars.pop(); |
| 8306 | } else { | 8337 | } else { |
| 8307 | if (!appendContent.empty()) { | ||
| 8308 | temp.push_back(indent() + appendContent); | ||
| 8309 | } | ||
| 8310 | temp.push_back(extraLabel); | 8338 | temp.push_back(extraLabel); |
| 8311 | _continueVars.pop(); | 8339 | _continueVars.pop(); |
| 8312 | } | 8340 | } |
| 8313 | } else if (!appendContent.empty()) { | ||
| 8314 | temp.back().append(indent() + appendContent); | ||
| 8315 | } | 8341 | } |
| 8316 | out.push_back(join(temp)); | 8342 | out.push_back(join(temp)); |
| 8317 | } | 8343 | } |
| @@ -8320,7 +8346,8 @@ private: | |||
| 8320 | str_list temp; | 8346 | str_list temp; |
| 8321 | bool extraDo = false; | 8347 | bool extraDo = false; |
| 8322 | auto body = repeatNode->body->content.get(); | 8348 | auto body = repeatNode->body->content.get(); |
| 8323 | bool withContinue = hasContinueStatement(body); | 8349 | auto breakLoopType = getBreakLoopType(body, Empty); |
| 8350 | bool withContinue = hasContinue(breakLoopType); | ||
| 8324 | std::string conditionVar; | 8351 | std::string conditionVar; |
| 8325 | std::string extraLabel; | 8352 | std::string extraLabel; |
| 8326 | ast_ptr<false, ExpListAssign_t> condAssign; | 8353 | ast_ptr<false, ExpListAssign_t> condAssign; |
| @@ -8331,7 +8358,7 @@ private: | |||
| 8331 | if (!block->statements.empty()) { | 8358 | if (!block->statements.empty()) { |
| 8332 | auto stmt = static_cast<Statement_t*>(block->statements.back()); | 8359 | auto stmt = static_cast<Statement_t*>(block->statements.back()); |
| 8333 | if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { | 8360 | if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { |
| 8334 | extraDo = _parser.toString(breakLoop) == "break"sv; | 8361 | extraDo = breakLoop->type.is<Break_t>(); |
| 8335 | } | 8362 | } |
| 8336 | } | 8363 | } |
| 8337 | } | 8364 | } |
| @@ -8394,7 +8421,8 @@ private: | |||
| 8394 | void transformFor(For_t* forNode, str_list& out) { | 8421 | void transformFor(For_t* forNode, str_list& out) { |
| 8395 | str_list temp; | 8422 | str_list temp; |
| 8396 | transformForHead(forNode, temp); | 8423 | transformForHead(forNode, temp); |
| 8397 | transformLoopBody(forNode->body, temp, Empty, ExpUsage::Common); | 8424 | auto breakLoopType = getBreakLoopType(forNode->body, Empty); |
| 8425 | transformLoopBody(forNode->body, temp, breakLoopType, ExpUsage::Common); | ||
| 8398 | popScope(); | 8426 | popScope(); |
| 8399 | out.push_back(join(temp) + indent() + "end"s + nlr(forNode)); | 8427 | out.push_back(join(temp) + indent() + "end"s + nlr(forNode)); |
| 8400 | } | 8428 | } |
| @@ -8405,13 +8433,19 @@ private: | |||
| 8405 | addToScope(accum); | 8433 | addToScope(accum); |
| 8406 | std::string len = getUnusedName("_len_"sv); | 8434 | std::string len = getUnusedName("_len_"sv); |
| 8407 | addToScope(len); | 8435 | addToScope(len); |
| 8408 | _buf << indent() << "local "sv << accum << " = { }"sv << nll(forNode); | 8436 | auto breakLoopType = getBreakLoopType(forNode->body, accum); |
| 8437 | _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(forNode); | ||
| 8438 | out.emplace_back(clearBuf()); | ||
| 8409 | _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode); | 8439 | _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode); |
| 8410 | out.push_back(clearBuf()); | 8440 | auto& lenAssign = out.emplace_back(clearBuf()); |
| 8411 | transformForHead(forNode, out); | 8441 | transformForHead(forNode, out); |
| 8412 | auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); | 8442 | auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); |
| 8413 | auto lenLine = len + " = "s + len + " + 1"s + nlr(forNode->body); | 8443 | auto followStmt = toAst<Statement_t>(len + "+=1"s, forNode->body); |
| 8414 | transformLoopBody(forNode->body, out, lenLine, ExpUsage::Assignment, expList); | 8444 | expList->followStmt = followStmt.get(); |
| 8445 | transformLoopBody(forNode->body, out, breakLoopType, ExpUsage::Assignment, expList); | ||
| 8446 | if (!expList->followStmtProcessed) { | ||
| 8447 | lenAssign.clear(); | ||
| 8448 | } | ||
| 8415 | popScope(); | 8449 | popScope(); |
| 8416 | out.push_back(indent() + "end"s + nlr(forNode)); | 8450 | out.push_back(indent() + "end"s + nlr(forNode)); |
| 8417 | return accum; | 8451 | return accum; |
| @@ -8490,7 +8524,8 @@ private: | |||
| 8490 | void transformForEach(ForEach_t* forEach, str_list& out) { | 8524 | void transformForEach(ForEach_t* forEach, str_list& out) { |
| 8491 | str_list temp; | 8525 | str_list temp; |
| 8492 | bool extraScoped = transformForEachHead(forEach->nameList, forEach->loopValue, temp, false); | 8526 | bool extraScoped = transformForEachHead(forEach->nameList, forEach->loopValue, temp, false); |
| 8493 | transformLoopBody(forEach->body, temp, Empty, ExpUsage::Common); | 8527 | auto breakLoopType = getBreakLoopType(forEach->body, Empty); |
| 8528 | transformLoopBody(forEach->body, temp, breakLoopType, ExpUsage::Common); | ||
| 8494 | popScope(); | 8529 | popScope(); |
| 8495 | out.push_back(temp.front() + temp.back() + indent() + "end"s + nlr(forEach)); | 8530 | out.push_back(temp.front() + temp.back() + indent() + "end"s + nlr(forEach)); |
| 8496 | if (extraScoped) { | 8531 | if (extraScoped) { |
| @@ -8505,13 +8540,19 @@ private: | |||
| 8505 | addToScope(accum); | 8540 | addToScope(accum); |
| 8506 | std::string len = getUnusedName("_len_"sv); | 8541 | std::string len = getUnusedName("_len_"sv); |
| 8507 | addToScope(len); | 8542 | addToScope(len); |
| 8508 | _buf << indent() << "local "sv << accum << " = { }"sv << nll(forEach); | 8543 | auto breakLoopType = getBreakLoopType(forEach->body, accum); |
| 8544 | _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(forEach); | ||
| 8545 | out.emplace_back(clearBuf()); | ||
| 8509 | _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach); | 8546 | _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach); |
| 8510 | out.push_back(clearBuf()); | 8547 | auto& lenAssign = out.emplace_back(clearBuf()); |
| 8511 | transformForEachHead(forEach->nameList, forEach->loopValue, out, true); | 8548 | transformForEachHead(forEach->nameList, forEach->loopValue, out, true); |
| 8512 | auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); | 8549 | auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); |
| 8513 | auto lenLine = len + " = "s + len + " + 1"s + nlr(forEach->body); | 8550 | auto followStmt = toAst<Statement_t>(len + "+=1"s, forEach->body); |
| 8514 | transformLoopBody(forEach->body, out, lenLine, ExpUsage::Assignment, expList); | 8551 | expList->followStmt = followStmt.get(); |
| 8552 | transformLoopBody(forEach->body, out, breakLoopType, ExpUsage::Assignment, expList); | ||
| 8553 | if (!expList->followStmtProcessed) { | ||
| 8554 | lenAssign.clear(); | ||
| 8555 | } | ||
| 8515 | popScope(); | 8556 | popScope(); |
| 8516 | out.push_back(indent() + "end"s + nlr(forEach)); | 8557 | out.push_back(indent() + "end"s + nlr(forEach)); |
| 8517 | return accum; | 8558 | return accum; |
| @@ -10440,15 +10481,22 @@ private: | |||
| 10440 | addToScope(accumVar); | 10481 | addToScope(accumVar); |
| 10441 | auto lenVar = getUnusedName("_len_"sv); | 10482 | auto lenVar = getUnusedName("_len_"sv); |
| 10442 | addToScope(lenVar); | 10483 | addToScope(lenVar); |
| 10443 | temp.push_back(indent() + "local "s + accumVar + " = { }"s + nll(whileNode)); | 10484 | auto breakLoopType = getBreakLoopType(whileNode->body, accumVar); |
| 10444 | temp.push_back(indent() + "local "s + lenVar + " = 1"s + nll(whileNode)); | 10485 | _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(whileNode); |
| 10486 | temp.emplace_back(clearBuf()); | ||
| 10487 | _buf << indent() << "local "s << lenVar << " = 1"s << nll(whileNode); | ||
| 10488 | auto& lenAssign = temp.emplace_back(clearBuf()); | ||
| 10445 | bool isUntil = _parser.toString(whileNode->type) == "until"sv; | 10489 | bool isUntil = _parser.toString(whileNode->type) == "until"sv; |
| 10446 | auto condStr = transformCondExp(whileNode->condition, isUntil); | 10490 | auto condStr = transformCondExp(whileNode->condition, isUntil); |
| 10447 | temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); | 10491 | temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); |
| 10448 | pushScope(); | 10492 | pushScope(); |
| 10449 | auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); | 10493 | auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); |
| 10450 | auto lenLine = lenVar + " = "s + lenVar + " + 1"s + nlr(whileNode); | 10494 | auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, whileNode); |
| 10451 | transformLoopBody(whileNode->body, temp, lenLine, ExpUsage::Assignment, assignLeft); | 10495 | assignLeft->followStmt = followStmt.get(); |
| 10496 | transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft); | ||
| 10497 | if (!assignLeft->followStmtProcessed) { | ||
| 10498 | lenAssign.clear(); | ||
| 10499 | } | ||
| 10452 | popScope(); | 10500 | popScope(); |
| 10453 | temp.push_back(indent() + "end"s + nlr(whileNode)); | 10501 | temp.push_back(indent() + "end"s + nlr(whileNode)); |
| 10454 | if (expList) { | 10502 | if (expList) { |
| @@ -10484,15 +10532,21 @@ private: | |||
| 10484 | addToScope(accumVar); | 10532 | addToScope(accumVar); |
| 10485 | auto lenVar = getUnusedName("_len_"sv); | 10533 | auto lenVar = getUnusedName("_len_"sv); |
| 10486 | addToScope(lenVar); | 10534 | addToScope(lenVar); |
| 10487 | temp.push_back(indent() + "local "s + accumVar + " = { }"s + nll(whileNode)); | 10535 | auto breakLoopType = getBreakLoopType(whileNode->body, accumVar); |
| 10488 | temp.push_back(indent() + "local "s + lenVar + " = 1"s + nll(whileNode)); | 10536 | _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(whileNode); |
| 10537 | temp.emplace_back(clearBuf()); | ||
| 10538 | auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nll(whileNode)); | ||
| 10489 | bool isUntil = _parser.toString(whileNode->type) == "until"sv; | 10539 | bool isUntil = _parser.toString(whileNode->type) == "until"sv; |
| 10490 | auto condStr = transformCondExp(whileNode->condition, isUntil); | 10540 | auto condStr = transformCondExp(whileNode->condition, isUntil); |
| 10491 | temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); | 10541 | temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); |
| 10492 | pushScope(); | 10542 | pushScope(); |
| 10493 | auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); | 10543 | auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); |
| 10494 | auto lenLine = lenVar + " = "s + lenVar + " + 1"s + nlr(whileNode); | 10544 | auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, whileNode); |
| 10495 | transformLoopBody(whileNode->body, temp, lenLine, ExpUsage::Assignment, assignLeft); | 10545 | assignLeft->followStmt = followStmt.get(); |
| 10546 | transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft); | ||
| 10547 | if (!assignLeft->followStmtProcessed) { | ||
| 10548 | lenAssign.clear(); | ||
| 10549 | } | ||
| 10496 | popScope(); | 10550 | popScope(); |
| 10497 | temp.push_back(indent() + "end"s + nlr(whileNode)); | 10551 | temp.push_back(indent() + "end"s + nlr(whileNode)); |
| 10498 | temp.push_back(indent() + "return "s + accumVar + nlr(whileNode)); | 10552 | temp.push_back(indent() + "return "s + accumVar + nlr(whileNode)); |
| @@ -10537,7 +10591,8 @@ private: | |||
| 10537 | pushScope(); | 10591 | pushScope(); |
| 10538 | bool isUntil = _parser.toString(whileNode->type) == "until"sv; | 10592 | bool isUntil = _parser.toString(whileNode->type) == "until"sv; |
| 10539 | auto condStr = transformCondExp(whileNode->condition, isUntil); | 10593 | auto condStr = transformCondExp(whileNode->condition, isUntil); |
| 10540 | transformLoopBody(whileNode->body, temp, Empty, ExpUsage::Common); | 10594 | auto breakLoopType = getBreakLoopType(whileNode->body, Empty); |
| 10595 | transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common); | ||
| 10541 | popScope(); | 10596 | popScope(); |
| 10542 | _buf << indent() << "while "sv << condStr << " do"sv << nll(whileNode); | 10597 | _buf << indent() << "while "sv << condStr << " do"sv << nll(whileNode); |
| 10543 | _buf << temp.back(); | 10598 | _buf << temp.back(); |
| @@ -11077,11 +11132,17 @@ private: | |||
| 11077 | } | 11132 | } |
| 11078 | 11133 | ||
| 11079 | void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) { | 11134 | void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) { |
| 11080 | auto keyword = _parser.toString(breakLoop); | 11135 | auto isBreak = breakLoop->type.is<Break_t>(); |
| 11136 | auto keyword = isBreak ? "break"s : "continue"s; | ||
| 11081 | if (_enableBreakLoop.empty() || !_enableBreakLoop.top()) { | 11137 | if (_enableBreakLoop.empty() || !_enableBreakLoop.top()) { |
| 11082 | throw CompileError(keyword + " is not inside a loop"s, breakLoop); | 11138 | throw CompileError(keyword + " is not inside a loop"s, breakLoop); |
| 11083 | } | 11139 | } |
| 11084 | if (keyword == "break"sv) { | 11140 | if (isBreak) { |
| 11141 | if (breakLoop->value) { | ||
| 11142 | auto exp = toAst<Exp_t>(breakLoop->varBWV, breakLoop->value); | ||
| 11143 | auto assignment = assignmentFrom(exp, breakLoop->value, breakLoop); | ||
| 11144 | transformAssignment(assignment, out); | ||
| 11145 | } | ||
| 11085 | out.push_back(indent() + keyword + nll(breakLoop)); | 11146 | out.push_back(indent() + keyword + nll(breakLoop)); |
| 11086 | return; | 11147 | return; |
| 11087 | } | 11148 | } |
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index 77c5901..eaabf0d 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp | |||
| @@ -350,7 +350,9 @@ YueParser::YueParser() { | |||
| 350 | 350 | ||
| 351 | ShortTabAppending = "[]" >> space >> Assign; | 351 | ShortTabAppending = "[]" >> space >> Assign; |
| 352 | 352 | ||
| 353 | BreakLoop = (expr("break") | "continue") >> not_alpha_num; | 353 | Break = key("break"); |
| 354 | Continue = key("continue"); | ||
| 355 | BreakLoop = (Break >> -(space >> Exp) | Continue) >> not_alpha_num; | ||
| 354 | 356 | ||
| 355 | Return = key("return") >> -(space >> (TableBlock | ExpListLow)); | 357 | Return = key("return") >> -(space >> (TableBlock | ExpListLow)); |
| 356 | 358 | ||
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index 7281ec3..63afcb9 100644 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h | |||
| @@ -427,6 +427,8 @@ private: | |||
| 427 | AST_RULE(ExpListAssign); | 427 | AST_RULE(ExpListAssign); |
| 428 | AST_RULE(IfLine); | 428 | AST_RULE(IfLine); |
| 429 | AST_RULE(WhileLine); | 429 | AST_RULE(WhileLine); |
| 430 | AST_RULE(Break); | ||
| 431 | AST_RULE(Continue); | ||
| 430 | AST_RULE(BreakLoop); | 432 | AST_RULE(BreakLoop); |
| 431 | AST_RULE(StatementAppendix); | 433 | AST_RULE(StatementAppendix); |
| 432 | AST_RULE(Statement); | 434 | AST_RULE(Statement); |
