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