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