diff options
Diffstat (limited to 'src')
| -rwxr-xr-x | src/3rdParty/colib/LICENSE | 21 | ||||
| -rw-r--r-- | src/3rdParty/colib/ljson.c | 925 | ||||
| -rwxr-xr-x | src/3rdParty/utf8cpp.h | 1277 | ||||
| -rw-r--r-- | src/yue.cpp | 45 | ||||
| -rw-r--r-- | src/yue_wasm.cpp | 2 | ||||
| -rw-r--r-- | src/yuescript/parser.cpp | 29 | ||||
| -rw-r--r-- | src/yuescript/parser.hpp | 7 | ||||
| -rw-r--r-- | src/yuescript/yue_ast.cpp | 264 | ||||
| -rw-r--r-- | src/yuescript/yue_ast.h | 159 | ||||
| -rw-r--r-- | src/yuescript/yue_compiler.cpp | 2037 | ||||
| -rw-r--r-- | src/yuescript/yue_compiler.h | 4 | ||||
| -rw-r--r-- | src/yuescript/yue_parser.cpp | 683 | ||||
| -rw-r--r-- | src/yuescript/yue_parser.h | 84 | ||||
| -rw-r--r-- | src/yuescript/yuescript.cpp | 41 |
14 files changed, 4575 insertions, 1003 deletions
diff --git a/src/3rdParty/colib/LICENSE b/src/3rdParty/colib/LICENSE new file mode 100755 index 0000000..e0eddeb --- /dev/null +++ b/src/3rdParty/colib/LICENSE | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | MIT License | ||
| 2 | |||
| 3 | Copyright (c) 2020 colin | ||
| 4 | |||
| 5 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 6 | of this software and associated documentation files (the "Software"), to deal | ||
| 7 | in the Software without restriction, including without limitation the rights | ||
| 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 9 | copies of the Software, and to permit persons to whom the Software is | ||
| 10 | furnished to do so, subject to the following conditions: | ||
| 11 | |||
| 12 | The above copyright notice and this permission notice shall be included in all | ||
| 13 | copies or substantial portions of the Software. | ||
| 14 | |||
| 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 21 | SOFTWARE. | ||
diff --git a/src/3rdParty/colib/ljson.c b/src/3rdParty/colib/ljson.c new file mode 100644 index 0000000..4daba07 --- /dev/null +++ b/src/3rdParty/colib/ljson.c | |||
| @@ -0,0 +1,925 @@ | |||
| 1 | /** | ||
| 2 | * json解析器:只支持utf-8格式,Lua只支持64位的数字 | ||
| 3 | */ | ||
| 4 | #define LUA_LIB | ||
| 5 | #include <stdlib.h> | ||
| 6 | #include <string.h> | ||
| 7 | #include <stdint.h> | ||
| 8 | #include <stdio.h> | ||
| 9 | #include <ctype.h> | ||
| 10 | #include <assert.h> | ||
| 11 | #include <errno.h> | ||
| 12 | #include <setjmp.h> | ||
| 13 | #include <ctype.h> | ||
| 14 | #include <limits.h> | ||
| 15 | #include <float.h> | ||
| 16 | #include <math.h> | ||
| 17 | #include "lua.h" | ||
| 18 | #include "lauxlib.h" | ||
| 19 | |||
| 20 | #if LUA_VERSION_NUM > 501 | ||
| 21 | #ifndef LUA_COMPAT_5_1 | ||
| 22 | #ifndef lua_objlen | ||
| 23 | #define lua_objlen lua_rawlen | ||
| 24 | #endif // lua_objlen | ||
| 25 | #endif // LUA_COMPAT_5_1 | ||
| 26 | #endif // LUA_VERSION_NUM | ||
| 27 | |||
| 28 | // 内存分配函数,方便替换 | ||
| 29 | #define co_malloc malloc | ||
| 30 | #define co_free free | ||
| 31 | #define co_realloc realloc | ||
| 32 | #define co_calloc calloc | ||
| 33 | |||
| 34 | |||
| 35 | #if !defined(likely) | ||
| 36 | #if defined(__GNUC__) | ||
| 37 | #define likely(x) (__builtin_expect(((x) != 0), 1)) | ||
| 38 | #define unlikely(x) (__builtin_expect(((x) != 0), 0)) | ||
| 39 | #else | ||
| 40 | #define likely(x) (x) | ||
| 41 | #define unlikely(x) (x) | ||
| 42 | #endif | ||
| 43 | |||
| 44 | #endif | ||
| 45 | |||
| 46 | //----------------------------------------------------------------------------- | ||
| 47 | // membuffer | ||
| 48 | |||
| 49 | #define STACK_BUFF_SIZE 512 | ||
| 50 | |||
| 51 | typedef struct membuffer { | ||
| 52 | char *b; // 内存buffer | ||
| 53 | size_t sz; // buffer已用长度 | ||
| 54 | size_t cap; // buffer实际大小 | ||
| 55 | char s[STACK_BUFF_SIZE]; | ||
| 56 | } membuffer_t; | ||
| 57 | |||
| 58 | // 初始化buffer | ||
| 59 | static inline void membuffer_init(membuffer_t *buff) { | ||
| 60 | buff->b = buff->s; | ||
| 61 | buff->cap = STACK_BUFF_SIZE; | ||
| 62 | buff->sz = 0; | ||
| 63 | } | ||
| 64 | |||
| 65 | static inline void membuffer_add_size(membuffer_t *buff, size_t sz) { | ||
| 66 | buff->sz += sz; | ||
| 67 | } | ||
| 68 | |||
| 69 | static inline void membuffer_reset(membuffer_t *buff) { | ||
| 70 | buff->sz = 0; | ||
| 71 | } | ||
| 72 | |||
| 73 | static inline void membuffer_free(membuffer_t *buff) { | ||
| 74 | if (buff->b && buff->b != buff->s) { | ||
| 75 | co_free(buff->b); | ||
| 76 | buff->b = NULL; | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | static inline void _membuffer_grow(membuffer_t *buff, size_t needsz) { | ||
| 81 | if (buff->cap < needsz) { | ||
| 82 | size_t newcap = buff->cap * 2; | ||
| 83 | if (newcap < needsz) | ||
| 84 | newcap = needsz; | ||
| 85 | if (buff->b == buff->s) { | ||
| 86 | buff->b = (char*)co_malloc(newcap); | ||
| 87 | memcpy(buff->b, buff->s, buff->sz); | ||
| 88 | } else { | ||
| 89 | buff->b = (char*)co_realloc(buff->b, newcap); | ||
| 90 | } | ||
| 91 | buff->cap = newcap; | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | // 确保缓存中还有sz的可用空间 | ||
| 96 | static inline void membuffer_ensure_space(membuffer_t *buff, size_t sz) { | ||
| 97 | if (buff->sz + sz > buff->cap) { | ||
| 98 | _membuffer_grow(buff, buff->sz+sz); | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | // 压入一个字符 | ||
| 103 | static inline void membuffer_putc(membuffer_t *buff, char c) { | ||
| 104 | membuffer_ensure_space(buff, 1); | ||
| 105 | buff->b[buff->sz++] = c; | ||
| 106 | } | ||
| 107 | |||
| 108 | // 写入一段内存 | ||
| 109 | static inline void membuffer_putb(membuffer_t *buff, const void *b, size_t sz) { | ||
| 110 | membuffer_ensure_space(buff, sz); | ||
| 111 | memcpy(buff->b + buff->sz, b, sz); | ||
| 112 | buff->sz += sz; | ||
| 113 | } | ||
| 114 | |||
| 115 | // 压入一个字符:不检查空间(不安全版本) | ||
| 116 | static inline void membuffer_putc_unsafe(membuffer_t *buff, char c) { | ||
| 117 | buff->b[buff->sz++] = c; | ||
| 118 | } | ||
| 119 | |||
| 120 | #if LUA_VERSION_NUM > 501 | ||
| 121 | // 写入一段内存:不检查空间(不安全版本) | ||
| 122 | static inline void membuffer_putb_unsafe(membuffer_t *buff, const void *b, size_t sz) { | ||
| 123 | memcpy(buff->b + buff->sz, b, sz); | ||
| 124 | buff->sz += sz; | ||
| 125 | } | ||
| 126 | #endif | ||
| 127 | |||
| 128 | // 取当前的指针 | ||
| 129 | static inline char* membuffer_getp(membuffer_t *buff) { | ||
| 130 | return buff->b + buff->sz; | ||
| 131 | } | ||
| 132 | |||
| 133 | //----------------------------------------------------------------------------- | ||
| 134 | // parser | ||
| 135 | |||
| 136 | //------------------------------------- | ||
| 137 | // 与Lua相关的代码 | ||
| 138 | |||
| 139 | static inline void l_add_object(lua_State *L) { | ||
| 140 | luaL_checkstack(L, 6, NULL); | ||
| 141 | lua_createtable(L, 0, 4); | ||
| 142 | } | ||
| 143 | static inline void l_begin_pair(lua_State *L, const char *k, size_t sz) { | ||
| 144 | lua_pushlstring(L, k, sz); | ||
| 145 | } | ||
| 146 | static inline void l_end_pair(lua_State *L) { | ||
| 147 | lua_rawset(L, -3); | ||
| 148 | } | ||
| 149 | static inline void l_add_array(lua_State *L) { | ||
| 150 | luaL_checkstack(L, 6, NULL); | ||
| 151 | lua_createtable(L, 4, 0); | ||
| 152 | } | ||
| 153 | static inline void l_add_index(lua_State *L, int i) { | ||
| 154 | lua_rawseti(L, -2, i+1); | ||
| 155 | } | ||
| 156 | static inline void l_add_string(lua_State *L, const char *s, size_t sz) { | ||
| 157 | lua_pushlstring(L, s, sz); | ||
| 158 | } | ||
| 159 | static inline void l_add_float(lua_State *L, double f) { | ||
| 160 | lua_pushnumber(L, (lua_Number)f); | ||
| 161 | } | ||
| 162 | static inline void l_add_integer(lua_State *L, int64_t i) { | ||
| 163 | lua_pushinteger(L, (lua_Integer)i); | ||
| 164 | } | ||
| 165 | static inline void l_add_boolean(lua_State *L, int b) { | ||
| 166 | lua_pushboolean(L, b); | ||
| 167 | } | ||
| 168 | static inline void l_add_null(lua_State *L) { | ||
| 169 | lua_pushlightuserdata(L, NULL); | ||
| 170 | } | ||
| 171 | static inline void l_error(lua_State *L, const char *msg) { | ||
| 172 | luaL_error(L, msg); | ||
| 173 | } | ||
| 174 | |||
| 175 | // 解析事件 | ||
| 176 | #define ON_ADD_OBJECT(ud) l_add_object((lua_State*)(ud)) | ||
| 177 | #define ON_BEGIN_PAIR(ud, k, sz) l_begin_pair((lua_State*)(ud), k, sz) | ||
| 178 | #define ON_END_PAIR(ud) l_end_pair((lua_State*)(ud)) | ||
| 179 | #define ON_ADD_ARRAY(ud) l_add_array((lua_State*)(ud)) | ||
| 180 | #define ON_ADD_INDEX(ud, i) l_add_index((lua_State*)(ud), i) | ||
| 181 | #define ON_ADD_STRING(ud, s, sz) l_add_string((lua_State*)(ud), s, sz) | ||
| 182 | #define ON_ADD_FLOAT(ud, f) l_add_float((lua_State*)(ud), f) | ||
| 183 | #define ON_ADD_INTEGER(ud, i) l_add_integer((lua_State*)(ud), i) | ||
| 184 | #define ON_ADD_BOOLEAN(ud, b) l_add_boolean((lua_State*)(ud), b) | ||
| 185 | #define ON_ADD_NULL(ud) l_add_null((lua_State*)(ud)) | ||
| 186 | #define ON_ERROR(ud, msg) l_error((lua_State*)(ud), msg) | ||
| 187 | |||
| 188 | //------------------------------------- | ||
| 189 | // 解析json,这部分代码与Lua无关,是通用的解析器;如果要移植这部分代码,需要把 //>>> 开头的注释去掉 | ||
| 190 | |||
| 191 | // 错误消息的大小 | ||
| 192 | #define ERRMSG_SIZE 256 | ||
| 193 | |||
| 194 | // json解析器 | ||
| 195 | typedef struct { | ||
| 196 | const char *str; // json字符串 | ||
| 197 | const char *ptr; // json字符串解析指针 | ||
| 198 | void *ud; // 解析事件的用户数据 | ||
| 199 | membuffer_t buff; // 临时缓存 | ||
| 200 | int curdepth; // 当前层次 | ||
| 201 | int maxdepth; // 最大层次 | ||
| 202 | int allowcomment; // 是否允许注释 | ||
| 203 | char errmsg[ERRMSG_SIZE]; // 保存错误消息 | ||
| 204 | //>>>jmp_buf jb; // 用于实现从解析中出错直接跳出 | ||
| 205 | } json_parser_t; | ||
| 206 | |||
| 207 | static inline void parser_init(json_parser_t *parser, const char *str, size_t size, void *ud, | ||
| 208 | int maxdepth, int allowcomment) { | ||
| 209 | membuffer_init(&parser->buff); | ||
| 210 | membuffer_ensure_space(&parser->buff, size); | ||
| 211 | parser->str = str; | ||
| 212 | parser->ptr = str; | ||
| 213 | parser->ud = ud; | ||
| 214 | parser->maxdepth = maxdepth; | ||
| 215 | parser->curdepth = 0; | ||
| 216 | parser->allowcomment = allowcomment; | ||
| 217 | } | ||
| 218 | |||
| 219 | static inline void parser_free(json_parser_t *parser) { | ||
| 220 | membuffer_free(&parser->buff); | ||
| 221 | } | ||
| 222 | |||
| 223 | // 抛出错误 | ||
| 224 | static void parser_throw_error(json_parser_t *parser, const char *fmt, ...) { | ||
| 225 | membuffer_free(&parser->buff); | ||
| 226 | va_list arg; | ||
| 227 | va_start(arg, fmt); | ||
| 228 | vsnprintf(parser->errmsg, ERRMSG_SIZE, fmt, arg); | ||
| 229 | va_end(arg); | ||
| 230 | ON_ERROR(parser->ud, parser->errmsg); | ||
| 231 | // 直接跳出解析代码,由于Lua的lua_error也是用longjmp,所以下面的代码没有机会执行到。但其他语言就不一定。 | ||
| 232 | //>>>longjmp(parser->jb, 1); | ||
| 233 | } | ||
| 234 | |||
| 235 | // 辅助宏 | ||
| 236 | #define peekchar(p) (*(p)->ptr) | ||
| 237 | #define skipchar(p) (++(p)->ptr) | ||
| 238 | #define get_and_next(p) (*(p)->ptr++) | ||
| 239 | #define next_and_get(p) (*(++(p)->ptr)) | ||
| 240 | #define savechar(p, c) membuffer_putc_unsafe(&(p)->buff, (c)) | ||
| 241 | #define currpos(p) (size_t)((p)->ptr - (p)->str) | ||
| 242 | |||
| 243 | // 取解析到的错误内容 | ||
| 244 | static const char* parser_error_content(json_parser_t *p) { | ||
| 245 | size_t n = currpos(p); | ||
| 246 | if (n > 50) n = 50; // 调整这个数获得更长的内容 | ||
| 247 | membuffer_reset(&p->buff); | ||
| 248 | membuffer_putb(&p->buff, p->ptr - n, n); | ||
| 249 | membuffer_putc(&p->buff, '\0'); | ||
| 250 | return p->buff.b; | ||
| 251 | } | ||
| 252 | |||
| 253 | // 增加深度 | ||
| 254 | static inline void parser_add_depth(json_parser_t *p) { | ||
| 255 | p->curdepth++; | ||
| 256 | if (p->curdepth >= p->maxdepth) | ||
| 257 | parser_throw_error(p, "Too many nested data, max depth is %d, at: %s[:%lu]", p->maxdepth, | ||
| 258 | parser_error_content(p), currpos(p)); | ||
| 259 | } | ||
| 260 | |||
| 261 | static inline void parser_skip_whitespaces(json_parser_t *p) { | ||
| 262 | // colin: 要支持注释,请将下面注释去掉 | ||
| 263 | // if (likely(!p->allowcomment)) { | ||
| 264 | char ch = peekchar(p); | ||
| 265 | while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') | ||
| 266 | ch = next_and_get(p); | ||
| 267 | // } else { | ||
| 268 | // char ch = peekchar(p); | ||
| 269 | // for (;;) { | ||
| 270 | // while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') | ||
| 271 | // ch = next_and_get(p); | ||
| 272 | // if (ch == '/') { | ||
| 273 | // ch = next_and_get(p); | ||
| 274 | // if (ch == '/') { | ||
| 275 | // ch = next_and_get(p); | ||
| 276 | // while (ch != '\n' && ch != '\r' && ch != '\0') | ||
| 277 | // ch = next_and_get(p); | ||
| 278 | // continue; | ||
| 279 | // } else { | ||
| 280 | // parser_throw_error(p, "Invalid comment, at: %s[:%lu]", parser_error_content(p), currpos(p)); | ||
| 281 | // } | ||
| 282 | // } | ||
| 283 | // break; | ||
| 284 | // } | ||
| 285 | // } | ||
| 286 | } | ||
| 287 | |||
| 288 | static inline void parser_expect_char(json_parser_t *p, char c) { | ||
| 289 | if (likely(peekchar(p) == c)) | ||
| 290 | skipchar(p); | ||
| 291 | else | ||
| 292 | parser_throw_error(p, "Expect '%c' at: %s[:%lu]", c, parser_error_content(p), currpos(p)); | ||
| 293 | } | ||
| 294 | |||
| 295 | static inline void parser_process_false(json_parser_t *p) { | ||
| 296 | if (likely(p->ptr[0] == 'a' && p->ptr[1] == 'l' && p->ptr[2] == 's' && p->ptr[3] == 'e')) { | ||
| 297 | p->ptr += 4; | ||
| 298 | ON_ADD_BOOLEAN(p->ud, 0); | ||
| 299 | } else { | ||
| 300 | parser_throw_error(p, "Invalid boolean, at: %s[:%lu]", parser_error_content(p), currpos(p)); | ||
| 301 | } | ||
| 302 | } | ||
| 303 | |||
| 304 | static inline void parser_process_true(json_parser_t *p) { | ||
| 305 | if (likely(p->ptr[0] == 'r' && p->ptr[1] == 'u' && p->ptr[2] == 'e')) { | ||
| 306 | p->ptr += 3; | ||
| 307 | ON_ADD_BOOLEAN(p->ud, 1); | ||
| 308 | } else { | ||
| 309 | parser_throw_error(p, "Invalid boolean, at: %s[:%lu]", parser_error_content(p), currpos(p)); | ||
| 310 | } | ||
| 311 | } | ||
| 312 | |||
| 313 | static inline void parser_process_null(json_parser_t *p) { | ||
| 314 | if (likely(p->ptr[0] == 'u' && p->ptr[1] == 'l' && p->ptr[2] == 'l')) { | ||
| 315 | p->ptr += 3; | ||
| 316 | ON_ADD_NULL(p->ud); | ||
| 317 | } else { | ||
| 318 | parser_throw_error(p, "Invalid null, at: %s[:%lu]", parser_error_content(p), currpos(p)); | ||
| 319 | } | ||
| 320 | } | ||
| 321 | |||
| 322 | static inline uint32_t parser_read_hex(json_parser_t *p) { | ||
| 323 | uint32_t cp = 0; | ||
| 324 | unsigned char ch; | ||
| 325 | int i = 4; | ||
| 326 | while (i--) { | ||
| 327 | ch = (unsigned char)get_and_next(p); | ||
| 328 | if ('0' <= ch && ch <= '9') | ||
| 329 | ch -= '0'; | ||
| 330 | else if (ch >= 'a' && ch <= 'f') | ||
| 331 | ch = ch - 'a' + 10; | ||
| 332 | else if (ch >= 'A' && ch <= 'F') | ||
| 333 | ch = ch - 'A' + 10; | ||
| 334 | else { | ||
| 335 | parser_throw_error(p, "Invalid utf8 escape sequence, at: %s[:%lu]", parser_error_content(p), currpos(p)); | ||
| 336 | return cp; | ||
| 337 | } | ||
| 338 | cp = (cp << 4) + ch; | ||
| 339 | } | ||
| 340 | return cp; | ||
| 341 | } | ||
| 342 | |||
| 343 | static inline void parser_process_utf8esc(json_parser_t *p) { | ||
| 344 | uint32_t cp = parser_read_hex(p); | ||
| 345 | // UTF-16 surrogate pairs, see https://unicodebook.readthedocs.io/unicode_encodings.html#utf-16-surrogate-pairs | ||
| 346 | if (cp >= 0xD800 && cp <= 0xDBFF) { | ||
| 347 | char p0 = p->ptr[0]; | ||
| 348 | char p1 = p->ptr[1]; | ||
| 349 | if (p0 != '\\' || p1 != 'u') | ||
| 350 | parser_throw_error(p, "Invalid utf8 escape sequence, at: %s[:%lu]", parser_error_content(p), currpos(p)); | ||
| 351 | p->ptr += 2; | ||
| 352 | uint32_t cp2 = parser_read_hex(p); | ||
| 353 | if (cp2 < 0xDC00 || cp2 > 0xDFFF) | ||
| 354 | parser_throw_error(p, "Invalid utf8 escape sequence, at: %s[:%lu]", parser_error_content(p), currpos(p)); | ||
| 355 | cp = 0x10000 + (((cp & 0x03FF) << 10) | (cp2 & 0x03FF)); | ||
| 356 | } | ||
| 357 | if (cp < 0x80) { | ||
| 358 | membuffer_putc_unsafe(&p->buff, (char)cp); | ||
| 359 | } else if (cp < 0x800) { | ||
| 360 | membuffer_putc_unsafe(&p->buff, 0xC0 | (cp >> 6)); | ||
| 361 | membuffer_putc_unsafe(&p->buff, 0x80 | (cp & 0x3F)); | ||
| 362 | } else if (cp < 0x10000) { | ||
| 363 | membuffer_putc_unsafe(&p->buff, 0xE0 | (cp >> 12)); | ||
| 364 | membuffer_putc_unsafe(&p->buff, 0x80 | ((cp >> 6) & 0x3F)); | ||
| 365 | membuffer_putc_unsafe(&p->buff, 0x80 | (cp & 0x3F)); | ||
| 366 | } else { | ||
| 367 | membuffer_putc_unsafe(&p->buff, 0xF0 | (cp >> 18)); | ||
| 368 | membuffer_putc_unsafe(&p->buff, 0x80 | ((cp >> 12) & 0x3F)); | ||
| 369 | membuffer_putc_unsafe(&p->buff, 0x80 | ((cp >> 6) & 0x3F)); | ||
| 370 | membuffer_putc_unsafe(&p->buff, 0x80 | (cp & 0x3F)); | ||
| 371 | } | ||
| 372 | } | ||
| 373 | |||
| 374 | static const char escape2char[256] = { | ||
| 375 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0~19 | ||
| 376 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\"',0, 0, 0, 0, 0, // 20~39 | ||
| 377 | 0, 0, 0, 0, 0, 0, 0, '/', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40~59 | ||
| 378 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60~79 | ||
| 379 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\',0, 0, 0, 0, 0, '\b',0, // 80~99 | ||
| 380 | 0, 0, '\f',0, 0, 0, 0, 0, 0, 0, '\n',0, 0, 0, '\r',0, '\t',0, 0, 0, // 100~119 | ||
| 381 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 120~139 | ||
| 382 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 140~159 | ||
| 383 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160~179 | ||
| 384 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 180~199 | ||
| 385 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 200~219 | ||
| 386 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 220~239 | ||
| 387 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 240~256 | ||
| 388 | }; | ||
| 389 | |||
| 390 | static inline void parser_process_string(json_parser_t *p) { | ||
| 391 | membuffer_reset(&p->buff); | ||
| 392 | char ch = get_and_next(p); | ||
| 393 | for (;;) { | ||
| 394 | if (ch == '\\') { | ||
| 395 | unsigned char nch = (unsigned char)peekchar(p); | ||
| 396 | if (likely(escape2char[nch])) { | ||
| 397 | savechar(p, escape2char[nch]); | ||
| 398 | skipchar(p); | ||
| 399 | } else if (nch == 'u') { | ||
| 400 | skipchar(p); | ||
| 401 | parser_process_utf8esc(p); | ||
| 402 | } else { | ||
| 403 | parser_throw_error(p, "Invalid escape sequence, at: %s[:%lu]", parser_error_content(p), currpos(p)); | ||
| 404 | } | ||
| 405 | } else if (ch == '"') { | ||
| 406 | break; | ||
| 407 | } else if ((unsigned char)ch < 0x20) { | ||
| 408 | parser_throw_error(p, "Invalid string, at: %s[:%lu]", parser_error_content(p), currpos(p)); | ||
| 409 | } else { | ||
| 410 | savechar(p, ch); | ||
| 411 | } | ||
| 412 | ch = get_and_next(p); | ||
| 413 | } | ||
| 414 | } | ||
| 415 | |||
| 416 | #define invalid_number(p) parser_throw_error(p, "Invalid value, at: %s[:%lu]", parser_error_content(p), currpos(p)) | ||
| 417 | #define MAXBY10 (int64_t)(922337203685477580) | ||
| 418 | #define MAXLASTD (int)(7) | ||
| 419 | static double powersOf10[] = {10., 100., 1.0e4, 1.0e8, 1.0e16, 1.0e32, 1.0e64, 1.0e128, 1.0e256}; | ||
| 420 | static inline void parser_process_number(json_parser_t *p, char ch) { | ||
| 421 | double db; // 浮点数 | ||
| 422 | int64_t in = 0; // 整型值 | ||
| 423 | int isdouble = 0; // 是否是浮点数 | ||
| 424 | int neg = 0; // 是否是负数 | ||
| 425 | int exponent = 0; // 指数位数 | ||
| 426 | |||
| 427 | if (ch == '-') { // 负值 | ||
| 428 | neg = 1; | ||
| 429 | ch = get_and_next(p); | ||
| 430 | } | ||
| 431 | if (unlikely(ch == '0')) { // 0开头的后面只能是:.eE或\0 | ||
| 432 | ch = peekchar(p); | ||
| 433 | } else if (likely(ch >= '1' && ch <= '9')) { | ||
| 434 | in = ch - '0'; | ||
| 435 | ch = peekchar(p); | ||
| 436 | while (ch >= '0' && ch <= '9') { | ||
| 437 | if (unlikely(in >= MAXBY10 && (in > MAXBY10 || (ch - '0') > MAXLASTD + neg))) { // 更大的数字就用浮点数表示 | ||
| 438 | isdouble = 1; | ||
| 439 | db = (double)in; | ||
| 440 | do { | ||
| 441 | db = db * 10.0 + (ch - '0'); | ||
| 442 | ch = next_and_get(p); | ||
| 443 | } while (ch >= '0' && ch <= '9'); | ||
| 444 | break; | ||
| 445 | } | ||
| 446 | in = in * 10 + (ch - '0'); | ||
| 447 | ch = next_and_get(p); | ||
| 448 | } | ||
| 449 | } else { | ||
| 450 | invalid_number(p); | ||
| 451 | } | ||
| 452 | |||
| 453 | if (ch == '.') { // 小数点部分 | ||
| 454 | if (likely(!isdouble)) { | ||
| 455 | isdouble = 1; | ||
| 456 | db = (double)in; | ||
| 457 | } | ||
| 458 | ch = next_and_get(p); | ||
| 459 | if (unlikely(!(ch >= '0' && ch <= '9'))) | ||
| 460 | invalid_number(p); // .后面一定是数字 | ||
| 461 | do { | ||
| 462 | db = db * 10. + (ch - '0'); | ||
| 463 | exponent--; | ||
| 464 | ch = next_and_get(p); | ||
| 465 | } while (ch >= '0' && ch <= '9'); | ||
| 466 | } | ||
| 467 | |||
| 468 | if (ch == 'e' || ch == 'E') { // 指数部分 | ||
| 469 | if (!isdouble) { // 有e强制认为是浮点数 | ||
| 470 | isdouble = 1; | ||
| 471 | db = (double)in; | ||
| 472 | } | ||
| 473 | ch = next_and_get(p); | ||
| 474 | int eneg = 0; | ||
| 475 | if (ch == '-') { | ||
| 476 | eneg = 1; | ||
| 477 | ch = next_and_get(p); | ||
| 478 | } else if (ch == '+') { | ||
| 479 | ch = next_and_get(p); | ||
| 480 | } | ||
| 481 | if (unlikely(!(ch >= '0' && ch <= '9'))) | ||
| 482 | invalid_number(p); // 后面一定是数字 | ||
| 483 | int exp = 0; | ||
| 484 | do { | ||
| 485 | exp = exp * 10. + (ch - '0'); | ||
| 486 | ch = next_and_get(p); | ||
| 487 | } while (ch >= '0' && ch <= '9'); | ||
| 488 | exponent += eneg ? (-exp) : (exp); | ||
| 489 | } | ||
| 490 | |||
| 491 | if (isdouble) { | ||
| 492 | int n = exponent < 0 ? -exponent : exponent; | ||
| 493 | if (unlikely(n>511)) | ||
| 494 | n = 511; // inf | ||
| 495 | double p10 = 1.0; | ||
| 496 | double *d; | ||
| 497 | for (d = powersOf10; n != 0; n >>= 1, d += 1) { | ||
| 498 | if (n & 1) p10 *= *d; | ||
| 499 | } | ||
| 500 | if (exponent < 0) | ||
| 501 | db /= p10; | ||
| 502 | else | ||
| 503 | db *= p10; | ||
| 504 | if (neg) db = -db; | ||
| 505 | ON_ADD_FLOAT(p->ud, db); | ||
| 506 | } else { | ||
| 507 | if (neg) in = -in; | ||
| 508 | ON_ADD_INTEGER(p->ud, in); | ||
| 509 | } | ||
| 510 | } | ||
| 511 | |||
| 512 | static void parser_process_value(json_parser_t *p); | ||
| 513 | |||
| 514 | static inline void parser_process_object(json_parser_t *p) { | ||
| 515 | parser_add_depth(p); | ||
| 516 | ON_ADD_OBJECT(p->ud); | ||
| 517 | parser_skip_whitespaces(p); | ||
| 518 | char ch = peekchar(p); | ||
| 519 | if (ch == '}') { | ||
| 520 | skipchar(p); | ||
| 521 | p->curdepth--; | ||
| 522 | return; | ||
| 523 | } | ||
| 524 | for (;;) { | ||
| 525 | parser_expect_char(p, '"'); | ||
| 526 | parser_process_string(p); // key | ||
| 527 | ON_BEGIN_PAIR(p->ud, p->buff.b, p->buff.sz); | ||
| 528 | |||
| 529 | parser_skip_whitespaces(p); | ||
| 530 | parser_expect_char(p, ':'); | ||
| 531 | |||
| 532 | parser_process_value(p); // value | ||
| 533 | ON_END_PAIR(p->ud); | ||
| 534 | |||
| 535 | parser_skip_whitespaces(p); | ||
| 536 | if (peekchar(p) == '}') { | ||
| 537 | skipchar(p); | ||
| 538 | p->curdepth--; | ||
| 539 | return; | ||
| 540 | } | ||
| 541 | else { | ||
| 542 | parser_expect_char(p, ','); | ||
| 543 | parser_skip_whitespaces(p); | ||
| 544 | } | ||
| 545 | } | ||
| 546 | } | ||
| 547 | |||
| 548 | static inline void parser_process_array(json_parser_t *p) { | ||
| 549 | parser_add_depth(p); | ||
| 550 | ON_ADD_ARRAY(p->ud); | ||
| 551 | parser_skip_whitespaces(p); | ||
| 552 | char ch = peekchar(p); | ||
| 553 | if (ch == ']') { | ||
| 554 | skipchar(p); | ||
| 555 | p->curdepth--; | ||
| 556 | return; | ||
| 557 | } | ||
| 558 | int i; | ||
| 559 | for (i = 0; ;++i) { | ||
| 560 | parser_process_value(p); | ||
| 561 | ON_ADD_INDEX(p->ud, i); | ||
| 562 | |||
| 563 | parser_skip_whitespaces(p); | ||
| 564 | if (peekchar(p) == ']') { | ||
| 565 | skipchar(p); | ||
| 566 | p->curdepth--; | ||
| 567 | return; | ||
| 568 | } | ||
| 569 | else { | ||
| 570 | parser_expect_char(p, ','); | ||
| 571 | } | ||
| 572 | } | ||
| 573 | } | ||
| 574 | |||
| 575 | static void parser_process_value(json_parser_t *p) { | ||
| 576 | parser_skip_whitespaces(p); | ||
| 577 | char ch = get_and_next(p); | ||
| 578 | switch (ch) { | ||
| 579 | case 'f': | ||
| 580 | parser_process_false(p); | ||
| 581 | break; | ||
| 582 | case 't': | ||
| 583 | parser_process_true(p); | ||
| 584 | break; | ||
| 585 | case 'n': | ||
| 586 | parser_process_null(p); | ||
| 587 | break; | ||
| 588 | case '"': | ||
| 589 | parser_process_string(p); | ||
| 590 | ON_ADD_STRING(p->ud, p->buff.b, p->buff.sz); | ||
| 591 | break; | ||
| 592 | case '{': | ||
| 593 | parser_process_object(p); | ||
| 594 | break; | ||
| 595 | case '[': | ||
| 596 | parser_process_array(p); | ||
| 597 | break; | ||
| 598 | default: | ||
| 599 | parser_process_number(p, ch); | ||
| 600 | break; | ||
| 601 | } | ||
| 602 | } | ||
| 603 | |||
| 604 | // 解析json文本 | ||
| 605 | static void parser_do_parse(const char *str, size_t size, void *ud, int maxdepth, int allowcomment) { | ||
| 606 | json_parser_t p; | ||
| 607 | parser_init(&p, str, size, ud, maxdepth, allowcomment); | ||
| 608 | //>>>if (setjmp(p.jb) == 0) { | ||
| 609 | parser_process_value(&p); | ||
| 610 | parser_skip_whitespaces(&p); | ||
| 611 | if (peekchar(&p) != '\0') { | ||
| 612 | parser_throw_error(&p, "Expect '<eof>' but got '%c', at: %s[:%lu]", peekchar(&p), | ||
| 613 | parser_error_content(&p), currpos(&p)); | ||
| 614 | } | ||
| 615 | parser_free(&p); | ||
| 616 | //>>>} | ||
| 617 | } | ||
| 618 | |||
| 619 | //----------------------------------------------------------------------------- | ||
| 620 | // dumpper | ||
| 621 | |||
| 622 | typedef struct { | ||
| 623 | membuffer_t buff; // 临时缓存 | ||
| 624 | int maxdepth; // 最大层次 | ||
| 625 | int format; // 是否格式化 | ||
| 626 | int empty_as_array; // 空表是否当成数组 | ||
| 627 | int num_as_str; // 数字Key转为字符串 | ||
| 628 | char errmsg[ERRMSG_SIZE]; // 保存错误消息 | ||
| 629 | } json_dumpper_t; | ||
| 630 | |||
| 631 | // 足够转换数字的缓存大小 | ||
| 632 | #define NUMBER_BUFF_SZ 44 | ||
| 633 | #define INTEGER_BUFF_SZ 24 | ||
| 634 | |||
| 635 | // 抛出错误 | ||
| 636 | static void dumpper_throw_error(json_dumpper_t *d, lua_State *L, const char *fmt, ...) { | ||
| 637 | membuffer_free(&d->buff); | ||
| 638 | va_list arg; | ||
| 639 | va_start(arg, fmt); | ||
| 640 | vsnprintf(d->errmsg, ERRMSG_SIZE, fmt, arg); | ||
| 641 | va_end(arg); | ||
| 642 | luaL_error(L, d->errmsg); | ||
| 643 | } | ||
| 644 | |||
| 645 | #if LUA_VERSION_NUM > 501 | ||
| 646 | static void dumpper_process_integer(json_dumpper_t *d, lua_State *L, int idx) { | ||
| 647 | char nbuff[INTEGER_BUFF_SZ]; | ||
| 648 | int i = INTEGER_BUFF_SZ; | ||
| 649 | membuffer_ensure_space(&d->buff, INTEGER_BUFF_SZ); | ||
| 650 | int64_t x = (int64_t)lua_tointeger(L, idx); | ||
| 651 | uint64_t ux = (uint64_t)x; | ||
| 652 | if (x < 0) { | ||
| 653 | membuffer_putc_unsafe(&d->buff, '-'); | ||
| 654 | ux = ~ux + 1; | ||
| 655 | } | ||
| 656 | do { | ||
| 657 | nbuff[--i] = (ux % 10) + '0'; | ||
| 658 | } while (ux /= 10); | ||
| 659 | membuffer_putb_unsafe(&d->buff, nbuff+i, INTEGER_BUFF_SZ-i); | ||
| 660 | } | ||
| 661 | #endif | ||
| 662 | |||
| 663 | static void dumpper_process_number(json_dumpper_t *d, lua_State *L, int idx) { | ||
| 664 | lua_Number num = lua_tonumber(L, idx); | ||
| 665 | if (isinf(num) || isnan(num)) | ||
| 666 | dumpper_throw_error(d, L, "The number is NaN or Infinity"); | ||
| 667 | membuffer_ensure_space(&d->buff, NUMBER_BUFF_SZ); | ||
| 668 | char *p = membuffer_getp(&d->buff); | ||
| 669 | int len = sprintf(p, LUA_NUMBER_FMT, num); | ||
| 670 | membuffer_add_size(&d->buff, len); | ||
| 671 | } | ||
| 672 | |||
| 673 | // 字符转义表 | ||
| 674 | static const char char2escape[256] = { | ||
| 675 | 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', 'u', 'u', 'u', 'u', // 0~19 | ||
| 676 | 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 0, 0, '"', 0, 0, 0, 0, 0, // 20~39 | ||
| 677 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40~59 | ||
| 678 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60~79 | ||
| 679 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0, 0, 0, 0, 0, // 80~99 | ||
| 680 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 100~119 | ||
| 681 | 0, 0, 0, 0, 0, 0, 0, 'u', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 120~139 | ||
| 682 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 140~159 | ||
| 683 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160~179 | ||
| 684 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 180~199 | ||
| 685 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 200~219 | ||
| 686 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 220~239 | ||
| 687 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 240~256 | ||
| 688 | }; | ||
| 689 | static const char hex_digits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; | ||
| 690 | |||
| 691 | static void dumpper_process_string(json_dumpper_t *d, lua_State *L, int idx) { | ||
| 692 | membuffer_t *buff = &d->buff; | ||
| 693 | size_t len, i; | ||
| 694 | const char *str = lua_tolstring(L, idx, &len); | ||
| 695 | membuffer_ensure_space(buff, len * 6 + 2); | ||
| 696 | membuffer_putc_unsafe(buff, '\"'); | ||
| 697 | char esc; | ||
| 698 | unsigned char ch; | ||
| 699 | for (i = 0; i < len; ++i) { | ||
| 700 | ch = (unsigned char)str[i]; | ||
| 701 | esc = char2escape[ch]; | ||
| 702 | if (likely(!esc)) | ||
| 703 | membuffer_putc_unsafe(buff, (char)ch); | ||
| 704 | else { | ||
| 705 | membuffer_putc_unsafe(buff, '\\'); | ||
| 706 | membuffer_putc_unsafe(buff, esc); | ||
| 707 | if (esc == 'u') { | ||
| 708 | membuffer_putc_unsafe(buff, '0'); | ||
| 709 | membuffer_putc_unsafe(buff, '0'); | ||
| 710 | membuffer_putc_unsafe(buff, hex_digits[(unsigned char)esc >> 4]); | ||
| 711 | membuffer_putc_unsafe(buff, hex_digits[(unsigned char)esc & 0xF]); | ||
| 712 | } | ||
| 713 | } | ||
| 714 | } | ||
| 715 | membuffer_putc_unsafe(buff, '\"'); | ||
| 716 | } | ||
| 717 | |||
| 718 | static void dumpper_process_value(json_dumpper_t *d, lua_State *L, int depth); | ||
| 719 | |||
| 720 | static int dumpper_check_array(json_dumpper_t *d, lua_State *L, int *len) { | ||
| 721 | int asize = lua_objlen(L, -1); | ||
| 722 | if (asize > 0) { | ||
| 723 | lua_pushinteger(L, asize); | ||
| 724 | if (lua_next(L, -2) == 0) { | ||
| 725 | *len = asize; | ||
| 726 | return 1; | ||
| 727 | } else { | ||
| 728 | lua_pop(L, 2); | ||
| 729 | return 0; | ||
| 730 | } | ||
| 731 | } else { | ||
| 732 | lua_pushnil(L); | ||
| 733 | if (lua_next(L, -2) == 0) { | ||
| 734 | *len = asize; | ||
| 735 | return d->empty_as_array; | ||
| 736 | } else { | ||
| 737 | lua_pop(L, 2); | ||
| 738 | return 0; | ||
| 739 | } | ||
| 740 | } | ||
| 741 | } | ||
| 742 | |||
| 743 | static inline void dumpper_add_indent(json_dumpper_t *d, int count) { | ||
| 744 | membuffer_ensure_space(&d->buff, count); | ||
| 745 | int i; | ||
| 746 | for (i = 0; i < count; ++i) | ||
| 747 | membuffer_putc_unsafe(&d->buff, '\t'); | ||
| 748 | } | ||
| 749 | |||
| 750 | static void dumpper_process_array(json_dumpper_t *d, lua_State *L, int len, int depth) { | ||
| 751 | membuffer_t *buff = &d->buff; | ||
| 752 | membuffer_putc(buff, '['); | ||
| 753 | |||
| 754 | int i; | ||
| 755 | for (i = 1; i <= len; ++i) { | ||
| 756 | if (unlikely(d->format && i == 1)) membuffer_putc(buff, '\n'); | ||
| 757 | lua_rawgeti(L, -1, i); | ||
| 758 | if (unlikely(d->format)) dumpper_add_indent(d, depth); | ||
| 759 | dumpper_process_value(d, L, depth); | ||
| 760 | lua_pop(L, 1); | ||
| 761 | if (i < len) | ||
| 762 | membuffer_putc(buff, ','); | ||
| 763 | if (unlikely(d->format)) membuffer_putc(buff, '\n'); | ||
| 764 | } | ||
| 765 | |||
| 766 | if (unlikely(d->format && i > 1)) dumpper_add_indent(d, depth-1); | ||
| 767 | membuffer_putc(buff, ']'); | ||
| 768 | } | ||
| 769 | |||
| 770 | static void dumpper_process_object(json_dumpper_t *d, lua_State *L, int depth) { | ||
| 771 | membuffer_t *buff = &d->buff; | ||
| 772 | membuffer_putc(buff, '{'); | ||
| 773 | |||
| 774 | int ktp; | ||
| 775 | int comma = 0; | ||
| 776 | lua_pushnil(L); // t nil | ||
| 777 | while (lua_next(L, -2) != 0) { // t k v | ||
| 778 | if (comma) { | ||
| 779 | membuffer_putc(buff, ','); | ||
| 780 | if (unlikely(d->format)) membuffer_putc(buff, '\n'); | ||
| 781 | } else { | ||
| 782 | comma = 1; | ||
| 783 | if (unlikely(d->format)) membuffer_putc(buff, '\n'); | ||
| 784 | } | ||
| 785 | // key | ||
| 786 | ktp = lua_type(L, -2); | ||
| 787 | if (ktp == LUA_TSTRING) { | ||
| 788 | if (unlikely(d->format)) dumpper_add_indent(d, depth); | ||
| 789 | dumpper_process_string(d, L, -2); | ||
| 790 | if (likely(!d->format)) | ||
| 791 | membuffer_putc(buff, ':'); | ||
| 792 | else | ||
| 793 | membuffer_putb(buff, " : ", 3); | ||
| 794 | } else if (ktp == LUA_TNUMBER && d->num_as_str) { | ||
| 795 | if (unlikely(d->format)) dumpper_add_indent(d, depth); | ||
| 796 | membuffer_putc(buff, '\"'); | ||
| 797 | #if LUA_VERSION_NUM > 501 | ||
| 798 | if (lua_isinteger(L, -2)) | ||
| 799 | dumpper_process_integer(d, L, -2); | ||
| 800 | else | ||
| 801 | #endif | ||
| 802 | dumpper_process_number(d, L, -2); | ||
| 803 | if (likely(!d->format)) | ||
| 804 | membuffer_putb(buff, "\":", 2); | ||
| 805 | else | ||
| 806 | membuffer_putb(buff, "\" : ", 4); | ||
| 807 | } else { | ||
| 808 | dumpper_throw_error(d, L, "Table key must be a string"); | ||
| 809 | } | ||
| 810 | // value | ||
| 811 | dumpper_process_value(d, L, depth); | ||
| 812 | lua_pop(L, 1); | ||
| 813 | } | ||
| 814 | if (unlikely(d->format && comma)) { | ||
| 815 | membuffer_putc(buff, '\n'); | ||
| 816 | dumpper_add_indent(d, depth-1); | ||
| 817 | } | ||
| 818 | membuffer_putc(buff, '}'); | ||
| 819 | } | ||
| 820 | |||
| 821 | static inline void dumpper_process_table(json_dumpper_t *d, lua_State *L, int depth) { | ||
| 822 | depth++; | ||
| 823 | if (depth > d->maxdepth) | ||
| 824 | dumpper_throw_error(d, L, "Too many nested data, max depth is %d", d->maxdepth); | ||
| 825 | luaL_checkstack(L, 6, NULL); | ||
| 826 | |||
| 827 | int len; | ||
| 828 | if (dumpper_check_array(d, L, &len)) | ||
| 829 | dumpper_process_array(d, L, len, depth); | ||
| 830 | else | ||
| 831 | dumpper_process_object(d, L, depth); | ||
| 832 | } | ||
| 833 | |||
| 834 | static void dumpper_process_value(json_dumpper_t *d, lua_State *L, int depth) { | ||
| 835 | int tp = lua_type(L, -1); | ||
| 836 | switch (tp) { | ||
| 837 | case LUA_TSTRING: | ||
| 838 | dumpper_process_string(d, L, -1); | ||
| 839 | break; | ||
| 840 | case LUA_TNUMBER: | ||
| 841 | #if LUA_VERSION_NUM > 501 | ||
| 842 | if (lua_isinteger(L, -1)) | ||
| 843 | dumpper_process_integer(d, L, -1); | ||
| 844 | else | ||
| 845 | #endif | ||
| 846 | dumpper_process_number(d, L, -1); | ||
| 847 | break; | ||
| 848 | case LUA_TBOOLEAN: | ||
| 849 | if (lua_toboolean(L, -1)) | ||
| 850 | membuffer_putb(&d->buff, "true", 4); | ||
| 851 | else | ||
| 852 | membuffer_putb(&d->buff, "false", 5); | ||
| 853 | break; | ||
| 854 | case LUA_TTABLE: | ||
| 855 | dumpper_process_table(d, L, depth); | ||
| 856 | break; | ||
| 857 | case LUA_TNIL: | ||
| 858 | membuffer_putb(&d->buff, "null", 4); | ||
| 859 | break; | ||
| 860 | case LUA_TLIGHTUSERDATA: | ||
| 861 | if (lua_touserdata(L, -1) == NULL) { | ||
| 862 | membuffer_putb(&d->buff, "null", 4); | ||
| 863 | break; | ||
| 864 | } | ||
| 865 | goto error; | ||
| 866 | default: | ||
| 867 | error: | ||
| 868 | dumpper_throw_error(d, L, "Unsupport type %s", lua_typename(L, tp)); | ||
| 869 | } | ||
| 870 | } | ||
| 871 | |||
| 872 | //----------------------------------------------------------------------------- | ||
| 873 | // 接口 | ||
| 874 | #define DEF_MAX_DEPTH 128 | ||
| 875 | |||
| 876 | // 从字符串加载:json.decode(str, maxdepth) -> obj | ||
| 877 | // 要求字符串必须以0结尾 | ||
| 878 | int colibc_json_decode(lua_State *L) { | ||
| 879 | size_t size; | ||
| 880 | const char *str = luaL_checklstring(L, 1, &size); | ||
| 881 | int maxdepth = (int)luaL_optinteger(L, 2, DEF_MAX_DEPTH); | ||
| 882 | int allowcomment = lua_toboolean(L, 3); | ||
| 883 | parser_do_parse(str, size, L, maxdepth, allowcomment); | ||
| 884 | return 1; | ||
| 885 | } | ||
| 886 | |||
| 887 | // 保存到字符串: json.encode(obj) -> str | ||
| 888 | int colibc_json_encode(lua_State *L) { | ||
| 889 | luaL_checkany(L, 1); | ||
| 890 | json_dumpper_t dumpper; | ||
| 891 | membuffer_init(&dumpper.buff); | ||
| 892 | dumpper.format = lua_toboolean(L, 2); | ||
| 893 | dumpper.empty_as_array = lua_toboolean(L, 3); | ||
| 894 | dumpper.num_as_str = lua_toboolean(L, 4); | ||
| 895 | dumpper.maxdepth = (int)luaL_optinteger(L, 5, DEF_MAX_DEPTH); | ||
| 896 | |||
| 897 | lua_settop(L, 1); | ||
| 898 | dumpper_process_value(&dumpper, L, 0); | ||
| 899 | lua_pushlstring(L, dumpper.buff.b, dumpper.buff.sz); | ||
| 900 | membuffer_free(&dumpper.buff); | ||
| 901 | return 1; | ||
| 902 | } | ||
| 903 | |||
| 904 | static const luaL_Reg lib[] = { | ||
| 905 | {"decode", colibc_json_decode}, | ||
| 906 | {"encode", colibc_json_encode}, | ||
| 907 | {NULL, NULL}, | ||
| 908 | }; | ||
| 909 | |||
| 910 | LUALIB_API int luaopen_colibc_json(lua_State* L) { | ||
| 911 | #if LUA_VERSION_NUM > 501 | ||
| 912 | luaL_newlib(L, lib); // json | ||
| 913 | #else | ||
| 914 | lua_getglobal(L, "package"); // package | ||
| 915 | lua_getfield(L, -1, "loaded"); // package loaded | ||
| 916 | lua_createtable(L, 0, 0); // package loaded json | ||
| 917 | lua_pushvalue(L, -1); // package loaded json json | ||
| 918 | lua_setfield(L, -3, "cojson"); // loaded["cojson"] = json, package loaded json | ||
| 919 | luaL_register(L, NULL, lib); // package loaded json | ||
| 920 | #endif | ||
| 921 | // json.null | ||
| 922 | lua_pushlightuserdata(L, NULL); | ||
| 923 | lua_setfield(L, -2, "null"); | ||
| 924 | return 1; | ||
| 925 | } | ||
diff --git a/src/3rdParty/utf8cpp.h b/src/3rdParty/utf8cpp.h new file mode 100755 index 0000000..76f0fa1 --- /dev/null +++ b/src/3rdParty/utf8cpp.h | |||
| @@ -0,0 +1,1277 @@ | |||
| 1 | // Copyright 2006 Nemanja Trifunovic | ||
| 2 | |||
| 3 | /* | ||
| 4 | Permission is hereby granted, free of charge, to any person or organization | ||
| 5 | obtaining a copy of the software and accompanying documentation covered by | ||
| 6 | this license (the "Software") to use, reproduce, display, distribute, | ||
| 7 | execute, and transmit the Software, and to prepare derivative works of the | ||
| 8 | Software, and to permit third-parties to whom the Software is furnished to | ||
| 9 | do so, all subject to the following: | ||
| 10 | |||
| 11 | The copyright notices in the Software and this entire statement, including | ||
| 12 | the above license grant, this restriction and the following disclaimer, | ||
| 13 | must be included in all copies of the Software, in whole or in part, and | ||
| 14 | all derivative works of the Software, unless such copies or derivative | ||
| 15 | works are solely in the form of machine-executable object code generated by | ||
| 16 | a source language processor. | ||
| 17 | |||
| 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 20 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT | ||
| 21 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE | ||
| 22 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, | ||
| 23 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 24 | DEALINGS IN THE SOFTWARE. | ||
| 25 | */ | ||
| 26 | |||
| 27 | |||
| 28 | #ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 | ||
| 29 | #define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 | ||
| 30 | |||
| 31 | /* | ||
| 32 | To control the C++ language version used by the library, you can define UTF_CPP_CPLUSPLUS macro | ||
| 33 | and set it to one of the values used by the __cplusplus predefined macro. | ||
| 34 | |||
| 35 | For instance, | ||
| 36 | #define UTF_CPP_CPLUSPLUS 199711L | ||
| 37 | will cause the UTF-8 CPP library to use only types and language features available in the C++ 98 standard. | ||
| 38 | Some library features will be disabled. | ||
| 39 | |||
| 40 | If you leave UTF_CPP_CPLUSPLUS undefined, it will be internally assigned to __cplusplus. | ||
| 41 | */ | ||
| 42 | |||
| 43 | #include <iterator> | ||
| 44 | #include <cstring> | ||
| 45 | #include <string> | ||
| 46 | |||
| 47 | // Determine the C++ standard version. | ||
| 48 | // If the user defines UTF_CPP_CPLUSPLUS, use that. | ||
| 49 | // Otherwise, trust the unreliable predefined macro __cplusplus | ||
| 50 | |||
| 51 | #if !defined UTF_CPP_CPLUSPLUS | ||
| 52 | #define UTF_CPP_CPLUSPLUS __cplusplus | ||
| 53 | #endif | ||
| 54 | |||
| 55 | #if UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later | ||
| 56 | #define UTF_CPP_OVERRIDE override | ||
| 57 | #define UTF_CPP_NOEXCEPT noexcept | ||
| 58 | #define UTF_CPP_STATIC_ASSERT(condition) static_assert(condition, "UTFCPP static assert"); | ||
| 59 | #else // C++ 98/03 | ||
| 60 | #define UTF_CPP_OVERRIDE | ||
| 61 | #define UTF_CPP_NOEXCEPT throw() | ||
| 62 | // Simulate static_assert: | ||
| 63 | template<bool> struct UtfCppCompileTimeAssert; | ||
| 64 | template<> struct UtfCppCompileTimeAssert <true> { }; | ||
| 65 | #define UTF_CPP_STATIC_ASSERT(condition) (UtfCppCompileTimeAssert <(condition) != 0>()) | ||
| 66 | #endif // C++ 11 or later | ||
| 67 | |||
| 68 | |||
| 69 | namespace utf8 | ||
| 70 | { | ||
| 71 | // The typedefs for 8-bit, 16-bit and 32-bit code units | ||
| 72 | #if UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later | ||
| 73 | #if UTF_CPP_CPLUSPLUS >= 202002L // C++ 20 or later | ||
| 74 | typedef char8_t utfchar8_t; | ||
| 75 | #else // C++ 11/14/17 | ||
| 76 | typedef unsigned char utfchar8_t; | ||
| 77 | #endif | ||
| 78 | typedef char16_t utfchar16_t; | ||
| 79 | typedef char32_t utfchar32_t; | ||
| 80 | #else // C++ 98/03 | ||
| 81 | typedef unsigned char utfchar8_t; | ||
| 82 | typedef unsigned short utfchar16_t; | ||
| 83 | typedef unsigned int utfchar32_t; | ||
| 84 | #endif // C++ 11 or later | ||
| 85 | |||
| 86 | // Helper code - not intended to be directly called by the library users. May be changed at any time | ||
| 87 | namespace internal | ||
| 88 | { | ||
| 89 | // Unicode constants | ||
| 90 | // Leading (high) surrogates: 0xd800 - 0xdbff | ||
| 91 | // Trailing (low) surrogates: 0xdc00 - 0xdfff | ||
| 92 | const utfchar16_t LEAD_SURROGATE_MIN = 0xd800u; | ||
| 93 | const utfchar16_t LEAD_SURROGATE_MAX = 0xdbffu; | ||
| 94 | const utfchar16_t TRAIL_SURROGATE_MIN = 0xdc00u; | ||
| 95 | const utfchar16_t TRAIL_SURROGATE_MAX = 0xdfffu; | ||
| 96 | const utfchar16_t LEAD_OFFSET = 0xd7c0u; // LEAD_SURROGATE_MIN - (0x10000 >> 10) | ||
| 97 | const utfchar32_t SURROGATE_OFFSET = 0xfca02400u; // 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN | ||
| 98 | |||
| 99 | // Maximum valid value for a Unicode code point | ||
| 100 | const utfchar32_t CODE_POINT_MAX = 0x0010ffffu; | ||
| 101 | |||
| 102 | template<typename octet_type> | ||
| 103 | inline utfchar8_t mask8(octet_type oc) | ||
| 104 | { | ||
| 105 | return static_cast<utfchar8_t>(0xff & oc); | ||
| 106 | } | ||
| 107 | |||
| 108 | template<typename u16_type> | ||
| 109 | inline utfchar16_t mask16(u16_type oc) | ||
| 110 | { | ||
| 111 | return static_cast<utfchar16_t>(0xffff & oc); | ||
| 112 | } | ||
| 113 | |||
| 114 | template<typename octet_type> | ||
| 115 | inline bool is_trail(octet_type oc) | ||
| 116 | { | ||
| 117 | return ((utf8::internal::mask8(oc) >> 6) == 0x2); | ||
| 118 | } | ||
| 119 | |||
| 120 | inline bool is_lead_surrogate(utfchar32_t cp) | ||
| 121 | { | ||
| 122 | return (cp >= static_cast<utfchar32_t>(LEAD_SURROGATE_MIN) && cp <= static_cast<utfchar32_t>(LEAD_SURROGATE_MAX)); | ||
| 123 | } | ||
| 124 | |||
| 125 | inline bool is_trail_surrogate(utfchar32_t cp) | ||
| 126 | { | ||
| 127 | return (cp >= static_cast<utfchar32_t>(TRAIL_SURROGATE_MIN) && cp <= static_cast<utfchar32_t>(TRAIL_SURROGATE_MAX)); | ||
| 128 | } | ||
| 129 | |||
| 130 | inline bool is_surrogate(utfchar32_t cp) | ||
| 131 | { | ||
| 132 | return (cp >= static_cast<utfchar32_t>(LEAD_SURROGATE_MIN) && cp <= static_cast<utfchar32_t>(TRAIL_SURROGATE_MAX)); | ||
| 133 | } | ||
| 134 | |||
| 135 | inline bool is_code_point_valid(utfchar32_t cp) | ||
| 136 | { | ||
| 137 | return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp)); | ||
| 138 | } | ||
| 139 | |||
| 140 | inline bool is_in_bmp(utfchar32_t cp) | ||
| 141 | { | ||
| 142 | return cp < utfchar32_t(0x10000); | ||
| 143 | } | ||
| 144 | |||
| 145 | template <typename octet_iterator> | ||
| 146 | int sequence_length(octet_iterator lead_it) | ||
| 147 | { | ||
| 148 | const utfchar8_t lead = utf8::internal::mask8(*lead_it); | ||
| 149 | if (lead < 0x80) | ||
| 150 | return 1; | ||
| 151 | else if ((lead >> 5) == 0x6) | ||
| 152 | return 2; | ||
| 153 | else if ((lead >> 4) == 0xe) | ||
| 154 | return 3; | ||
| 155 | else if ((lead >> 3) == 0x1e) | ||
| 156 | return 4; | ||
| 157 | else | ||
| 158 | return 0; | ||
| 159 | } | ||
| 160 | |||
| 161 | inline bool is_overlong_sequence(utfchar32_t cp, int length) | ||
| 162 | { | ||
| 163 | if (cp < 0x80) { | ||
| 164 | if (length != 1) | ||
| 165 | return true; | ||
| 166 | } | ||
| 167 | else if (cp < 0x800) { | ||
| 168 | if (length != 2) | ||
| 169 | return true; | ||
| 170 | } | ||
| 171 | else if (cp < 0x10000) { | ||
| 172 | if (length != 3) | ||
| 173 | return true; | ||
| 174 | } | ||
| 175 | return false; | ||
| 176 | } | ||
| 177 | |||
| 178 | enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT}; | ||
| 179 | |||
| 180 | /// Helper for get_sequence_x | ||
| 181 | template <typename octet_iterator> | ||
| 182 | utf_error increase_safely(octet_iterator& it, const octet_iterator end) | ||
| 183 | { | ||
| 184 | if (++it == end) | ||
| 185 | return NOT_ENOUGH_ROOM; | ||
| 186 | |||
| 187 | if (!utf8::internal::is_trail(*it)) | ||
| 188 | return INCOMPLETE_SEQUENCE; | ||
| 189 | |||
| 190 | return UTF8_OK; | ||
| 191 | } | ||
| 192 | |||
| 193 | #define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;} | ||
| 194 | |||
| 195 | /// get_sequence_x functions decode utf-8 sequences of the length x | ||
| 196 | template <typename octet_iterator> | ||
| 197 | utf_error get_sequence_1(octet_iterator& it, octet_iterator end, utfchar32_t& code_point) | ||
| 198 | { | ||
| 199 | if (it == end) | ||
| 200 | return NOT_ENOUGH_ROOM; | ||
| 201 | |||
| 202 | code_point = static_cast<utfchar32_t>(utf8::internal::mask8(*it)); | ||
| 203 | |||
| 204 | return UTF8_OK; | ||
| 205 | } | ||
| 206 | |||
| 207 | template <typename octet_iterator> | ||
| 208 | utf_error get_sequence_2(octet_iterator& it, octet_iterator end, utfchar32_t& code_point) | ||
| 209 | { | ||
| 210 | if (it == end) | ||
| 211 | return NOT_ENOUGH_ROOM; | ||
| 212 | |||
| 213 | code_point = static_cast<utfchar32_t>(utf8::internal::mask8(*it)); | ||
| 214 | |||
| 215 | UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) | ||
| 216 | |||
| 217 | code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f); | ||
| 218 | |||
| 219 | return UTF8_OK; | ||
| 220 | } | ||
| 221 | |||
| 222 | template <typename octet_iterator> | ||
| 223 | utf_error get_sequence_3(octet_iterator& it, octet_iterator end, utfchar32_t& code_point) | ||
| 224 | { | ||
| 225 | if (it == end) | ||
| 226 | return NOT_ENOUGH_ROOM; | ||
| 227 | |||
| 228 | code_point = static_cast<utfchar32_t>(utf8::internal::mask8(*it)); | ||
| 229 | |||
| 230 | UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) | ||
| 231 | |||
| 232 | code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff); | ||
| 233 | |||
| 234 | UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) | ||
| 235 | |||
| 236 | code_point = static_cast<utfchar32_t>(code_point + ((*it) & 0x3f)); | ||
| 237 | |||
| 238 | return UTF8_OK; | ||
| 239 | } | ||
| 240 | |||
| 241 | template <typename octet_iterator> | ||
| 242 | utf_error get_sequence_4(octet_iterator& it, octet_iterator end, utfchar32_t& code_point) | ||
| 243 | { | ||
| 244 | if (it == end) | ||
| 245 | return NOT_ENOUGH_ROOM; | ||
| 246 | |||
| 247 | code_point = static_cast<utfchar32_t>(utf8::internal::mask8(*it)); | ||
| 248 | |||
| 249 | UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) | ||
| 250 | |||
| 251 | code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff); | ||
| 252 | |||
| 253 | UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) | ||
| 254 | |||
| 255 | code_point = static_cast<utfchar32_t>(code_point + ((utf8::internal::mask8(*it) << 6) & 0xfff)); | ||
| 256 | |||
| 257 | UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) | ||
| 258 | |||
| 259 | code_point = static_cast<utfchar32_t>(code_point + ((*it) & 0x3f)); | ||
| 260 | |||
| 261 | return UTF8_OK; | ||
| 262 | } | ||
| 263 | |||
| 264 | #undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR | ||
| 265 | |||
| 266 | template <typename octet_iterator> | ||
| 267 | utf_error validate_next(octet_iterator& it, octet_iterator end, utfchar32_t& code_point) | ||
| 268 | { | ||
| 269 | if (it == end) | ||
| 270 | return NOT_ENOUGH_ROOM; | ||
| 271 | |||
| 272 | // Save the original value of it so we can go back in case of failure | ||
| 273 | // Of course, it does not make much sense with i.e. stream iterators | ||
| 274 | octet_iterator original_it = it; | ||
| 275 | |||
| 276 | utfchar32_t cp = 0; | ||
| 277 | // Determine the sequence length based on the lead octet | ||
| 278 | const int length = utf8::internal::sequence_length(it); | ||
| 279 | |||
| 280 | // Get trail octets and calculate the code point | ||
| 281 | utf_error err = UTF8_OK; | ||
| 282 | switch (length) { | ||
| 283 | case 0: | ||
| 284 | return INVALID_LEAD; | ||
| 285 | case 1: | ||
| 286 | err = utf8::internal::get_sequence_1(it, end, cp); | ||
| 287 | break; | ||
| 288 | case 2: | ||
| 289 | err = utf8::internal::get_sequence_2(it, end, cp); | ||
| 290 | break; | ||
| 291 | case 3: | ||
| 292 | err = utf8::internal::get_sequence_3(it, end, cp); | ||
| 293 | break; | ||
| 294 | case 4: | ||
| 295 | err = utf8::internal::get_sequence_4(it, end, cp); | ||
| 296 | break; | ||
| 297 | } | ||
| 298 | |||
| 299 | if (err == UTF8_OK) { | ||
| 300 | // Decoding succeeded. Now, security checks... | ||
| 301 | if (utf8::internal::is_code_point_valid(cp)) { | ||
| 302 | if (!utf8::internal::is_overlong_sequence(cp, length)){ | ||
| 303 | // Passed! Return here. | ||
| 304 | code_point = cp; | ||
| 305 | ++it; | ||
| 306 | return UTF8_OK; | ||
| 307 | } | ||
| 308 | else | ||
| 309 | err = OVERLONG_SEQUENCE; | ||
| 310 | } | ||
| 311 | else | ||
| 312 | err = INVALID_CODE_POINT; | ||
| 313 | } | ||
| 314 | |||
| 315 | // Failure branch - restore the original value of the iterator | ||
| 316 | it = original_it; | ||
| 317 | return err; | ||
| 318 | } | ||
| 319 | |||
| 320 | template <typename octet_iterator> | ||
| 321 | inline utf_error validate_next(octet_iterator& it, octet_iterator end) { | ||
| 322 | utfchar32_t ignored; | ||
| 323 | return utf8::internal::validate_next(it, end, ignored); | ||
| 324 | } | ||
| 325 | |||
| 326 | template <typename word_iterator> | ||
| 327 | utf_error validate_next16(word_iterator& it, word_iterator end, utfchar32_t& code_point) | ||
| 328 | { | ||
| 329 | // Make sure the iterator dereferences a large enough type | ||
| 330 | typedef typename std::iterator_traits<word_iterator>::value_type word_type; | ||
| 331 | UTF_CPP_STATIC_ASSERT(sizeof(word_type) >= sizeof(utfchar16_t)); | ||
| 332 | // Check the edge case: | ||
| 333 | if (it == end) | ||
| 334 | return NOT_ENOUGH_ROOM; | ||
| 335 | // Save the original value of it so we can go back in case of failure | ||
| 336 | // Of course, it does not make much sense with i.e. stream iterators | ||
| 337 | word_iterator original_it = it; | ||
| 338 | |||
| 339 | utf_error err = UTF8_OK; | ||
| 340 | |||
| 341 | const utfchar16_t first_word = *it++; | ||
| 342 | if (!is_surrogate(first_word)) { | ||
| 343 | code_point = first_word; | ||
| 344 | return UTF8_OK; | ||
| 345 | } | ||
| 346 | else { | ||
| 347 | if (it == end) | ||
| 348 | err = NOT_ENOUGH_ROOM; | ||
| 349 | else if (is_lead_surrogate(first_word)) { | ||
| 350 | const utfchar16_t second_word = *it++; | ||
| 351 | if (is_trail_surrogate(static_cast<utfchar32_t>(second_word))) { | ||
| 352 | code_point = static_cast<utfchar32_t>(first_word << 10) + static_cast<utfchar32_t>(second_word) + SURROGATE_OFFSET; | ||
| 353 | return UTF8_OK; | ||
| 354 | } else | ||
| 355 | err = INCOMPLETE_SEQUENCE; | ||
| 356 | |||
| 357 | } else { | ||
| 358 | err = INVALID_LEAD; | ||
| 359 | } | ||
| 360 | } | ||
| 361 | // error branch | ||
| 362 | it = original_it; | ||
| 363 | return err; | ||
| 364 | } | ||
| 365 | |||
| 366 | // Internal implementation of both checked and unchecked append() function | ||
| 367 | // This function will be invoked by the overloads below, as they will know | ||
| 368 | // the octet_type. | ||
| 369 | template <typename octet_iterator, typename octet_type> | ||
| 370 | octet_iterator append(utfchar32_t cp, octet_iterator result) { | ||
| 371 | if (cp < 0x80) // one octet | ||
| 372 | *(result++) = static_cast<octet_type>(cp); | ||
| 373 | else if (cp < 0x800) { // two octets | ||
| 374 | *(result++) = static_cast<octet_type>((cp >> 6) | 0xc0); | ||
| 375 | *(result++) = static_cast<octet_type>((cp & 0x3f) | 0x80); | ||
| 376 | } | ||
| 377 | else if (cp < 0x10000) { // three octets | ||
| 378 | *(result++) = static_cast<octet_type>((cp >> 12) | 0xe0); | ||
| 379 | *(result++) = static_cast<octet_type>(((cp >> 6) & 0x3f) | 0x80); | ||
| 380 | *(result++) = static_cast<octet_type>((cp & 0x3f) | 0x80); | ||
| 381 | } | ||
| 382 | else { // four octets | ||
| 383 | *(result++) = static_cast<octet_type>((cp >> 18) | 0xf0); | ||
| 384 | *(result++) = static_cast<octet_type>(((cp >> 12) & 0x3f)| 0x80); | ||
| 385 | *(result++) = static_cast<octet_type>(((cp >> 6) & 0x3f) | 0x80); | ||
| 386 | *(result++) = static_cast<octet_type>((cp & 0x3f) | 0x80); | ||
| 387 | } | ||
| 388 | return result; | ||
| 389 | } | ||
| 390 | |||
| 391 | // One of the following overloads will be invoked from the API calls | ||
| 392 | |||
| 393 | // A simple (but dangerous) case: the caller appends byte(s) to a char array | ||
| 394 | inline char* append(utfchar32_t cp, char* result) { | ||
| 395 | return append<char*, char>(cp, result); | ||
| 396 | } | ||
| 397 | |||
| 398 | // Hopefully, most common case: the caller uses back_inserter | ||
| 399 | // i.e. append(cp, std::back_inserter(str)); | ||
| 400 | template<typename container_type> | ||
| 401 | std::back_insert_iterator<container_type> append | ||
| 402 | (utfchar32_t cp, std::back_insert_iterator<container_type> result) { | ||
| 403 | return append<std::back_insert_iterator<container_type>, | ||
| 404 | typename container_type::value_type>(cp, result); | ||
| 405 | } | ||
| 406 | |||
| 407 | // The caller uses some other kind of output operator - not covered above | ||
| 408 | // Note that in this case we are not able to determine octet_type | ||
| 409 | // so we assume it's utfchar8_t; that can cause a conversion warning if we are wrong. | ||
| 410 | template <typename octet_iterator> | ||
| 411 | octet_iterator append(utfchar32_t cp, octet_iterator result) { | ||
| 412 | return append<octet_iterator, utfchar8_t>(cp, result); | ||
| 413 | } | ||
| 414 | |||
| 415 | // Internal implementation of both checked and unchecked append16() function | ||
| 416 | // This function will be invoked by the overloads below, as they will know | ||
| 417 | // the word_type. | ||
| 418 | template <typename word_iterator, typename word_type> | ||
| 419 | word_iterator append16(utfchar32_t cp, word_iterator result) { | ||
| 420 | UTF_CPP_STATIC_ASSERT(sizeof(word_type) >= sizeof(utfchar16_t)); | ||
| 421 | if (is_in_bmp(cp)) | ||
| 422 | *(result++) = static_cast<word_type>(cp); | ||
| 423 | else { | ||
| 424 | // Code points from the supplementary planes are encoded via surrogate pairs | ||
| 425 | *(result++) = static_cast<word_type>(LEAD_OFFSET + (cp >> 10)); | ||
| 426 | *(result++) = static_cast<word_type>(TRAIL_SURROGATE_MIN + (cp & 0x3FF)); | ||
| 427 | } | ||
| 428 | return result; | ||
| 429 | } | ||
| 430 | |||
| 431 | // Hopefully, most common case: the caller uses back_inserter | ||
| 432 | // i.e. append16(cp, std::back_inserter(str)); | ||
| 433 | template<typename container_type> | ||
| 434 | std::back_insert_iterator<container_type> append16 | ||
| 435 | (utfchar32_t cp, std::back_insert_iterator<container_type> result) { | ||
| 436 | return append16<std::back_insert_iterator<container_type>, | ||
| 437 | typename container_type::value_type>(cp, result); | ||
| 438 | } | ||
| 439 | |||
| 440 | // The caller uses some other kind of output operator - not covered above | ||
| 441 | // Note that in this case we are not able to determine word_type | ||
| 442 | // so we assume it's utfchar16_t; that can cause a conversion warning if we are wrong. | ||
| 443 | template <typename word_iterator> | ||
| 444 | word_iterator append16(utfchar32_t cp, word_iterator result) { | ||
| 445 | return append16<word_iterator, utfchar16_t>(cp, result); | ||
| 446 | } | ||
| 447 | |||
| 448 | } // namespace internal | ||
| 449 | |||
| 450 | /// The library API - functions intended to be called by the users | ||
| 451 | |||
| 452 | // Byte order mark | ||
| 453 | const utfchar8_t bom[] = {0xef, 0xbb, 0xbf}; | ||
| 454 | |||
| 455 | template <typename octet_iterator> | ||
| 456 | octet_iterator find_invalid(octet_iterator start, octet_iterator end) | ||
| 457 | { | ||
| 458 | octet_iterator result = start; | ||
| 459 | while (result != end) { | ||
| 460 | utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end); | ||
| 461 | if (err_code != internal::UTF8_OK) | ||
| 462 | return result; | ||
| 463 | } | ||
| 464 | return result; | ||
| 465 | } | ||
| 466 | |||
| 467 | inline const char* find_invalid(const char* str) | ||
| 468 | { | ||
| 469 | const char* end = str + std::strlen(str); | ||
| 470 | return find_invalid(str, end); | ||
| 471 | } | ||
| 472 | |||
| 473 | inline std::size_t find_invalid(const std::string& s) | ||
| 474 | { | ||
| 475 | std::string::const_iterator invalid = find_invalid(s.begin(), s.end()); | ||
| 476 | return (invalid == s.end()) ? std::string::npos : static_cast<std::size_t>(invalid - s.begin()); | ||
| 477 | } | ||
| 478 | |||
| 479 | template <typename octet_iterator> | ||
| 480 | inline bool is_valid(octet_iterator start, octet_iterator end) | ||
| 481 | { | ||
| 482 | return (utf8::find_invalid(start, end) == end); | ||
| 483 | } | ||
| 484 | |||
| 485 | inline bool is_valid(const char* str) | ||
| 486 | { | ||
| 487 | return (*(utf8::find_invalid(str)) == '\0'); | ||
| 488 | } | ||
| 489 | |||
| 490 | inline bool is_valid(const std::string& s) | ||
| 491 | { | ||
| 492 | return is_valid(s.begin(), s.end()); | ||
| 493 | } | ||
| 494 | |||
| 495 | |||
| 496 | |||
| 497 | template <typename octet_iterator> | ||
| 498 | inline bool starts_with_bom (octet_iterator it, octet_iterator end) | ||
| 499 | { | ||
| 500 | return ( | ||
| 501 | ((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) && | ||
| 502 | ((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) && | ||
| 503 | ((it != end) && (utf8::internal::mask8(*it)) == bom[2]) | ||
| 504 | ); | ||
| 505 | } | ||
| 506 | |||
| 507 | inline bool starts_with_bom(const std::string& s) | ||
| 508 | { | ||
| 509 | return starts_with_bom(s.begin(), s.end()); | ||
| 510 | } | ||
| 511 | } // namespace utf8 | ||
| 512 | |||
| 513 | #include <stdexcept> | ||
| 514 | |||
| 515 | namespace utf8 | ||
| 516 | { | ||
| 517 | // Base for the exceptions that may be thrown from the library | ||
| 518 | class exception : public ::std::exception { | ||
| 519 | }; | ||
| 520 | |||
| 521 | // Exceptions that may be thrown from the library functions. | ||
| 522 | class invalid_code_point : public exception { | ||
| 523 | utfchar32_t cp; | ||
| 524 | public: | ||
| 525 | invalid_code_point(utfchar32_t codepoint) : cp(codepoint) {} | ||
| 526 | virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid code point"; } | ||
| 527 | utfchar32_t code_point() const {return cp;} | ||
| 528 | }; | ||
| 529 | |||
| 530 | class invalid_utf8 : public exception { | ||
| 531 | utfchar8_t u8; | ||
| 532 | public: | ||
| 533 | invalid_utf8 (utfchar8_t u) : u8(u) {} | ||
| 534 | invalid_utf8 (char c) : u8(static_cast<utfchar8_t>(c)) {} | ||
| 535 | virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid UTF-8"; } | ||
| 536 | utfchar8_t utf8_octet() const {return u8;} | ||
| 537 | }; | ||
| 538 | |||
| 539 | class invalid_utf16 : public exception { | ||
| 540 | utfchar16_t u16; | ||
| 541 | public: | ||
| 542 | invalid_utf16 (utfchar16_t u) : u16(u) {} | ||
| 543 | virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid UTF-16"; } | ||
| 544 | utfchar16_t utf16_word() const {return u16;} | ||
| 545 | }; | ||
| 546 | |||
| 547 | class not_enough_room : public exception { | ||
| 548 | public: | ||
| 549 | virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Not enough space"; } | ||
| 550 | }; | ||
| 551 | |||
| 552 | /// The library API - functions intended to be called by the users | ||
| 553 | |||
| 554 | template <typename octet_iterator> | ||
| 555 | octet_iterator append(utfchar32_t cp, octet_iterator result) | ||
| 556 | { | ||
| 557 | if (!utf8::internal::is_code_point_valid(cp)) | ||
| 558 | throw invalid_code_point(cp); | ||
| 559 | |||
| 560 | return internal::append(cp, result); | ||
| 561 | } | ||
| 562 | |||
| 563 | inline void append(utfchar32_t cp, std::string& s) | ||
| 564 | { | ||
| 565 | append(cp, std::back_inserter(s)); | ||
| 566 | } | ||
| 567 | |||
| 568 | template <typename word_iterator> | ||
| 569 | word_iterator append16(utfchar32_t cp, word_iterator result) | ||
| 570 | { | ||
| 571 | if (!utf8::internal::is_code_point_valid(cp)) | ||
| 572 | throw invalid_code_point(cp); | ||
| 573 | |||
| 574 | return internal::append16(cp, result); | ||
| 575 | } | ||
| 576 | |||
| 577 | template <typename octet_iterator, typename output_iterator> | ||
| 578 | output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, utfchar32_t replacement) | ||
| 579 | { | ||
| 580 | while (start != end) { | ||
| 581 | octet_iterator sequence_start = start; | ||
| 582 | internal::utf_error err_code = utf8::internal::validate_next(start, end); | ||
| 583 | switch (err_code) { | ||
| 584 | case internal::UTF8_OK : | ||
| 585 | for (octet_iterator it = sequence_start; it != start; ++it) | ||
| 586 | *out++ = *it; | ||
| 587 | break; | ||
| 588 | case internal::NOT_ENOUGH_ROOM: | ||
| 589 | out = utf8::append (replacement, out); | ||
| 590 | start = end; | ||
| 591 | break; | ||
| 592 | case internal::INVALID_LEAD: | ||
| 593 | out = utf8::append (replacement, out); | ||
| 594 | ++start; | ||
| 595 | break; | ||
| 596 | case internal::INCOMPLETE_SEQUENCE: | ||
| 597 | case internal::OVERLONG_SEQUENCE: | ||
| 598 | case internal::INVALID_CODE_POINT: | ||
| 599 | out = utf8::append (replacement, out); | ||
| 600 | ++start; | ||
| 601 | // just one replacement mark for the sequence | ||
| 602 | while (start != end && utf8::internal::is_trail(*start)) | ||
| 603 | ++start; | ||
| 604 | break; | ||
| 605 | } | ||
| 606 | } | ||
| 607 | return out; | ||
| 608 | } | ||
| 609 | |||
| 610 | template <typename octet_iterator, typename output_iterator> | ||
| 611 | inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out) | ||
| 612 | { | ||
| 613 | static const utfchar32_t replacement_marker = static_cast<utfchar32_t>(utf8::internal::mask16(0xfffd)); | ||
| 614 | return utf8::replace_invalid(start, end, out, replacement_marker); | ||
| 615 | } | ||
| 616 | |||
| 617 | inline std::string replace_invalid(const std::string& s, utfchar32_t replacement) | ||
| 618 | { | ||
| 619 | std::string result; | ||
| 620 | replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement); | ||
| 621 | return result; | ||
| 622 | } | ||
| 623 | |||
| 624 | inline std::string replace_invalid(const std::string& s) | ||
| 625 | { | ||
| 626 | std::string result; | ||
| 627 | replace_invalid(s.begin(), s.end(), std::back_inserter(result)); | ||
| 628 | return result; | ||
| 629 | } | ||
| 630 | |||
| 631 | template <typename octet_iterator> | ||
| 632 | utfchar32_t next(octet_iterator& it, octet_iterator end) | ||
| 633 | { | ||
| 634 | utfchar32_t cp = 0; | ||
| 635 | internal::utf_error err_code = utf8::internal::validate_next(it, end, cp); | ||
| 636 | switch (err_code) { | ||
| 637 | case internal::UTF8_OK : | ||
| 638 | break; | ||
| 639 | case internal::NOT_ENOUGH_ROOM : | ||
| 640 | throw not_enough_room(); | ||
| 641 | case internal::INVALID_LEAD : | ||
| 642 | case internal::INCOMPLETE_SEQUENCE : | ||
| 643 | case internal::OVERLONG_SEQUENCE : | ||
| 644 | throw invalid_utf8(static_cast<utfchar8_t>(*it)); | ||
| 645 | case internal::INVALID_CODE_POINT : | ||
| 646 | throw invalid_code_point(cp); | ||
| 647 | } | ||
| 648 | return cp; | ||
| 649 | } | ||
| 650 | |||
| 651 | template <typename word_iterator> | ||
| 652 | utfchar32_t next16(word_iterator& it, word_iterator end) | ||
| 653 | { | ||
| 654 | utfchar32_t cp = 0; | ||
| 655 | internal::utf_error err_code = utf8::internal::validate_next16(it, end, cp); | ||
| 656 | if (err_code == internal::NOT_ENOUGH_ROOM) | ||
| 657 | throw not_enough_room(); | ||
| 658 | return cp; | ||
| 659 | } | ||
| 660 | |||
| 661 | template <typename octet_iterator> | ||
| 662 | utfchar32_t peek_next(octet_iterator it, octet_iterator end) | ||
| 663 | { | ||
| 664 | return utf8::next(it, end); | ||
| 665 | } | ||
| 666 | |||
| 667 | template <typename octet_iterator> | ||
| 668 | utfchar32_t prior(octet_iterator& it, octet_iterator start) | ||
| 669 | { | ||
| 670 | // can't do much if it == start | ||
| 671 | if (it == start) | ||
| 672 | throw not_enough_room(); | ||
| 673 | |||
| 674 | octet_iterator end = it; | ||
| 675 | // Go back until we hit either a lead octet or start | ||
| 676 | while (utf8::internal::is_trail(*(--it))) | ||
| 677 | if (it == start) | ||
| 678 | throw invalid_utf8(*it); // error - no lead byte in the sequence | ||
| 679 | return utf8::peek_next(it, end); | ||
| 680 | } | ||
| 681 | |||
| 682 | template <typename octet_iterator, typename distance_type> | ||
| 683 | void advance (octet_iterator& it, distance_type n, octet_iterator end) | ||
| 684 | { | ||
| 685 | const distance_type zero(0); | ||
| 686 | if (n < zero) { | ||
| 687 | // backward | ||
| 688 | for (distance_type i = n; i < zero; ++i) | ||
| 689 | utf8::prior(it, end); | ||
| 690 | } else { | ||
| 691 | // forward | ||
| 692 | for (distance_type i = zero; i < n; ++i) | ||
| 693 | utf8::next(it, end); | ||
| 694 | } | ||
| 695 | } | ||
| 696 | |||
| 697 | template <typename octet_iterator> | ||
| 698 | typename std::iterator_traits<octet_iterator>::difference_type | ||
| 699 | distance (octet_iterator first, octet_iterator last) | ||
| 700 | { | ||
| 701 | typename std::iterator_traits<octet_iterator>::difference_type dist; | ||
| 702 | for (dist = 0; first < last; ++dist) | ||
| 703 | utf8::next(first, last); | ||
| 704 | return dist; | ||
| 705 | } | ||
| 706 | |||
| 707 | template <typename u16bit_iterator, typename octet_iterator> | ||
| 708 | octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) | ||
| 709 | { | ||
| 710 | while (start != end) { | ||
| 711 | utfchar32_t cp = static_cast<utfchar32_t>(utf8::internal::mask16(*start++)); | ||
| 712 | // Take care of surrogate pairs first | ||
| 713 | if (utf8::internal::is_lead_surrogate(cp)) { | ||
| 714 | if (start != end) { | ||
| 715 | const utfchar32_t trail_surrogate = static_cast<utfchar32_t>(utf8::internal::mask16(*start++)); | ||
| 716 | if (utf8::internal::is_trail_surrogate(trail_surrogate)) | ||
| 717 | cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; | ||
| 718 | else | ||
| 719 | throw invalid_utf16(static_cast<utfchar16_t>(trail_surrogate)); | ||
| 720 | } | ||
| 721 | else | ||
| 722 | throw invalid_utf16(static_cast<utfchar16_t>(cp)); | ||
| 723 | |||
| 724 | } | ||
| 725 | // Lone trail surrogate | ||
| 726 | else if (utf8::internal::is_trail_surrogate(cp)) | ||
| 727 | throw invalid_utf16(static_cast<utfchar16_t>(cp)); | ||
| 728 | |||
| 729 | result = utf8::append(cp, result); | ||
| 730 | } | ||
| 731 | return result; | ||
| 732 | } | ||
| 733 | |||
| 734 | template <typename u16bit_iterator, typename octet_iterator> | ||
| 735 | u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) | ||
| 736 | { | ||
| 737 | while (start < end) { | ||
| 738 | const utfchar32_t cp = utf8::next(start, end); | ||
| 739 | if (cp > 0xffff) { //make a surrogate pair | ||
| 740 | *result++ = static_cast<utfchar16_t>((cp >> 10) + internal::LEAD_OFFSET); | ||
| 741 | *result++ = static_cast<utfchar16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); | ||
| 742 | } | ||
| 743 | else | ||
| 744 | *result++ = static_cast<utfchar16_t>(cp); | ||
| 745 | } | ||
| 746 | return result; | ||
| 747 | } | ||
| 748 | |||
| 749 | template <typename octet_iterator, typename u32bit_iterator> | ||
| 750 | octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) | ||
| 751 | { | ||
| 752 | while (start != end) | ||
| 753 | result = utf8::append(*(start++), result); | ||
| 754 | |||
| 755 | return result; | ||
| 756 | } | ||
| 757 | |||
| 758 | template <typename octet_iterator, typename u32bit_iterator> | ||
| 759 | u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) | ||
| 760 | { | ||
| 761 | while (start < end) | ||
| 762 | (*result++) = utf8::next(start, end); | ||
| 763 | |||
| 764 | return result; | ||
| 765 | } | ||
| 766 | |||
| 767 | // The iterator class | ||
| 768 | template <typename octet_iterator> | ||
| 769 | class iterator { | ||
| 770 | octet_iterator it; | ||
| 771 | octet_iterator range_start; | ||
| 772 | octet_iterator range_end; | ||
| 773 | public: | ||
| 774 | typedef utfchar32_t value_type; | ||
| 775 | typedef utfchar32_t* pointer; | ||
| 776 | typedef utfchar32_t& reference; | ||
| 777 | typedef std::ptrdiff_t difference_type; | ||
| 778 | typedef std::bidirectional_iterator_tag iterator_category; | ||
| 779 | iterator () {} | ||
| 780 | explicit iterator (const octet_iterator& octet_it, | ||
| 781 | const octet_iterator& rangestart, | ||
| 782 | const octet_iterator& rangeend) : | ||
| 783 | it(octet_it), range_start(rangestart), range_end(rangeend) | ||
| 784 | { | ||
| 785 | if (it < range_start || it > range_end) | ||
| 786 | throw std::out_of_range("Invalid utf-8 iterator position"); | ||
| 787 | } | ||
| 788 | // the default "big three" are OK | ||
| 789 | octet_iterator base () const { return it; } | ||
| 790 | utfchar32_t operator * () const | ||
| 791 | { | ||
| 792 | octet_iterator temp = it; | ||
| 793 | return utf8::next(temp, range_end); | ||
| 794 | } | ||
| 795 | bool operator == (const iterator& rhs) const | ||
| 796 | { | ||
| 797 | if (range_start != rhs.range_start || range_end != rhs.range_end) | ||
| 798 | throw std::logic_error("Comparing utf-8 iterators defined with different ranges"); | ||
| 799 | return (it == rhs.it); | ||
| 800 | } | ||
| 801 | bool operator != (const iterator& rhs) const | ||
| 802 | { | ||
| 803 | return !(operator == (rhs)); | ||
| 804 | } | ||
| 805 | iterator& operator ++ () | ||
| 806 | { | ||
| 807 | utf8::next(it, range_end); | ||
| 808 | return *this; | ||
| 809 | } | ||
| 810 | iterator operator ++ (int) | ||
| 811 | { | ||
| 812 | iterator temp = *this; | ||
| 813 | utf8::next(it, range_end); | ||
| 814 | return temp; | ||
| 815 | } | ||
| 816 | iterator& operator -- () | ||
| 817 | { | ||
| 818 | utf8::prior(it, range_start); | ||
| 819 | return *this; | ||
| 820 | } | ||
| 821 | iterator operator -- (int) | ||
| 822 | { | ||
| 823 | iterator temp = *this; | ||
| 824 | utf8::prior(it, range_start); | ||
| 825 | return temp; | ||
| 826 | } | ||
| 827 | }; // class iterator | ||
| 828 | |||
| 829 | } // namespace utf8 | ||
| 830 | |||
| 831 | #if UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later | ||
| 832 | namespace utf8 | ||
| 833 | { | ||
| 834 | inline void append16(utfchar32_t cp, std::u16string& s) | ||
| 835 | { | ||
| 836 | append16(cp, std::back_inserter(s)); | ||
| 837 | } | ||
| 838 | |||
| 839 | inline std::string utf16to8(const std::u16string& s) | ||
| 840 | { | ||
| 841 | std::string result; | ||
| 842 | utf16to8(s.begin(), s.end(), std::back_inserter(result)); | ||
| 843 | return result; | ||
| 844 | } | ||
| 845 | |||
| 846 | inline std::u16string utf8to16(const std::string& s) | ||
| 847 | { | ||
| 848 | std::u16string result; | ||
| 849 | utf8to16(s.begin(), s.end(), std::back_inserter(result)); | ||
| 850 | return result; | ||
| 851 | } | ||
| 852 | |||
| 853 | inline std::string utf32to8(const std::u32string& s) | ||
| 854 | { | ||
| 855 | std::string result; | ||
| 856 | utf32to8(s.begin(), s.end(), std::back_inserter(result)); | ||
| 857 | return result; | ||
| 858 | } | ||
| 859 | |||
| 860 | inline std::u32string utf8to32(const std::string& s) | ||
| 861 | { | ||
| 862 | std::u32string result; | ||
| 863 | utf8to32(s.begin(), s.end(), std::back_inserter(result)); | ||
| 864 | return result; | ||
| 865 | } | ||
| 866 | } // namespace utf8 | ||
| 867 | #endif // C++ 11 or later | ||
| 868 | |||
| 869 | #if UTF_CPP_CPLUSPLUS >= 201703L // C++ 17 or later | ||
| 870 | namespace utf8 | ||
| 871 | { | ||
| 872 | inline std::string utf16to8(std::u16string_view s) | ||
| 873 | { | ||
| 874 | std::string result; | ||
| 875 | utf16to8(s.begin(), s.end(), std::back_inserter(result)); | ||
| 876 | return result; | ||
| 877 | } | ||
| 878 | |||
| 879 | inline std::u16string utf8to16(std::string_view s) | ||
| 880 | { | ||
| 881 | std::u16string result; | ||
| 882 | utf8to16(s.begin(), s.end(), std::back_inserter(result)); | ||
| 883 | return result; | ||
| 884 | } | ||
| 885 | |||
| 886 | inline std::string utf32to8(std::u32string_view s) | ||
| 887 | { | ||
| 888 | std::string result; | ||
| 889 | utf32to8(s.begin(), s.end(), std::back_inserter(result)); | ||
| 890 | return result; | ||
| 891 | } | ||
| 892 | |||
| 893 | inline std::u32string utf8to32(std::string_view s) | ||
| 894 | { | ||
| 895 | std::u32string result; | ||
| 896 | utf8to32(s.begin(), s.end(), std::back_inserter(result)); | ||
| 897 | return result; | ||
| 898 | } | ||
| 899 | |||
| 900 | inline std::size_t find_invalid(std::string_view s) | ||
| 901 | { | ||
| 902 | std::string_view::const_iterator invalid = find_invalid(s.begin(), s.end()); | ||
| 903 | return (invalid == s.end()) ? std::string_view::npos : static_cast<std::size_t>(invalid - s.begin()); | ||
| 904 | } | ||
| 905 | |||
| 906 | inline bool is_valid(std::string_view s) | ||
| 907 | { | ||
| 908 | return is_valid(s.begin(), s.end()); | ||
| 909 | } | ||
| 910 | |||
| 911 | inline std::string replace_invalid(std::string_view s, char32_t replacement) | ||
| 912 | { | ||
| 913 | std::string result; | ||
| 914 | replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement); | ||
| 915 | return result; | ||
| 916 | } | ||
| 917 | |||
| 918 | inline std::string replace_invalid(std::string_view s) | ||
| 919 | { | ||
| 920 | std::string result; | ||
| 921 | replace_invalid(s.begin(), s.end(), std::back_inserter(result)); | ||
| 922 | return result; | ||
| 923 | } | ||
| 924 | |||
| 925 | inline bool starts_with_bom(std::string_view s) | ||
| 926 | { | ||
| 927 | return starts_with_bom(s.begin(), s.end()); | ||
| 928 | } | ||
| 929 | |||
| 930 | } // namespace utf8 | ||
| 931 | #endif // C++ 17 or later | ||
| 932 | |||
| 933 | #if UTF_CPP_CPLUSPLUS >= 202002L // C++ 20 or later | ||
| 934 | namespace utf8 | ||
| 935 | { | ||
| 936 | inline std::u8string utf16tou8(const std::u16string& s) | ||
| 937 | { | ||
| 938 | std::u8string result; | ||
| 939 | utf16to8(s.begin(), s.end(), std::back_inserter(result)); | ||
| 940 | return result; | ||
| 941 | } | ||
| 942 | |||
| 943 | inline std::u8string utf16tou8(std::u16string_view s) | ||
| 944 | { | ||
| 945 | std::u8string result; | ||
| 946 | utf16to8(s.begin(), s.end(), std::back_inserter(result)); | ||
| 947 | return result; | ||
| 948 | } | ||
| 949 | |||
| 950 | inline std::u16string utf8to16(const std::u8string& s) | ||
| 951 | { | ||
| 952 | std::u16string result; | ||
| 953 | utf8to16(s.begin(), s.end(), std::back_inserter(result)); | ||
| 954 | return result; | ||
| 955 | } | ||
| 956 | |||
| 957 | inline std::u16string utf8to16(const std::u8string_view& s) | ||
| 958 | { | ||
| 959 | std::u16string result; | ||
| 960 | utf8to16(s.begin(), s.end(), std::back_inserter(result)); | ||
| 961 | return result; | ||
| 962 | } | ||
| 963 | |||
| 964 | inline std::u8string utf32tou8(const std::u32string& s) | ||
| 965 | { | ||
| 966 | std::u8string result; | ||
| 967 | utf32to8(s.begin(), s.end(), std::back_inserter(result)); | ||
| 968 | return result; | ||
| 969 | } | ||
| 970 | |||
| 971 | inline std::u8string utf32tou8(const std::u32string_view& s) | ||
| 972 | { | ||
| 973 | std::u8string result; | ||
| 974 | utf32to8(s.begin(), s.end(), std::back_inserter(result)); | ||
| 975 | return result; | ||
| 976 | } | ||
| 977 | |||
| 978 | inline std::u32string utf8to32(const std::u8string& s) | ||
| 979 | { | ||
| 980 | std::u32string result; | ||
| 981 | utf8to32(s.begin(), s.end(), std::back_inserter(result)); | ||
| 982 | return result; | ||
| 983 | } | ||
| 984 | |||
| 985 | inline std::u32string utf8to32(const std::u8string_view& s) | ||
| 986 | { | ||
| 987 | std::u32string result; | ||
| 988 | utf8to32(s.begin(), s.end(), std::back_inserter(result)); | ||
| 989 | return result; | ||
| 990 | } | ||
| 991 | |||
| 992 | inline std::size_t find_invalid(const std::u8string& s) | ||
| 993 | { | ||
| 994 | std::u8string::const_iterator invalid = find_invalid(s.begin(), s.end()); | ||
| 995 | return (invalid == s.end()) ? std::string_view::npos : static_cast<std::size_t>(invalid - s.begin()); | ||
| 996 | } | ||
| 997 | |||
| 998 | inline bool is_valid(const std::u8string& s) | ||
| 999 | { | ||
| 1000 | return is_valid(s.begin(), s.end()); | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | inline std::u8string replace_invalid(const std::u8string& s, char32_t replacement) | ||
| 1004 | { | ||
| 1005 | std::u8string result; | ||
| 1006 | replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement); | ||
| 1007 | return result; | ||
| 1008 | } | ||
| 1009 | |||
| 1010 | inline std::u8string replace_invalid(const std::u8string& s) | ||
| 1011 | { | ||
| 1012 | std::u8string result; | ||
| 1013 | replace_invalid(s.begin(), s.end(), std::back_inserter(result)); | ||
| 1014 | return result; | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | inline bool starts_with_bom(const std::u8string& s) | ||
| 1018 | { | ||
| 1019 | return starts_with_bom(s.begin(), s.end()); | ||
| 1020 | } | ||
| 1021 | |||
| 1022 | } // namespace utf8 | ||
| 1023 | #endif // C++ 20 or later | ||
| 1024 | |||
| 1025 | namespace utf8 | ||
| 1026 | { | ||
| 1027 | namespace unchecked | ||
| 1028 | { | ||
| 1029 | template <typename octet_iterator> | ||
| 1030 | octet_iterator append(utfchar32_t cp, octet_iterator result) | ||
| 1031 | { | ||
| 1032 | return internal::append(cp, result); | ||
| 1033 | } | ||
| 1034 | |||
| 1035 | template <typename word_iterator> | ||
| 1036 | word_iterator append16(utfchar32_t cp, word_iterator result) | ||
| 1037 | { | ||
| 1038 | return internal::append16(cp, result); | ||
| 1039 | } | ||
| 1040 | |||
| 1041 | template <typename octet_iterator, typename output_iterator> | ||
| 1042 | output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, utfchar32_t replacement) | ||
| 1043 | { | ||
| 1044 | while (start != end) { | ||
| 1045 | octet_iterator sequence_start = start; | ||
| 1046 | internal::utf_error err_code = utf8::internal::validate_next(start, end); | ||
| 1047 | switch (err_code) { | ||
| 1048 | case internal::UTF8_OK : | ||
| 1049 | for (octet_iterator it = sequence_start; it != start; ++it) | ||
| 1050 | *out++ = *it; | ||
| 1051 | break; | ||
| 1052 | case internal::NOT_ENOUGH_ROOM: | ||
| 1053 | out = utf8::unchecked::append(replacement, out); | ||
| 1054 | start = end; | ||
| 1055 | break; | ||
| 1056 | case internal::INVALID_LEAD: | ||
| 1057 | out = utf8::unchecked::append(replacement, out); | ||
| 1058 | ++start; | ||
| 1059 | break; | ||
| 1060 | case internal::INCOMPLETE_SEQUENCE: | ||
| 1061 | case internal::OVERLONG_SEQUENCE: | ||
| 1062 | case internal::INVALID_CODE_POINT: | ||
| 1063 | out = utf8::unchecked::append(replacement, out); | ||
| 1064 | ++start; | ||
| 1065 | // just one replacement mark for the sequence | ||
| 1066 | while (start != end && utf8::internal::is_trail(*start)) | ||
| 1067 | ++start; | ||
| 1068 | break; | ||
| 1069 | } | ||
| 1070 | } | ||
| 1071 | return out; | ||
| 1072 | } | ||
| 1073 | |||
| 1074 | template <typename octet_iterator, typename output_iterator> | ||
| 1075 | inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out) | ||
| 1076 | { | ||
| 1077 | static const utfchar32_t replacement_marker = static_cast<utfchar32_t>(utf8::internal::mask16(0xfffd)); | ||
| 1078 | return utf8::unchecked::replace_invalid(start, end, out, replacement_marker); | ||
| 1079 | } | ||
| 1080 | |||
| 1081 | inline std::string replace_invalid(const std::string& s, utfchar32_t replacement) | ||
| 1082 | { | ||
| 1083 | std::string result; | ||
| 1084 | replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement); | ||
| 1085 | return result; | ||
| 1086 | } | ||
| 1087 | |||
| 1088 | inline std::string replace_invalid(const std::string& s) | ||
| 1089 | { | ||
| 1090 | std::string result; | ||
| 1091 | replace_invalid(s.begin(), s.end(), std::back_inserter(result)); | ||
| 1092 | return result; | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | template <typename octet_iterator> | ||
| 1096 | utfchar32_t next(octet_iterator& it) | ||
| 1097 | { | ||
| 1098 | utfchar32_t cp = utf8::internal::mask8(*it); | ||
| 1099 | switch (utf8::internal::sequence_length(it)) { | ||
| 1100 | case 1: | ||
| 1101 | break; | ||
| 1102 | case 2: | ||
| 1103 | ++it; | ||
| 1104 | cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f); | ||
| 1105 | break; | ||
| 1106 | case 3: | ||
| 1107 | ++it; | ||
| 1108 | cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff); | ||
| 1109 | ++it; | ||
| 1110 | cp = static_cast<utfchar32_t>(cp + ((*it) & 0x3f)); | ||
| 1111 | break; | ||
| 1112 | case 4: | ||
| 1113 | ++it; | ||
| 1114 | cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff); | ||
| 1115 | ++it; | ||
| 1116 | cp = static_cast<utfchar32_t>(cp + ((utf8::internal::mask8(*it) << 6) & 0xfff)); | ||
| 1117 | ++it; | ||
| 1118 | cp = static_cast<utfchar32_t>(cp + ((*it) & 0x3f)); | ||
| 1119 | break; | ||
| 1120 | } | ||
| 1121 | ++it; | ||
| 1122 | return cp; | ||
| 1123 | } | ||
| 1124 | |||
| 1125 | template <typename octet_iterator> | ||
| 1126 | utfchar32_t peek_next(octet_iterator it) | ||
| 1127 | { | ||
| 1128 | return utf8::unchecked::next(it); | ||
| 1129 | } | ||
| 1130 | |||
| 1131 | template <typename word_iterator> | ||
| 1132 | utfchar32_t next16(word_iterator& it) | ||
| 1133 | { | ||
| 1134 | utfchar32_t cp = utf8::internal::mask16(*it++); | ||
| 1135 | if (utf8::internal::is_lead_surrogate(cp)) | ||
| 1136 | return (cp << 10) + *it++ + utf8::internal::SURROGATE_OFFSET; | ||
| 1137 | return cp; | ||
| 1138 | } | ||
| 1139 | |||
| 1140 | template <typename octet_iterator> | ||
| 1141 | utfchar32_t prior(octet_iterator& it) | ||
| 1142 | { | ||
| 1143 | while (utf8::internal::is_trail(*(--it))) ; | ||
| 1144 | octet_iterator temp = it; | ||
| 1145 | return utf8::unchecked::next(temp); | ||
| 1146 | } | ||
| 1147 | |||
| 1148 | template <typename octet_iterator, typename distance_type> | ||
| 1149 | void advance(octet_iterator& it, distance_type n) | ||
| 1150 | { | ||
| 1151 | const distance_type zero(0); | ||
| 1152 | if (n < zero) { | ||
| 1153 | // backward | ||
| 1154 | for (distance_type i = n; i < zero; ++i) | ||
| 1155 | utf8::unchecked::prior(it); | ||
| 1156 | } else { | ||
| 1157 | // forward | ||
| 1158 | for (distance_type i = zero; i < n; ++i) | ||
| 1159 | utf8::unchecked::next(it); | ||
| 1160 | } | ||
| 1161 | } | ||
| 1162 | |||
| 1163 | template <typename octet_iterator> | ||
| 1164 | typename std::iterator_traits<octet_iterator>::difference_type | ||
| 1165 | distance(octet_iterator first, octet_iterator last) | ||
| 1166 | { | ||
| 1167 | typename std::iterator_traits<octet_iterator>::difference_type dist; | ||
| 1168 | for (dist = 0; first < last; ++dist) | ||
| 1169 | utf8::unchecked::next(first); | ||
| 1170 | return dist; | ||
| 1171 | } | ||
| 1172 | |||
| 1173 | template <typename u16bit_iterator, typename octet_iterator> | ||
| 1174 | octet_iterator utf16to8(u16bit_iterator start, u16bit_iterator end, octet_iterator result) | ||
| 1175 | { | ||
| 1176 | while (start != end) { | ||
| 1177 | utfchar32_t cp = utf8::internal::mask16(*start++); | ||
| 1178 | // Take care of surrogate pairs first | ||
| 1179 | if (utf8::internal::is_lead_surrogate(cp)) { | ||
| 1180 | if (start == end) | ||
| 1181 | return result; | ||
| 1182 | utfchar32_t trail_surrogate = utf8::internal::mask16(*start++); | ||
| 1183 | cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; | ||
| 1184 | } | ||
| 1185 | result = utf8::unchecked::append(cp, result); | ||
| 1186 | } | ||
| 1187 | return result; | ||
| 1188 | } | ||
| 1189 | |||
| 1190 | template <typename u16bit_iterator, typename octet_iterator> | ||
| 1191 | u16bit_iterator utf8to16(octet_iterator start, octet_iterator end, u16bit_iterator result) | ||
| 1192 | { | ||
| 1193 | while (start < end) { | ||
| 1194 | utfchar32_t cp = utf8::unchecked::next(start); | ||
| 1195 | if (cp > 0xffff) { //make a surrogate pair | ||
| 1196 | *result++ = static_cast<utfchar16_t>((cp >> 10) + internal::LEAD_OFFSET); | ||
| 1197 | *result++ = static_cast<utfchar16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); | ||
| 1198 | } | ||
| 1199 | else | ||
| 1200 | *result++ = static_cast<utfchar16_t>(cp); | ||
| 1201 | } | ||
| 1202 | return result; | ||
| 1203 | } | ||
| 1204 | |||
| 1205 | template <typename octet_iterator, typename u32bit_iterator> | ||
| 1206 | octet_iterator utf32to8(u32bit_iterator start, u32bit_iterator end, octet_iterator result) | ||
| 1207 | { | ||
| 1208 | while (start != end) | ||
| 1209 | result = utf8::unchecked::append(*(start++), result); | ||
| 1210 | |||
| 1211 | return result; | ||
| 1212 | } | ||
| 1213 | |||
| 1214 | template <typename octet_iterator, typename u32bit_iterator> | ||
| 1215 | u32bit_iterator utf8to32(octet_iterator start, octet_iterator end, u32bit_iterator result) | ||
| 1216 | { | ||
| 1217 | while (start < end) | ||
| 1218 | (*result++) = utf8::unchecked::next(start); | ||
| 1219 | |||
| 1220 | return result; | ||
| 1221 | } | ||
| 1222 | |||
| 1223 | // The iterator class | ||
| 1224 | template <typename octet_iterator> | ||
| 1225 | class iterator { | ||
| 1226 | octet_iterator it; | ||
| 1227 | public: | ||
| 1228 | typedef utfchar32_t value_type; | ||
| 1229 | typedef utfchar32_t* pointer; | ||
| 1230 | typedef utfchar32_t& reference; | ||
| 1231 | typedef std::ptrdiff_t difference_type; | ||
| 1232 | typedef std::bidirectional_iterator_tag iterator_category; | ||
| 1233 | iterator () {} | ||
| 1234 | explicit iterator (const octet_iterator& octet_it): it(octet_it) {} | ||
| 1235 | // the default "big three" are OK | ||
| 1236 | octet_iterator base () const { return it; } | ||
| 1237 | utfchar32_t operator * () const | ||
| 1238 | { | ||
| 1239 | octet_iterator temp = it; | ||
| 1240 | return utf8::unchecked::next(temp); | ||
| 1241 | } | ||
| 1242 | bool operator == (const iterator& rhs) const | ||
| 1243 | { | ||
| 1244 | return (it == rhs.it); | ||
| 1245 | } | ||
| 1246 | bool operator != (const iterator& rhs) const | ||
| 1247 | { | ||
| 1248 | return !(operator == (rhs)); | ||
| 1249 | } | ||
| 1250 | iterator& operator ++ () | ||
| 1251 | { | ||
| 1252 | ::std::advance(it, utf8::internal::sequence_length(it)); | ||
| 1253 | return *this; | ||
| 1254 | } | ||
| 1255 | iterator operator ++ (int) | ||
| 1256 | { | ||
| 1257 | iterator temp = *this; | ||
| 1258 | ::std::advance(it, utf8::internal::sequence_length(it)); | ||
| 1259 | return temp; | ||
| 1260 | } | ||
| 1261 | iterator& operator -- () | ||
| 1262 | { | ||
| 1263 | utf8::unchecked::prior(it); | ||
| 1264 | return *this; | ||
| 1265 | } | ||
| 1266 | iterator operator -- (int) | ||
| 1267 | { | ||
| 1268 | iterator temp = *this; | ||
| 1269 | utf8::unchecked::prior(it); | ||
| 1270 | return temp; | ||
| 1271 | } | ||
| 1272 | }; // class iterator | ||
| 1273 | |||
| 1274 | } // namespace utf8::unchecked | ||
| 1275 | } // namespace utf8 | ||
| 1276 | |||
| 1277 | #endif // header guard | ||
diff --git a/src/yue.cpp b/src/yue.cpp index fc57767..b93f75e 100644 --- a/src/yue.cpp +++ b/src/yue.cpp | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> | 1 | /* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com> |
| 2 | 2 | ||
| 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
| 4 | 4 | ||
| @@ -30,6 +30,38 @@ using namespace std::chrono_literals; | |||
| 30 | #include "ghc/fs_std.hpp" | 30 | #include "ghc/fs_std.hpp" |
| 31 | #include "linenoise.hpp" | 31 | #include "linenoise.hpp" |
| 32 | 32 | ||
| 33 | #if __has_include(<pthread.h>) | ||
| 34 | #include <pthread.h> | ||
| 35 | template<class R> | ||
| 36 | std::future<R> async(const std::function<R()>& f) { | ||
| 37 | using Fn = std::packaged_task<R()>; | ||
| 38 | auto task = new Fn(f); | ||
| 39 | std::future<R> fut = task->get_future(); | ||
| 40 | |||
| 41 | pthread_attr_t attr; | ||
| 42 | pthread_attr_init(&attr); | ||
| 43 | pthread_attr_setstacksize(&attr, 8 * 1024 * 1024); | ||
| 44 | |||
| 45 | pthread_t th; | ||
| 46 | pthread_create(&th, &attr, | ||
| 47 | [](void* p)->void* { | ||
| 48 | std::unique_ptr<Fn> fn(static_cast<Fn*>(p)); | ||
| 49 | (*fn)(); | ||
| 50 | return nullptr; | ||
| 51 | }, | ||
| 52 | task); | ||
| 53 | pthread_attr_destroy(&attr); | ||
| 54 | pthread_detach(th); | ||
| 55 | return fut; | ||
| 56 | } | ||
| 57 | #else | ||
| 58 | template<class R> | ||
| 59 | std::future<R> async(const std::function<R()>& f) { | ||
| 60 | // fallback: ignore stack size | ||
| 61 | return std::async(std::launch::async, f); | ||
| 62 | } | ||
| 63 | #endif | ||
| 64 | |||
| 33 | #if not(defined YUE_NO_MACRO && defined YUE_COMPILER_ONLY) | 65 | #if not(defined YUE_NO_MACRO && defined YUE_COMPILER_ONLY) |
| 34 | #define _DEFER(code, line) std::shared_ptr<void> _defer_##line(nullptr, [&](auto) { \ | 66 | #define _DEFER(code, line) std::shared_ptr<void> _defer_##line(nullptr, [&](auto) { \ |
| 35 | code; \ | 67 | code; \ |
| @@ -40,18 +72,23 @@ extern "C" { | |||
| 40 | #include "lua.h" | 72 | #include "lua.h" |
| 41 | #include "lualib.h" | 73 | #include "lualib.h" |
| 42 | int luaopen_yue(lua_State* L); | 74 | int luaopen_yue(lua_State* L); |
| 75 | int luaopen_colibc_json(lua_State* L); | ||
| 43 | } // extern "C" | 76 | } // extern "C" |
| 44 | 77 | ||
| 45 | static void openlibs(void* state) { | 78 | static void openlibs(void* state) { |
| 46 | lua_State* L = static_cast<lua_State*>(state); | 79 | lua_State* L = static_cast<lua_State*>(state); |
| 80 | int top = lua_gettop(L); | ||
| 81 | DEFER(lua_settop(L, top)); | ||
| 47 | luaL_openlibs(L); | 82 | luaL_openlibs(L); |
| 48 | #if LUA_VERSION_NUM > 501 | 83 | #if LUA_VERSION_NUM > 501 |
| 49 | luaL_requiref(L, "yue", luaopen_yue, 0); | 84 | luaL_requiref(L, "yue", luaopen_yue, 0); |
| 85 | luaL_requiref(L, "cojson", luaopen_colibc_json, 0); | ||
| 50 | #else | 86 | #else |
| 51 | lua_pushcfunction(L, luaopen_yue); | 87 | lua_pushcfunction(L, luaopen_yue); |
| 52 | lua_call(L, 0, 0); | 88 | lua_call(L, 0, 0); |
| 89 | lua_pushcfunction(L, luaopen_colibc_json); | ||
| 90 | lua_call(L, 0, 0); | ||
| 53 | #endif | 91 | #endif |
| 54 | lua_pop(L, 1); | ||
| 55 | } | 92 | } |
| 56 | 93 | ||
| 57 | void pushYue(lua_State* L, std::string_view name) { | 94 | void pushYue(lua_State* L, std::string_view name) { |
| @@ -699,7 +736,7 @@ int main(int narg, const char** args) { | |||
| 699 | } | 736 | } |
| 700 | std::list<std::future<std::string>> results; | 737 | std::list<std::future<std::string>> results; |
| 701 | for (const auto& file : files) { | 738 | for (const auto& file : files) { |
| 702 | auto task = std::async(std::launch::async, [=]() { | 739 | auto task = async<std::string>([=]() { |
| 703 | #ifndef YUE_COMPILER_ONLY | 740 | #ifndef YUE_COMPILER_ONLY |
| 704 | return compileFile(fs::absolute(file.first), config, fullWorkPath, fullTargetPath, minify, rewrite); | 741 | return compileFile(fs::absolute(file.first), config, fullWorkPath, fullTargetPath, minify, rewrite); |
| 705 | #else | 742 | #else |
| @@ -737,7 +774,7 @@ int main(int narg, const char** args) { | |||
| 737 | #endif // YUE_NO_WATCHER | 774 | #endif // YUE_NO_WATCHER |
| 738 | std::list<std::future<std::tuple<int, std::string, std::string>>> results; | 775 | std::list<std::future<std::tuple<int, std::string, std::string>>> results; |
| 739 | for (const auto& file : files) { | 776 | for (const auto& file : files) { |
| 740 | auto task = std::async(std::launch::async, [=]() { | 777 | auto task = async<std::tuple<int, std::string, std::string>>([=]() { |
| 741 | std::ifstream input(file.first, std::ios::in); | 778 | std::ifstream input(file.first, std::ios::in); |
| 742 | if (input) { | 779 | if (input) { |
| 743 | std::string s( | 780 | std::string s( |
diff --git a/src/yue_wasm.cpp b/src/yue_wasm.cpp index 20f3794..abb291e 100644 --- a/src/yue_wasm.cpp +++ b/src/yue_wasm.cpp | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> | 1 | /* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com> |
| 2 | 2 | ||
| 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
| 4 | 4 | ||
diff --git a/src/yuescript/parser.cpp b/src/yuescript/parser.cpp index f0ddd06..5910348 100644 --- a/src/yuescript/parser.cpp +++ b/src/yuescript/parser.cpp | |||
| @@ -18,8 +18,33 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
| 18 | 18 | ||
| 19 | #include "yuescript/parser.hpp" | 19 | #include "yuescript/parser.hpp" |
| 20 | 20 | ||
| 21 | #ifndef YUE_UTF8_IMPL | ||
| 22 | namespace CodeCvt { | ||
| 23 | std::u32string utf8to32(const std::string& str); | ||
| 24 | std::string utf32to8(const std::u32string& str); | ||
| 25 | } // namespace CodeCvt | ||
| 26 | #else | ||
| 27 | #include "utf8cpp.h" | ||
| 28 | namespace CodeCvt { | ||
| 29 | std::u32string utf8to32(const std::string& str) { | ||
| 30 | return utf8::utf8to32(str); | ||
| 31 | } | ||
| 32 | std::string utf32to8(const std::u32string& str) { | ||
| 33 | return utf8::utf32to8(str); | ||
| 34 | } | ||
| 35 | } // namespace CodeCvt | ||
| 36 | #endif // YUE_UTF8_IMPL | ||
| 37 | |||
| 21 | namespace parserlib { | 38 | namespace parserlib { |
| 22 | 39 | ||
| 40 | input utf8_decode(const std::string& str) { | ||
| 41 | return CodeCvt::utf8to32(str); | ||
| 42 | } | ||
| 43 | |||
| 44 | std::string utf8_encode(const input& str) { | ||
| 45 | return CodeCvt::utf32to8(str); | ||
| 46 | } | ||
| 47 | |||
| 23 | // internal private class that manages access to the public classes' internals. | 48 | // internal private class that manages access to the public classes' internals. |
| 24 | class _private { | 49 | class _private { |
| 25 | public: | 50 | public: |
| @@ -241,7 +266,7 @@ class _string : public _expr { | |||
| 241 | public: | 266 | public: |
| 242 | // constructor from ansi string. | 267 | // constructor from ansi string. |
| 243 | _string(const char* s) | 268 | _string(const char* s) |
| 244 | : m_string(Converter{}.from_bytes(s)) { | 269 | : m_string(utf8_decode(s)) { |
| 245 | } | 270 | } |
| 246 | 271 | ||
| 247 | // parse with whitespace | 272 | // parse with whitespace |
| @@ -279,7 +304,7 @@ class _set : public _expr { | |||
| 279 | public: | 304 | public: |
| 280 | // constructor from ansi string. | 305 | // constructor from ansi string. |
| 281 | _set(const char* s) { | 306 | _set(const char* s) { |
| 282 | auto str = Converter{}.from_bytes(s); | 307 | auto str = utf8_decode(s); |
| 283 | for (auto ch : str) { | 308 | for (auto ch : str) { |
| 284 | _add(ch); | 309 | _add(ch); |
| 285 | } | 310 | } |
diff --git a/src/yuescript/parser.hpp b/src/yuescript/parser.hpp index c544785..4742539 100644 --- a/src/yuescript/parser.hpp +++ b/src/yuescript/parser.hpp | |||
| @@ -17,7 +17,6 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
| 17 | #pragma warning(disable : 4521) | 17 | #pragma warning(disable : 4521) |
| 18 | #endif | 18 | #endif |
| 19 | 19 | ||
| 20 | #include <codecvt> | ||
| 21 | #include <functional> | 20 | #include <functional> |
| 22 | #include <list> | 21 | #include <list> |
| 23 | #include <locale> | 22 | #include <locale> |
| @@ -27,9 +26,11 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
| 27 | namespace parserlib { | 26 | namespace parserlib { |
| 28 | 27 | ||
| 29 | /// type of the parser's input. | 28 | /// type of the parser's input. |
| 30 | typedef std::basic_string<wchar_t> input; | 29 | typedef std::basic_string<char32_t> input; |
| 31 | typedef input::iterator input_it; | 30 | typedef input::iterator input_it; |
| 32 | typedef std::wstring_convert<std::codecvt_utf8_utf16<input::value_type>> Converter; | 31 | |
| 32 | input utf8_decode(const std::string& str); | ||
| 33 | std::string utf8_encode(const input& str); | ||
| 33 | 34 | ||
| 34 | class _private; | 35 | class _private; |
| 35 | class _expr; | 36 | class _expr; |
diff --git a/src/yuescript/yue_ast.cpp b/src/yuescript/yue_ast.cpp index fdb1d20..14d8db8 100644 --- a/src/yuescript/yue_ast.cpp +++ b/src/yuescript/yue_ast.cpp | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> | 1 | /* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com> |
| 2 | 2 | ||
| 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
| 4 | 4 | ||
| @@ -30,7 +30,7 @@ std::string YueFormat::ind() const { | |||
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | std::string YueFormat::convert(const ast_node* node) { | 32 | std::string YueFormat::convert(const ast_node* node) { |
| 33 | return converter.to_bytes(std::wstring(node->m_begin.m_it, node->m_end.m_it)); | 33 | return utf8_encode({node->m_begin.m_it, node->m_end.m_it}); |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | std::string YueFormat::toString(ast_node* node) { | 36 | std::string YueFormat::toString(ast_node* node) { |
| @@ -82,6 +82,13 @@ std::string SelfClass_t::to_string(void*) const { | |||
| 82 | std::string VarArg_t::to_string(void*) const { | 82 | std::string VarArg_t::to_string(void*) const { |
| 83 | return "..."s; | 83 | return "..."s; |
| 84 | } | 84 | } |
| 85 | std::string VarArgDef_t::to_string(void* ud) const { | ||
| 86 | if (name) { | ||
| 87 | return "..."s + name->to_string(ud); | ||
| 88 | } else { | ||
| 89 | return "..."s; | ||
| 90 | } | ||
| 91 | } | ||
| 85 | std::string Seperator_t::to_string(void*) const { | 92 | std::string Seperator_t::to_string(void*) const { |
| 86 | return {}; | 93 | return {}; |
| 87 | } | 94 | } |
| @@ -167,7 +174,7 @@ std::string ExistentialOp_t::to_string(void*) const { | |||
| 167 | std::string TableAppendingOp_t::to_string(void*) const { | 174 | std::string TableAppendingOp_t::to_string(void*) const { |
| 168 | return "[]"s; | 175 | return "[]"s; |
| 169 | } | 176 | } |
| 170 | std::string PlainItem_t::to_string(void *) const { | 177 | std::string PlainItem_t::to_string(void*) const { |
| 171 | return {}; | 178 | return {}; |
| 172 | } | 179 | } |
| 173 | std::string GlobalOp_t::to_string(void*) const { | 180 | std::string GlobalOp_t::to_string(void*) const { |
| @@ -203,14 +210,18 @@ std::string YueLineComment_t::to_string(void* ud) const { | |||
| 203 | auto info = reinterpret_cast<YueFormat*>(ud); | 210 | auto info = reinterpret_cast<YueFormat*>(ud); |
| 204 | return "--"s + info->convert(this); | 211 | return "--"s + info->convert(this); |
| 205 | } | 212 | } |
| 206 | std::string MultilineCommentInner_t::to_string(void* ud) const { | 213 | std::string YueMultilineComment_t::to_string(void* ud) const { |
| 207 | auto info = reinterpret_cast<YueFormat*>(ud); | 214 | auto info = reinterpret_cast<YueFormat*>(ud); |
| 208 | return info->convert(this); | 215 | return "--[["s + info->convert(this) + "]]"s; |
| 209 | } | 216 | } |
| 210 | std::string Variable_t::to_string(void* ud) const { | 217 | std::string YueComment_t::to_string(void* ud) const { |
| 211 | return name->to_string(ud); | 218 | if (comment) { |
| 219 | return comment->to_string(ud); | ||
| 220 | } else { | ||
| 221 | return {}; | ||
| 222 | } | ||
| 212 | } | 223 | } |
| 213 | std::string LabelName_t::to_string(void* ud) const { | 224 | std::string Variable_t::to_string(void* ud) const { |
| 214 | return name->to_string(ud); | 225 | return name->to_string(ud); |
| 215 | } | 226 | } |
| 216 | std::string LuaKeyword_t::to_string(void* ud) const { | 227 | std::string LuaKeyword_t::to_string(void* ud) const { |
| @@ -304,6 +315,17 @@ std::string ImportAs_t::to_string(void* ud) const { | |||
| 304 | } | 315 | } |
| 305 | return join(temp, " "s); | 316 | return join(temp, " "s); |
| 306 | } | 317 | } |
| 318 | std::string ImportGlobal_t::to_string(void* ud) const { | ||
| 319 | str_list temp; | ||
| 320 | for (auto seg : segs.objects()) { | ||
| 321 | temp.emplace_back(seg->to_string(ud)); | ||
| 322 | } | ||
| 323 | auto item = join(temp, "."s); | ||
| 324 | if (target) { | ||
| 325 | return item + " as "s + target->to_string(ud); | ||
| 326 | } | ||
| 327 | return item; | ||
| 328 | } | ||
| 307 | std::string Import_t::to_string(void* ud) const { | 329 | std::string Import_t::to_string(void* ud) const { |
| 308 | if (ast_is<FromImport_t>(content)) { | 330 | if (ast_is<FromImport_t>(content)) { |
| 309 | return content->to_string(ud); | 331 | return content->to_string(ud); |
| @@ -372,8 +394,8 @@ std::string With_t::to_string(void* ud) const { | |||
| 372 | str_list temp{ | 394 | str_list temp{ |
| 373 | eop ? "with?"s : "with"s, | 395 | eop ? "with?"s : "with"s, |
| 374 | valueList->to_string(ud)}; | 396 | valueList->to_string(ud)}; |
| 375 | if (assigns) { | 397 | if (assign) { |
| 376 | temp.push_back(assigns->to_string(ud)); | 398 | temp.push_back(':' + assign->to_string(ud)); |
| 377 | } | 399 | } |
| 378 | if (body.is<Statement_t>()) { | 400 | if (body.is<Statement_t>()) { |
| 379 | return join(temp, " "sv) + " do "s + body->to_string(ud); | 401 | return join(temp, " "sv) + " do "s + body->to_string(ud); |
| @@ -419,6 +441,9 @@ std::string SwitchCase_t::to_string(void* ud) const { | |||
| 419 | std::string Switch_t::to_string(void* ud) const { | 441 | std::string Switch_t::to_string(void* ud) const { |
| 420 | auto info = reinterpret_cast<YueFormat*>(ud); | 442 | auto info = reinterpret_cast<YueFormat*>(ud); |
| 421 | str_list temp{"switch "s + target->to_string(ud)}; | 443 | str_list temp{"switch "s + target->to_string(ud)}; |
| 444 | if (assignment) { | ||
| 445 | temp.back().append(assignment->to_string(ud)); | ||
| 446 | } | ||
| 422 | info->pushScope(); | 447 | info->pushScope(); |
| 423 | for (auto branch : branches.objects()) { | 448 | for (auto branch : branches.objects()) { |
| 424 | temp.emplace_back(info->ind() + branch->to_string(ud)); | 449 | temp.emplace_back(info->ind() + branch->to_string(ud)); |
| @@ -462,41 +487,75 @@ std::string If_t::to_string(void* ud) const { | |||
| 462 | temp.back() += " then"s; | 487 | temp.back() += " then"s; |
| 463 | } | 488 | } |
| 464 | ++it; | 489 | ++it; |
| 465 | bool condition = true; | 490 | enum class NType { |
| 491 | Cond, | ||
| 492 | Stat, | ||
| 493 | Block | ||
| 494 | }; | ||
| 495 | NType lastType = NType::Cond; | ||
| 466 | for (; it != nodes.objects().end(); ++it) { | 496 | for (; it != nodes.objects().end(); ++it) { |
| 467 | auto node = *it; | 497 | auto node = *it; |
| 468 | switch (node->get_id()) { | 498 | switch (node->get_id()) { |
| 469 | case id<IfCond_t>(): | 499 | case id<IfCond_t>(): |
| 470 | temp.emplace_back(info->ind() + "elseif "s + node->to_string(ud)); | 500 | temp.emplace_back(info->ind() + "elseif "s + node->to_string(ud)); |
| 471 | condition = true; | 501 | lastType = NType::Cond; |
| 472 | break; | 502 | break; |
| 473 | case id<Statement_t>(): { | 503 | case id<Statement_t>(): { |
| 474 | if (condition) { | 504 | switch (lastType) { |
| 475 | temp.back() += " then "s + node->to_string(ud); | 505 | case NType::Cond: |
| 476 | } else { | 506 | temp.back() += " then "s + node->to_string(ud); |
| 477 | temp.emplace_back(info->ind() + "else "s + node->to_string(ud)); | 507 | break; |
| 508 | case NType::Stat: | ||
| 509 | if (temp.back().back() == '\n') { | ||
| 510 | temp.emplace_back(info->ind() + "else "s + node->to_string(ud)); | ||
| 511 | } else { | ||
| 512 | temp.back() += " else "s + node->to_string(ud); | ||
| 513 | } | ||
| 514 | break; | ||
| 515 | case NType::Block: | ||
| 516 | temp.emplace_back(info->ind() + "else "s + node->to_string(ud)); | ||
| 517 | break; | ||
| 478 | } | 518 | } |
| 479 | condition = false; | 519 | lastType = NType::Stat; |
| 480 | break; | 520 | break; |
| 481 | } | 521 | } |
| 482 | case id<Block_t>(): { | 522 | case id<Block_t>(): { |
| 483 | if (condition) { | 523 | switch (lastType) { |
| 484 | info->pushScope(); | 524 | case NType::Cond: { |
| 485 | temp.emplace_back(node->to_string(ud)); | 525 | info->pushScope(); |
| 486 | if (temp.back().empty()) { | 526 | temp.emplace_back(node->to_string(ud)); |
| 487 | temp.back() = info->ind() + "--"s; | 527 | if (temp.back().empty()) { |
| 528 | temp.back() = info->ind() + "--"s; | ||
| 529 | } | ||
| 530 | info->popScope(); | ||
| 531 | break; | ||
| 532 | } | ||
| 533 | case NType::Stat: { | ||
| 534 | if (temp.back().back() == '\n') { | ||
| 535 | temp.emplace_back(info->ind() + "else"s); | ||
| 536 | } else { | ||
| 537 | temp.back() += " else"s; | ||
| 538 | } | ||
| 539 | info->pushScope(); | ||
| 540 | temp.emplace_back(node->to_string(ud)); | ||
| 541 | if (temp.back().empty()) { | ||
| 542 | temp.back() = info->ind() + "--"s; | ||
| 543 | } | ||
| 544 | info->popScope(); | ||
| 545 | break; | ||
| 488 | } | 546 | } |
| 489 | info->popScope(); | 547 | case NType::Block: { |
| 490 | } else { | 548 | temp.emplace_back(info->ind() + "else"s); |
| 491 | temp.emplace_back(info->ind() + "else"s); | 549 | info->pushScope(); |
| 492 | info->pushScope(); | 550 | temp.emplace_back(node->to_string(ud)); |
| 493 | temp.emplace_back(node->to_string(ud)); | 551 | if (temp.back().empty()) { |
| 494 | if (temp.back().empty()) { | 552 | temp.back() = info->ind() + "--"s; |
| 495 | temp.back() = info->ind() + "--"s; | 553 | } |
| 554 | info->popScope(); | ||
| 555 | break; | ||
| 496 | } | 556 | } |
| 497 | info->popScope(); | ||
| 498 | } | 557 | } |
| 499 | condition = false; | 558 | lastType = NType::Block; |
| 500 | break; | 559 | break; |
| 501 | } | 560 | } |
| 502 | } | 561 | } |
| @@ -524,10 +583,10 @@ std::string While_t::to_string(void* ud) const { | |||
| 524 | } | 583 | } |
| 525 | std::string Repeat_t::to_string(void* ud) const { | 584 | std::string Repeat_t::to_string(void* ud) const { |
| 526 | auto info = reinterpret_cast<YueFormat*>(ud); | 585 | auto info = reinterpret_cast<YueFormat*>(ud); |
| 527 | str_list temp; | 586 | if (body.is<Statement_t>()) { |
| 528 | if (body->content.is<Statement_t>()) { | 587 | return "repeat "s + body->to_string(ud) + " until "s + condition->to_string(ud); |
| 529 | temp.emplace_back("repeat "s + body->to_string(ud)); | ||
| 530 | } else { | 588 | } else { |
| 589 | str_list temp; | ||
| 531 | temp.emplace_back("repeat"s); | 590 | temp.emplace_back("repeat"s); |
| 532 | info->pushScope(); | 591 | info->pushScope(); |
| 533 | temp.emplace_back(body->to_string(ud)); | 592 | temp.emplace_back(body->to_string(ud)); |
| @@ -535,14 +594,14 @@ std::string Repeat_t::to_string(void* ud) const { | |||
| 535 | temp.back() = info->ind() + "--"s; | 594 | temp.back() = info->ind() + "--"s; |
| 536 | } | 595 | } |
| 537 | info->popScope(); | 596 | info->popScope(); |
| 597 | temp.emplace_back(info->ind() + "until "s + condition->to_string(ud)); | ||
| 598 | return join(temp, "\n"sv); | ||
| 538 | } | 599 | } |
| 539 | temp.emplace_back(info->ind() + "until "s + condition->to_string(ud)); | ||
| 540 | return join(temp, "\n"sv); | ||
| 541 | } | 600 | } |
| 542 | std::string ForStepValue_t::to_string(void* ud) const { | 601 | std::string ForStepValue_t::to_string(void* ud) const { |
| 543 | return value->to_string(ud); | 602 | return value->to_string(ud); |
| 544 | } | 603 | } |
| 545 | std::string For_t::to_string(void* ud) const { | 604 | std::string ForNum_t::to_string(void* ud) const { |
| 546 | auto info = reinterpret_cast<YueFormat*>(ud); | 605 | auto info = reinterpret_cast<YueFormat*>(ud); |
| 547 | auto line = "for "s + varName->to_string(ud) + " = "s + startValue->to_string(ud) + ", "s + stopValue->to_string(ud); | 606 | auto line = "for "s + varName->to_string(ud) + " = "s + startValue->to_string(ud) + ", "s + stopValue->to_string(ud); |
| 548 | if (stepValue) { | 607 | if (stepValue) { |
| @@ -581,6 +640,9 @@ std::string ForEach_t::to_string(void* ud) const { | |||
| 581 | return line + '\n' + block; | 640 | return line + '\n' + block; |
| 582 | } | 641 | } |
| 583 | } | 642 | } |
| 643 | std::string For_t::to_string(void* ud) const { | ||
| 644 | return forLoop->to_string(ud); | ||
| 645 | } | ||
| 584 | std::string Do_t::to_string(void* ud) const { | 646 | std::string Do_t::to_string(void* ud) const { |
| 585 | auto info = reinterpret_cast<YueFormat*>(ud); | 647 | auto info = reinterpret_cast<YueFormat*>(ud); |
| 586 | if (body->content.is<Statement_t>()) { | 648 | if (body->content.is<Statement_t>()) { |
| @@ -609,10 +671,13 @@ std::string CatchBlock_t::to_string(void* ud) const { | |||
| 609 | std::string Try_t::to_string(void* ud) const { | 671 | std::string Try_t::to_string(void* ud) const { |
| 610 | auto info = reinterpret_cast<YueFormat*>(ud); | 672 | auto info = reinterpret_cast<YueFormat*>(ud); |
| 611 | str_list temp; | 673 | str_list temp; |
| 674 | temp.emplace_back("try"s); | ||
| 675 | if (eop) { | ||
| 676 | temp.back() += eop->to_string(ud); | ||
| 677 | } | ||
| 612 | if (func.is<Exp_t>()) { | 678 | if (func.is<Exp_t>()) { |
| 613 | temp.emplace_back("try "s + func->to_string(ud)); | 679 | temp.back() += (" "s + func->to_string(ud)); |
| 614 | } else { | 680 | } else { |
| 615 | temp.emplace_back("try"s); | ||
| 616 | info->pushScope(); | 681 | info->pushScope(); |
| 617 | temp.emplace_back(func->to_string(ud)); | 682 | temp.emplace_back(func->to_string(ud)); |
| 618 | if (temp.back().empty()) { | 683 | if (temp.back().empty()) { |
| @@ -729,7 +794,7 @@ static bool isInBlockExp(ast_node* node, bool last = false) { | |||
| 729 | return false; | 794 | return false; |
| 730 | } | 795 | } |
| 731 | std::string Comprehension_t::to_string(void* ud) const { | 796 | std::string Comprehension_t::to_string(void* ud) const { |
| 732 | if (items.size() != 2 || !ast_is<CompInner_t>(items.back())) { | 797 | if (items.size() != 2 || !ast_is<CompFor_t>(items.back())) { |
| 733 | if (items.size() == 1) { | 798 | if (items.size() == 1) { |
| 734 | str_list temp; | 799 | str_list temp; |
| 735 | for (const auto& item : items.objects()) { | 800 | for (const auto& item : items.objects()) { |
| @@ -796,14 +861,14 @@ std::string StarExp_t::to_string(void* ud) const { | |||
| 796 | std::string CompForEach_t::to_string(void* ud) const { | 861 | std::string CompForEach_t::to_string(void* ud) const { |
| 797 | return "for "s + nameList->to_string(ud) + " in "s + loopValue->to_string(ud); | 862 | return "for "s + nameList->to_string(ud) + " in "s + loopValue->to_string(ud); |
| 798 | } | 863 | } |
| 799 | std::string CompFor_t::to_string(void* ud) const { | 864 | std::string CompForNum_t::to_string(void* ud) const { |
| 800 | auto line = "for "s + varName->to_string(ud) + " = "s + startValue->to_string(ud) + ", "s + stopValue->to_string(ud); | 865 | auto line = "for "s + varName->to_string(ud) + " = "s + startValue->to_string(ud) + ", "s + stopValue->to_string(ud); |
| 801 | if (stepValue) { | 866 | if (stepValue) { |
| 802 | line += stepValue->to_string(ud); | 867 | line += stepValue->to_string(ud); |
| 803 | } | 868 | } |
| 804 | return line; | 869 | return line; |
| 805 | } | 870 | } |
| 806 | std::string CompInner_t::to_string(void* ud) const { | 871 | std::string CompFor_t::to_string(void* ud) const { |
| 807 | str_list temp; | 872 | str_list temp; |
| 808 | for (auto item : items.objects()) { | 873 | for (auto item : items.objects()) { |
| 809 | if (ast_is<Exp_t>(item)) { | 874 | if (ast_is<Exp_t>(item)) { |
| @@ -864,6 +929,12 @@ std::string Exp_t::to_string(void* ud) const { | |||
| 864 | } | 929 | } |
| 865 | return join(temp, " "sv); | 930 | return join(temp, " "sv); |
| 866 | } | 931 | } |
| 932 | std::string ReversedIndex_t::to_string(void* ud) const { | ||
| 933 | if (modifier) { | ||
| 934 | return "[# - "s + modifier->to_string(ud) + ']'; | ||
| 935 | } | ||
| 936 | return "[#]"s; | ||
| 937 | } | ||
| 867 | std::string Callable_t::to_string(void* ud) const { | 938 | std::string Callable_t::to_string(void* ud) const { |
| 868 | return item->to_string(ud); | 939 | return item->to_string(ud); |
| 869 | } | 940 | } |
| @@ -950,6 +1021,51 @@ std::string DoubleString_t::to_string(void* ud) const { | |||
| 950 | } | 1021 | } |
| 951 | return '"' + join(temp) + '"'; | 1022 | return '"' + join(temp) + '"'; |
| 952 | } | 1023 | } |
| 1024 | std::string YAMLIndent_t::to_string(void* ud) const { | ||
| 1025 | auto info = reinterpret_cast<YueFormat*>(ud); | ||
| 1026 | return info->convert(this); | ||
| 1027 | } | ||
| 1028 | std::string YAMLLineInner_t::to_string(void* ud) const { | ||
| 1029 | auto info = reinterpret_cast<YueFormat*>(ud); | ||
| 1030 | return info->convert(this); | ||
| 1031 | } | ||
| 1032 | std::string YAMLLineContent_t::to_string(void* ud) const { | ||
| 1033 | if (content.is<Exp_t>()) { | ||
| 1034 | return "#{"s + content->to_string(ud) + '}'; | ||
| 1035 | } | ||
| 1036 | return content->to_string(ud); | ||
| 1037 | } | ||
| 1038 | std::string YAMLLine_t::to_string(void* ud) const { | ||
| 1039 | str_list temp; | ||
| 1040 | for (auto seg : segments.objects()) { | ||
| 1041 | temp.emplace_back(seg->to_string(ud)); | ||
| 1042 | } | ||
| 1043 | return join(temp); | ||
| 1044 | } | ||
| 1045 | std::string YAMLMultiline_t::to_string(void* ud) const { | ||
| 1046 | auto info = reinterpret_cast<YueFormat*>(ud); | ||
| 1047 | int currentIndent = info->indent; | ||
| 1048 | str_list temp; | ||
| 1049 | int lastIndent = -1; | ||
| 1050 | for (auto line_ : lines.objects()) { | ||
| 1051 | auto line = static_cast<YAMLLine_t*>(line_); | ||
| 1052 | auto indent = line->indent->to_string(ud); | ||
| 1053 | int ind = 0; | ||
| 1054 | for (auto c : indent) { | ||
| 1055 | if (c == ' ') ind++; | ||
| 1056 | if (c == '\t') ind += 4; | ||
| 1057 | } | ||
| 1058 | if (lastIndent < ind) { | ||
| 1059 | info->pushScope(); | ||
| 1060 | } else if (lastIndent > ind) { | ||
| 1061 | info->popScope(); | ||
| 1062 | } | ||
| 1063 | lastIndent = ind; | ||
| 1064 | temp.emplace_back(indent + line->to_string(ud)); | ||
| 1065 | } | ||
| 1066 | info->indent = currentIndent; | ||
| 1067 | return "|\n" + join(temp, "\n"sv) + '\n'; | ||
| 1068 | } | ||
| 953 | std::string String_t::to_string(void* ud) const { | 1069 | std::string String_t::to_string(void* ud) const { |
| 954 | return str->to_string(ud); | 1070 | return str->to_string(ud); |
| 955 | } | 1071 | } |
| @@ -1248,6 +1364,9 @@ std::string FnArgDef_t::to_string(void* ud) const { | |||
| 1248 | if (op) { | 1364 | if (op) { |
| 1249 | line += op->to_string(ud); | 1365 | line += op->to_string(ud); |
| 1250 | } | 1366 | } |
| 1367 | if (label) { | ||
| 1368 | line += '`' + label->to_string(ud); | ||
| 1369 | } | ||
| 1251 | if (defaultValue) { | 1370 | if (defaultValue) { |
| 1252 | line += " = "s + defaultValue->to_string(ud); | 1371 | line += " = "s + defaultValue->to_string(ud); |
| 1253 | } | 1372 | } |
| @@ -1270,6 +1389,9 @@ std::string FnArgDefList_t::to_string(void* ud) const { | |||
| 1270 | } | 1389 | } |
| 1271 | if (varArg) { | 1390 | if (varArg) { |
| 1272 | temp.emplace_back(info->ind() + varArg->to_string(ud)); | 1391 | temp.emplace_back(info->ind() + varArg->to_string(ud)); |
| 1392 | if (label) { | ||
| 1393 | temp.back().append('`' + label->to_string(ud)); | ||
| 1394 | } | ||
| 1273 | } | 1395 | } |
| 1274 | return join(temp, "\n"sv); | 1396 | return join(temp, "\n"sv); |
| 1275 | } else { | 1397 | } else { |
| @@ -1278,6 +1400,9 @@ std::string FnArgDefList_t::to_string(void* ud) const { | |||
| 1278 | } | 1400 | } |
| 1279 | if (varArg) { | 1401 | if (varArg) { |
| 1280 | temp.emplace_back(varArg->to_string(ud)); | 1402 | temp.emplace_back(varArg->to_string(ud)); |
| 1403 | if (label) { | ||
| 1404 | temp.back().append('`' + label->to_string(ud)); | ||
| 1405 | } | ||
| 1281 | } | 1406 | } |
| 1282 | return join(temp, ", "sv); | 1407 | return join(temp, ", "sv); |
| 1283 | } | 1408 | } |
| @@ -1488,37 +1613,17 @@ std::string StatementAppendix_t::to_string(void* ud) const { | |||
| 1488 | return item->to_string(ud); | 1613 | return item->to_string(ud); |
| 1489 | } | 1614 | } |
| 1490 | std::string Statement_t::to_string(void* ud) const { | 1615 | std::string Statement_t::to_string(void* ud) const { |
| 1491 | std::string line; | 1616 | if (appendix) { |
| 1492 | if (!comments.empty()) { | 1617 | return content->to_string(ud) + ' ' + appendix->to_string(ud); |
| 1493 | auto info = reinterpret_cast<YueFormat*>(ud); | ||
| 1494 | str_list temp; | ||
| 1495 | for (ast_node* comment : comments.objects()) { | ||
| 1496 | if (comment == comments.front()) { | ||
| 1497 | temp.push_back(comment->to_string(ud)); | ||
| 1498 | } else { | ||
| 1499 | temp.push_back(info->ind() + comment->to_string(ud)); | ||
| 1500 | } | ||
| 1501 | } | ||
| 1502 | if (appendix) { | ||
| 1503 | temp.push_back(info->ind() + content->to_string(ud) + ' ' + appendix->to_string(ud)); | ||
| 1504 | return join(temp, "\n"sv); | ||
| 1505 | } else { | ||
| 1506 | temp.push_back(info->ind() + content->to_string(ud)); | ||
| 1507 | return join(temp, "\n"sv); | ||
| 1508 | } | ||
| 1509 | } else { | 1618 | } else { |
| 1510 | if (appendix) { | 1619 | return content->to_string(ud); |
| 1511 | return content->to_string(ud) + ' ' + appendix->to_string(ud); | ||
| 1512 | } else { | ||
| 1513 | return content->to_string(ud); | ||
| 1514 | } | ||
| 1515 | } | 1620 | } |
| 1516 | } | 1621 | } |
| 1517 | std::string StatementSep_t::to_string(void*) const { | 1622 | std::string StatementSep_t::to_string(void*) const { |
| 1518 | return {}; | 1623 | return {}; |
| 1519 | } | 1624 | } |
| 1520 | std::string YueMultilineComment_t::to_string(void* ud) const { | 1625 | std::string EmptyLine_t::to_string(void*) const { |
| 1521 | return "--[["s + inner->to_string(ud) + "]]"s; | 1626 | return {}; |
| 1522 | } | 1627 | } |
| 1523 | std::string ChainAssign_t::to_string(void* ud) const { | 1628 | std::string ChainAssign_t::to_string(void* ud) const { |
| 1524 | str_list temp; | 1629 | str_list temp; |
| @@ -1533,14 +1638,22 @@ std::string Body_t::to_string(void* ud) const { | |||
| 1533 | std::string Block_t::to_string(void* ud) const { | 1638 | std::string Block_t::to_string(void* ud) const { |
| 1534 | auto info = reinterpret_cast<YueFormat*>(ud); | 1639 | auto info = reinterpret_cast<YueFormat*>(ud); |
| 1535 | str_list temp; | 1640 | str_list temp; |
| 1536 | for (auto stmt_ : statements.objects()) { | 1641 | for (auto stmt_ : statementOrComments.objects()) { |
| 1537 | auto stmt = static_cast<Statement_t*>(stmt_); | 1642 | if (auto stmt = ast_cast<Statement_t>(stmt_)) { |
| 1538 | if (stmt->content.is<PipeBody_t>()) { | 1643 | if (stmt->content.is<PipeBody_t>()) { |
| 1539 | info->pushScope(); | 1644 | info->pushScope(); |
| 1540 | temp.emplace_back(stmt->to_string(ud)); | 1645 | temp.emplace_back(stmt->to_string(ud)); |
| 1541 | info->popScope(); | 1646 | info->popScope(); |
| 1542 | } else { | 1647 | } else { |
| 1543 | temp.emplace_back(info->ind() + stmt->to_string(ud)); | 1648 | temp.emplace_back(info->ind() + stmt->to_string(ud)); |
| 1649 | } | ||
| 1650 | } else if (info->reserveComment) { | ||
| 1651 | if (auto comment = ast_cast<YueComment_t>(stmt_)) { | ||
| 1652 | temp.emplace_back(info->ind() + comment->to_string(ud)); | ||
| 1653 | } else { | ||
| 1654 | auto empty = ast_to<EmptyLine_t>(stmt_); | ||
| 1655 | temp.emplace_back(empty->to_string(ud)); | ||
| 1656 | } | ||
| 1544 | } | 1657 | } |
| 1545 | } | 1658 | } |
| 1546 | return join(temp, "\n"sv); | 1659 | return join(temp, "\n"sv); |
| @@ -1559,3 +1672,4 @@ std::string File_t::to_string(void* ud) const { | |||
| 1559 | } // namespace yue | 1672 | } // namespace yue |
| 1560 | 1673 | ||
| 1561 | } // namespace parserlib | 1674 | } // namespace parserlib |
| 1675 | |||
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index 0c15fac..ba4186d 100644 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> | 1 | /* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com> |
| 2 | 2 | ||
| 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
| 4 | 4 | ||
| @@ -68,7 +68,7 @@ class Statement_t; | |||
| 68 | class Body_t; | 68 | class Body_t; |
| 69 | class AssignableNameList_t; | 69 | class AssignableNameList_t; |
| 70 | class StarExp_t; | 70 | class StarExp_t; |
| 71 | class CompInner_t; | 71 | class CompFor_t; |
| 72 | class AssignableChain_t; | 72 | class AssignableChain_t; |
| 73 | class UnaryExp_t; | 73 | class UnaryExp_t; |
| 74 | class Parens_t; | 74 | class Parens_t; |
| @@ -103,11 +103,6 @@ AST_NODE(Variable) | |||
| 103 | AST_MEMBER(Variable, &name) | 103 | AST_MEMBER(Variable, &name) |
| 104 | AST_END(Variable) | 104 | AST_END(Variable) |
| 105 | 105 | ||
| 106 | AST_NODE(LabelName) | ||
| 107 | ast_ptr<true, UnicodeName_t> name; | ||
| 108 | AST_MEMBER(LabelName, &name) | ||
| 109 | AST_END(LabelName) | ||
| 110 | |||
| 111 | AST_NODE(LuaKeyword) | 106 | AST_NODE(LuaKeyword) |
| 112 | ast_ptr<true, Name_t> name; | 107 | ast_ptr<true, Name_t> name; |
| 113 | AST_MEMBER(LuaKeyword, &name) | 108 | AST_MEMBER(LuaKeyword, &name) |
| @@ -139,6 +134,11 @@ AST_NODE(KeyName) | |||
| 139 | AST_MEMBER(KeyName, &name) | 134 | AST_MEMBER(KeyName, &name) |
| 140 | AST_END(KeyName) | 135 | AST_END(KeyName) |
| 141 | 136 | ||
| 137 | AST_NODE(VarArgDef) | ||
| 138 | ast_ptr<false, Variable_t> name; | ||
| 139 | AST_MEMBER(VarArgDef, &name) | ||
| 140 | AST_END(VarArgDef) | ||
| 141 | |||
| 142 | AST_LEAF(VarArg) | 142 | AST_LEAF(VarArg) |
| 143 | AST_END(VarArg) | 143 | AST_END(VarArg) |
| 144 | 144 | ||
| @@ -233,18 +233,25 @@ AST_NODE(ImportAs) | |||
| 233 | AST_MEMBER(ImportAs, &literal, &target) | 233 | AST_MEMBER(ImportAs, &literal, &target) |
| 234 | AST_END(ImportAs) | 234 | AST_END(ImportAs) |
| 235 | 235 | ||
| 236 | AST_NODE(ImportGlobal) | ||
| 237 | ast_ptr<true, Seperator_t> sep; | ||
| 238 | ast_list<true, UnicodeName_t> segs; | ||
| 239 | ast_ptr<false, Variable_t> target; | ||
| 240 | AST_MEMBER(ImportGlobal, &sep, &segs, &target) | ||
| 241 | AST_END(ImportGlobal) | ||
| 242 | |||
| 236 | AST_NODE(Import) | 243 | AST_NODE(Import) |
| 237 | ast_sel<true, ImportAs_t, ImportFrom_t, FromImport_t> content; | 244 | ast_sel<true, ImportAs_t, ImportFrom_t, FromImport_t, ImportGlobal_t> content; |
| 238 | AST_MEMBER(Import, &content) | 245 | AST_MEMBER(Import, &content) |
| 239 | AST_END(Import) | 246 | AST_END(Import) |
| 240 | 247 | ||
| 241 | AST_NODE(Label) | 248 | AST_NODE(Label) |
| 242 | ast_ptr<true, LabelName_t> label; | 249 | ast_ptr<true, UnicodeName_t> label; |
| 243 | AST_MEMBER(Label, &label) | 250 | AST_MEMBER(Label, &label) |
| 244 | AST_END(Label) | 251 | AST_END(Label) |
| 245 | 252 | ||
| 246 | AST_NODE(Goto) | 253 | AST_NODE(Goto) |
| 247 | ast_ptr<true, LabelName_t> label; | 254 | ast_ptr<true, UnicodeName_t> label; |
| 248 | AST_MEMBER(Goto, &label) | 255 | AST_MEMBER(Goto, &label) |
| 249 | AST_END(Goto) | 256 | AST_END(Goto) |
| 250 | 257 | ||
| @@ -287,9 +294,9 @@ AST_END(Return) | |||
| 287 | AST_NODE(With) | 294 | AST_NODE(With) |
| 288 | ast_ptr<false, ExistentialOp_t> eop; | 295 | ast_ptr<false, ExistentialOp_t> eop; |
| 289 | ast_ptr<true, ExpList_t> valueList; | 296 | ast_ptr<true, ExpList_t> valueList; |
| 290 | ast_ptr<false, Assign_t> assigns; | 297 | ast_ptr<false, Assign_t> assign; |
| 291 | ast_sel<true, Block_t, Statement_t> body; | 298 | ast_sel<true, Block_t, Statement_t> body; |
| 292 | AST_MEMBER(With, &eop, &valueList, &assigns, &body) | 299 | AST_MEMBER(With, &eop, &valueList, &assign, &body) |
| 293 | AST_END(With) | 300 | AST_END(With) |
| 294 | 301 | ||
| 295 | AST_NODE(SwitchList) | 302 | AST_NODE(SwitchList) |
| @@ -304,20 +311,21 @@ AST_NODE(SwitchCase) | |||
| 304 | AST_MEMBER(SwitchCase, &condition, &body) | 311 | AST_MEMBER(SwitchCase, &condition, &body) |
| 305 | AST_END(SwitchCase) | 312 | AST_END(SwitchCase) |
| 306 | 313 | ||
| 314 | AST_NODE(Assignment) | ||
| 315 | ast_ptr<false, ExpList_t> expList; | ||
| 316 | ast_ptr<true, Assign_t> assign; | ||
| 317 | AST_MEMBER(Assignment, &expList, &assign) | ||
| 318 | AST_END(Assignment) | ||
| 319 | |||
| 307 | AST_NODE(Switch) | 320 | AST_NODE(Switch) |
| 308 | ast_ptr<true, Exp_t> target; | 321 | ast_ptr<true, Exp_t> target; |
| 322 | ast_ptr<false, Assignment_t> assignment; | ||
| 309 | ast_ptr<true, Seperator_t> sep; | 323 | ast_ptr<true, Seperator_t> sep; |
| 310 | ast_list<true, SwitchCase_t> branches; | 324 | ast_list<true, SwitchCase_t> branches; |
| 311 | ast_sel<false, Block_t, Statement_t> lastBranch; | 325 | ast_sel<false, Block_t, Statement_t> lastBranch; |
| 312 | AST_MEMBER(Switch, &target, &sep, &branches, &lastBranch) | 326 | AST_MEMBER(Switch, &target, &assignment, &sep, &branches, &lastBranch) |
| 313 | AST_END(Switch) | 327 | AST_END(Switch) |
| 314 | 328 | ||
| 315 | AST_NODE(Assignment) | ||
| 316 | ast_ptr<false, ExpList_t> expList; | ||
| 317 | ast_ptr<true, Assign_t> assign; | ||
| 318 | AST_MEMBER(Assignment, &expList, &assign) | ||
| 319 | AST_END(Assignment) | ||
| 320 | |||
| 321 | AST_NODE(IfCond) | 329 | AST_NODE(IfCond) |
| 322 | ast_ptr<true, Exp_t> condition; | 330 | ast_ptr<true, Exp_t> condition; |
| 323 | ast_ptr<false, Assignment_t> assignment; | 331 | ast_ptr<false, Assignment_t> assignment; |
| @@ -345,7 +353,7 @@ AST_NODE(While) | |||
| 345 | AST_END(While) | 353 | AST_END(While) |
| 346 | 354 | ||
| 347 | AST_NODE(Repeat) | 355 | AST_NODE(Repeat) |
| 348 | ast_ptr<true, Body_t> body; | 356 | ast_sel<true, Block_t, Statement_t> body; |
| 349 | ast_ptr<true, Exp_t> condition; | 357 | ast_ptr<true, Exp_t> condition; |
| 350 | AST_MEMBER(Repeat, &body, &condition) | 358 | AST_MEMBER(Repeat, &body, &condition) |
| 351 | AST_END(Repeat) | 359 | AST_END(Repeat) |
| @@ -355,14 +363,14 @@ AST_NODE(ForStepValue) | |||
| 355 | AST_MEMBER(ForStepValue, &value) | 363 | AST_MEMBER(ForStepValue, &value) |
| 356 | AST_END(ForStepValue) | 364 | AST_END(ForStepValue) |
| 357 | 365 | ||
| 358 | AST_NODE(For) | 366 | AST_NODE(ForNum) |
| 359 | ast_ptr<true, Variable_t> varName; | 367 | ast_ptr<true, Variable_t> varName; |
| 360 | ast_ptr<true, Exp_t> startValue; | 368 | ast_ptr<true, Exp_t> startValue; |
| 361 | ast_ptr<true, Exp_t> stopValue; | 369 | ast_ptr<true, Exp_t> stopValue; |
| 362 | ast_ptr<false, ForStepValue_t> stepValue; | 370 | ast_ptr<false, ForStepValue_t> stepValue; |
| 363 | ast_sel<true, Block_t, Statement_t> body; | 371 | ast_sel<true, Block_t, Statement_t> body; |
| 364 | AST_MEMBER(For, &varName, &startValue, &stopValue, &stepValue, &body) | 372 | AST_MEMBER(ForNum, &varName, &startValue, &stopValue, &stepValue, &body) |
| 365 | AST_END(For) | 373 | AST_END(ForNum) |
| 366 | 374 | ||
| 367 | AST_NODE(ForEach) | 375 | AST_NODE(ForEach) |
| 368 | ast_ptr<true, AssignableNameList_t> nameList; | 376 | ast_ptr<true, AssignableNameList_t> nameList; |
| @@ -371,6 +379,11 @@ AST_NODE(ForEach) | |||
| 371 | AST_MEMBER(ForEach, &nameList, &loopValue, &body) | 379 | AST_MEMBER(ForEach, &nameList, &loopValue, &body) |
| 372 | AST_END(ForEach) | 380 | AST_END(ForEach) |
| 373 | 381 | ||
| 382 | AST_NODE(For) | ||
| 383 | ast_sel<true, ForEach_t, ForNum_t> forLoop; | ||
| 384 | AST_MEMBER(For, &forLoop) | ||
| 385 | AST_END(For) | ||
| 386 | |||
| 374 | AST_NODE(Do) | 387 | AST_NODE(Do) |
| 375 | ast_ptr<true, Body_t> body; | 388 | ast_ptr<true, Body_t> body; |
| 376 | AST_MEMBER(Do, &body) | 389 | AST_MEMBER(Do, &body) |
| @@ -383,14 +396,15 @@ AST_NODE(CatchBlock) | |||
| 383 | AST_END(CatchBlock) | 396 | AST_END(CatchBlock) |
| 384 | 397 | ||
| 385 | AST_NODE(Try) | 398 | AST_NODE(Try) |
| 399 | ast_ptr<false, ExistentialOp_t> eop; | ||
| 386 | ast_sel<true, Block_t, Exp_t> func; | 400 | ast_sel<true, Block_t, Exp_t> func; |
| 387 | ast_ptr<false, CatchBlock_t> catchBlock; | 401 | ast_ptr<false, CatchBlock_t> catchBlock; |
| 388 | AST_MEMBER(Try, &func, &catchBlock) | 402 | AST_MEMBER(Try, &eop, &func, &catchBlock) |
| 389 | AST_END(Try) | 403 | AST_END(Try) |
| 390 | 404 | ||
| 391 | AST_NODE(Comprehension) | 405 | AST_NODE(Comprehension) |
| 392 | ast_ptr<true, Seperator_t> sep; | 406 | ast_ptr<true, Seperator_t> sep; |
| 393 | ast_sel_list<false, NormalDef_t, SpreadListExp_t, CompInner_t, | 407 | ast_sel_list<false, NormalDef_t, SpreadListExp_t, CompFor_t, |
| 394 | /*non-syntax-rule*/ Statement_t> items; | 408 | /*non-syntax-rule*/ Statement_t> items; |
| 395 | AST_MEMBER(Comprehension, &sep, &items) | 409 | AST_MEMBER(Comprehension, &sep, &items) |
| 396 | AST_END(Comprehension) | 410 | AST_END(Comprehension) |
| @@ -403,7 +417,7 @@ AST_END(CompValue) | |||
| 403 | AST_NODE(TblComprehension) | 417 | AST_NODE(TblComprehension) |
| 404 | ast_ptr<true, Exp_t> key; | 418 | ast_ptr<true, Exp_t> key; |
| 405 | ast_ptr<false, CompValue_t> value; | 419 | ast_ptr<false, CompValue_t> value; |
| 406 | ast_ptr<true, CompInner_t> forLoop; | 420 | ast_ptr<true, CompFor_t> forLoop; |
| 407 | AST_MEMBER(TblComprehension, &key, &value, &forLoop) | 421 | AST_MEMBER(TblComprehension, &key, &value, &forLoop) |
| 408 | AST_END(TblComprehension) | 422 | AST_END(TblComprehension) |
| 409 | 423 | ||
| @@ -418,23 +432,23 @@ AST_NODE(CompForEach) | |||
| 418 | AST_MEMBER(CompForEach, &nameList, &loopValue) | 432 | AST_MEMBER(CompForEach, &nameList, &loopValue) |
| 419 | AST_END(CompForEach) | 433 | AST_END(CompForEach) |
| 420 | 434 | ||
| 421 | AST_NODE(CompFor) | 435 | AST_NODE(CompForNum) |
| 422 | ast_ptr<true, Variable_t> varName; | 436 | ast_ptr<true, Variable_t> varName; |
| 423 | ast_ptr<true, Exp_t> startValue; | 437 | ast_ptr<true, Exp_t> startValue; |
| 424 | ast_ptr<true, Exp_t> stopValue; | 438 | ast_ptr<true, Exp_t> stopValue; |
| 425 | ast_ptr<false, ForStepValue_t> stepValue; | 439 | ast_ptr<false, ForStepValue_t> stepValue; |
| 426 | AST_MEMBER(CompFor, &varName, &startValue, &stopValue, &stepValue) | 440 | AST_MEMBER(CompForNum, &varName, &startValue, &stopValue, &stepValue) |
| 427 | AST_END(CompFor) | 441 | AST_END(CompForNum) |
| 428 | 442 | ||
| 429 | AST_NODE(CompInner) | 443 | AST_NODE(CompFor) |
| 430 | ast_ptr<true, Seperator_t> sep; | 444 | ast_ptr<true, Seperator_t> sep; |
| 431 | ast_sel_list<true, CompFor_t, CompForEach_t, Exp_t> items; | 445 | ast_sel_list<true, CompForNum_t, CompForEach_t, Exp_t> items; |
| 432 | AST_MEMBER(CompInner, &sep, &items) | 446 | AST_MEMBER(CompFor, &sep, &items) |
| 433 | AST_END(CompInner) | 447 | AST_END(CompFor) |
| 434 | 448 | ||
| 435 | AST_NODE(Assign) | 449 | AST_NODE(Assign) |
| 436 | ast_ptr<true, Seperator_t> sep; | 450 | ast_ptr<true, Seperator_t> sep; |
| 437 | ast_sel_list<true, With_t, If_t, Switch_t, TableBlock_t, Exp_t> values; | 451 | ast_sel_list<true, With_t, If_t, Switch_t, TableBlock_t, Exp_t, SpreadListExp_t> values; |
| 438 | AST_MEMBER(Assign, &sep, &values) | 452 | AST_MEMBER(Assign, &sep, &values) |
| 439 | AST_END(Assign) | 453 | AST_END(Assign) |
| 440 | 454 | ||
| @@ -549,8 +563,8 @@ AST_NODE(SimpleValue) | |||
| 549 | ast_sel<true, | 563 | ast_sel<true, |
| 550 | TableLit_t, ConstValue_t, | 564 | TableLit_t, ConstValue_t, |
| 551 | If_t, Switch_t, With_t, ClassDecl_t, | 565 | If_t, Switch_t, With_t, ClassDecl_t, |
| 552 | ForEach_t, For_t, While_t, Do_t, Try_t, | 566 | For_t, While_t, Repeat_t, |
| 553 | UnaryValue_t, | 567 | Do_t, Try_t, UnaryValue_t, |
| 554 | TblComprehension_t, Comprehension_t, | 568 | TblComprehension_t, Comprehension_t, |
| 555 | FunLit_t, Num_t, VarArg_t> value; | 569 | FunLit_t, Num_t, VarArg_t> value; |
| 556 | AST_MEMBER(SimpleValue, &value) | 570 | AST_MEMBER(SimpleValue, &value) |
| @@ -589,8 +603,31 @@ AST_NODE(DoubleString) | |||
| 589 | AST_MEMBER(DoubleString, &sep, &segments) | 603 | AST_MEMBER(DoubleString, &sep, &segments) |
| 590 | AST_END(DoubleString) | 604 | AST_END(DoubleString) |
| 591 | 605 | ||
| 606 | AST_LEAF(YAMLIndent) | ||
| 607 | AST_END(YAMLIndent) | ||
| 608 | |||
| 609 | AST_LEAF(YAMLLineInner) | ||
| 610 | AST_END(YAMLLineInner) | ||
| 611 | |||
| 612 | AST_NODE(YAMLLineContent) | ||
| 613 | ast_sel<true, YAMLLineInner_t, Exp_t> content; | ||
| 614 | AST_MEMBER(YAMLLineContent, &content) | ||
| 615 | AST_END(YAMLLineContent) | ||
| 616 | |||
| 617 | AST_NODE(YAMLLine) | ||
| 618 | ast_ptr<true, YAMLIndent_t> indent; | ||
| 619 | ast_list<true, YAMLLineContent_t> segments; | ||
| 620 | AST_MEMBER(YAMLLine, &indent, &segments) | ||
| 621 | AST_END(YAMLLine) | ||
| 622 | |||
| 623 | AST_NODE(YAMLMultiline) | ||
| 624 | ast_ptr<true, Seperator_t> sep; | ||
| 625 | ast_list<true, YAMLLine_t> lines; | ||
| 626 | AST_MEMBER(YAMLMultiline, &sep, &lines) | ||
| 627 | AST_END(YAMLMultiline) | ||
| 628 | |||
| 592 | AST_NODE(String) | 629 | AST_NODE(String) |
| 593 | ast_sel<true, DoubleString_t, SingleString_t, LuaString_t> str; | 630 | ast_sel<true, DoubleString_t, SingleString_t, LuaString_t, YAMLMultiline_t> str; |
| 594 | AST_MEMBER(String, &str) | 631 | AST_MEMBER(String, &str) |
| 595 | AST_END(String) | 632 | AST_END(String) |
| 596 | 633 | ||
| @@ -641,9 +678,14 @@ AST_END(TableAppendingOp) | |||
| 641 | AST_LEAF(PlainItem) | 678 | AST_LEAF(PlainItem) |
| 642 | AST_END(PlainItem) | 679 | AST_END(PlainItem) |
| 643 | 680 | ||
| 681 | AST_NODE(ReversedIndex) | ||
| 682 | ast_ptr<false, Exp_t> modifier; | ||
| 683 | AST_MEMBER(ReversedIndex, &modifier) | ||
| 684 | AST_END(ReversedIndex) | ||
| 685 | |||
| 644 | AST_NODE(ChainValue) | 686 | AST_NODE(ChainValue) |
| 645 | ast_ptr<true, Seperator_t> sep; | 687 | ast_ptr<true, Seperator_t> sep; |
| 646 | ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Slice_t, Exp_t, String_t, InvokeArgs_t, ExistentialOp_t, TableAppendingOp_t, | 688 | ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Slice_t, Exp_t, String_t, InvokeArgs_t, ExistentialOp_t, TableAppendingOp_t, ReversedIndex_t, |
| 647 | /*non-syntax-rule*/ PlainItem_t> items; | 689 | /*non-syntax-rule*/ PlainItem_t> items; |
| 648 | AST_MEMBER(ChainValue, &sep, &items) | 690 | AST_MEMBER(ChainValue, &sep, &items) |
| 649 | AST_END(ChainValue) | 691 | AST_END(ChainValue) |
| @@ -743,17 +785,19 @@ AST_NODE(Export) | |||
| 743 | AST_END(Export) | 785 | AST_END(Export) |
| 744 | 786 | ||
| 745 | AST_NODE(FnArgDef) | 787 | AST_NODE(FnArgDef) |
| 746 | ast_sel<true, Variable_t, SelfItem_t> name; | 788 | ast_sel<true, Variable_t, SelfItem_t, SimpleTable_t, TableLit_t> name; |
| 747 | ast_ptr<false, ExistentialOp_t> op; | 789 | ast_ptr<false, ExistentialOp_t> op; |
| 790 | ast_ptr<false, Name_t> label; | ||
| 748 | ast_ptr<false, Exp_t> defaultValue; | 791 | ast_ptr<false, Exp_t> defaultValue; |
| 749 | AST_MEMBER(FnArgDef, &name, &op, &defaultValue) | 792 | AST_MEMBER(FnArgDef, &name, &op, &label, &defaultValue) |
| 750 | AST_END(FnArgDef) | 793 | AST_END(FnArgDef) |
| 751 | 794 | ||
| 752 | AST_NODE(FnArgDefList) | 795 | AST_NODE(FnArgDefList) |
| 753 | ast_ptr<true, Seperator_t> sep; | 796 | ast_ptr<true, Seperator_t> sep; |
| 754 | ast_list<false, FnArgDef_t> definitions; | 797 | ast_list<false, FnArgDef_t> definitions; |
| 755 | ast_ptr<false, VarArg_t> varArg; | 798 | ast_ptr<false, VarArgDef_t> varArg; |
| 756 | AST_MEMBER(FnArgDefList, &sep, &definitions, &varArg) | 799 | ast_ptr<false, Name_t> label; |
| 800 | AST_MEMBER(FnArgDefList, &sep, &definitions, &varArg, &label) | ||
| 757 | AST_END(FnArgDefList) | 801 | AST_END(FnArgDefList) |
| 758 | 802 | ||
| 759 | AST_NODE(OuterVarShadow) | 803 | AST_NODE(OuterVarShadow) |
| @@ -809,7 +853,7 @@ AST_NODE(Macro) | |||
| 809 | AST_END(Macro) | 853 | AST_END(Macro) |
| 810 | 854 | ||
| 811 | AST_NODE(NameOrDestructure) | 855 | AST_NODE(NameOrDestructure) |
| 812 | ast_sel<true, Variable_t, TableLit_t, Comprehension_t> item; | 856 | ast_sel<true, Variable_t, SimpleTable_t, TableLit_t, Comprehension_t> item; |
| 813 | AST_MEMBER(NameOrDestructure, &item) | 857 | AST_MEMBER(NameOrDestructure, &item) |
| 814 | AST_END(NameOrDestructure) | 858 | AST_END(NameOrDestructure) |
| 815 | 859 | ||
| @@ -885,7 +929,7 @@ AST_NODE(PipeBody) | |||
| 885 | AST_END(PipeBody) | 929 | AST_END(PipeBody) |
| 886 | 930 | ||
| 887 | AST_NODE(StatementAppendix) | 931 | AST_NODE(StatementAppendix) |
| 888 | ast_sel<true, IfLine_t, WhileLine_t, CompInner_t> item; | 932 | ast_sel<true, IfLine_t, WhileLine_t, CompFor_t> item; |
| 889 | AST_MEMBER(StatementAppendix, &item) | 933 | AST_MEMBER(StatementAppendix, &item) |
| 890 | AST_END(StatementAppendix) | 934 | AST_END(StatementAppendix) |
| 891 | 935 | ||
| @@ -895,14 +939,17 @@ AST_END(StatementSep) | |||
| 895 | AST_LEAF(YueLineComment) | 939 | AST_LEAF(YueLineComment) |
| 896 | AST_END(YueLineComment) | 940 | AST_END(YueLineComment) |
| 897 | 941 | ||
| 898 | AST_LEAF(MultilineCommentInner) | 942 | AST_LEAF(YueMultilineComment) |
| 899 | AST_END(MultilineCommentInner) | ||
| 900 | |||
| 901 | AST_NODE(YueMultilineComment) | ||
| 902 | ast_ptr<true, MultilineCommentInner_t> inner; | ||
| 903 | AST_MEMBER(YueMultilineComment, &inner) | ||
| 904 | AST_END(YueMultilineComment) | 943 | AST_END(YueMultilineComment) |
| 905 | 944 | ||
| 945 | AST_NODE(YueComment) | ||
| 946 | ast_sel<true, YueLineComment_t, YueMultilineComment_t> comment; | ||
| 947 | AST_MEMBER(YueComment, &comment) | ||
| 948 | AST_END(YueComment) | ||
| 949 | |||
| 950 | AST_LEAF(EmptyLine) | ||
| 951 | AST_END(EmptyLine) | ||
| 952 | |||
| 906 | AST_NODE(ChainAssign) | 953 | AST_NODE(ChainAssign) |
| 907 | ast_ptr<true, Seperator_t> sep; | 954 | ast_ptr<true, Seperator_t> sep; |
| 908 | ast_list<true, Exp_t> exprs; | 955 | ast_list<true, Exp_t> exprs; |
| @@ -911,16 +958,14 @@ AST_NODE(ChainAssign) | |||
| 911 | AST_END(ChainAssign) | 958 | AST_END(ChainAssign) |
| 912 | 959 | ||
| 913 | AST_NODE(Statement) | 960 | AST_NODE(Statement) |
| 914 | ast_ptr<true, Seperator_t> sep; | ||
| 915 | ast_sel_list<false, YueLineComment_t, YueMultilineComment_t> comments; | ||
| 916 | ast_sel<true, | 961 | ast_sel<true, |
| 917 | Import_t, While_t, Repeat_t, For_t, ForEach_t, | 962 | Import_t, While_t, Repeat_t, For_t, |
| 918 | Return_t, Local_t, Global_t, Export_t, Macro_t, MacroInPlace_t, | 963 | Return_t, Local_t, Global_t, Export_t, Macro_t, MacroInPlace_t, |
| 919 | BreakLoop_t, Label_t, Goto_t, ShortTabAppending_t, | 964 | BreakLoop_t, Label_t, Goto_t, ShortTabAppending_t, |
| 920 | Backcall_t, LocalAttrib_t, PipeBody_t, ExpListAssign_t, ChainAssign_t | 965 | Backcall_t, LocalAttrib_t, PipeBody_t, ExpListAssign_t, ChainAssign_t |
| 921 | > content; | 966 | > content; |
| 922 | ast_ptr<false, StatementAppendix_t> appendix; | 967 | ast_ptr<false, StatementAppendix_t> appendix; |
| 923 | AST_MEMBER(Statement, &sep, &comments, &content, &appendix) | 968 | AST_MEMBER(Statement, &content, &appendix) |
| 924 | AST_END(Statement) | 969 | AST_END(Statement) |
| 925 | 970 | ||
| 926 | AST_NODE(Body) | 971 | AST_NODE(Body) |
| @@ -930,8 +975,8 @@ AST_END(Body) | |||
| 930 | 975 | ||
| 931 | AST_NODE(Block) | 976 | AST_NODE(Block) |
| 932 | ast_ptr<true, Seperator_t> sep; | 977 | ast_ptr<true, Seperator_t> sep; |
| 933 | ast_list<false, Statement_t> statements; | 978 | ast_sel_list<false, Statement_t, YueComment_t, EmptyLine_t> statementOrComments; |
| 934 | AST_MEMBER(Block, &sep, &statements) | 979 | AST_MEMBER(Block, &sep, &statementOrComments) |
| 935 | AST_END(Block) | 980 | AST_END(Block) |
| 936 | 981 | ||
| 937 | AST_NODE(BlockEnd) | 982 | AST_NODE(BlockEnd) |
| @@ -950,9 +995,9 @@ struct YueFormat { | |||
| 950 | int indent = 0; | 995 | int indent = 0; |
| 951 | bool spaceOverTab = false; | 996 | bool spaceOverTab = false; |
| 952 | int tabSpaces = 4; | 997 | int tabSpaces = 4; |
| 998 | bool reserveComment = true; | ||
| 953 | std::string toString(ast_node* node); | 999 | std::string toString(ast_node* node); |
| 954 | 1000 | ||
| 955 | Converter converter{}; | ||
| 956 | void pushScope(); | 1001 | void pushScope(); |
| 957 | void popScope(); | 1002 | void popScope(); |
| 958 | std::string convert(const ast_node* node); | 1003 | std::string convert(const ast_node* node); |
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 7abc929..cffa7a8 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> | 1 | /* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com> |
| 2 | 2 | ||
| 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
| 4 | 4 | ||
| @@ -78,7 +78,7 @@ static std::unordered_set<std::string> Metamethods = { | |||
| 78 | "close"s // Lua 5.4 | 78 | "close"s // Lua 5.4 |
| 79 | }; | 79 | }; |
| 80 | 80 | ||
| 81 | const std::string_view version = "0.28.3"sv; | 81 | const std::string_view version = "0.30.4"sv; |
| 82 | const std::string_view extension = "yue"sv; | 82 | const std::string_view extension = "yue"sv; |
| 83 | 83 | ||
| 84 | class CompileError : public std::logic_error { | 84 | class CompileError : public std::logic_error { |
| @@ -165,12 +165,12 @@ public: | |||
| 165 | double compileTime = 0.0; | 165 | double compileTime = 0.0; |
| 166 | if (config.profiling) { | 166 | if (config.profiling) { |
| 167 | auto start = std::chrono::high_resolution_clock::now(); | 167 | auto start = std::chrono::high_resolution_clock::now(); |
| 168 | _info = _parser.parse<File_t>(codes); | 168 | _info = _parser.parse<File_t>(codes, config.lax); |
| 169 | auto stop = std::chrono::high_resolution_clock::now(); | 169 | auto stop = std::chrono::high_resolution_clock::now(); |
| 170 | std::chrono::duration<double> diff = stop - start; | 170 | std::chrono::duration<double> diff = stop - start; |
| 171 | parseTime = diff.count(); | 171 | parseTime = diff.count(); |
| 172 | } else { | 172 | } else { |
| 173 | _info = _parser.parse<File_t>(codes); | 173 | _info = _parser.parse<File_t>(codes, config.lax); |
| 174 | } | 174 | } |
| 175 | std::unique_ptr<GlobalVars> globals; | 175 | std::unique_ptr<GlobalVars> globals; |
| 176 | std::unique_ptr<Options> options; | 176 | std::unique_ptr<Options> options; |
| @@ -182,8 +182,9 @@ public: | |||
| 182 | try { | 182 | try { |
| 183 | auto block = _info.node.to<File_t>()->block.get(); | 183 | auto block = _info.node.to<File_t>()->block.get(); |
| 184 | if (_info.exportMacro) { | 184 | if (_info.exportMacro) { |
| 185 | for (auto stmt_ : block->statements.objects()) { | 185 | for (auto stmt_ : block->statementOrComments.objects()) { |
| 186 | auto stmt = static_cast<Statement_t*>(stmt_); | 186 | auto stmt = ast_cast<Statement_t>(stmt_); |
| 187 | if (!stmt) continue; | ||
| 187 | switch (stmt->content->get_id()) { | 188 | switch (stmt->content->get_id()) { |
| 188 | case id<MacroInPlace_t>(): | 189 | case id<MacroInPlace_t>(): |
| 189 | case id<Macro_t>(): | 190 | case id<Macro_t>(): |
| @@ -258,8 +259,8 @@ public: | |||
| 258 | if (config.lintGlobalVariable) { | 259 | if (config.lintGlobalVariable) { |
| 259 | globals = std::make_unique<GlobalVars>(); | 260 | globals = std::make_unique<GlobalVars>(); |
| 260 | for (const auto& var : _globals) { | 261 | for (const auto& var : _globals) { |
| 261 | auto [name, line, col, accessType] = var.second; | 262 | auto [name, line, col, accessType, defined] = var.second; |
| 262 | globals->push_back({name, line + _config.lineOffset, col, accessType}); | 263 | globals->push_back({name, line + _config.lineOffset, col, accessType, defined}); |
| 263 | } | 264 | } |
| 264 | std::sort(globals->begin(), globals->end(), [](const GlobalVar& varA, const GlobalVar& varB) { | 265 | std::sort(globals->begin(), globals->end(), [](const GlobalVar& varA, const GlobalVar& varB) { |
| 265 | if (varA.line < varB.line) { | 266 | if (varA.line < varB.line) { |
| @@ -396,7 +397,7 @@ private: | |||
| 396 | }; | 397 | }; |
| 397 | std::stack<ContinueVar> _continueVars; | 398 | std::stack<ContinueVar> _continueVars; |
| 398 | std::list<std::unique_ptr<input>> _codeCache; | 399 | std::list<std::unique_ptr<input>> _codeCache; |
| 399 | std::unordered_map<std::string, std::tuple<std::string, int, int, AccessType>> _globals; | 400 | std::unordered_map<std::string, std::tuple<std::string, int, int, AccessType, bool>> _globals; |
| 400 | std::ostringstream _buf; | 401 | std::ostringstream _buf; |
| 401 | std::ostringstream _joinBuf; | 402 | std::ostringstream _joinBuf; |
| 402 | const std::string _newLine = "\n"; | 403 | const std::string _newLine = "\n"; |
| @@ -875,6 +876,10 @@ private: | |||
| 875 | return false; | 876 | return false; |
| 876 | } | 877 | } |
| 877 | 878 | ||
| 879 | bool isListComp(Comprehension_t* comp) const { | ||
| 880 | return comp->items.size() == 2 && ast_is<CompFor_t>(comp->items.back()); | ||
| 881 | } | ||
| 882 | |||
| 878 | void markVarLocalConst(const std::string& name) { | 883 | void markVarLocalConst(const std::string& name) { |
| 879 | auto& scope = _scopes.back(); | 884 | auto& scope = _scopes.back(); |
| 880 | scope.vars->insert_or_assign(name, VarType::LocalConst); | 885 | scope.vars->insert_or_assign(name, VarType::LocalConst); |
| @@ -967,7 +972,7 @@ private: | |||
| 967 | } | 972 | } |
| 968 | } | 973 | } |
| 969 | 974 | ||
| 970 | const std::string nll(ast_node* node) const { | 975 | const std::string nl(ast_node* node) const { |
| 971 | if (_config.reserveLineNumber) { | 976 | if (_config.reserveLineNumber) { |
| 972 | return " -- "s + std::to_string(node->m_begin.m_line + _config.lineOffset) + _newLine; | 977 | return " -- "s + std::to_string(node->m_begin.m_line + _config.lineOffset) + _newLine; |
| 973 | } else { | 978 | } else { |
| @@ -975,14 +980,6 @@ private: | |||
| 975 | } | 980 | } |
| 976 | } | 981 | } |
| 977 | 982 | ||
| 978 | const std::string nlr(ast_node* node) const { | ||
| 979 | if (_config.reserveLineNumber) { | ||
| 980 | return " -- "s + std::to_string(node->m_end.m_line + _config.lineOffset) + _newLine; | ||
| 981 | } else { | ||
| 982 | return _newLine; | ||
| 983 | } | ||
| 984 | } | ||
| 985 | |||
| 986 | void incIndentOffset() { | 983 | void incIndentOffset() { |
| 987 | _indentOffset++; | 984 | _indentOffset++; |
| 988 | } | 985 | } |
| @@ -1169,14 +1166,22 @@ private: | |||
| 1169 | return nullptr; | 1166 | return nullptr; |
| 1170 | } | 1167 | } |
| 1171 | 1168 | ||
| 1172 | Statement_t* lastStatementFrom(const node_container& stmts) const { | 1169 | Statement_t* lastStatementFrom(const node_container& statementOrComments) const { |
| 1173 | if (!stmts.empty()) { | 1170 | if (!statementOrComments.empty()) { |
| 1174 | auto it = stmts.end(); | 1171 | for (auto it = statementOrComments.rbegin(); it != statementOrComments.rend(); ++it) { |
| 1175 | --it; | 1172 | if (auto stmt = ast_cast<Statement_t>(*it)) { |
| 1176 | while (!static_cast<Statement_t*>(*it)->content && it != stmts.begin()) { | 1173 | return stmt; |
| 1177 | --it; | 1174 | } |
| 1175 | } | ||
| 1176 | } | ||
| 1177 | return nullptr; | ||
| 1178 | } | ||
| 1179 | |||
| 1180 | Statement_t* firstStatementFrom(Block_t* block) const { | ||
| 1181 | for (auto stmt_ : block->statementOrComments.objects()) { | ||
| 1182 | if (auto stmt = ast_cast<Statement_t>(stmt_)) { | ||
| 1183 | return stmt; | ||
| 1178 | } | 1184 | } |
| 1179 | return static_cast<Statement_t*>(*it); | ||
| 1180 | } | 1185 | } |
| 1181 | return nullptr; | 1186 | return nullptr; |
| 1182 | } | 1187 | } |
| @@ -1185,16 +1190,26 @@ private: | |||
| 1185 | if (auto stmt = body->content.as<Statement_t>()) { | 1190 | if (auto stmt = body->content.as<Statement_t>()) { |
| 1186 | return stmt; | 1191 | return stmt; |
| 1187 | } else { | 1192 | } else { |
| 1188 | const auto& stmts = body->content.to<Block_t>()->statements.objects(); | 1193 | const auto& stmts = body->content.to<Block_t>()->statementOrComments.objects(); |
| 1189 | return lastStatementFrom(stmts); | 1194 | return lastStatementFrom(stmts); |
| 1190 | } | 1195 | } |
| 1191 | } | 1196 | } |
| 1192 | 1197 | ||
| 1193 | Statement_t* lastStatementFrom(Block_t* block) const { | 1198 | Statement_t* lastStatementFrom(Block_t* block) const { |
| 1194 | const auto& stmts = block->statements.objects(); | 1199 | const auto& stmts = block->statementOrComments.objects(); |
| 1195 | return lastStatementFrom(stmts); | 1200 | return lastStatementFrom(stmts); |
| 1196 | } | 1201 | } |
| 1197 | 1202 | ||
| 1203 | int countStatementFrom(Block_t* block) const { | ||
| 1204 | int count = 0; | ||
| 1205 | for (auto stmt_ : block->statementOrComments.objects()) { | ||
| 1206 | if (ast_is<Statement_t>(stmt_)) { | ||
| 1207 | count++; | ||
| 1208 | } | ||
| 1209 | } | ||
| 1210 | return count; | ||
| 1211 | } | ||
| 1212 | |||
| 1198 | Exp_t* lastExpFromAssign(ast_node* action) { | 1213 | Exp_t* lastExpFromAssign(ast_node* action) { |
| 1199 | switch (action->get_id()) { | 1214 | switch (action->get_id()) { |
| 1200 | case id<Update_t>(): { | 1215 | case id<Update_t>(): { |
| @@ -1258,7 +1273,7 @@ private: | |||
| 1258 | 1273 | ||
| 1259 | template <class T> | 1274 | template <class T> |
| 1260 | ast_ptr<false, T> toAst(std::string_view codes, ast_node* parent) { | 1275 | ast_ptr<false, T> toAst(std::string_view codes, ast_node* parent) { |
| 1261 | auto res = _parser.parse<T>(std::string(codes)); | 1276 | auto res = _parser.parse<T>(std::string(codes), false); |
| 1262 | if (res.error) { | 1277 | if (res.error) { |
| 1263 | throw CompileError(res.error.value().msg, parent); | 1278 | throw CompileError(res.error.value().msg, parent); |
| 1264 | } | 1279 | } |
| @@ -1281,6 +1296,8 @@ private: | |||
| 1281 | Common, | 1296 | Common, |
| 1282 | EndWithColon, | 1297 | EndWithColon, |
| 1283 | EndWithEOP, | 1298 | EndWithEOP, |
| 1299 | EndWithSlice, | ||
| 1300 | HasRIndex, | ||
| 1284 | HasEOP, | 1301 | HasEOP, |
| 1285 | HasKeyword, | 1302 | HasKeyword, |
| 1286 | HasUnicode, | 1303 | HasUnicode, |
| @@ -1299,6 +1316,9 @@ private: | |||
| 1299 | if (ast_is<ExistentialOp_t>(chainValue->items.back())) { | 1316 | if (ast_is<ExistentialOp_t>(chainValue->items.back())) { |
| 1300 | return ChainType::EndWithEOP; | 1317 | return ChainType::EndWithEOP; |
| 1301 | } | 1318 | } |
| 1319 | if (ast_is<Slice_t>(chainValue->items.back())) { | ||
| 1320 | return ChainType::EndWithSlice; | ||
| 1321 | } | ||
| 1302 | if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) { | 1322 | if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) { |
| 1303 | if (dot->name.is<Metatable_t>()) { | 1323 | if (dot->name.is<Metatable_t>()) { |
| 1304 | return ChainType::Metatable; | 1324 | return ChainType::Metatable; |
| @@ -1324,6 +1344,8 @@ private: | |||
| 1324 | } | 1344 | } |
| 1325 | } else if (ast_is<ExistentialOp_t>(item)) { | 1345 | } else if (ast_is<ExistentialOp_t>(item)) { |
| 1326 | return ChainType::HasEOP; | 1346 | return ChainType::HasEOP; |
| 1347 | } else if (ast_is<ReversedIndex_t>(item)) { | ||
| 1348 | return ChainType::HasRIndex; | ||
| 1327 | } | 1349 | } |
| 1328 | } | 1350 | } |
| 1329 | return type; | 1351 | return type; |
| @@ -1353,10 +1375,10 @@ private: | |||
| 1353 | std::ostringstream buf; | 1375 | std::ostringstream buf; |
| 1354 | for (auto it = uname->m_begin.m_it; it != uname->m_end.m_it; ++it) { | 1376 | for (auto it = uname->m_begin.m_it; it != uname->m_end.m_it; ++it) { |
| 1355 | auto ch = *it; | 1377 | auto ch = *it; |
| 1356 | if (ch > 255) { | 1378 | if (ch <= 0x7F && ((ch == '_') || ((ch | 0x20) >= 'a' && (ch | 0x20) <= 'z') || (ch >= '0' && ch <= '9'))) { |
| 1357 | buf << "_u"sv << std::hex << static_cast<int>(ch); | ||
| 1358 | } else { | ||
| 1359 | buf << static_cast<char>(ch); | 1379 | buf << static_cast<char>(ch); |
| 1380 | } else { | ||
| 1381 | buf << "_u"sv << std::hex << static_cast<uint32_t>(ch); | ||
| 1360 | } | 1382 | } |
| 1361 | } | 1383 | } |
| 1362 | return buf.str(); | 1384 | return buf.str(); |
| @@ -1438,6 +1460,7 @@ private: | |||
| 1438 | case id<DotChainItem_t>(): | 1460 | case id<DotChainItem_t>(): |
| 1439 | case id<Exp_t>(): | 1461 | case id<Exp_t>(): |
| 1440 | case id<TableAppendingOp_t>(): | 1462 | case id<TableAppendingOp_t>(): |
| 1463 | case id<ReversedIndex_t>(): | ||
| 1441 | return true; | 1464 | return true; |
| 1442 | } | 1465 | } |
| 1443 | } | 1466 | } |
| @@ -1455,7 +1478,7 @@ private: | |||
| 1455 | if (simpleValue->value.is<TableLit_t>()) { | 1478 | if (simpleValue->value.is<TableLit_t>()) { |
| 1456 | return true; | 1479 | return true; |
| 1457 | } else if (auto comp = simpleValue->value.as<Comprehension_t>()) { | 1480 | } else if (auto comp = simpleValue->value.as<Comprehension_t>()) { |
| 1458 | if (comp->items.size() != 2 || !ast_is<CompInner_t>(comp->items.back())) { | 1481 | if (!isListComp(comp)) { |
| 1459 | return true; | 1482 | return true; |
| 1460 | } | 1483 | } |
| 1461 | } | 1484 | } |
| @@ -1596,7 +1619,7 @@ private: | |||
| 1596 | if (accessType == AccessType::Read && _funcLevel > 1) { | 1619 | if (accessType == AccessType::Read && _funcLevel > 1) { |
| 1597 | accessType = AccessType::Capture; | 1620 | accessType = AccessType::Capture; |
| 1598 | } | 1621 | } |
| 1599 | _globals[key] = {str, x->m_begin.m_line, x->m_begin.m_col, accessType}; | 1622 | _globals[key] = {str, x->m_begin.m_line, x->m_begin.m_col, accessType, isSolidDefined(str)}; |
| 1600 | } | 1623 | } |
| 1601 | } | 1624 | } |
| 1602 | } | 1625 | } |
| @@ -1638,24 +1661,31 @@ private: | |||
| 1638 | return; | 1661 | return; |
| 1639 | } | 1662 | } |
| 1640 | 1663 | ||
| 1641 | void transformStatement(Statement_t* statement, str_list& out) { | 1664 | void transformComment(YueComment_t* comment, str_list& out) { |
| 1642 | auto x = statement; | 1665 | if (!_config.reserveComment) { |
| 1643 | if (_config.reserveComment && !x->comments.empty()) { | 1666 | return; |
| 1644 | for (ast_node* node : x->comments.objects()) { | 1667 | } |
| 1645 | switch (node->get_id()) { | 1668 | auto node = comment->comment.get(); |
| 1646 | case id<YueLineComment_t>(): { | 1669 | if (!node) { |
| 1647 | auto comment = ast_cast<YueLineComment_t>(node); | 1670 | out.push_back("\n"s); |
| 1648 | out.push_back(indent() + "--"s + _parser.toString(comment) + '\n'); | 1671 | return; |
| 1649 | break; | 1672 | } |
| 1650 | } | 1673 | switch (node->get_id()) { |
| 1651 | case id<YueMultilineComment_t>(): { | 1674 | case id<YueLineComment_t>(): { |
| 1652 | auto comment = ast_cast<YueMultilineComment_t>(node); | 1675 | auto content = static_cast<YueLineComment_t*>(node); |
| 1653 | out.push_back(indent() + _parser.toString(comment) + '\n'); | 1676 | out.push_back(indent() + "--"s + _parser.toString(content) + '\n'); |
| 1654 | break; | 1677 | break; |
| 1655 | } | 1678 | } |
| 1656 | } | 1679 | case id<YueMultilineComment_t>(): { |
| 1680 | auto content = static_cast<YueMultilineComment_t*>(node); | ||
| 1681 | out.push_back(indent() + "--[["s + _parser.toString(content) + "]]\n"s); | ||
| 1682 | break; | ||
| 1657 | } | 1683 | } |
| 1658 | } | 1684 | } |
| 1685 | } | ||
| 1686 | |||
| 1687 | void transformStatement(Statement_t* statement, str_list& out) { | ||
| 1688 | auto x = statement; | ||
| 1659 | if (statement->appendix) { | 1689 | if (statement->appendix) { |
| 1660 | if (auto assignment = assignmentFrom(statement)) { | 1690 | if (auto assignment = assignmentFrom(statement)) { |
| 1661 | auto preDefine = getPreDefineLine(assignment); | 1691 | auto preDefine = getPreDefineLine(assignment); |
| @@ -1719,7 +1749,7 @@ private: | |||
| 1719 | throw CompileError("while-loop line decorator is not supported here"sv, appendix->item.get()); | 1749 | throw CompileError("while-loop line decorator is not supported here"sv, appendix->item.get()); |
| 1720 | break; | 1750 | break; |
| 1721 | } | 1751 | } |
| 1722 | case id<CompInner_t>(): { | 1752 | case id<CompFor_t>(): { |
| 1723 | throw CompileError("for-loop line decorator is not supported here"sv, appendix->item.get()); | 1753 | throw CompileError("for-loop line decorator is not supported here"sv, appendix->item.get()); |
| 1724 | break; | 1754 | break; |
| 1725 | } | 1755 | } |
| @@ -1780,8 +1810,8 @@ private: | |||
| 1780 | statement->content.set(expListAssign); | 1810 | statement->content.set(expListAssign); |
| 1781 | break; | 1811 | break; |
| 1782 | } | 1812 | } |
| 1783 | case id<CompInner_t>(): { | 1813 | case id<CompFor_t>(): { |
| 1784 | auto compInner = appendix->item.to<CompInner_t>(); | 1814 | auto compInner = appendix->item.to<CompFor_t>(); |
| 1785 | auto comp = x->new_ptr<Comprehension_t>(); | 1815 | auto comp = x->new_ptr<Comprehension_t>(); |
| 1786 | auto stmt = x->new_ptr<Statement_t>(); | 1816 | auto stmt = x->new_ptr<Statement_t>(); |
| 1787 | stmt->content.set(statement->content); | 1817 | stmt->content.set(statement->content); |
| @@ -1846,11 +1876,12 @@ private: | |||
| 1846 | case id<ForEach_t>(): transformForEach(static_cast<ForEach_t*>(value), out); break; | 1876 | case id<ForEach_t>(): transformForEach(static_cast<ForEach_t*>(value), out); break; |
| 1847 | case id<For_t>(): transformFor(static_cast<For_t*>(value), out); break; | 1877 | case id<For_t>(): transformFor(static_cast<For_t*>(value), out); break; |
| 1848 | case id<While_t>(): transformWhile(static_cast<While_t*>(value), out); break; | 1878 | case id<While_t>(): transformWhile(static_cast<While_t*>(value), out); break; |
| 1879 | case id<Repeat_t>(): transformRepeat(static_cast<Repeat_t*>(value), out); break; | ||
| 1849 | case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Common); break; | 1880 | case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Common); break; |
| 1850 | case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Common); break; | 1881 | case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Common); break; |
| 1851 | case id<Comprehension_t>(): { | 1882 | case id<Comprehension_t>(): { |
| 1852 | auto comp = static_cast<Comprehension_t*>(value); | 1883 | auto comp = static_cast<Comprehension_t*>(value); |
| 1853 | if (comp->items.size() == 2 && ast_is<CompInner_t>(comp->items.back())) { | 1884 | if (isListComp(comp)) { |
| 1854 | transformCompCommon(comp, out); | 1885 | transformCompCommon(comp, out); |
| 1855 | } else { | 1886 | } else { |
| 1856 | specialSingleValue = false; | 1887 | specialSingleValue = false; |
| @@ -1974,7 +2005,7 @@ private: | |||
| 1974 | return indent() + "local "s + join(defs, ", "sv); | 2005 | return indent() + "local "s + join(defs, ", "sv); |
| 1975 | } | 2006 | } |
| 1976 | 2007 | ||
| 1977 | std::string getDestrucureDefine(ExpListAssign_t* assignment) { | 2008 | std::string getDestructureDefine(ExpListAssign_t* assignment) { |
| 1978 | auto info = extractDestructureInfo(assignment, true, false); | 2009 | auto info = extractDestructureInfo(assignment, true, false); |
| 1979 | if (!info.destructures.empty()) { | 2010 | if (!info.destructures.empty()) { |
| 1980 | str_list defs; | 2011 | str_list defs; |
| @@ -2005,8 +2036,31 @@ private: | |||
| 2005 | return clearBuf(); | 2036 | return clearBuf(); |
| 2006 | } | 2037 | } |
| 2007 | 2038 | ||
| 2039 | str_list getArgDestructureList(ExpListAssign_t* assignment) { | ||
| 2040 | str_list defs; | ||
| 2041 | auto info = extractDestructureInfo(assignment, true, false); | ||
| 2042 | if (!info.destructures.empty()) { | ||
| 2043 | for (const auto& des : info.destructures) { | ||
| 2044 | if (std::holds_alternative<Destructure>(des)) { | ||
| 2045 | const auto& destruct = std::get<Destructure>(des); | ||
| 2046 | for (const auto& item : destruct.items) { | ||
| 2047 | if (item.targetVar.empty()) { | ||
| 2048 | throw CompileError("can only destruct argument to variable"sv, item.target); | ||
| 2049 | } else { | ||
| 2050 | defs.push_back(item.targetVar); | ||
| 2051 | } | ||
| 2052 | } | ||
| 2053 | } else { | ||
| 2054 | const auto& assignment = std::get<AssignmentPtr>(des); | ||
| 2055 | YUEE("AST node mismatch", assignment.ptr); | ||
| 2056 | } | ||
| 2057 | } | ||
| 2058 | } | ||
| 2059 | return defs; | ||
| 2060 | } | ||
| 2061 | |||
| 2008 | std::string getPreDefine(ExpListAssign_t* assignment) { | 2062 | std::string getPreDefine(ExpListAssign_t* assignment) { |
| 2009 | auto preDefine = getDestrucureDefine(assignment); | 2063 | auto preDefine = getDestructureDefine(assignment); |
| 2010 | if (preDefine.empty()) { | 2064 | if (preDefine.empty()) { |
| 2011 | preDefine = toLocalDecl(transformAssignDefs(assignment->expList, DefOp::Mark)); | 2065 | preDefine = toLocalDecl(transformAssignDefs(assignment->expList, DefOp::Mark)); |
| 2012 | } | 2066 | } |
| @@ -2015,7 +2069,7 @@ private: | |||
| 2015 | 2069 | ||
| 2016 | std::string getPreDefineLine(ExpListAssign_t* assignment) { | 2070 | std::string getPreDefineLine(ExpListAssign_t* assignment) { |
| 2017 | auto preDefine = getPreDefine(assignment); | 2071 | auto preDefine = getPreDefine(assignment); |
| 2018 | if (!preDefine.empty()) preDefine += nll(assignment); | 2072 | if (!preDefine.empty()) preDefine += nl(assignment); |
| 2019 | return preDefine; | 2073 | return preDefine; |
| 2020 | } | 2074 | } |
| 2021 | 2075 | ||
| @@ -2171,14 +2225,14 @@ private: | |||
| 2171 | temp.push_back(getPreDefineLine(assignment)); | 2225 | temp.push_back(getPreDefineLine(assignment)); |
| 2172 | bool needScope = !currentScope().lastStatement; | 2226 | bool needScope = !currentScope().lastStatement; |
| 2173 | if (needScope) { | 2227 | if (needScope) { |
| 2174 | temp.push_back(indent() + "do"s + nll(assignment)); | 2228 | temp.push_back(indent() + "do"s + nl(assignment)); |
| 2175 | pushScope(); | 2229 | pushScope(); |
| 2176 | } | 2230 | } |
| 2177 | transformAssignment(preAssignment, temp); | 2231 | transformAssignment(preAssignment, temp); |
| 2178 | transformAssignment(assignment, temp); | 2232 | transformAssignment(assignment, temp); |
| 2179 | if (needScope) { | 2233 | if (needScope) { |
| 2180 | popScope(); | 2234 | popScope(); |
| 2181 | temp.push_back(indent() + "end"s + nll(assignment)); | 2235 | temp.push_back(indent() + "end"s + nl(assignment)); |
| 2182 | } | 2236 | } |
| 2183 | out.push_back(join(temp)); | 2237 | out.push_back(join(temp)); |
| 2184 | return false; | 2238 | return false; |
| @@ -2223,7 +2277,8 @@ private: | |||
| 2223 | BREAK_IF(!value); | 2277 | BREAK_IF(!value); |
| 2224 | auto chainValue = value->item.as<ChainValue_t>(); | 2278 | auto chainValue = value->item.as<ChainValue_t>(); |
| 2225 | BREAK_IF(!chainValue); | 2279 | BREAK_IF(!chainValue); |
| 2226 | if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) { | 2280 | auto last = chainValue->items.back(); |
| 2281 | if (auto dot = ast_cast<DotChainItem_t>(last)) { | ||
| 2227 | BREAK_IF(!dot->name.is<Metatable_t>()); | 2282 | BREAK_IF(!dot->name.is<Metatable_t>()); |
| 2228 | str_list temp; | 2283 | str_list temp; |
| 2229 | auto [beforeAssignment, afterAssignment] = splitAssignment(); | 2284 | auto [beforeAssignment, afterAssignment] = splitAssignment(); |
| @@ -2247,14 +2302,14 @@ private: | |||
| 2247 | throw CompileError("right value missing"sv, values.front()); | 2302 | throw CompileError("right value missing"sv, values.front()); |
| 2248 | } | 2303 | } |
| 2249 | transformAssignItem(*vit, args); | 2304 | transformAssignItem(*vit, args); |
| 2250 | _buf << indent() << globalVar("setmetatable"sv, x, AccessType::Read) << '(' << join(args, ", "sv) << ')' << nll(x); | 2305 | _buf << indent() << globalVar("setmetatable"sv, x, AccessType::Read) << '(' << join(args, ", "sv) << ')' << nl(x); |
| 2251 | temp.push_back(clearBuf()); | 2306 | temp.push_back(clearBuf()); |
| 2252 | if (!afterAssignment->expList->exprs.empty()) { | 2307 | if (!afterAssignment->expList->exprs.empty()) { |
| 2253 | transformAssignment(afterAssignment, temp); | 2308 | transformAssignment(afterAssignment, temp); |
| 2254 | } | 2309 | } |
| 2255 | out.push_back(join(temp)); | 2310 | out.push_back(join(temp)); |
| 2256 | return false; | 2311 | return false; |
| 2257 | } else if (ast_is<TableAppendingOp_t>(chainValue->items.back())) { | 2312 | } else if (ast_is<TableAppendingOp_t>(last)) { |
| 2258 | str_list temp; | 2313 | str_list temp; |
| 2259 | auto [beforeAssignment, afterAssignment] = splitAssignment(); | 2314 | auto [beforeAssignment, afterAssignment] = splitAssignment(); |
| 2260 | if (!beforeAssignment->expList->exprs.empty()) { | 2315 | if (!beforeAssignment->expList->exprs.empty()) { |
| @@ -2276,7 +2331,7 @@ private: | |||
| 2276 | if (varName.empty() || !isLocal(varName)) { | 2331 | if (varName.empty() || !isLocal(varName)) { |
| 2277 | if (needScope) { | 2332 | if (needScope) { |
| 2278 | extraScoped = true; | 2333 | extraScoped = true; |
| 2279 | temp.push_back(indent() + "do"s + nll(x)); | 2334 | temp.push_back(indent() + "do"s + nl(x)); |
| 2280 | pushScope(); | 2335 | pushScope(); |
| 2281 | } | 2336 | } |
| 2282 | auto objVar = getUnusedName("_obj_"sv); | 2337 | auto objVar = getUnusedName("_obj_"sv); |
| @@ -2288,19 +2343,69 @@ private: | |||
| 2288 | transformAssignment(newAssignment, temp); | 2343 | transformAssignment(newAssignment, temp); |
| 2289 | varName = objVar; | 2344 | varName = objVar; |
| 2290 | } | 2345 | } |
| 2291 | auto newAssignment = x->new_ptr<ExpListAssign_t>(); | 2346 | if (auto spread = ast_cast<SpreadListExp_t>(*vit)) { |
| 2292 | newAssignment->expList.set(toAst<ExpList_t>(varName + "[#"s + varName + "+1]"s, x)); | 2347 | auto lenVar = getUnusedName("_len_"sv); |
| 2293 | auto assign = x->new_ptr<Assign_t>(); | 2348 | forceAddToScope(lenVar); |
| 2294 | if (vit == values.end()) { | 2349 | temp.push_back(indent() + "local "s + lenVar + " = #"s + varName + " + 1"s + nl(spread)); |
| 2295 | throw CompileError("right value missing"sv, values.front()); | 2350 | auto elmVar = getUnusedName("_elm_"sv); |
| 2351 | _buf << varName << '[' << lenVar << "],"s << lenVar << "="s << elmVar << ',' << lenVar << "+1 for "s << elmVar << " in *nil"s; | ||
| 2352 | auto stmt = toAst<Statement_t>(clearBuf(), spread); | ||
| 2353 | auto comp = stmt->appendix->item.to<CompFor_t>(); | ||
| 2354 | ast_to<CompForEach_t>(comp->items.front())->loopValue.to<StarExp_t>()->value.set(spread->exp); | ||
| 2355 | transformStatement(stmt, temp); | ||
| 2356 | } else { | ||
| 2357 | auto newAssignment = x->new_ptr<ExpListAssign_t>(); | ||
| 2358 | newAssignment->expList.set(toAst<ExpList_t>(varName + "[#"s + varName + "+1]"s, x)); | ||
| 2359 | auto assign = x->new_ptr<Assign_t>(); | ||
| 2360 | if (vit == values.end()) { | ||
| 2361 | throw CompileError("right value missing"sv, values.front()); | ||
| 2362 | } | ||
| 2363 | assign->values.push_back(*vit); | ||
| 2364 | newAssignment->action.set(assign); | ||
| 2365 | transformAssignment(newAssignment, temp); | ||
| 2296 | } | 2366 | } |
| 2297 | assign->values.push_back(*vit); | ||
| 2298 | newAssignment->action.set(assign); | ||
| 2299 | transformAssignment(newAssignment, temp); | ||
| 2300 | if (extraScoped) { | 2367 | if (extraScoped) { |
| 2301 | popScope(); | 2368 | popScope(); |
| 2302 | temp.push_back(indent() + "end"s + nlr(x)); | 2369 | temp.push_back(indent() + "end"s + nl(x)); |
| 2370 | } | ||
| 2371 | if (!afterAssignment->expList->exprs.empty()) { | ||
| 2372 | transformAssignment(afterAssignment, temp); | ||
| 2373 | } | ||
| 2374 | out.push_back(join(temp)); | ||
| 2375 | return false; | ||
| 2376 | } else if (ast_is<ReversedIndex_t>(last)) { | ||
| 2377 | if (chainValue->items.size() == 1) { | ||
| 2378 | if (_withVars.empty()) { | ||
| 2379 | throw CompileError("short dot/colon syntax must be called within a with block"sv, x); | ||
| 2380 | } else { | ||
| 2381 | break; | ||
| 2382 | } | ||
| 2383 | } | ||
| 2384 | auto tmpChain = chainValue->new_ptr<ChainValue_t>(); | ||
| 2385 | tmpChain->items.dup(chainValue->items); | ||
| 2386 | tmpChain->items.pop_back(); | ||
| 2387 | auto tmpLeft = newExp(tmpChain, tmpChain); | ||
| 2388 | auto leftVar = singleVariableFrom(tmpLeft, AccessType::Read); | ||
| 2389 | if (!leftVar.empty() && isLocal(leftVar)) { | ||
| 2390 | break; | ||
| 2391 | } | ||
| 2392 | leftVar = getUnusedName("_obj_"sv); | ||
| 2393 | auto tmpAsmt = assignmentFrom(toAst<Exp_t>(leftVar, tmpLeft), tmpLeft, tmpLeft); | ||
| 2394 | str_list temp; | ||
| 2395 | transformAssignment(tmpAsmt, temp); | ||
| 2396 | auto [beforeAssignment, afterAssignment] = splitAssignment(); | ||
| 2397 | if (!beforeAssignment->expList->exprs.empty()) { | ||
| 2398 | transformAssignment(beforeAssignment, temp); | ||
| 2303 | } | 2399 | } |
| 2400 | if (vit == values.end()) { | ||
| 2401 | throw CompileError("right value missing"sv, values.front()); | ||
| 2402 | } | ||
| 2403 | auto newChain = chainValue->new_ptr<ChainValue_t>(); | ||
| 2404 | newChain->items.push_back(toAst<Callable_t>(leftVar, newChain)); | ||
| 2405 | newChain->items.push_back(chainValue->items.back()); | ||
| 2406 | auto newLeft = newExp(newChain, newChain); | ||
| 2407 | auto newAsmt = assignmentFrom(newLeft, *vit, newLeft); | ||
| 2408 | transformAssignment(newAsmt, temp); | ||
| 2304 | if (!afterAssignment->expList->exprs.empty()) { | 2409 | if (!afterAssignment->expList->exprs.empty()) { |
| 2305 | transformAssignment(afterAssignment, temp); | 2410 | transformAssignment(afterAssignment, temp); |
| 2306 | } | 2411 | } |
| @@ -2329,6 +2434,17 @@ private: | |||
| 2329 | out.back().insert(0, preDefine); | 2434 | out.back().insert(0, preDefine); |
| 2330 | return false; | 2435 | return false; |
| 2331 | } | 2436 | } |
| 2437 | case id<Try_t>(): { | ||
| 2438 | auto tryNode = static_cast<Try_t*>(value); | ||
| 2439 | if (tryNode->eop) { | ||
| 2440 | auto assignList = assignment->expList.get(); | ||
| 2441 | std::string preDefine = getPreDefineLine(assignment); | ||
| 2442 | transformTry(tryNode, out, ExpUsage::Assignment, assignList); | ||
| 2443 | out.back().insert(0, preDefine); | ||
| 2444 | return false; | ||
| 2445 | } | ||
| 2446 | break; | ||
| 2447 | } | ||
| 2332 | case id<Switch_t>(): { | 2448 | case id<Switch_t>(): { |
| 2333 | auto switchNode = static_cast<Switch_t*>(value); | 2449 | auto switchNode = static_cast<Switch_t*>(value); |
| 2334 | auto assignList = assignment->expList.get(); | 2450 | auto assignList = assignment->expList.get(); |
| @@ -2356,7 +2472,7 @@ private: | |||
| 2356 | case id<Comprehension_t>(): { | 2472 | case id<Comprehension_t>(): { |
| 2357 | auto comp = static_cast<Comprehension_t*>(value); | 2473 | auto comp = static_cast<Comprehension_t*>(value); |
| 2358 | auto expList = assignment->expList.get(); | 2474 | auto expList = assignment->expList.get(); |
| 2359 | if (comp->items.size() == 2 && ast_is<CompInner_t>(comp->items.back())) { | 2475 | if (isListComp(comp)) { |
| 2360 | std::string preDefine = getPreDefineLine(assignment); | 2476 | std::string preDefine = getPreDefineLine(assignment); |
| 2361 | transformComprehension(comp, out, ExpUsage::Assignment, expList); | 2477 | transformComprehension(comp, out, ExpUsage::Assignment, expList); |
| 2362 | out.back().insert(0, preDefine); | 2478 | out.back().insert(0, preDefine); |
| @@ -2400,6 +2516,13 @@ private: | |||
| 2400 | out.back().insert(0, preDefine); | 2516 | out.back().insert(0, preDefine); |
| 2401 | return false; | 2517 | return false; |
| 2402 | } | 2518 | } |
| 2519 | case id<Repeat_t>(): { | ||
| 2520 | auto expList = assignment->expList.get(); | ||
| 2521 | std::string preDefine = getPreDefineLine(assignment); | ||
| 2522 | transformRepeatInPlace(static_cast<Repeat_t*>(value), out, expList); | ||
| 2523 | out.back().insert(0, preDefine); | ||
| 2524 | return false; | ||
| 2525 | } | ||
| 2403 | case id<TableLit_t>(): { | 2526 | case id<TableLit_t>(): { |
| 2404 | auto tableLit = static_cast<TableLit_t*>(value); | 2527 | auto tableLit = static_cast<TableLit_t*>(value); |
| 2405 | if (hasSpreadExp(tableLit->values.objects())) { | 2528 | if (hasSpreadExp(tableLit->values.objects())) { |
| @@ -2452,12 +2575,14 @@ private: | |||
| 2452 | switch (type) { | 2575 | switch (type) { |
| 2453 | case ChainType::HasEOP: | 2576 | case ChainType::HasEOP: |
| 2454 | case ChainType::EndWithColon: | 2577 | case ChainType::EndWithColon: |
| 2578 | case ChainType::EndWithSlice: | ||
| 2455 | case ChainType::MetaFieldInvocation: { | 2579 | case ChainType::MetaFieldInvocation: { |
| 2456 | std::string preDefine = getPreDefineLine(assignment); | 2580 | std::string preDefine = getPreDefineLine(assignment); |
| 2457 | transformChainValue(chainValue, out, ExpUsage::Assignment, expList, false, optionalDestruct); | 2581 | transformChainValue(chainValue, out, ExpUsage::Assignment, expList, false, optionalDestruct); |
| 2458 | out.back().insert(0, preDefine); | 2582 | out.back().insert(0, preDefine); |
| 2459 | return false; | 2583 | return false; |
| 2460 | } | 2584 | } |
| 2585 | case ChainType::HasRIndex: | ||
| 2461 | case ChainType::HasKeyword: | 2586 | case ChainType::HasKeyword: |
| 2462 | case ChainType::HasUnicode: | 2587 | case ChainType::HasUnicode: |
| 2463 | case ChainType::Macro: | 2588 | case ChainType::Macro: |
| @@ -2512,11 +2637,11 @@ private: | |||
| 2512 | checkConst(def, x); | 2637 | checkConst(def, x); |
| 2513 | addToScope(def); | 2638 | addToScope(def); |
| 2514 | } | 2639 | } |
| 2515 | temp.push_back(indent() + "local "s + join(defs, ", "sv) + nll(x)); | 2640 | temp.push_back(indent() + "local "s + join(defs, ", "sv) + nl(x)); |
| 2516 | } | 2641 | } |
| 2517 | if (needScope) { | 2642 | if (needScope) { |
| 2518 | extraScope = true; | 2643 | extraScope = true; |
| 2519 | temp.push_back(indent() + "do"s + nll(x)); | 2644 | temp.push_back(indent() + "do"s + nl(x)); |
| 2520 | pushScope(); | 2645 | pushScope(); |
| 2521 | } | 2646 | } |
| 2522 | } | 2647 | } |
| @@ -2568,13 +2693,13 @@ private: | |||
| 2568 | continue; | 2693 | continue; |
| 2569 | } | 2694 | } |
| 2570 | if (extraScope) { | 2695 | if (extraScope) { |
| 2571 | temp.push_back(indent() + "do"s + nll(x)); | 2696 | temp.push_back(indent() + "do"s + nl(x)); |
| 2572 | pushScope(); | 2697 | pushScope(); |
| 2573 | } | 2698 | } |
| 2574 | if (!pair.targetVar.empty()) { | 2699 | if (!pair.targetVar.empty()) { |
| 2575 | checkConst(pair.targetVar, x); | 2700 | checkConst(pair.targetVar, x); |
| 2576 | if (addToScope(pair.targetVar)) { | 2701 | if (addToScope(pair.targetVar)) { |
| 2577 | _buf << indent() << "local "sv << pair.targetVar << nll(x); | 2702 | _buf << indent() << "local "sv << pair.targetVar << nl(x); |
| 2578 | temp.push_back(clearBuf()); | 2703 | temp.push_back(clearBuf()); |
| 2579 | } | 2704 | } |
| 2580 | } | 2705 | } |
| @@ -2584,7 +2709,7 @@ private: | |||
| 2584 | objVar = destruct.valueVar; | 2709 | objVar = destruct.valueVar; |
| 2585 | } else { | 2710 | } else { |
| 2586 | if (needScope) { | 2711 | if (needScope) { |
| 2587 | temp.push_back(indent() + "do"s + nll(x)); | 2712 | temp.push_back(indent() + "do"s + nl(x)); |
| 2588 | pushScope(); | 2713 | pushScope(); |
| 2589 | } | 2714 | } |
| 2590 | objVar = getUnusedName("_obj_"sv); | 2715 | objVar = getUnusedName("_obj_"sv); |
| @@ -2600,7 +2725,7 @@ private: | |||
| 2600 | if (!isLocalValue) { | 2725 | if (!isLocalValue) { |
| 2601 | if (needScope) { | 2726 | if (needScope) { |
| 2602 | popScope(); | 2727 | popScope(); |
| 2603 | _buf << indent() << "end"sv << nlr(x); | 2728 | _buf << indent() << "end"sv << nl(x); |
| 2604 | temp.push_back(clearBuf()); | 2729 | temp.push_back(clearBuf()); |
| 2605 | } | 2730 | } |
| 2606 | } | 2731 | } |
| @@ -2638,9 +2763,9 @@ private: | |||
| 2638 | checkConst(def, x); | 2763 | checkConst(def, x); |
| 2639 | addToScope(def); | 2764 | addToScope(def); |
| 2640 | } | 2765 | } |
| 2641 | temp.push_back(indent() + "local "s + join(defs, ", "sv) + nll(x)); | 2766 | temp.push_back(indent() + "local "s + join(defs, ", "sv) + nl(x)); |
| 2642 | } | 2767 | } |
| 2643 | temp.push_back(indent() + "do"s + nll(x)); | 2768 | temp.push_back(indent() + "do"s + nl(x)); |
| 2644 | pushScope(); | 2769 | pushScope(); |
| 2645 | } | 2770 | } |
| 2646 | } else { | 2771 | } else { |
| @@ -2649,11 +2774,11 @@ private: | |||
| 2649 | checkConst(def, x); | 2774 | checkConst(def, x); |
| 2650 | addToScope(def); | 2775 | addToScope(def); |
| 2651 | } | 2776 | } |
| 2652 | temp.push_back(indent() + "local "s + join(defs, ", "sv) + nll(x)); | 2777 | temp.push_back(indent() + "local "s + join(defs, ", "sv) + nl(x)); |
| 2653 | } | 2778 | } |
| 2654 | if (needScope) { | 2779 | if (needScope) { |
| 2655 | extraScope = true; | 2780 | extraScope = true; |
| 2656 | temp.push_back(indent() + "do"s + nll(x)); | 2781 | temp.push_back(indent() + "do"s + nl(x)); |
| 2657 | pushScope(); | 2782 | pushScope(); |
| 2658 | } | 2783 | } |
| 2659 | auto valVar = getUnusedName("_obj_"sv); | 2784 | auto valVar = getUnusedName("_obj_"sv); |
| @@ -2668,7 +2793,7 @@ private: | |||
| 2668 | if (destruct.inlineAssignment) { | 2793 | if (destruct.inlineAssignment) { |
| 2669 | if (needScope && !extraScope) { | 2794 | if (needScope && !extraScope) { |
| 2670 | extraScope = true; | 2795 | extraScope = true; |
| 2671 | temp.push_back(indent() + "do"s + nll(x)); | 2796 | temp.push_back(indent() + "do"s + nl(x)); |
| 2672 | pushScope(); | 2797 | pushScope(); |
| 2673 | } | 2798 | } |
| 2674 | transformAssignment(destruct.inlineAssignment, temp); | 2799 | transformAssignment(destruct.inlineAssignment, temp); |
| @@ -2733,13 +2858,13 @@ private: | |||
| 2733 | } | 2858 | } |
| 2734 | if (extraScope) { | 2859 | if (extraScope) { |
| 2735 | popScope(); | 2860 | popScope(); |
| 2736 | _buf << indent() << "end"sv << nlr(x); | 2861 | _buf << indent() << "end"sv << nl(x); |
| 2737 | temp.push_back(clearBuf()); | 2862 | temp.push_back(clearBuf()); |
| 2738 | } | 2863 | } |
| 2739 | } | 2864 | } |
| 2740 | if (extraScope) { | 2865 | if (extraScope) { |
| 2741 | popScope(); | 2866 | popScope(); |
| 2742 | temp.push_back(indent() + "end"s + nlr(x)); | 2867 | temp.push_back(indent() + "end"s + nl(x)); |
| 2743 | } | 2868 | } |
| 2744 | out.push_back(join(temp)); | 2869 | out.push_back(join(temp)); |
| 2745 | if (assignment->expList->followStmt) { | 2870 | if (assignment->expList->followStmt) { |
| @@ -2757,6 +2882,7 @@ private: | |||
| 2757 | case id<Switch_t>(): transformSwitch(static_cast<Switch_t*>(value), out, ExpUsage::Closure); break; | 2882 | case id<Switch_t>(): transformSwitch(static_cast<Switch_t*>(value), out, ExpUsage::Closure); break; |
| 2758 | case id<TableBlock_t>(): transformTableBlock(static_cast<TableBlock_t*>(value), out); break; | 2883 | case id<TableBlock_t>(): transformTableBlock(static_cast<TableBlock_t*>(value), out); break; |
| 2759 | case id<Exp_t>(): transformExp(static_cast<Exp_t*>(value), out, ExpUsage::Closure); break; | 2884 | case id<Exp_t>(): transformExp(static_cast<Exp_t*>(value), out, ExpUsage::Closure); break; |
| 2885 | case id<SpreadListExp_t>(): throw CompileError("can only be used for ranged table append assignments"sv, value); break; | ||
| 2760 | default: YUEE("AST node mismatch", value); break; | 2886 | default: YUEE("AST node mismatch", value); break; |
| 2761 | } | 2887 | } |
| 2762 | } | 2888 | } |
| @@ -2771,7 +2897,7 @@ private: | |||
| 2771 | if (auto tbA = item->get_by_path<TableLit_t>()) { | 2897 | if (auto tbA = item->get_by_path<TableLit_t>()) { |
| 2772 | tableItems = &tbA->values.objects(); | 2898 | tableItems = &tbA->values.objects(); |
| 2773 | } else if (auto tbB = item->get_by_path<Comprehension_t>()) { | 2899 | } else if (auto tbB = item->get_by_path<Comprehension_t>()) { |
| 2774 | if (tbB->items.size() == 2 && ast_is<CompInner_t>(tbB->items.back())) { | 2900 | if (isListComp(tbB)) { |
| 2775 | throw CompileError("invalid destructure value"sv, tbB); | 2901 | throw CompileError("invalid destructure value"sv, tbB); |
| 2776 | } | 2902 | } |
| 2777 | tableItems = &tbB->items.objects(); | 2903 | tableItems = &tbB->items.objects(); |
| @@ -2802,7 +2928,7 @@ private: | |||
| 2802 | } | 2928 | } |
| 2803 | case id<Comprehension_t>(): { | 2929 | case id<Comprehension_t>(): { |
| 2804 | auto table = static_cast<Comprehension_t*>(node); | 2930 | auto table = static_cast<Comprehension_t*>(node); |
| 2805 | if (table->items.size() == 2 && ast_is<CompInner_t>(table->items.back())) { | 2931 | if (isListComp(table)) { |
| 2806 | throw CompileError("invalid destructure value"sv, table); | 2932 | throw CompileError("invalid destructure value"sv, table); |
| 2807 | } | 2933 | } |
| 2808 | tableItems = &table->items.objects(); | 2934 | tableItems = &table->items.objects(); |
| @@ -2813,17 +2939,19 @@ private: | |||
| 2813 | if (!tableItems) throw CompileError("invalid destructure value"sv, node); | 2939 | if (!tableItems) throw CompileError("invalid destructure value"sv, node); |
| 2814 | std::list<DestructItem> pairs; | 2940 | std::list<DestructItem> pairs; |
| 2815 | int index = 0; | 2941 | int index = 0; |
| 2942 | int count = 0; | ||
| 2943 | bool hasSpread = false; | ||
| 2816 | auto subMetaDestruct = node->new_ptr<TableLit_t>(); | 2944 | auto subMetaDestruct = node->new_ptr<TableLit_t>(); |
| 2817 | for (auto pair : *tableItems) { | 2945 | for (auto pair : *tableItems) { |
| 2818 | switch (pair->get_id()) { | 2946 | switch (pair->get_id()) { |
| 2819 | case id<Exp_t>(): | 2947 | case id<Exp_t>(): |
| 2820 | case id<NormalDef_t>(): { | 2948 | case id<NormalDef_t>(): { |
| 2949 | ++index; | ||
| 2821 | Exp_t* defVal = nullptr; | 2950 | Exp_t* defVal = nullptr; |
| 2822 | if (auto nd = ast_cast<NormalDef_t>(pair)) { | 2951 | if (auto nd = ast_cast<NormalDef_t>(pair)) { |
| 2823 | pair = nd->item.get(); | 2952 | pair = nd->item.get(); |
| 2824 | defVal = nd->defVal.get(); | 2953 | defVal = nd->defVal.get(); |
| 2825 | } | 2954 | } |
| 2826 | ++index; | ||
| 2827 | bool assignable = false; | 2955 | bool assignable = false; |
| 2828 | try { | 2956 | try { |
| 2829 | assignable = isAssignable(static_cast<Exp_t*>(pair)); | 2957 | assignable = isAssignable(static_cast<Exp_t*>(pair)); |
| @@ -2834,13 +2962,19 @@ private: | |||
| 2834 | if (optional) break; | 2962 | if (optional) break; |
| 2835 | throw CompileError("can't destructure value"sv, pair); | 2963 | throw CompileError("can't destructure value"sv, pair); |
| 2836 | } | 2964 | } |
| 2965 | ast_ptr<true, ast_node> indexItem; | ||
| 2966 | if (hasSpread) { | ||
| 2967 | int rIndex = count - index; | ||
| 2968 | indexItem.set(toAst<ReversedIndex_t>('#' + (rIndex == 0 ? Empty : "-"s + std::to_string(rIndex)), pair)); | ||
| 2969 | } else { | ||
| 2970 | indexItem.set(toAst<Exp_t>(std::to_string(index), pair)); | ||
| 2971 | } | ||
| 2837 | if (optional && varDefOnly && !assignable) { | 2972 | if (optional && varDefOnly && !assignable) { |
| 2838 | if (defVal) { | 2973 | if (defVal) { |
| 2839 | throw CompileError("default value is not supported here"sv, defVal); | 2974 | throw CompileError("default value is not supported here"sv, defVal); |
| 2840 | } | 2975 | } |
| 2841 | auto exp = static_cast<Exp_t*>(pair); | 2976 | auto exp = static_cast<Exp_t*>(pair); |
| 2842 | auto chain = exp->new_ptr<ChainValue_t>(); | 2977 | auto chain = exp->new_ptr<ChainValue_t>(); |
| 2843 | auto indexItem = toAst<Exp_t>(std::to_string(index), exp); | ||
| 2844 | chain->items.push_back(indexItem); | 2978 | chain->items.push_back(indexItem); |
| 2845 | pairs.push_back({exp, Empty, chain, nullptr}); | 2979 | pairs.push_back({exp, Empty, chain, nullptr}); |
| 2846 | break; | 2980 | break; |
| @@ -2855,7 +2989,6 @@ private: | |||
| 2855 | throw CompileError("default value is not supported here"sv, defVal); | 2989 | throw CompileError("default value is not supported here"sv, defVal); |
| 2856 | } | 2990 | } |
| 2857 | } | 2991 | } |
| 2858 | auto indexItem = toAst<Exp_t>(std::to_string(index), value); | ||
| 2859 | for (auto& p : subPairs) { | 2992 | for (auto& p : subPairs) { |
| 2860 | if (sep) p.structure->items.push_front(sep); | 2993 | if (sep) p.structure->items.push_front(sep); |
| 2861 | p.structure->items.push_front(indexItem); | 2994 | p.structure->items.push_front(indexItem); |
| @@ -2866,7 +2999,6 @@ private: | |||
| 2866 | auto varName = singleVariableFrom(exp, AccessType::None); | 2999 | auto varName = singleVariableFrom(exp, AccessType::None); |
| 2867 | if (varName == "_"sv) break; | 3000 | if (varName == "_"sv) break; |
| 2868 | auto chain = exp->new_ptr<ChainValue_t>(); | 3001 | auto chain = exp->new_ptr<ChainValue_t>(); |
| 2869 | auto indexItem = toAst<Exp_t>(std::to_string(index), exp); | ||
| 2870 | chain->items.push_back(indexItem); | 3002 | chain->items.push_back(indexItem); |
| 2871 | pairs.push_back({exp, | 3003 | pairs.push_back({exp, |
| 2872 | varName, | 3004 | varName, |
| @@ -2991,7 +3123,13 @@ private: | |||
| 2991 | auto tb = static_cast<TableBlockIndent_t*>(pair); | 3123 | auto tb = static_cast<TableBlockIndent_t*>(pair); |
| 2992 | ++index; | 3124 | ++index; |
| 2993 | auto subPairs = destructFromExp(tb, varDefOnly, optional); | 3125 | auto subPairs = destructFromExp(tb, varDefOnly, optional); |
| 2994 | auto indexItem = toAst<Exp_t>(std::to_string(index), tb); | 3126 | ast_ptr<true, ast_node> indexItem; |
| 3127 | if (hasSpread) { | ||
| 3128 | int rIndex = count - index; | ||
| 3129 | indexItem.set(toAst<ReversedIndex_t>('#' + (rIndex == 0 ? Empty : "-"s + std::to_string(rIndex)), tb)); | ||
| 3130 | } else { | ||
| 3131 | indexItem.set(toAst<Exp_t>(std::to_string(index), tb)); | ||
| 3132 | } | ||
| 2995 | for (auto& p : subPairs) { | 3133 | for (auto& p : subPairs) { |
| 2996 | if (sep) p.structure->items.push_front(sep); | 3134 | if (sep) p.structure->items.push_front(sep); |
| 2997 | p.structure->items.push_front(indexItem); | 3135 | p.structure->items.push_front(indexItem); |
| @@ -3048,6 +3186,42 @@ private: | |||
| 3048 | subMetaDestruct->values.push_back(newPairDef); | 3186 | subMetaDestruct->values.push_back(newPairDef); |
| 3049 | break; | 3187 | break; |
| 3050 | } | 3188 | } |
| 3189 | case id<SpreadListExp_t>(): | ||
| 3190 | case id<SpreadExp_t>(): { | ||
| 3191 | ++index; | ||
| 3192 | if (hasSpread) { | ||
| 3193 | throw CompileError("duplicated spread expression"sv, pair); | ||
| 3194 | } | ||
| 3195 | hasSpread = true; | ||
| 3196 | for (auto item : *tableItems) { | ||
| 3197 | if (ast_is< | ||
| 3198 | SpreadListExp_t, SpreadExp_t, | ||
| 3199 | TableBlockIndent_t, | ||
| 3200 | Exp_t, NormalDef_t>(item)) { | ||
| 3201 | count++; | ||
| 3202 | } | ||
| 3203 | } | ||
| 3204 | Exp_t* exp = nullptr; | ||
| 3205 | if (auto se = ast_cast<SpreadExp_t>(pair)) { | ||
| 3206 | exp = se->exp.get(); | ||
| 3207 | } else { | ||
| 3208 | exp = ast_to<SpreadListExp_t>(pair)->exp.get(); | ||
| 3209 | } | ||
| 3210 | auto varName = singleVariableFrom(exp, AccessType::None); | ||
| 3211 | if (varName == "_"sv) break; | ||
| 3212 | int start = index; | ||
| 3213 | int stop = index - count - 1; | ||
| 3214 | auto chain = exp->new_ptr<ChainValue_t>(); | ||
| 3215 | auto slice = toAst<Slice_t>( | ||
| 3216 | '[' + (start == 1 ? Empty : std::to_string(start)) + ',' + (stop == -1 ? Empty : std::to_string(stop)) + ']', exp); | ||
| 3217 | chain->items.push_back(slice); | ||
| 3218 | auto nil = toAst<Exp_t>("nil"sv, slice); | ||
| 3219 | pairs.push_back({exp, | ||
| 3220 | varName, | ||
| 3221 | chain, | ||
| 3222 | nil.get()}); | ||
| 3223 | break; | ||
| 3224 | } | ||
| 3051 | default: YUEE("AST node mismatch", pair); break; | 3225 | default: YUEE("AST node mismatch", pair); break; |
| 3052 | } | 3226 | } |
| 3053 | } | 3227 | } |
| @@ -3125,7 +3299,7 @@ private: | |||
| 3125 | if (auto tab = sVal->value.as<TableLit_t>()) { | 3299 | if (auto tab = sVal->value.as<TableLit_t>()) { |
| 3126 | destructNode = tab; | 3300 | destructNode = tab; |
| 3127 | } else if (auto comp = sVal->value.as<Comprehension_t>()) { | 3301 | } else if (auto comp = sVal->value.as<Comprehension_t>()) { |
| 3128 | if (comp->items.size() != 2 || !ast_is<CompInner_t>(comp->items.back())) { | 3302 | if (!isListComp(comp)) { |
| 3129 | destructNode = comp; | 3303 | destructNode = comp; |
| 3130 | } | 3304 | } |
| 3131 | } | 3305 | } |
| @@ -3512,7 +3686,7 @@ private: | |||
| 3512 | _buf << defs; | 3686 | _buf << defs; |
| 3513 | else | 3687 | else |
| 3514 | _buf << indent() << left; | 3688 | _buf << indent() << left; |
| 3515 | _buf << " = "sv << left << ' ' << op << ' ' << right << nll(assignment); | 3689 | _buf << " = "sv << left << ' ' << op << ' ' << right << nl(assignment); |
| 3516 | out.push_back(clearBuf()); | 3690 | out.push_back(clearBuf()); |
| 3517 | break; | 3691 | break; |
| 3518 | } | 3692 | } |
| @@ -3559,9 +3733,9 @@ private: | |||
| 3559 | transformExpList(expList, temp); | 3733 | transformExpList(expList, temp); |
| 3560 | std::string left = std::move(temp.back()); | 3734 | std::string left = std::move(temp.back()); |
| 3561 | temp.pop_back(); | 3735 | temp.pop_back(); |
| 3562 | out.push_back(indent() + left + " = "s + join(temp, ", "sv) + nll(assignment)); | 3736 | out.push_back(indent() + left + " = "s + join(temp, ", "sv) + nl(assignment)); |
| 3563 | } else { | 3737 | } else { |
| 3564 | out.push_back(preDefine + " = "s + join(temp, ", "sv) + nll(assignment)); | 3738 | out.push_back(preDefine + " = "s + join(temp, ", "sv) + nl(assignment)); |
| 3565 | } | 3739 | } |
| 3566 | } else { | 3740 | } else { |
| 3567 | std::string preDefine = toLocalDecl(defs); | 3741 | std::string preDefine = toLocalDecl(defs); |
| @@ -3577,7 +3751,7 @@ private: | |||
| 3577 | for (auto value : assign->values.objects()) { | 3751 | for (auto value : assign->values.objects()) { |
| 3578 | transformAssignItem(value, temp); | 3752 | transformAssignItem(value, temp); |
| 3579 | } | 3753 | } |
| 3580 | out.push_back((preDefine.empty() ? Empty : preDefine + nll(assignment)) + indent() + left + " = "s + join(temp, ", "sv) + nll(assignment)); | 3754 | out.push_back((preDefine.empty() ? Empty : preDefine + nl(assignment)) + indent() + left + " = "s + join(temp, ", "sv) + nl(assignment)); |
| 3581 | } | 3755 | } |
| 3582 | break; | 3756 | break; |
| 3583 | } | 3757 | } |
| @@ -3678,7 +3852,7 @@ private: | |||
| 3678 | if (usage != ExpUsage::Closure) { | 3852 | if (usage != ExpUsage::Closure) { |
| 3679 | if (!currentScope().lastStatement) { | 3853 | if (!currentScope().lastStatement) { |
| 3680 | extraScope = true; | 3854 | extraScope = true; |
| 3681 | temp.push_back(indent() + "do"s + nll(asmt)); | 3855 | temp.push_back(indent() + "do"s + nl(asmt)); |
| 3682 | pushScope(); | 3856 | pushScope(); |
| 3683 | } | 3857 | } |
| 3684 | } | 3858 | } |
| @@ -3711,7 +3885,7 @@ private: | |||
| 3711 | if (usage != ExpUsage::Closure) { | 3885 | if (usage != ExpUsage::Closure) { |
| 3712 | if (!currentScope().lastStatement) { | 3886 | if (!currentScope().lastStatement) { |
| 3713 | extraScope = true; | 3887 | extraScope = true; |
| 3714 | temp.push_back(indent() + "do"s + nll(asmt)); | 3888 | temp.push_back(indent() + "do"s + nl(asmt)); |
| 3715 | pushScope(); | 3889 | pushScope(); |
| 3716 | } | 3890 | } |
| 3717 | } | 3891 | } |
| @@ -3740,12 +3914,12 @@ private: | |||
| 3740 | if (pair != ifCondPairs.front()) { | 3914 | if (pair != ifCondPairs.front()) { |
| 3741 | _buf << "else"sv; | 3915 | _buf << "else"sv; |
| 3742 | } | 3916 | } |
| 3743 | _buf << "if "sv << condStr << " then"sv << nll(condition); | 3917 | _buf << "if "sv << condStr << " then"sv << nl(condition); |
| 3744 | temp.push_back(clearBuf()); | 3918 | temp.push_back(clearBuf()); |
| 3745 | } | 3919 | } |
| 3746 | if (pair.second) { | 3920 | if (pair.second) { |
| 3747 | if (!pair.first) { | 3921 | if (!pair.first) { |
| 3748 | temp.push_back(indent() + "else"s + nll(pair.second)); | 3922 | temp.push_back(indent() + "else"s + nl(pair.second)); |
| 3749 | } | 3923 | } |
| 3750 | pushScope(); | 3924 | pushScope(); |
| 3751 | if (pair == ifCondPairs.front() && extraAssignment) { | 3925 | if (pair == ifCondPairs.front() && extraAssignment) { |
| @@ -3755,17 +3929,17 @@ private: | |||
| 3755 | popScope(); | 3929 | popScope(); |
| 3756 | } | 3930 | } |
| 3757 | if (!pair.first) { | 3931 | if (!pair.first) { |
| 3758 | temp.push_back(indent() + "end"s + nll(nodes.front())); | 3932 | temp.push_back(indent() + "end"s + nl(nodes.front())); |
| 3759 | break; | 3933 | break; |
| 3760 | } | 3934 | } |
| 3761 | } | 3935 | } |
| 3762 | if (extraScope) { | 3936 | if (extraScope) { |
| 3763 | popScope(); | 3937 | popScope(); |
| 3764 | temp.push_back(indent() + "end"s + nlr(nodes.front())); | 3938 | temp.push_back(indent() + "end"s + nl(nodes.front())); |
| 3765 | } | 3939 | } |
| 3766 | if (usage == ExpUsage::Closure) { | 3940 | if (usage == ExpUsage::Closure) { |
| 3767 | popScope(); | 3941 | popScope(); |
| 3768 | *funcStart = anonFuncStart() + nll(nodes.front()); | 3942 | *funcStart = anonFuncStart() + nl(nodes.front()); |
| 3769 | temp.push_back(indent() + anonFuncEnd()); | 3943 | temp.push_back(indent() + anonFuncEnd()); |
| 3770 | popAnonVarArg(); | 3944 | popAnonVarArg(); |
| 3771 | popFunctionScope(); | 3945 | popFunctionScope(); |
| @@ -3860,7 +4034,7 @@ private: | |||
| 3860 | } else { | 4034 | } else { |
| 3861 | transformExp(arg, out, ExpUsage::Closure); | 4035 | transformExp(arg, out, ExpUsage::Closure); |
| 3862 | out.back().insert(0, indent()); | 4036 | out.back().insert(0, indent()); |
| 3863 | out.back().append(nlr(x)); | 4037 | out.back().append(nl(x)); |
| 3864 | } | 4038 | } |
| 3865 | return; | 4039 | return; |
| 3866 | } | 4040 | } |
| @@ -3984,7 +4158,7 @@ private: | |||
| 3984 | auto stmt = exp->new_ptr<Statement_t>(); | 4158 | auto stmt = exp->new_ptr<Statement_t>(); |
| 3985 | stmt->content.set(preDefine); | 4159 | stmt->content.set(preDefine); |
| 3986 | preDefine.set(nullptr); | 4160 | preDefine.set(nullptr); |
| 3987 | block->statements.push_back(stmt); | 4161 | block->statementOrComments.push_back(stmt); |
| 3988 | auto simpleValue = exp->new_ptr<SimpleValue_t>(); | 4162 | auto simpleValue = exp->new_ptr<SimpleValue_t>(); |
| 3989 | simpleValue->value.set(ifNode); | 4163 | simpleValue->value.set(ifNode); |
| 3990 | auto explist = exp->new_ptr<ExpList_t>(); | 4164 | auto explist = exp->new_ptr<ExpList_t>(); |
| @@ -3993,7 +4167,7 @@ private: | |||
| 3993 | expListAssign->expList.set(explist); | 4167 | expListAssign->expList.set(explist); |
| 3994 | stmt = exp->new_ptr<Statement_t>(); | 4168 | stmt = exp->new_ptr<Statement_t>(); |
| 3995 | stmt->content.set(expListAssign); | 4169 | stmt->content.set(expListAssign); |
| 3996 | block->statements.push_back(stmt); | 4170 | block->statementOrComments.push_back(stmt); |
| 3997 | nodes->push_back(block); | 4171 | nodes->push_back(block); |
| 3998 | nodes = &ifNode->nodes; | 4172 | nodes = &ifNode->nodes; |
| 3999 | } else { | 4173 | } else { |
| @@ -4001,7 +4175,7 @@ private: | |||
| 4001 | auto stmt = exp->new_ptr<Statement_t>(); | 4175 | auto stmt = exp->new_ptr<Statement_t>(); |
| 4002 | stmt->content.set(preDefine); | 4176 | stmt->content.set(preDefine); |
| 4003 | preDefine.set(nullptr); | 4177 | preDefine.set(nullptr); |
| 4004 | block->statements.push_back(stmt); | 4178 | block->statementOrComments.push_back(stmt); |
| 4005 | auto simpleValue = exp->new_ptr<SimpleValue_t>(); | 4179 | auto simpleValue = exp->new_ptr<SimpleValue_t>(); |
| 4006 | simpleValue->value.set(ifNode); | 4180 | simpleValue->value.set(ifNode); |
| 4007 | auto explist = exp->new_ptr<ExpList_t>(); | 4181 | auto explist = exp->new_ptr<ExpList_t>(); |
| @@ -4010,7 +4184,7 @@ private: | |||
| 4010 | expListAssign->expList.set(explist); | 4184 | expListAssign->expList.set(explist); |
| 4011 | stmt = exp->new_ptr<Statement_t>(); | 4185 | stmt = exp->new_ptr<Statement_t>(); |
| 4012 | stmt->content.set(expListAssign); | 4186 | stmt->content.set(expListAssign); |
| 4013 | block->statements.push_back(stmt); | 4187 | block->statementOrComments.push_back(stmt); |
| 4014 | auto body = exp->new_ptr<Body_t>(); | 4188 | auto body = exp->new_ptr<Body_t>(); |
| 4015 | body->content.set(block); | 4189 | body->content.set(block); |
| 4016 | auto doNode = exp->new_ptr<Do_t>(); | 4190 | auto doNode = exp->new_ptr<Do_t>(); |
| @@ -4172,7 +4346,7 @@ private: | |||
| 4172 | auto stmt = x->new_ptr<Statement_t>(); | 4346 | auto stmt = x->new_ptr<Statement_t>(); |
| 4173 | stmt->content.set(expListAssign); | 4347 | stmt->content.set(expListAssign); |
| 4174 | auto blk = x->new_ptr<Block_t>(); | 4348 | auto blk = x->new_ptr<Block_t>(); |
| 4175 | blk->statements.push_back(stmt); | 4349 | blk->statementOrComments.push_back(stmt); |
| 4176 | newBlock.set(blk); | 4350 | newBlock.set(blk); |
| 4177 | } | 4351 | } |
| 4178 | if (!globals.empty()) { | 4352 | if (!globals.empty()) { |
| @@ -4264,15 +4438,25 @@ private: | |||
| 4264 | 4438 | ||
| 4265 | std::optional<std::pair<std::string, str_list>> upValueFuncFromExp(Exp_t* exp, str_list* ensureArgListInTheEnd, bool blockRewrite) { | 4439 | std::optional<std::pair<std::string, str_list>> upValueFuncFromExp(Exp_t* exp, str_list* ensureArgListInTheEnd, bool blockRewrite) { |
| 4266 | if (checkUpValueFuncAvailable(exp)) { | 4440 | if (checkUpValueFuncAvailable(exp)) { |
| 4441 | auto block = exp->new_ptr<Block_t>(); | ||
| 4442 | if (auto sVal = simpleSingleValueFrom(exp)) { | ||
| 4443 | if (auto doNode = sVal->value.as<Do_t>()) { | ||
| 4444 | if (auto blk = doNode->body->content.as<Block_t>()) { | ||
| 4445 | block->statementOrComments.dup(blk->statementOrComments); | ||
| 4446 | } else { | ||
| 4447 | block->statementOrComments.push_back(doNode->body->content.to<Statement_t>()); | ||
| 4448 | } | ||
| 4449 | return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false, blockRewrite); | ||
| 4450 | } | ||
| 4451 | } | ||
| 4267 | auto returnNode = exp->new_ptr<Return_t>(); | 4452 | auto returnNode = exp->new_ptr<Return_t>(); |
| 4268 | returnNode->explicitReturn = false; | 4453 | returnNode->explicitReturn = false; |
| 4269 | auto returnList = exp->new_ptr<ExpListLow_t>(); | 4454 | auto returnList = exp->new_ptr<ExpListLow_t>(); |
| 4270 | returnList->exprs.push_back(exp); | 4455 | returnList->exprs.push_back(exp); |
| 4271 | returnNode->valueList.set(returnList); | 4456 | returnNode->valueList.set(returnList); |
| 4272 | auto block = exp->new_ptr<Block_t>(); | ||
| 4273 | auto stmt = exp->new_ptr<Statement_t>(); | 4457 | auto stmt = exp->new_ptr<Statement_t>(); |
| 4274 | stmt->content.set(returnNode); | 4458 | stmt->content.set(returnNode); |
| 4275 | block->statements.push_back(stmt); | 4459 | block->statementOrComments.push_back(stmt); |
| 4276 | return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false, blockRewrite); | 4460 | return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false, blockRewrite); |
| 4277 | } | 4461 | } |
| 4278 | return std::nullopt; | 4462 | return std::nullopt; |
| @@ -4329,7 +4513,7 @@ private: | |||
| 4329 | bool extraScope = !currentScope().lastStatement; | 4513 | bool extraScope = !currentScope().lastStatement; |
| 4330 | if (forAssignment) { | 4514 | if (forAssignment) { |
| 4331 | if (extraScope) { | 4515 | if (extraScope) { |
| 4332 | temp.push_back(indent() + "do"s + nll(x)); | 4516 | temp.push_back(indent() + "do"s + nl(x)); |
| 4333 | pushScope(); | 4517 | pushScope(); |
| 4334 | } | 4518 | } |
| 4335 | } | 4519 | } |
| @@ -4352,9 +4536,9 @@ private: | |||
| 4352 | case ExpUsage::Return: | 4536 | case ExpUsage::Return: |
| 4353 | case ExpUsage::Closure: { | 4537 | case ExpUsage::Closure: { |
| 4354 | prepareValue(); | 4538 | prepareValue(); |
| 4355 | _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); | 4539 | _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nl(x); |
| 4356 | _buf << indent(1) << "return "s << objVar << nll(x); | 4540 | _buf << indent(1) << "return "s << objVar << nl(x); |
| 4357 | _buf << indent() << "else"s << nll(x); | 4541 | _buf << indent() << "else"s << nl(x); |
| 4358 | temp.push_back(clearBuf()); | 4542 | temp.push_back(clearBuf()); |
| 4359 | auto ret = x->new_ptr<Return_t>(); | 4543 | auto ret = x->new_ptr<Return_t>(); |
| 4360 | ret->explicitReturn = false; | 4544 | ret->explicitReturn = false; |
| @@ -4364,10 +4548,10 @@ private: | |||
| 4364 | incIndentOffset(); | 4548 | incIndentOffset(); |
| 4365 | transformReturn(ret, temp); | 4549 | transformReturn(ret, temp); |
| 4366 | decIndentOffset(); | 4550 | decIndentOffset(); |
| 4367 | temp.push_back(indent() + "end"s + nll(x)); | 4551 | temp.push_back(indent() + "end"s + nl(x)); |
| 4368 | if (usage == ExpUsage::Closure) { | 4552 | if (usage == ExpUsage::Closure) { |
| 4369 | popScope(); | 4553 | popScope(); |
| 4370 | *funcStart = anonFuncStart() + nll(x); | 4554 | *funcStart = anonFuncStart() + nl(x); |
| 4371 | temp.push_back(indent() + anonFuncEnd()); | 4555 | temp.push_back(indent() + anonFuncEnd()); |
| 4372 | popAnonVarArg(); | 4556 | popAnonVarArg(); |
| 4373 | popFunctionScope(); | 4557 | popFunctionScope(); |
| @@ -4384,14 +4568,14 @@ private: | |||
| 4384 | assign->values.push_back(exp); | 4568 | assign->values.push_back(exp); |
| 4385 | temp.push_back(getPreDefineLine(assignment)); | 4569 | temp.push_back(getPreDefineLine(assignment)); |
| 4386 | extraScope = prepareValue(true); | 4570 | extraScope = prepareValue(true); |
| 4387 | _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); | 4571 | _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nl(x); |
| 4388 | temp.push_back(clearBuf()); | 4572 | temp.push_back(clearBuf()); |
| 4389 | pushScope(); | 4573 | pushScope(); |
| 4390 | assign->values.clear(); | 4574 | assign->values.clear(); |
| 4391 | assign->values.push_back(toAst<Exp_t>(objVar, x)); | 4575 | assign->values.push_back(toAst<Exp_t>(objVar, x)); |
| 4392 | transformAssignment(assignment, temp); | 4576 | transformAssignment(assignment, temp); |
| 4393 | popScope(); | 4577 | popScope(); |
| 4394 | temp.push_back(indent() + "else"s + nll(x)); | 4578 | temp.push_back(indent() + "else"s + nl(x)); |
| 4395 | assign->values.clear(); | 4579 | assign->values.clear(); |
| 4396 | assign->values.push_back(exp->nilCoalesed); | 4580 | assign->values.push_back(exp->nilCoalesed); |
| 4397 | } else { | 4581 | } else { |
| @@ -4399,17 +4583,17 @@ private: | |||
| 4399 | assign->values.push_back(exp->nilCoalesed); | 4583 | assign->values.push_back(exp->nilCoalesed); |
| 4400 | temp.push_back(getPreDefineLine(assignment)); | 4584 | temp.push_back(getPreDefineLine(assignment)); |
| 4401 | transformExp(left, temp, ExpUsage::Closure); | 4585 | transformExp(left, temp, ExpUsage::Closure); |
| 4402 | _buf << indent() << "if "sv << temp.back() << " == nil then"sv << nll(x); | 4586 | _buf << indent() << "if "sv << temp.back() << " == nil then"sv << nl(x); |
| 4403 | temp.pop_back(); | 4587 | temp.pop_back(); |
| 4404 | temp.push_back(clearBuf()); | 4588 | temp.push_back(clearBuf()); |
| 4405 | } | 4589 | } |
| 4406 | pushScope(); | 4590 | pushScope(); |
| 4407 | transformAssignment(assignment, temp); | 4591 | transformAssignment(assignment, temp); |
| 4408 | popScope(); | 4592 | popScope(); |
| 4409 | temp.push_back(indent() + "end"s + nlr(x)); | 4593 | temp.push_back(indent() + "end"s + nl(x)); |
| 4410 | if (extraScope) { | 4594 | if (extraScope) { |
| 4411 | popScope(); | 4595 | popScope(); |
| 4412 | temp.push_back(indent() + "end"s + nlr(x)); | 4596 | temp.push_back(indent() + "end"s + nl(x)); |
| 4413 | } | 4597 | } |
| 4414 | break; | 4598 | break; |
| 4415 | } | 4599 | } |
| @@ -4439,7 +4623,7 @@ private: | |||
| 4439 | if (accessType == AccessType::Read && _funcLevel > 1) { | 4623 | if (accessType == AccessType::Read && _funcLevel > 1) { |
| 4440 | accessType = AccessType::Capture; | 4624 | accessType = AccessType::Capture; |
| 4441 | } | 4625 | } |
| 4442 | _globals[key] = {out.back(), item->m_begin.m_line, item->m_begin.m_col, accessType}; | 4626 | _globals[key] = {out.back(), item->m_begin.m_line, item->m_begin.m_col, accessType, isSolidDefined(out.back())}; |
| 4443 | } | 4627 | } |
| 4444 | } | 4628 | } |
| 4445 | break; | 4629 | break; |
| @@ -4471,6 +4655,7 @@ private: | |||
| 4471 | case id<ForEach_t>(): transformForEachClosure(static_cast<ForEach_t*>(value), out); break; | 4655 | case id<ForEach_t>(): transformForEachClosure(static_cast<ForEach_t*>(value), out); break; |
| 4472 | case id<For_t>(): transformForClosure(static_cast<For_t*>(value), out); break; | 4656 | case id<For_t>(): transformForClosure(static_cast<For_t*>(value), out); break; |
| 4473 | case id<While_t>(): transformWhileClosure(static_cast<While_t*>(value), out); break; | 4657 | case id<While_t>(): transformWhileClosure(static_cast<While_t*>(value), out); break; |
| 4658 | case id<Repeat_t>(): transformRepeatClosure(static_cast<Repeat_t*>(value), out); break; | ||
| 4474 | case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Closure); break; | 4659 | case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Closure); break; |
| 4475 | case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Closure); break; | 4660 | case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Closure); break; |
| 4476 | case id<UnaryValue_t>(): transformUnaryValue(static_cast<UnaryValue_t*>(value), out); break; | 4661 | case id<UnaryValue_t>(): transformUnaryValue(static_cast<UnaryValue_t*>(value), out); break; |
| @@ -4507,11 +4692,11 @@ private: | |||
| 4507 | switch (content->get_id()) { | 4692 | switch (content->get_id()) { |
| 4508 | case id<Block_t>(): { | 4693 | case id<Block_t>(): { |
| 4509 | auto block = static_cast<Block_t*>(content); | 4694 | auto block = static_cast<Block_t*>(content); |
| 4510 | newBlock->statements.dup(block->statements); | 4695 | newBlock->statementOrComments.dup(block->statementOrComments); |
| 4511 | break; | 4696 | break; |
| 4512 | } | 4697 | } |
| 4513 | case id<Statement_t>(): { | 4698 | case id<Statement_t>(): { |
| 4514 | newBlock->statements.push_back(content); | 4699 | newBlock->statementOrComments.push_back(content); |
| 4515 | break; | 4700 | break; |
| 4516 | } | 4701 | } |
| 4517 | default: YUEE("AST node mismatch", content); break; | 4702 | default: YUEE("AST node mismatch", content); break; |
| @@ -4523,7 +4708,7 @@ private: | |||
| 4523 | returnNode->valueList.set(funLit->defaultReturn); | 4708 | returnNode->valueList.set(funLit->defaultReturn); |
| 4524 | auto stmt = newBlock->new_ptr<Statement_t>(); | 4709 | auto stmt = newBlock->new_ptr<Statement_t>(); |
| 4525 | stmt->content.set(returnNode); | 4710 | stmt->content.set(returnNode); |
| 4526 | newBlock->statements.push_back(stmt); | 4711 | newBlock->statementOrComments.push_back(stmt); |
| 4527 | } | 4712 | } |
| 4528 | transformBlock(newBlock, temp, ExpUsage::Common); | 4713 | transformBlock(newBlock, temp, ExpUsage::Common); |
| 4529 | } else { | 4714 | } else { |
| @@ -4545,7 +4730,7 @@ private: | |||
| 4545 | } | 4730 | } |
| 4546 | _buf << args << ')'; | 4731 | _buf << args << ')'; |
| 4547 | if (!initArgs.empty() || !bodyCodes.empty()) { | 4732 | if (!initArgs.empty() || !bodyCodes.empty()) { |
| 4548 | _buf << nlr(argsDef) << initArgs << bodyCodes; | 4733 | _buf << nl(argsDef) << initArgs << bodyCodes; |
| 4549 | popScope(); | 4734 | popScope(); |
| 4550 | _buf << indent() << "end"sv; | 4735 | _buf << indent() << "end"sv; |
| 4551 | } else { | 4736 | } else { |
| @@ -4556,7 +4741,7 @@ private: | |||
| 4556 | auto& bodyCodes = temp.back(); | 4741 | auto& bodyCodes = temp.back(); |
| 4557 | _buf << "function("sv << (isFatArrow ? "self"s : Empty) << ')'; | 4742 | _buf << "function("sv << (isFatArrow ? "self"s : Empty) << ')'; |
| 4558 | if (!bodyCodes.empty()) { | 4743 | if (!bodyCodes.empty()) { |
| 4559 | _buf << nll(funLit) << bodyCodes; | 4744 | _buf << nl(funLit) << bodyCodes; |
| 4560 | popScope(); | 4745 | popScope(); |
| 4561 | _buf << indent() << "end"sv; | 4746 | _buf << indent() << "end"sv; |
| 4562 | } else { | 4747 | } else { |
| @@ -4573,7 +4758,7 @@ private: | |||
| 4573 | auto x = body; | 4758 | auto x = body; |
| 4574 | if (auto stmt = body->content.as<Statement_t>()) { | 4759 | if (auto stmt = body->content.as<Statement_t>()) { |
| 4575 | auto block = x->new_ptr<Block_t>(); | 4760 | auto block = x->new_ptr<Block_t>(); |
| 4576 | block->statements.push_back(stmt); | 4761 | block->statementOrComments.push_back(stmt); |
| 4577 | transformBlock(block, out, usage, assignList); | 4762 | transformBlock(block, out, usage, assignList); |
| 4578 | } else { | 4763 | } else { |
| 4579 | transformBlock(body->content.to<Block_t>(), out, usage, assignList); | 4764 | transformBlock(body->content.to<Block_t>(), out, usage, assignList); |
| @@ -4585,13 +4770,15 @@ private: | |||
| 4585 | out.push_back(Empty); | 4770 | out.push_back(Empty); |
| 4586 | return; | 4771 | return; |
| 4587 | } | 4772 | } |
| 4588 | const auto& nodes = block->statements.objects(); | 4773 | const auto& nodes = block->statementOrComments.objects(); |
| 4774 | auto lastStmt = lastStatementFrom(nodes); | ||
| 4589 | LocalMode mode = LocalMode::None; | 4775 | LocalMode mode = LocalMode::None; |
| 4590 | Local_t *any = nullptr, *capital = nullptr; | 4776 | Local_t *any = nullptr, *capital = nullptr; |
| 4591 | for (auto it = nodes.begin(); it != nodes.end(); ++it) { | 4777 | for (auto it = nodes.begin(); it != nodes.end(); ++it) { |
| 4592 | auto node = *it; | 4778 | auto node = *it; |
| 4593 | auto stmt = static_cast<Statement_t*>(node); | 4779 | auto stmt = ast_cast<Statement_t>(node); |
| 4594 | if (!stmt->appendix && stmt->content.is<Return_t>() && stmt != nodes.back()) { | 4780 | if (!stmt) continue; |
| 4781 | if (!stmt->appendix && stmt->content.is<Return_t>() && stmt != lastStmt) { | ||
| 4595 | throw CompileError("'return' statement must be the last line in the block"sv, stmt->content); | 4782 | throw CompileError("'return' statement must be the last line in the block"sv, stmt->content); |
| 4596 | } else if (auto pipeBody = stmt->content.as<PipeBody_t>()) { | 4783 | } else if (auto pipeBody = stmt->content.as<PipeBody_t>()) { |
| 4597 | auto x = stmt; | 4784 | auto x = stmt; |
| @@ -4600,6 +4787,16 @@ private: | |||
| 4600 | BREAK_IF(it == nodes.begin()); | 4787 | BREAK_IF(it == nodes.begin()); |
| 4601 | auto last = it; | 4788 | auto last = it; |
| 4602 | --last; | 4789 | --last; |
| 4790 | bool found = true; | ||
| 4791 | while (!ast_is<Statement_t>(*last)) { | ||
| 4792 | if (last == nodes.begin()) { | ||
| 4793 | found = false; | ||
| 4794 | break; | ||
| 4795 | } else { | ||
| 4796 | --last; | ||
| 4797 | } | ||
| 4798 | } | ||
| 4799 | BREAK_IF(!found); | ||
| 4603 | auto lst = static_cast<Statement_t*>(*last); | 4800 | auto lst = static_cast<Statement_t*>(*last); |
| 4604 | if (lst->appendix) { | 4801 | if (lst->appendix) { |
| 4605 | throw CompileError("statement decorator must be placed at the end of pipe chain"sv, lst->appendix.get()); | 4802 | throw CompileError("statement decorator must be placed at the end of pipe chain"sv, lst->appendix.get()); |
| @@ -4617,9 +4814,17 @@ private: | |||
| 4617 | stmt->content.set(nullptr); | 4814 | stmt->content.set(nullptr); |
| 4618 | auto next = it; | 4815 | auto next = it; |
| 4619 | ++next; | 4816 | ++next; |
| 4817 | Statement_t* nextStmt = nullptr; | ||
| 4818 | while (next != nodes.end()) { | ||
| 4819 | nextStmt = ast_cast<Statement_t>(*next); | ||
| 4820 | if (nextStmt) { | ||
| 4821 | break; | ||
| 4822 | } | ||
| 4823 | ++next; | ||
| 4824 | } | ||
| 4620 | BLOCK_START | 4825 | BLOCK_START |
| 4621 | BREAK_IF(next == nodes.end()); | 4826 | BREAK_IF(!nextStmt); |
| 4622 | BREAK_IF(!static_cast<Statement_t*>(*next)->content.as<PipeBody_t>()); | 4827 | BREAK_IF(!nextStmt->content.as<PipeBody_t>()); |
| 4623 | throw CompileError("indent mismatch in pipe chain"sv, *next); | 4828 | throw CompileError("indent mismatch in pipe chain"sv, *next); |
| 4624 | BLOCK_END | 4829 | BLOCK_END |
| 4625 | } else if (auto backcall = stmt->content.as<Backcall_t>()) { | 4830 | } else if (auto backcall = stmt->content.as<Backcall_t>()) { |
| @@ -4627,7 +4832,7 @@ private: | |||
| 4627 | auto newBlock = x->new_ptr<Block_t>(); | 4832 | auto newBlock = x->new_ptr<Block_t>(); |
| 4628 | if (it != nodes.begin()) { | 4833 | if (it != nodes.begin()) { |
| 4629 | for (auto i = nodes.begin(); i != it; ++i) { | 4834 | for (auto i = nodes.begin(); i != it; ++i) { |
| 4630 | newBlock->statements.push_back(*i); | 4835 | newBlock->statementOrComments.push_back(*i); |
| 4631 | } | 4836 | } |
| 4632 | } | 4837 | } |
| 4633 | x = backcall; | 4838 | x = backcall; |
| @@ -4638,7 +4843,7 @@ private: | |||
| 4638 | ++next; | 4843 | ++next; |
| 4639 | if (next != nodes.end()) { | 4844 | if (next != nodes.end()) { |
| 4640 | for (auto i = next; i != nodes.end(); ++i) { | 4845 | for (auto i = next; i != nodes.end(); ++i) { |
| 4641 | block->statements.push_back(*i); | 4846 | block->statementOrComments.push_back(*i); |
| 4642 | } | 4847 | } |
| 4643 | } | 4848 | } |
| 4644 | auto body = x->new_ptr<Body_t>(); | 4849 | auto body = x->new_ptr<Body_t>(); |
| @@ -4690,7 +4895,7 @@ private: | |||
| 4690 | expListAssign->expList.set(expList); | 4895 | expListAssign->expList.set(expList); |
| 4691 | newStmt->content.set(expListAssign); | 4896 | newStmt->content.set(expListAssign); |
| 4692 | newStmt->appendix.set(stmt->appendix); | 4897 | newStmt->appendix.set(stmt->appendix); |
| 4693 | newBlock->statements.push_back(newStmt); | 4898 | newBlock->statementOrComments.push_back(newStmt); |
| 4694 | } | 4899 | } |
| 4695 | transformBlock(newBlock, out, usage, assignList, isRoot); | 4900 | transformBlock(newBlock, out, usage, assignList, isRoot); |
| 4696 | return; | 4901 | return; |
| @@ -4717,7 +4922,7 @@ private: | |||
| 4717 | throw CompileError("while-loop line decorator is not supported here"sv, appendix->item.get()); | 4922 | throw CompileError("while-loop line decorator is not supported here"sv, appendix->item.get()); |
| 4718 | break; | 4923 | break; |
| 4719 | } | 4924 | } |
| 4720 | case id<CompInner_t>(): { | 4925 | case id<CompFor_t>(): { |
| 4721 | throw CompileError("for-loop line decorator is not supported here"sv, appendix->item.get()); | 4926 | throw CompileError("for-loop line decorator is not supported here"sv, appendix->item.get()); |
| 4722 | break; | 4927 | break; |
| 4723 | } | 4928 | } |
| @@ -4746,7 +4951,7 @@ private: | |||
| 4746 | auto newBlock = x->new_ptr<Block_t>(); | 4951 | auto newBlock = x->new_ptr<Block_t>(); |
| 4747 | if (it != nodes.begin()) { | 4952 | if (it != nodes.begin()) { |
| 4748 | for (auto i = nodes.begin(); i != it; ++i) { | 4953 | for (auto i = nodes.begin(); i != it; ++i) { |
| 4749 | newBlock->statements.push_back(*i); | 4954 | newBlock->statementOrComments.push_back(*i); |
| 4750 | } | 4955 | } |
| 4751 | } | 4956 | } |
| 4752 | x = expListAssign; | 4957 | x = expListAssign; |
| @@ -4756,7 +4961,7 @@ private: | |||
| 4756 | ++next; | 4961 | ++next; |
| 4757 | if (next != nodes.end()) { | 4962 | if (next != nodes.end()) { |
| 4758 | for (auto i = next; i != nodes.end(); ++i) { | 4963 | for (auto i = next; i != nodes.end(); ++i) { |
| 4759 | followingBlock->statements.push_back(*i); | 4964 | followingBlock->statementOrComments.push_back(*i); |
| 4760 | } | 4965 | } |
| 4761 | } | 4966 | } |
| 4762 | } | 4967 | } |
| @@ -4784,17 +4989,13 @@ private: | |||
| 4784 | newAssignment->action.set(newAssign); | 4989 | newAssignment->action.set(newAssign); |
| 4785 | auto newStatement = x->new_ptr<Statement_t>(); | 4990 | auto newStatement = x->new_ptr<Statement_t>(); |
| 4786 | newStatement->content.set(newAssignment); | 4991 | newStatement->content.set(newAssignment); |
| 4787 | followingBlock->statements.push_front(newStatement); | 4992 | followingBlock->statementOrComments.push_front(newStatement); |
| 4788 | } | 4993 | } |
| 4789 | argNames.push_back("..."s); | 4994 | argNames.push_back("..."s); |
| 4790 | auto newBody = x->new_ptr<Body_t>(); | 4995 | auto newBody = x->new_ptr<Body_t>(); |
| 4791 | newBody->content.set(followingBlock); | 4996 | newBody->content.set(followingBlock); |
| 4792 | { | 4997 | { |
| 4793 | auto doNode = x->new_ptr<Do_t>(); | 4998 | if (auto result = upValueFuncFromBlock(followingBlock.get(), &argNames, false, true)) { |
| 4794 | doNode->body.set(newBody); | ||
| 4795 | auto simpleValue = x->new_ptr<SimpleValue_t>(); | ||
| 4796 | simpleValue->value.set(doNode); | ||
| 4797 | if (auto result = upValueFuncFromExp(newExp(simpleValue, x), &argNames, true)) { | ||
| 4798 | auto [funcName, args] = std::move(*result); | 4999 | auto [funcName, args] = std::move(*result); |
| 4799 | str_list finalArgs; | 5000 | str_list finalArgs; |
| 4800 | for (const auto& arg : args) { | 5001 | for (const auto& arg : args) { |
| @@ -4802,9 +5003,14 @@ private: | |||
| 4802 | finalArgs.push_back(arg); | 5003 | finalArgs.push_back(arg); |
| 4803 | } | 5004 | } |
| 4804 | } | 5005 | } |
| 4805 | newBlock->statements.push_back(toAst<Statement_t>(funcName + ' ' + join(finalArgs, ","sv), x)); | 5006 | auto lastNewStmt = toAst<Statement_t>(funcName + ' ' + (finalArgs.empty() ? "nil"s : join(finalArgs, ","sv)), x); |
| 4806 | auto sVal = singleValueFrom(static_cast<Statement_t*>(newBlock->statements.back())->content.to<ExpListAssign_t>()->expList); | 5007 | newBlock->statementOrComments.push_back(lastNewStmt); |
| 4807 | ast_to<InvokeArgs_t>(sVal->item.to<ChainValue_t>()->items.back())->args.dup(newInvoke->args); | 5008 | auto sVal = singleValueFrom(lastNewStmt->content.to<ExpListAssign_t>()->expList); |
| 5009 | auto invokArgs = ast_to<InvokeArgs_t>(sVal->item.to<ChainValue_t>()->items.back()); | ||
| 5010 | if (finalArgs.empty()) { | ||
| 5011 | invokArgs->args.clear(); | ||
| 5012 | } | ||
| 5013 | invokArgs->args.dup(newInvoke->args); | ||
| 4808 | transformBlock(newBlock, out, usage, assignList, isRoot); | 5014 | transformBlock(newBlock, out, usage, assignList, isRoot); |
| 4809 | return; | 5015 | return; |
| 4810 | } | 5016 | } |
| @@ -4829,7 +5035,7 @@ private: | |||
| 4829 | newItemListAssign->expList.set(newItemList); | 5035 | newItemListAssign->expList.set(newItemList); |
| 4830 | auto newItemStatement = x->new_ptr<Statement_t>(); | 5036 | auto newItemStatement = x->new_ptr<Statement_t>(); |
| 4831 | newItemStatement->content.set(newItemListAssign); | 5037 | newItemStatement->content.set(newItemListAssign); |
| 4832 | newBlock->statements.push_back(newItemStatement); | 5038 | newBlock->statementOrComments.push_back(newItemStatement); |
| 4833 | transformBlock(newBlock, out, usage, assignList, isRoot); | 5039 | transformBlock(newBlock, out, usage, assignList, isRoot); |
| 4834 | return; | 5040 | return; |
| 4835 | BLOCK_END | 5041 | BLOCK_END |
| @@ -4838,11 +5044,11 @@ private: | |||
| 4838 | auto newBlock = x->new_ptr<Block_t>(); | 5044 | auto newBlock = x->new_ptr<Block_t>(); |
| 4839 | if (it != nodes.begin()) { | 5045 | if (it != nodes.begin()) { |
| 4840 | for (auto i = nodes.begin(); i != it; ++i) { | 5046 | for (auto i = nodes.begin(); i != it; ++i) { |
| 4841 | newBlock->statements.push_back(*i); | 5047 | newBlock->statementOrComments.push_back(*i); |
| 4842 | } | 5048 | } |
| 4843 | } | 5049 | } |
| 4844 | localAttrib->attrib.set(localAttrib->new_ptr<ConstAttrib_t>()); | 5050 | localAttrib->attrib.set(localAttrib->new_ptr<ConstAttrib_t>()); |
| 4845 | newBlock->statements.push_back(*it); | 5051 | newBlock->statementOrComments.push_back(*it); |
| 4846 | x = localAttrib; | 5052 | x = localAttrib; |
| 4847 | auto followingBlock = x->new_ptr<Block_t>(); | 5053 | auto followingBlock = x->new_ptr<Block_t>(); |
| 4848 | { | 5054 | { |
| @@ -4850,7 +5056,7 @@ private: | |||
| 4850 | ++next; | 5056 | ++next; |
| 4851 | if (next != nodes.end()) { | 5057 | if (next != nodes.end()) { |
| 4852 | for (auto i = next; i != nodes.end(); ++i) { | 5058 | for (auto i = next; i != nodes.end(); ++i) { |
| 4853 | followingBlock->statements.push_back(*i); | 5059 | followingBlock->statementOrComments.push_back(*i); |
| 4854 | } | 5060 | } |
| 4855 | } | 5061 | } |
| 4856 | } | 5062 | } |
| @@ -4872,13 +5078,13 @@ private: | |||
| 4872 | auto value = singleValueFrom(pCallExp); | 5078 | auto value = singleValueFrom(pCallExp); |
| 4873 | value->item.to<SimpleValue_t>()->value.to<Try_t>()->func.set(followingBlock); | 5079 | value->item.to<SimpleValue_t>()->value.to<Try_t>()->func.set(followingBlock); |
| 4874 | for (const auto& stmt : getCloses) { | 5080 | for (const auto& stmt : getCloses) { |
| 4875 | newBlock->statements.push_back(toAst<Statement_t>(stmt, x)); | 5081 | newBlock->statementOrComments.push_back(toAst<Statement_t>(stmt, x)); |
| 4876 | } | 5082 | } |
| 4877 | newBlock->statements.push_back(pCallStmt); | 5083 | newBlock->statementOrComments.push_back(pCallStmt); |
| 4878 | for (const auto& stmt : doCloses) { | 5084 | for (const auto& stmt : doCloses) { |
| 4879 | newBlock->statements.push_back(toAst<Statement_t>(stmt, x)); | 5085 | newBlock->statementOrComments.push_back(toAst<Statement_t>(stmt, x)); |
| 4880 | } | 5086 | } |
| 4881 | newBlock->statements.push_back(toAst<Statement_t>("if "s + okVar + " then return ... else error ..."s, x)); | 5087 | newBlock->statementOrComments.push_back(toAst<Statement_t>("if "s + okVar + " then return ... else error ..."s, x)); |
| 4882 | transformBlock(newBlock, out, usage, assignList, isRoot); | 5088 | transformBlock(newBlock, out, usage, assignList, isRoot); |
| 4883 | return; | 5089 | return; |
| 4884 | } else if (auto expListAssign = stmt->content.as<ExpListAssign_t>(); | 5090 | } else if (auto expListAssign = stmt->content.as<ExpListAssign_t>(); |
| @@ -4887,7 +5093,7 @@ private: | |||
| 4887 | auto newBlock = x->new_ptr<Block_t>(); | 5093 | auto newBlock = x->new_ptr<Block_t>(); |
| 4888 | if (it != nodes.begin()) { | 5094 | if (it != nodes.begin()) { |
| 4889 | for (auto i = nodes.begin(); i != it; ++i) { | 5095 | for (auto i = nodes.begin(); i != it; ++i) { |
| 4890 | newBlock->statements.push_back(*i); | 5096 | newBlock->statementOrComments.push_back(*i); |
| 4891 | } | 5097 | } |
| 4892 | } | 5098 | } |
| 4893 | auto doBackcall = static_cast<SubBackcall_t*>(expListAssign->action.get()); | 5099 | auto doBackcall = static_cast<SubBackcall_t*>(expListAssign->action.get()); |
| @@ -4904,12 +5110,11 @@ private: | |||
| 4904 | backcall->value.set(doBackcall->value); | 5110 | backcall->value.set(doBackcall->value); |
| 4905 | auto newStmt = backcall->new_ptr<Statement_t>(); | 5111 | auto newStmt = backcall->new_ptr<Statement_t>(); |
| 4906 | newStmt->content.set(backcall); | 5112 | newStmt->content.set(backcall); |
| 4907 | newStmt->comments.dup(stmt->comments); | ||
| 4908 | newStmt->appendix.set(stmt->appendix); | 5113 | newStmt->appendix.set(stmt->appendix); |
| 4909 | newBlock->statements.push_back(newStmt); | 5114 | newBlock->statementOrComments.push_back(newStmt); |
| 4910 | auto ait = it; | 5115 | auto ait = it; |
| 4911 | for (auto i = ++ait; i != nodes.end(); ++i) { | 5116 | for (auto i = ++ait; i != nodes.end(); ++i) { |
| 4912 | newBlock->statements.push_back(*i); | 5117 | newBlock->statementOrComments.push_back(*i); |
| 4913 | } | 5118 | } |
| 4914 | transformBlock(newBlock, out, usage, assignList, isRoot); | 5119 | transformBlock(newBlock, out, usage, assignList, isRoot); |
| 4915 | return; | 5120 | return; |
| @@ -5021,7 +5226,7 @@ private: | |||
| 5021 | } | 5226 | } |
| 5022 | } | 5227 | } |
| 5023 | if (isRoot && !_info.moduleName.empty() && !_info.exportMacro) { | 5228 | if (isRoot && !_info.moduleName.empty() && !_info.exportMacro) { |
| 5024 | block->statements.push_front(toAst<Statement_t>(_info.moduleName + (_info.exportDefault ? "=nil"s : (_info.exportMetatable ? "=<>:{}"s : "={}"s)), block)); | 5229 | block->statementOrComments.push_front(toAst<Statement_t>(_info.moduleName + (_info.exportDefault ? "=nil"s : (_info.exportMetatable ? "=<>:{}"s : "={}"s)), block)); |
| 5025 | } | 5230 | } |
| 5026 | switch (usage) { | 5231 | switch (usage) { |
| 5027 | case ExpUsage::Closure: | 5232 | case ExpUsage::Closure: |
| @@ -5058,7 +5263,7 @@ private: | |||
| 5058 | break; | 5263 | break; |
| 5059 | } | 5264 | } |
| 5060 | } | 5265 | } |
| 5061 | bool lastAssignable = (expListFrom(last) || ast_is<For_t, ForEach_t, While_t>(last->content)); | 5266 | bool lastAssignable = (expListFrom(last) || ast_is<For_t, While_t>(last->content)); |
| 5062 | if (lastAssignable) { | 5267 | if (lastAssignable) { |
| 5063 | auto x = last; | 5268 | auto x = last; |
| 5064 | auto newAssignment = x->new_ptr<ExpListAssign_t>(); | 5269 | auto newAssignment = x->new_ptr<ExpListAssign_t>(); |
| @@ -5083,37 +5288,54 @@ private: | |||
| 5083 | } | 5288 | } |
| 5084 | if (!nodes.empty()) { | 5289 | if (!nodes.empty()) { |
| 5085 | str_list temp; | 5290 | str_list temp; |
| 5291 | auto lastStmt = lastStatementFrom(nodes); | ||
| 5086 | for (auto node : nodes) { | 5292 | for (auto node : nodes) { |
| 5087 | currentScope().lastStatement = (node == nodes.back()) && currentScope().mode == GlobalMode::None; | 5293 | if (auto comment = ast_cast<YueComment_t>(node)) { |
| 5088 | transformStatement(static_cast<Statement_t*>(node), temp); | 5294 | transformComment(comment, temp); |
| 5089 | if (isRoot && !_rootDefs.empty()) { | 5295 | continue; |
| 5090 | auto last = std::move(temp.back()); | 5296 | } |
| 5091 | temp.pop_back(); | 5297 | if (!ast_is<Statement_t>(node)) { |
| 5092 | temp.insert(temp.end(), _rootDefs.begin(), _rootDefs.end()); | 5298 | continue; |
| 5093 | _rootDefs.clear(); | 5299 | } |
| 5094 | temp.push_back(std::move(last)); | 5300 | auto transformNode = [&]() { |
| 5095 | } | 5301 | currentScope().lastStatement = (node == lastStmt) && currentScope().mode == GlobalMode::None; |
| 5096 | if (!temp.empty() && _parser.startWith<StatementSep_t>(temp.back())) { | 5302 | transformStatement(static_cast<Statement_t*>(node), temp); |
| 5097 | auto rit = ++temp.rbegin(); | 5303 | if (isRoot && !_rootDefs.empty()) { |
| 5098 | if (rit != temp.rend() && !rit->empty()) { | 5304 | auto last = std::move(temp.back()); |
| 5099 | auto index = std::string::npos; | 5305 | temp.pop_back(); |
| 5100 | if (_config.reserveLineNumber) { | 5306 | temp.insert(temp.end(), _rootDefs.begin(), _rootDefs.end()); |
| 5101 | index = rit->rfind(" -- "sv); | 5307 | _rootDefs.clear(); |
| 5102 | } else { | 5308 | temp.push_back(std::move(last)); |
| 5103 | index = rit->find_last_not_of('\n'); | 5309 | } |
| 5104 | if (index != std::string::npos) index++; | 5310 | if (!temp.empty() && _parser.startWith<StatementSep_t>(temp.back())) { |
| 5105 | } | 5311 | auto rit = ++temp.rbegin(); |
| 5106 | if (index != std::string::npos) { | 5312 | if (rit != temp.rend() && !rit->empty()) { |
| 5107 | auto ending = rit->substr(0, index); | 5313 | auto index = std::string::npos; |
| 5108 | auto ind = ending.find_last_of(" \t\n"sv); | 5314 | if (_config.reserveLineNumber) { |
| 5109 | if (ind != std::string::npos) { | 5315 | index = rit->rfind(" -- "sv); |
| 5110 | ending = ending.substr(ind + 1); | 5316 | } else { |
| 5317 | index = rit->find_last_not_of('\n'); | ||
| 5318 | if (index != std::string::npos) index++; | ||
| 5111 | } | 5319 | } |
| 5112 | if (LuaKeywords.find(ending) == LuaKeywords.end()) { | 5320 | if (index != std::string::npos) { |
| 5113 | rit->insert(index, ";"sv); | 5321 | auto ending = rit->substr(0, index); |
| 5322 | auto ind = ending.find_last_of(" \t\n"sv); | ||
| 5323 | if (ind != std::string::npos) { | ||
| 5324 | ending = ending.substr(ind + 1); | ||
| 5325 | } | ||
| 5326 | if (LuaKeywords.find(ending) == LuaKeywords.end()) { | ||
| 5327 | rit->insert(index, ";"sv); | ||
| 5328 | } | ||
| 5114 | } | 5329 | } |
| 5115 | } | 5330 | } |
| 5116 | } | 5331 | } |
| 5332 | }; | ||
| 5333 | if (_config.lax) { | ||
| 5334 | try { | ||
| 5335 | transformNode(); | ||
| 5336 | } catch (const CompileError&) { } | ||
| 5337 | } else { | ||
| 5338 | transformNode(); | ||
| 5117 | } | 5339 | } |
| 5118 | } | 5340 | } |
| 5119 | out.push_back(join(temp)); | 5341 | out.push_back(join(temp)); |
| @@ -5121,7 +5343,7 @@ private: | |||
| 5121 | out.push_back(Empty); | 5343 | out.push_back(Empty); |
| 5122 | } | 5344 | } |
| 5123 | if (isRoot && !_info.moduleName.empty() && !_info.exportMacro) { | 5345 | if (isRoot && !_info.moduleName.empty() && !_info.exportMacro) { |
| 5124 | out.back().append(indent() + "return "s + _info.moduleName + nlr(block)); | 5346 | out.back().append(indent() + "return "s + _info.moduleName + nl(block)); |
| 5125 | } | 5347 | } |
| 5126 | } | 5348 | } |
| 5127 | 5349 | ||
| @@ -5322,18 +5544,29 @@ private: | |||
| 5322 | auto macroLit = macro->decl.to<MacroLit_t>(); | 5544 | auto macroLit = macro->decl.to<MacroLit_t>(); |
| 5323 | auto argsDef = macroLit->argsDef.get(); | 5545 | auto argsDef = macroLit->argsDef.get(); |
| 5324 | str_list newArgs; | 5546 | str_list newArgs; |
| 5547 | str_list argChecks; | ||
| 5548 | bool hasCheck = false; | ||
| 5325 | if (argsDef) { | 5549 | if (argsDef) { |
| 5326 | for (auto def_ : argsDef->definitions.objects()) { | 5550 | for (auto def_ : argsDef->definitions.objects()) { |
| 5327 | auto def = static_cast<FnArgDef_t*>(def_); | 5551 | auto def = static_cast<FnArgDef_t*>(def_); |
| 5328 | if (def->name.is<SelfItem_t>()) { | 5552 | if (def->name.is<SelfItem_t>()) { |
| 5329 | throw CompileError("self name is not supported for macro function argument"sv, def->name); | 5553 | throw CompileError("self name is not supported for macro function argument"sv, def->name); |
| 5330 | } else { | 5554 | } else { |
| 5555 | if (def->op) throw CompileError("invalid existence checking"sv, def->op); | ||
| 5556 | if (def->label) { | ||
| 5557 | hasCheck = true; | ||
| 5558 | const auto& astName = argChecks.emplace_back(_parser.toString(def->label)); | ||
| 5559 | if (!_parser.hasAST(astName)) { | ||
| 5560 | throw CompileError("invalid AST name"sv, def->label); | ||
| 5561 | } | ||
| 5562 | } else { | ||
| 5563 | argChecks.emplace_back(); | ||
| 5564 | } | ||
| 5331 | std::string defVal; | 5565 | std::string defVal; |
| 5332 | if (def->defaultValue) { | 5566 | if (def->defaultValue) { |
| 5333 | defVal = _parser.toString(def->defaultValue); | 5567 | defVal = _parser.toString(def->defaultValue); |
| 5334 | Utils::trim(defVal); | 5568 | Utils::trim(defVal); |
| 5335 | defVal.insert(0, "=[==========["sv); | 5569 | defVal = '=' + Utils::toLuaDoubleString(defVal); |
| 5336 | defVal.append("]==========]"sv); | ||
| 5337 | } | 5570 | } |
| 5338 | newArgs.emplace_back(_parser.toString(def->name) + defVal); | 5571 | newArgs.emplace_back(_parser.toString(def->name) + defVal); |
| 5339 | } | 5572 | } |
| @@ -5341,6 +5574,14 @@ private: | |||
| 5341 | if (argsDef->varArg) { | 5574 | if (argsDef->varArg) { |
| 5342 | newArgs.emplace_back(_parser.toString(argsDef->varArg)); | 5575 | newArgs.emplace_back(_parser.toString(argsDef->varArg)); |
| 5343 | } | 5576 | } |
| 5577 | if (argsDef->label) { | ||
| 5578 | hasCheck = true; | ||
| 5579 | const auto& astName = _parser.toString(argsDef->label); | ||
| 5580 | if (!_parser.hasAST(astName)) { | ||
| 5581 | throw CompileError("invalid AST name"sv, argsDef->label); | ||
| 5582 | } | ||
| 5583 | argChecks.emplace_back("..."s + astName); | ||
| 5584 | } | ||
| 5344 | } | 5585 | } |
| 5345 | std::string macroCodes = "_ENV=require('yue').macro_env\n("s + join(newArgs, ","sv) + ")->"s + _parser.toString(macroLit->body); | 5586 | std::string macroCodes = "_ENV=require('yue').macro_env\n("s + join(newArgs, ","sv) + ")->"s + _parser.toString(macroLit->body); |
| 5346 | auto chunkName = "=(macro "s + macroName + ')'; | 5587 | auto chunkName = "=(macro "s + macroName + ')'; |
| @@ -5371,6 +5612,24 @@ private: | |||
| 5371 | throw CompileError("failed to generate macro function\n"s + err, macroLit); | 5612 | throw CompileError("failed to generate macro function\n"s + err, macroLit); |
| 5372 | } // cur true macro | 5613 | } // cur true macro |
| 5373 | lua_remove(L, -2); // cur macro | 5614 | lua_remove(L, -2); // cur macro |
| 5615 | if (hasCheck) { | ||
| 5616 | lua_createtable(L, 0, 0); // cur macro checks | ||
| 5617 | int i = 1; | ||
| 5618 | for (const auto& check : argChecks) { | ||
| 5619 | if (check.empty()) { | ||
| 5620 | lua_pushboolean(L, 0); | ||
| 5621 | lua_rawseti(L, -2, i); | ||
| 5622 | } else { | ||
| 5623 | lua_pushlstring(L, check.c_str(), check.size()); | ||
| 5624 | lua_rawseti(L, -2, i); | ||
| 5625 | } | ||
| 5626 | i++; | ||
| 5627 | } | ||
| 5628 | lua_createtable(L, 2, 0); // cur macro checks macrotab | ||
| 5629 | lua_insert(L, -3); // cur macrotab macro checks | ||
| 5630 | lua_rawseti(L, -3, 1); // macrotab[1] = checks, cur macrotab macro | ||
| 5631 | lua_rawseti(L, -2, 2); // macrotab[2] = macro, cur macrotab | ||
| 5632 | } // cur macro | ||
| 5374 | if (exporting && _config.exporting && !_config.module.empty()) { | 5633 | if (exporting && _config.exporting && !_config.module.empty()) { |
| 5375 | pushModuleTable(_config.module); // cur macro module | 5634 | pushModuleTable(_config.module); // cur macro module |
| 5376 | lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro module name | 5635 | lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro module name |
| @@ -5445,11 +5704,11 @@ private: | |||
| 5445 | case id<While_t>(): | 5704 | case id<While_t>(): |
| 5446 | transformWhileInPlace(static_cast<While_t*>(value), out); | 5705 | transformWhileInPlace(static_cast<While_t*>(value), out); |
| 5447 | return; | 5706 | return; |
| 5448 | case id<For_t>(): | 5707 | case id<Repeat_t>(): |
| 5449 | transformForInPlace(static_cast<For_t*>(value), out); | 5708 | transformRepeatInPlace(static_cast<Repeat_t*>(value), out); |
| 5450 | return; | 5709 | return; |
| 5451 | case id<ForEach_t>(): | 5710 | case id<For_t>(): |
| 5452 | transformForEachInPlace(static_cast<ForEach_t*>(value), out); | 5711 | transformForInPlace(static_cast<For_t*>(value), out, nullptr); |
| 5453 | return; | 5712 | return; |
| 5454 | case id<If_t>(): | 5713 | case id<If_t>(): |
| 5455 | transformIf(static_cast<If_t*>(value), out, ExpUsage::Return); | 5714 | transformIf(static_cast<If_t*>(value), out, ExpUsage::Return); |
| @@ -5469,12 +5728,12 @@ private: | |||
| 5469 | } | 5728 | } |
| 5470 | } | 5729 | } |
| 5471 | transformValue(singleValue, out); | 5730 | transformValue(singleValue, out); |
| 5472 | out.back() = indent() + "return "s + out.back() + nlr(returnNode); | 5731 | out.back() = indent() + "return "s + out.back() + nl(returnNode); |
| 5473 | return; | 5732 | return; |
| 5474 | } else { | 5733 | } else { |
| 5475 | str_list temp; | 5734 | str_list temp; |
| 5476 | transformExpListLow(valueList, temp); | 5735 | transformExpListLow(valueList, temp); |
| 5477 | out.push_back(indent() + "return "s + temp.back() + nlr(returnNode)); | 5736 | out.push_back(indent() + "return "s + temp.back() + nl(returnNode)); |
| 5478 | } | 5737 | } |
| 5479 | } else if (auto tableBlock = returnNode->valueList.as<TableBlock_t>()) { | 5738 | } else if (auto tableBlock = returnNode->valueList.as<TableBlock_t>()) { |
| 5480 | const auto& values = tableBlock->values.objects(); | 5739 | const auto& values = tableBlock->values.objects(); |
| @@ -5482,10 +5741,10 @@ private: | |||
| 5482 | transformSpreadTable(values, out, ExpUsage::Return, nullptr, false); | 5741 | transformSpreadTable(values, out, ExpUsage::Return, nullptr, false); |
| 5483 | } else { | 5742 | } else { |
| 5484 | transformTable(values, out); | 5743 | transformTable(values, out); |
| 5485 | out.back() = indent() + "return "s + out.back() + nlr(returnNode); | 5744 | out.back() = indent() + "return "s + out.back() + nl(returnNode); |
| 5486 | } | 5745 | } |
| 5487 | } else { | 5746 | } else { |
| 5488 | out.push_back(indent() + "return"s + nll(returnNode)); | 5747 | out.push_back(indent() + "return"s + nl(returnNode)); |
| 5489 | } | 5748 | } |
| 5490 | } | 5749 | } |
| 5491 | 5750 | ||
| @@ -5516,6 +5775,7 @@ private: | |||
| 5516 | bool checkExistence = false; | 5775 | bool checkExistence = false; |
| 5517 | std::string name; | 5776 | std::string name; |
| 5518 | std::string assignSelf; | 5777 | std::string assignSelf; |
| 5778 | ast_ptr<false, ExpListAssign_t> assignment; | ||
| 5519 | }; | 5779 | }; |
| 5520 | std::list<ArgItem> argItems; | 5780 | std::list<ArgItem> argItems; |
| 5521 | str_list temp; | 5781 | str_list temp; |
| @@ -5525,7 +5785,11 @@ private: | |||
| 5525 | auto def = static_cast<FnArgDef_t*>(_def); | 5785 | auto def = static_cast<FnArgDef_t*>(_def); |
| 5526 | auto& arg = argItems.emplace_back(); | 5786 | auto& arg = argItems.emplace_back(); |
| 5527 | switch (def->name->get_id()) { | 5787 | switch (def->name->get_id()) { |
| 5528 | case id<Variable_t>(): arg.name = variableToString(static_cast<Variable_t*>(def->name.get())); break; | 5788 | case id<Variable_t>(): { |
| 5789 | if (def->op) throw CompileError("invalid existence checking"sv, def->op); | ||
| 5790 | arg.name = variableToString(static_cast<Variable_t*>(def->name.get())); | ||
| 5791 | break; | ||
| 5792 | } | ||
| 5529 | case id<SelfItem_t>(): { | 5793 | case id<SelfItem_t>(): { |
| 5530 | assignSelf = true; | 5794 | assignSelf = true; |
| 5531 | if (def->op) { | 5795 | if (def->op) { |
| @@ -5566,6 +5830,22 @@ private: | |||
| 5566 | } | 5830 | } |
| 5567 | break; | 5831 | break; |
| 5568 | } | 5832 | } |
| 5833 | case id<TableLit_t>(): { | ||
| 5834 | arg.name = getUnusedName("_arg_"sv); | ||
| 5835 | auto simpleValue = def->new_ptr<SimpleValue_t>(); | ||
| 5836 | simpleValue->value.set(def->name); | ||
| 5837 | auto asmt = assignmentFrom(newExp(simpleValue, def), toAst<Exp_t>(arg.name, def), def); | ||
| 5838 | arg.assignment = asmt; | ||
| 5839 | break; | ||
| 5840 | } | ||
| 5841 | case id<SimpleTable_t>(): { | ||
| 5842 | arg.name = getUnusedName("_arg_"sv); | ||
| 5843 | auto value = def->new_ptr<Value_t>(); | ||
| 5844 | value->item.set(def->name); | ||
| 5845 | auto asmt = assignmentFrom(newExp(value, def), toAst<Exp_t>(arg.name, def), def); | ||
| 5846 | arg.assignment = asmt; | ||
| 5847 | break; | ||
| 5848 | } | ||
| 5569 | default: YUEE("AST node mismatch", def->name.get()); break; | 5849 | default: YUEE("AST node mismatch", def->name.get()); break; |
| 5570 | } | 5850 | } |
| 5571 | forceAddToScope(arg.name); | 5851 | forceAddToScope(arg.name); |
| @@ -5579,23 +5859,46 @@ private: | |||
| 5579 | assignment->action.set(assign); | 5859 | assignment->action.set(assign); |
| 5580 | transformAssignment(assignment, temp); | 5860 | transformAssignment(assignment, temp); |
| 5581 | popScope(); | 5861 | popScope(); |
| 5582 | _buf << indent() << "if "sv << arg.name << " == nil then"sv << nll(def); | 5862 | _buf << indent() << "if "sv << arg.name << " == nil then"sv << nl(def); |
| 5583 | _buf << temp.back(); | 5863 | _buf << temp.back(); |
| 5584 | _buf << indent() << "end"sv << nll(def); | 5864 | _buf << indent() << "end"sv << nl(def); |
| 5585 | temp.back() = clearBuf(); | 5865 | temp.back() = clearBuf(); |
| 5586 | } | 5866 | } |
| 5587 | if (varNames.empty()) | 5867 | if (arg.assignment) { |
| 5868 | auto names = getArgDestructureList(arg.assignment); | ||
| 5869 | for (const auto& name : names) { | ||
| 5870 | forceAddToScope(name); | ||
| 5871 | } | ||
| 5872 | temp.emplace_back(indent() + "local "s + join(names, ", "sv) + nl(def)); | ||
| 5873 | transformAssignment(arg.assignment, temp); | ||
| 5874 | } | ||
| 5875 | if (varNames.empty()) { | ||
| 5588 | varNames = arg.name; | 5876 | varNames = arg.name; |
| 5589 | else | 5877 | } else { |
| 5590 | varNames.append(", "s + arg.name); | 5878 | varNames.append(", "s + arg.name); |
| 5879 | } | ||
| 5591 | } | 5880 | } |
| 5592 | if (argDefList->varArg) { | 5881 | if (argDefList->varArg) { |
| 5882 | std::string varStr; | ||
| 5883 | if (auto varName = argDefList->varArg->name.get()) { | ||
| 5884 | varStr = variableToString(varName); | ||
| 5885 | int target = getLuaTarget(varName); | ||
| 5886 | forceAddToScope(varStr); | ||
| 5887 | if (target < 505) { | ||
| 5888 | temp.push_back(indent() + "local "s + varStr + " = {"s + nl(varName)); | ||
| 5889 | temp.push_back(indent(1) + "n = "s + globalVar("select", varName, AccessType::Read) + "(\"#\", ...),"s + nl(varName)); | ||
| 5890 | temp.push_back(indent(1) + "..."s + nl(varName)); | ||
| 5891 | temp.push_back(indent() + '}' + nl(varName)); | ||
| 5892 | varStr.clear(); | ||
| 5893 | } | ||
| 5894 | } | ||
| 5593 | auto& arg = argItems.emplace_back(); | 5895 | auto& arg = argItems.emplace_back(); |
| 5594 | arg.name = "..."sv; | 5896 | arg.name = "..."sv; |
| 5595 | if (varNames.empty()) | 5897 | if (varNames.empty()) { |
| 5596 | varNames = arg.name; | 5898 | varNames = arg.name + varStr; |
| 5597 | else | 5899 | } else { |
| 5598 | varNames.append(", "s + arg.name); | 5900 | varNames.append(", "s + arg.name + varStr); |
| 5901 | } | ||
| 5599 | _varArgs.top().hasVar = true; | 5902 | _varArgs.top().hasVar = true; |
| 5600 | } | 5903 | } |
| 5601 | if (assignSelf) { | 5904 | if (assignSelf) { |
| @@ -5664,6 +5967,45 @@ private: | |||
| 5664 | } | 5967 | } |
| 5665 | } | 5968 | } |
| 5666 | 5969 | ||
| 5970 | bool transformChainEndWithSlice(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) { | ||
| 5971 | auto x = chainList.front(); | ||
| 5972 | if (ast_is<Slice_t>(chainList.back())) { | ||
| 5973 | auto comp = x->new_ptr<Comprehension_t>(); | ||
| 5974 | { | ||
| 5975 | auto chainValue = x->new_ptr<ChainValue_t>(); | ||
| 5976 | for (auto item : chainList) { | ||
| 5977 | chainValue->items.push_back(item); | ||
| 5978 | } | ||
| 5979 | auto itemVar = getUnusedName("_item_"sv); | ||
| 5980 | auto expCode = YueFormat{}.toString(chainValue); | ||
| 5981 | auto compCode = '[' + itemVar + " for "s + itemVar + " in *"s + expCode + ']'; | ||
| 5982 | comp.set(toAst<Comprehension_t>(compCode, x)); | ||
| 5983 | } | ||
| 5984 | switch (usage) { | ||
| 5985 | case ExpUsage::Assignment: { | ||
| 5986 | auto simpleValue = x->new_ptr<SimpleValue_t>(); | ||
| 5987 | simpleValue->value.set(comp); | ||
| 5988 | auto exp = newExp(simpleValue, x); | ||
| 5989 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
| 5990 | assignment->expList.set(assignList); | ||
| 5991 | auto assign = x->new_ptr<Assign_t>(); | ||
| 5992 | assign->values.push_back(exp); | ||
| 5993 | assignment->action.set(assign); | ||
| 5994 | transformAssignment(assignment, out); | ||
| 5995 | break; | ||
| 5996 | } | ||
| 5997 | case ExpUsage::Return: | ||
| 5998 | transformComprehension(comp, out, ExpUsage::Return); | ||
| 5999 | break; | ||
| 6000 | default: | ||
| 6001 | transformComprehension(comp, out, ExpUsage::Closure); | ||
| 6002 | break; | ||
| 6003 | } | ||
| 6004 | return true; | ||
| 6005 | } | ||
| 6006 | return false; | ||
| 6007 | } | ||
| 6008 | |||
| 5667 | bool transformChainEndWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) { | 6009 | bool transformChainEndWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) { |
| 5668 | auto x = chainList.front(); | 6010 | auto x = chainList.front(); |
| 5669 | if (ast_is<ExistentialOp_t>(chainList.back())) { | 6011 | if (ast_is<ExistentialOp_t>(chainList.back())) { |
| @@ -5698,7 +6040,7 @@ private: | |||
| 5698 | case ExpUsage::Return: | 6040 | case ExpUsage::Return: |
| 5699 | transformParens(parens, out); | 6041 | transformParens(parens, out); |
| 5700 | out.back().insert(0, indent() + "return "s); | 6042 | out.back().insert(0, indent() + "return "s); |
| 5701 | out.back().append(nlr(x)); | 6043 | out.back().append(nl(x)); |
| 5702 | break; | 6044 | break; |
| 5703 | default: | 6045 | default: |
| 5704 | transformParens(parens, out); | 6046 | transformParens(parens, out); |
| @@ -5769,7 +6111,7 @@ private: | |||
| 5769 | } | 6111 | } |
| 5770 | } | 6112 | } |
| 5771 | if (isScoped) { | 6113 | if (isScoped) { |
| 5772 | temp.push_back(indent() + "do"s + nll(x)); | 6114 | temp.push_back(indent() + "do"s + nl(x)); |
| 5773 | pushScope(); | 6115 | pushScope(); |
| 5774 | } | 6116 | } |
| 5775 | objVar = getUnusedName("_obj_"sv); | 6117 | objVar = getUnusedName("_obj_"sv); |
| @@ -5829,9 +6171,9 @@ private: | |||
| 5829 | _buf << typeVar << "=type "sv << objVar; | 6171 | _buf << typeVar << "=type "sv << objVar; |
| 5830 | auto typeAssign = toAst<ExpListAssign_t>(clearBuf(), partOne); | 6172 | auto typeAssign = toAst<ExpListAssign_t>(clearBuf(), partOne); |
| 5831 | transformAssignment(typeAssign, temp); | 6173 | transformAssignment(typeAssign, temp); |
| 5832 | _buf << indent() << "if \"table\" == " << typeVar << " or \"userdata\" == "sv << typeVar << " then"sv << nll(x); | 6174 | _buf << indent() << "if \"table\" == " << typeVar << " or \"userdata\" == "sv << typeVar << " then"sv << nl(x); |
| 5833 | } else { | 6175 | } else { |
| 5834 | _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); | 6176 | _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nl(x); |
| 5835 | } | 6177 | } |
| 5836 | temp.push_back(clearBuf()); | 6178 | temp.push_back(clearBuf()); |
| 5837 | pushScope(); | 6179 | pushScope(); |
| @@ -5867,15 +6209,15 @@ private: | |||
| 5867 | } | 6209 | } |
| 5868 | } | 6210 | } |
| 5869 | popScope(); | 6211 | popScope(); |
| 5870 | temp.push_back(indent() + "end"s + nlr(x)); | 6212 | temp.push_back(indent() + "end"s + nl(x)); |
| 5871 | switch (usage) { | 6213 | switch (usage) { |
| 5872 | case ExpUsage::Return: | 6214 | case ExpUsage::Return: |
| 5873 | temp.push_back(indent() + "return nil"s + nlr(x)); | 6215 | temp.push_back(indent() + "return nil"s + nl(x)); |
| 5874 | break; | 6216 | break; |
| 5875 | case ExpUsage::Closure: | 6217 | case ExpUsage::Closure: |
| 5876 | temp.push_back(indent() + "return nil"s + nlr(x)); | 6218 | temp.push_back(indent() + "return nil"s + nl(x)); |
| 5877 | popScope(); | 6219 | popScope(); |
| 5878 | *funcStart = anonFuncStart() + nll(x); | 6220 | *funcStart = anonFuncStart() + nl(x); |
| 5879 | temp.push_back(indent() + anonFuncEnd()); | 6221 | temp.push_back(indent() + anonFuncEnd()); |
| 5880 | popAnonVarArg(); | 6222 | popAnonVarArg(); |
| 5881 | popFunctionScope(); | 6223 | popFunctionScope(); |
| @@ -5885,7 +6227,7 @@ private: | |||
| 5885 | } | 6227 | } |
| 5886 | if (isScoped) { | 6228 | if (isScoped) { |
| 5887 | popScope(); | 6229 | popScope(); |
| 5888 | temp.push_back(indent() + "end"s + nlr(x)); | 6230 | temp.push_back(indent() + "end"s + nl(x)); |
| 5889 | } | 6231 | } |
| 5890 | out.push_back(join(temp)); | 6232 | out.push_back(join(temp)); |
| 5891 | return true; | 6233 | return true; |
| @@ -5902,7 +6244,7 @@ private: | |||
| 5902 | switch (usage) { | 6244 | switch (usage) { |
| 5903 | case ExpUsage::Assignment: | 6245 | case ExpUsage::Assignment: |
| 5904 | if (isScoped) { | 6246 | if (isScoped) { |
| 5905 | temp.push_back(indent() + "do"s + nll(x)); | 6247 | temp.push_back(indent() + "do"s + nl(x)); |
| 5906 | pushScope(); | 6248 | pushScope(); |
| 5907 | } | 6249 | } |
| 5908 | break; | 6250 | break; |
| @@ -5980,12 +6322,12 @@ private: | |||
| 5980 | case ExpUsage::Assignment: | 6322 | case ExpUsage::Assignment: |
| 5981 | if (isScoped) { | 6323 | if (isScoped) { |
| 5982 | popScope(); | 6324 | popScope(); |
| 5983 | temp.push_back(indent() + "end"s + nlr(x)); | 6325 | temp.push_back(indent() + "end"s + nl(x)); |
| 5984 | } | 6326 | } |
| 5985 | break; | 6327 | break; |
| 5986 | case ExpUsage::Closure: | 6328 | case ExpUsage::Closure: |
| 5987 | popScope(); | 6329 | popScope(); |
| 5988 | *funcStart = anonFuncStart() + nll(x); | 6330 | *funcStart = anonFuncStart() + nl(x); |
| 5989 | temp.push_back(indent() + anonFuncEnd()); | 6331 | temp.push_back(indent() + anonFuncEnd()); |
| 5990 | popAnonVarArg(); | 6332 | popAnonVarArg(); |
| 5991 | popFunctionScope(); | 6333 | popFunctionScope(); |
| @@ -6061,7 +6403,7 @@ private: | |||
| 6061 | pushScope(); | 6403 | pushScope(); |
| 6062 | } else if (usage != ExpUsage::Return) { | 6404 | } else if (usage != ExpUsage::Return) { |
| 6063 | if (isScoped) { | 6405 | if (isScoped) { |
| 6064 | temp.push_back(indent() + "do"s + nll(x)); | 6406 | temp.push_back(indent() + "do"s + nl(x)); |
| 6065 | pushScope(); | 6407 | pushScope(); |
| 6066 | } | 6408 | } |
| 6067 | } | 6409 | } |
| @@ -6098,7 +6440,7 @@ private: | |||
| 6098 | returnNode->valueList.set(values); | 6440 | returnNode->valueList.set(values); |
| 6099 | transformReturn(returnNode, temp); | 6441 | transformReturn(returnNode, temp); |
| 6100 | popScope(); | 6442 | popScope(); |
| 6101 | *funcStart = anonFuncStart() + nll(x); | 6443 | *funcStart = anonFuncStart() + nl(x); |
| 6102 | temp.push_back(indent() + anonFuncEnd()); | 6444 | temp.push_back(indent() + anonFuncEnd()); |
| 6103 | popAnonVarArg(); | 6445 | popAnonVarArg(); |
| 6104 | popFunctionScope(); | 6446 | popFunctionScope(); |
| @@ -6122,7 +6464,7 @@ private: | |||
| 6122 | transformAssignment(assignment, temp); | 6464 | transformAssignment(assignment, temp); |
| 6123 | if (isScoped) { | 6465 | if (isScoped) { |
| 6124 | popScope(); | 6466 | popScope(); |
| 6125 | temp.push_back(indent() + "end"s + nlr(x)); | 6467 | temp.push_back(indent() + "end"s + nl(x)); |
| 6126 | } | 6468 | } |
| 6127 | break; | 6469 | break; |
| 6128 | } | 6470 | } |
| @@ -6130,7 +6472,7 @@ private: | |||
| 6130 | transformExp(newChainExp, temp, usage); | 6472 | transformExp(newChainExp, temp, usage); |
| 6131 | if (isScoped) { | 6473 | if (isScoped) { |
| 6132 | popScope(); | 6474 | popScope(); |
| 6133 | temp.push_back(indent() + "end"s + nlr(x)); | 6475 | temp.push_back(indent() + "end"s + nl(x)); |
| 6134 | } | 6476 | } |
| 6135 | break; | 6477 | break; |
| 6136 | } | 6478 | } |
| @@ -6181,7 +6523,7 @@ private: | |||
| 6181 | case id<ColonChainItem_t>(): | 6523 | case id<ColonChainItem_t>(): |
| 6182 | case id<Exp_t>(): | 6524 | case id<Exp_t>(): |
| 6183 | if (_withVars.empty()) { | 6525 | if (_withVars.empty()) { |
| 6184 | throw CompileError("short dot/colon and indexing syntax must be called within a with block"sv, x); | 6526 | throw CompileError("short dot/colon/indexing syntax must be called within a with block"sv, x); |
| 6185 | } else { | 6527 | } else { |
| 6186 | temp.push_back(_withVars.top()); | 6528 | temp.push_back(_withVars.top()); |
| 6187 | } | 6529 | } |
| @@ -6235,7 +6577,7 @@ private: | |||
| 6235 | assignment->action.set(assign); | 6577 | assignment->action.set(assign); |
| 6236 | auto stmt = x->new_ptr<Statement_t>(); | 6578 | auto stmt = x->new_ptr<Statement_t>(); |
| 6237 | stmt->content.set(assignment); | 6579 | stmt->content.set(assignment); |
| 6238 | block->statements.push_back(stmt); | 6580 | block->statementOrComments.push_back(stmt); |
| 6239 | } | 6581 | } |
| 6240 | } | 6582 | } |
| 6241 | ast_ptr<false, Exp_t> nexp; | 6583 | ast_ptr<false, Exp_t> nexp; |
| @@ -6281,7 +6623,7 @@ private: | |||
| 6281 | expListAssign->expList.set(expList); | 6623 | expListAssign->expList.set(expList); |
| 6282 | auto stmt = x->new_ptr<Statement_t>(); | 6624 | auto stmt = x->new_ptr<Statement_t>(); |
| 6283 | stmt->content.set(expListAssign); | 6625 | stmt->content.set(expListAssign); |
| 6284 | block->statements.push_back(stmt); | 6626 | block->statementOrComments.push_back(stmt); |
| 6285 | } | 6627 | } |
| 6286 | switch (usage) { | 6628 | switch (usage) { |
| 6287 | case ExpUsage::Common: | 6629 | case ExpUsage::Common: |
| @@ -6295,7 +6637,7 @@ private: | |||
| 6295 | default: | 6637 | default: |
| 6296 | break; | 6638 | break; |
| 6297 | } | 6639 | } |
| 6298 | if (block->statements.size() == 1) { | 6640 | if (block->statementOrComments.size() == 1) { |
| 6299 | transformExp(nexp, out, usage, assignList); | 6641 | transformExp(nexp, out, usage, assignList); |
| 6300 | } else { | 6642 | } else { |
| 6301 | auto body = x->new_ptr<Body_t>(); | 6643 | auto body = x->new_ptr<Body_t>(); |
| @@ -6327,6 +6669,120 @@ private: | |||
| 6327 | } | 6669 | } |
| 6328 | return; | 6670 | return; |
| 6329 | } | 6671 | } |
| 6672 | break; | ||
| 6673 | } | ||
| 6674 | case id<ReversedIndex_t>(): { | ||
| 6675 | auto rIndex = static_cast<ReversedIndex_t*>(*it); | ||
| 6676 | auto current = it; | ||
| 6677 | auto prevChain = x->new_ptr<ChainValue_t>(); | ||
| 6678 | for (auto i = chainList.begin(); i != current; ++i) { | ||
| 6679 | prevChain->items.push_back(*i); | ||
| 6680 | } | ||
| 6681 | auto var = singleVariableFrom(prevChain, AccessType::None); | ||
| 6682 | if (!var.empty() && isLocal(var)) { | ||
| 6683 | auto indexNode = toAst<Exp_t>('#' + var, rIndex); | ||
| 6684 | if (rIndex->modifier) { | ||
| 6685 | auto opValue = rIndex->new_ptr<ExpOpValue_t>(); | ||
| 6686 | opValue->op.set(toAst<BinaryOperator_t>("-"sv, rIndex)); | ||
| 6687 | opValue->pipeExprs.dup(rIndex->modifier->pipeExprs); | ||
| 6688 | indexNode->opValues.push_back(opValue); | ||
| 6689 | indexNode->opValues.dup(rIndex->modifier->opValues); | ||
| 6690 | indexNode->nilCoalesed.set(rIndex->modifier->nilCoalesed); | ||
| 6691 | } | ||
| 6692 | prevChain->items.push_back(indexNode); | ||
| 6693 | auto next = current; | ||
| 6694 | ++next; | ||
| 6695 | for (auto i = next; i != chainList.end(); ++i) { | ||
| 6696 | prevChain->items.push_back(*i); | ||
| 6697 | } | ||
| 6698 | if (usage == ExpUsage::Assignment) { | ||
| 6699 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
| 6700 | assignment->expList.set(assignList); | ||
| 6701 | auto assign = x->new_ptr<Assign_t>(); | ||
| 6702 | assign->values.push_back(newExp(prevChain, x)); | ||
| 6703 | assignment->action.set(assign); | ||
| 6704 | transformAssignment(assignment, out); | ||
| 6705 | return; | ||
| 6706 | } | ||
| 6707 | transformChainValue(prevChain, out, usage, assignList); | ||
| 6708 | return; | ||
| 6709 | } else { | ||
| 6710 | auto itemVar = getUnusedName("_item_"sv); | ||
| 6711 | auto asmt = assignmentFrom(toAst<Exp_t>(itemVar, x), newExp(prevChain, x), x); | ||
| 6712 | auto stmt1 = x->new_ptr<Statement_t>(); | ||
| 6713 | stmt1->content.set(asmt); | ||
| 6714 | auto newChain = x->new_ptr<ChainValue_t>(); | ||
| 6715 | newChain->items.push_back(toAst<Callable_t>(itemVar, x)); | ||
| 6716 | auto indexNode = toAst<Exp_t>('#' + itemVar, rIndex); | ||
| 6717 | if (rIndex->modifier) { | ||
| 6718 | auto opValue = rIndex->new_ptr<ExpOpValue_t>(); | ||
| 6719 | opValue->op.set(toAst<BinaryOperator_t>("-"sv, rIndex)); | ||
| 6720 | opValue->pipeExprs.dup(rIndex->modifier->pipeExprs); | ||
| 6721 | indexNode->opValues.push_back(opValue); | ||
| 6722 | indexNode->opValues.dup(rIndex->modifier->opValues); | ||
| 6723 | indexNode->nilCoalesed.set(rIndex->modifier->nilCoalesed); | ||
| 6724 | } | ||
| 6725 | newChain->items.push_back(indexNode); | ||
| 6726 | auto expList = x->new_ptr<ExpList_t>(); | ||
| 6727 | expList->exprs.push_back(newExp(newChain, x)); | ||
| 6728 | auto expListAssign = x->new_ptr<ExpListAssign_t>(); | ||
| 6729 | expListAssign->expList.set(expList); | ||
| 6730 | auto stmt2 = x->new_ptr<Statement_t>(); | ||
| 6731 | stmt2->content.set(expListAssign); | ||
| 6732 | auto block = x->new_ptr<Block_t>(); | ||
| 6733 | block->statementOrComments.push_back(stmt1); | ||
| 6734 | block->statementOrComments.push_back(stmt2); | ||
| 6735 | auto body = x->new_ptr<Body_t>(); | ||
| 6736 | body->content.set(block); | ||
| 6737 | auto doNode = x->new_ptr<Do_t>(); | ||
| 6738 | doNode->body.set(body); | ||
| 6739 | if (usage == ExpUsage::Assignment) { | ||
| 6740 | auto next = current; | ||
| 6741 | ++next; | ||
| 6742 | for (auto i = next; i != chainList.end(); ++i) { | ||
| 6743 | newChain->items.push_back(*i); | ||
| 6744 | } | ||
| 6745 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
| 6746 | assignment->expList.set(assignList); | ||
| 6747 | auto assign = x->new_ptr<Assign_t>(); | ||
| 6748 | auto sVal = x->new_ptr<SimpleValue_t>(); | ||
| 6749 | sVal->value.set(doNode); | ||
| 6750 | assign->values.push_back(newExp(sVal, x)); | ||
| 6751 | assignment->action.set(assign); | ||
| 6752 | transformAssignment(assignment, out); | ||
| 6753 | return; | ||
| 6754 | } | ||
| 6755 | if (usage == ExpUsage::Closure) { | ||
| 6756 | auto next = current; | ||
| 6757 | ++next; | ||
| 6758 | if (next != chainList.end()) { | ||
| 6759 | doNode->new_ptr<ChainValue_t>(); | ||
| 6760 | auto dVal = doNode->new_ptr<SimpleValue_t>(); | ||
| 6761 | dVal->value.set(doNode); | ||
| 6762 | auto dExp = newExp(dVal, dVal); | ||
| 6763 | auto dParen = dExp->new_ptr<Parens_t>(); | ||
| 6764 | dParen->extra = true; | ||
| 6765 | dParen->expr.set(dExp); | ||
| 6766 | auto dCallable = dExp->new_ptr<Callable_t>(); | ||
| 6767 | dCallable->item.set(dParen); | ||
| 6768 | auto dChain = doNode->new_ptr<ChainValue_t>(); | ||
| 6769 | dChain->items.push_back(dCallable); | ||
| 6770 | for (auto i = next; i != chainList.end(); ++i) { | ||
| 6771 | dChain->items.push_back(*i); | ||
| 6772 | } | ||
| 6773 | transformExp(newExp(dChain, dExp), out, usage); | ||
| 6774 | return; | ||
| 6775 | } | ||
| 6776 | } | ||
| 6777 | auto next = current; | ||
| 6778 | ++next; | ||
| 6779 | for (auto i = next; i != chainList.end(); ++i) { | ||
| 6780 | newChain->items.push_back(*i); | ||
| 6781 | } | ||
| 6782 | transformDo(doNode, out, usage); | ||
| 6783 | return; | ||
| 6784 | } | ||
| 6785 | break; | ||
| 6330 | } | 6786 | } |
| 6331 | } | 6787 | } |
| 6332 | } | 6788 | } |
| @@ -6376,10 +6832,10 @@ private: | |||
| 6376 | } | 6832 | } |
| 6377 | switch (usage) { | 6833 | switch (usage) { |
| 6378 | case ExpUsage::Common: | 6834 | case ExpUsage::Common: |
| 6379 | out.push_back(indent() + join(temp) + nll(x)); | 6835 | out.push_back(indent() + join(temp) + nl(x)); |
| 6380 | break; | 6836 | break; |
| 6381 | case ExpUsage::Return: | 6837 | case ExpUsage::Return: |
| 6382 | out.push_back(indent() + "return "s + join(temp) + nll(x)); | 6838 | out.push_back(indent() + "return "s + join(temp) + nl(x)); |
| 6383 | break; | 6839 | break; |
| 6384 | case ExpUsage::Assignment: YUEE("invalid expression usage", x); break; | 6840 | case ExpUsage::Assignment: YUEE("invalid expression usage", x); break; |
| 6385 | default: | 6841 | default: |
| @@ -6511,7 +6967,7 @@ private: | |||
| 6511 | } | 6967 | } |
| 6512 | } | 6968 | } |
| 6513 | } | 6969 | } |
| 6514 | int len = lua_objlen(L, -1); | 6970 | int len = static_cast<int>(lua_objlen(L, -1)); |
| 6515 | lua_pushnil(L); // cur nil | 6971 | lua_pushnil(L); // cur nil |
| 6516 | for (int i = len; i >= 1; i--) { | 6972 | for (int i = len; i >= 1; i--) { |
| 6517 | lua_pop(L, 1); // cur | 6973 | lua_pop(L, 1); // cur |
| @@ -6523,7 +6979,25 @@ private: | |||
| 6523 | break; | 6979 | break; |
| 6524 | } | 6980 | } |
| 6525 | } | 6981 | } |
| 6526 | if (!lua_isfunction(L, -1)) { | 6982 | str_list checks; |
| 6983 | if (lua_istable(L, -1)) { | ||
| 6984 | lua_rawgeti(L, -1, 1); // cur macrotab checks | ||
| 6985 | int len = static_cast<int>(lua_objlen(L, -1)); | ||
| 6986 | for (int i = 1; i <= len; i++) { | ||
| 6987 | lua_rawgeti(L, -1, i); | ||
| 6988 | if (lua_toboolean(L, -1) == 0) { | ||
| 6989 | checks.emplace_back(); | ||
| 6990 | } else { | ||
| 6991 | size_t str_len = 0; | ||
| 6992 | auto str = lua_tolstring(L, -1, &str_len); | ||
| 6993 | checks.emplace_back(std::string{str, str_len}); | ||
| 6994 | } | ||
| 6995 | lua_pop(L, 1); | ||
| 6996 | } | ||
| 6997 | lua_pop(L, 1); | ||
| 6998 | lua_rawgeti(L, -1, 2); // cur macrotab macroFunc | ||
| 6999 | lua_remove(L, -2); // cur macroFunc | ||
| 7000 | } else if (!lua_isfunction(L, -1)) { | ||
| 6527 | auto code = expandBuiltinMacro(macroName, x); | 7001 | auto code = expandBuiltinMacro(macroName, x); |
| 6528 | if (!code.empty()) return code; | 7002 | if (!code.empty()) return code; |
| 6529 | if (macroName == "is_ast"sv) { | 7003 | if (macroName == "is_ast"sv) { |
| @@ -6568,11 +7042,34 @@ private: | |||
| 6568 | } // cur macroFunc | 7042 | } // cur macroFunc |
| 6569 | pushYue("pcall"sv); // cur macroFunc pcall | 7043 | pushYue("pcall"sv); // cur macroFunc pcall |
| 6570 | lua_insert(L, -2); // cur pcall macroFunc | 7044 | lua_insert(L, -2); // cur pcall macroFunc |
| 6571 | if (!lua_checkstack(L, argStrs.size())) { | 7045 | if (!lua_checkstack(L, static_cast<int>(argStrs.size()))) { |
| 6572 | throw CompileError("too much macro params"s, x); | 7046 | throw CompileError("too much macro params"s, x); |
| 6573 | } | 7047 | } |
| 7048 | auto checkIt = checks.begin(); | ||
| 7049 | node_container::const_iterator argIt; | ||
| 7050 | if (args) { | ||
| 7051 | argIt = args->begin(); | ||
| 7052 | } | ||
| 6574 | for (const auto& arg : argStrs) { | 7053 | for (const auto& arg : argStrs) { |
| 7054 | if (checkIt != checks.end()) { | ||
| 7055 | if (checkIt->empty()) { | ||
| 7056 | ++checkIt; | ||
| 7057 | } else { | ||
| 7058 | if ((*checkIt)[0] == '.') { | ||
| 7059 | auto astName = checkIt->substr(3); | ||
| 7060 | if (!_parser.match(astName, arg)) { | ||
| 7061 | throw CompileError("expecting \""s + astName + "\", AST mismatch"s, *argIt); | ||
| 7062 | } | ||
| 7063 | } else { | ||
| 7064 | if (!_parser.match(*checkIt, arg)) { | ||
| 7065 | throw CompileError("expecting \""s + *checkIt + "\", AST mismatch"s, *argIt); | ||
| 7066 | } | ||
| 7067 | ++checkIt; | ||
| 7068 | } | ||
| 7069 | } | ||
| 7070 | } | ||
| 6575 | lua_pushlstring(L, arg.c_str(), arg.size()); | 7071 | lua_pushlstring(L, arg.c_str(), arg.size()); |
| 7072 | ++argIt; | ||
| 6576 | } // cur pcall macroFunc args... | 7073 | } // cur pcall macroFunc args... |
| 6577 | bool success = lua_pcall(L, static_cast<int>(argStrs.size()), 1, 0) == 0; | 7074 | bool success = lua_pcall(L, static_cast<int>(argStrs.size()), 1, 0) == 0; |
| 6578 | if (!success) { // cur err | 7075 | if (!success) { // cur err |
| @@ -6664,8 +7161,8 @@ private: | |||
| 6664 | throw CompileError("lua macro is not expanding to valid block\n"s + err, x); | 7161 | throw CompileError("lua macro is not expanding to valid block\n"s + err, x); |
| 6665 | } | 7162 | } |
| 6666 | if (!codes.empty()) { | 7163 | if (!codes.empty()) { |
| 6667 | codes.insert(0, indent() + "do"s + nll(chainValue)); | 7164 | codes.insert(0, indent() + "do"s + nl(chainValue)); |
| 6668 | codes.append(_newLine + indent() + "end"s + nlr(chainValue)); | 7165 | codes.append(_newLine + indent() + "end"s + nl(chainValue)); |
| 6669 | } | 7166 | } |
| 6670 | return {nullptr, nullptr, std::move(codes), std::move(localVars)}; | 7167 | return {nullptr, nullptr, std::move(codes), std::move(localVars)}; |
| 6671 | } else { | 7168 | } else { |
| @@ -6702,14 +7199,14 @@ private: | |||
| 6702 | } else { | 7199 | } else { |
| 6703 | if (!codes.empty()) { | 7200 | if (!codes.empty()) { |
| 6704 | if (isBlock) { | 7201 | if (isBlock) { |
| 6705 | info = _parser.parse<BlockEnd_t>(codes); | 7202 | info = _parser.parse<BlockEnd_t>(codes, false); |
| 6706 | if (info.error) { | 7203 | if (info.error) { |
| 6707 | throw CompileError("failed to expand macro as block: "s + info.error.value().msg, x); | 7204 | throw CompileError("failed to expand macro as block: "s + info.error.value().msg, x); |
| 6708 | } | 7205 | } |
| 6709 | } else { | 7206 | } else { |
| 6710 | info = _parser.parse<Exp_t>(codes); | 7207 | info = _parser.parse<Exp_t>(codes, false); |
| 6711 | if (!info.node && allowBlockMacroReturn) { | 7208 | if (!info.node && allowBlockMacroReturn) { |
| 6712 | info = _parser.parse<BlockEnd_t>(codes); | 7209 | info = _parser.parse<BlockEnd_t>(codes, false); |
| 6713 | if (info.error) { | 7210 | if (info.error) { |
| 6714 | throw CompileError("failed to expand macro as expr or block: "s + info.error.value().msg, x); | 7211 | throw CompileError("failed to expand macro as expr or block: "s + info.error.value().msg, x); |
| 6715 | } | 7212 | } |
| @@ -6754,7 +7251,7 @@ private: | |||
| 6754 | auto stmt = x->new_ptr<Statement_t>(); | 7251 | auto stmt = x->new_ptr<Statement_t>(); |
| 6755 | stmt->content.set(exps); | 7252 | stmt->content.set(exps); |
| 6756 | auto block = x->new_ptr<Block_t>(); | 7253 | auto block = x->new_ptr<Block_t>(); |
| 6757 | block->statements.push_back(stmt); | 7254 | block->statementOrComments.push_back(stmt); |
| 6758 | info.node.set(block); | 7255 | info.node.set(block); |
| 6759 | } else { | 7256 | } else { |
| 6760 | info.node.set(exp); | 7257 | info.node.set(exp); |
| @@ -6791,7 +7288,7 @@ private: | |||
| 6791 | return; | 7288 | return; |
| 6792 | } | 7289 | } |
| 6793 | if (usage == ExpUsage::Common || (usage == ExpUsage::Return && node.is<Block_t>())) { | 7290 | if (usage == ExpUsage::Common || (usage == ExpUsage::Return && node.is<Block_t>())) { |
| 6794 | if (node.to<Block_t>()->statements.empty()) { | 7291 | if (node.to<Block_t>()->statementOrComments.empty()) { |
| 6795 | out.push_back(Empty); | 7292 | out.push_back(Empty); |
| 6796 | } else { | 7293 | } else { |
| 6797 | auto doBody = node->new_ptr<Body_t>(); | 7294 | auto doBody = node->new_ptr<Body_t>(); |
| @@ -6845,6 +7342,9 @@ private: | |||
| 6845 | if (transformChainEndWithColonItem(chainList, out, usage, assignList)) { | 7342 | if (transformChainEndWithColonItem(chainList, out, usage, assignList)) { |
| 6846 | return; | 7343 | return; |
| 6847 | } | 7344 | } |
| 7345 | if (transformChainEndWithSlice(chainList, out, usage, assignList)) { | ||
| 7346 | return; | ||
| 7347 | } | ||
| 6848 | transformChainList(chainList, out, usage, assignList); | 7348 | transformChainList(chainList, out, usage, assignList); |
| 6849 | } | 7349 | } |
| 6850 | 7350 | ||
| @@ -6941,7 +7441,7 @@ private: | |||
| 6941 | } | 7441 | } |
| 6942 | } | 7442 | } |
| 6943 | } else if (auto comp = sval->value.as<Comprehension_t>()) { | 7443 | } else if (auto comp = sval->value.as<Comprehension_t>()) { |
| 6944 | if (comp->items.size() != 2 || !ast_is<CompInner_t>(comp->items.back())) { | 7444 | if (!isListComp(comp)) { |
| 6945 | discrete = inExp->new_ptr<ExpList_t>(); | 7445 | discrete = inExp->new_ptr<ExpList_t>(); |
| 6946 | for (ast_node* val : comp->items.objects()) { | 7446 | for (ast_node* val : comp->items.objects()) { |
| 6947 | if (auto def = ast_cast<NormalDef_t>(val)) { | 7447 | if (auto def = ast_cast<NormalDef_t>(val)) { |
| @@ -6970,7 +7470,7 @@ private: | |||
| 6970 | auto assignment = assignmentFrom(toAst<Exp_t>(checkVar, inExp), newExp(inExp, inExp), inExp); | 7470 | auto assignment = assignmentFrom(toAst<Exp_t>(checkVar, inExp), newExp(inExp, inExp), inExp); |
| 6971 | auto stmt = x->new_ptr<Statement_t>(); | 7471 | auto stmt = x->new_ptr<Statement_t>(); |
| 6972 | stmt->content.set(assignment); | 7472 | stmt->content.set(assignment); |
| 6973 | block->statements.push_back(stmt); | 7473 | block->statementOrComments.push_back(stmt); |
| 6974 | } | 7474 | } |
| 6975 | if (varName.empty()) { | 7475 | if (varName.empty()) { |
| 6976 | auto newUnaryExp = x->new_ptr<UnaryExp_t>(); | 7476 | auto newUnaryExp = x->new_ptr<UnaryExp_t>(); |
| @@ -6982,7 +7482,7 @@ private: | |||
| 6982 | auto assignment = assignmentFrom(assignExp, exp, x); | 7482 | auto assignment = assignmentFrom(assignExp, exp, x); |
| 6983 | auto stmt = x->new_ptr<Statement_t>(); | 7483 | auto stmt = x->new_ptr<Statement_t>(); |
| 6984 | stmt->content.set(assignment); | 7484 | stmt->content.set(assignment); |
| 6985 | block->statements.push_back(stmt); | 7485 | block->statementOrComments.push_back(stmt); |
| 6986 | } | 7486 | } |
| 6987 | auto findVar = getUnusedName("_find_"); | 7487 | auto findVar = getUnusedName("_find_"); |
| 6988 | auto itemVar = getUnusedName("_item_"); | 7488 | auto itemVar = getUnusedName("_item_"); |
| @@ -6998,7 +7498,7 @@ private: | |||
| 6998 | } | 7498 | } |
| 6999 | auto blockStr = clearBuf(); | 7499 | auto blockStr = clearBuf(); |
| 7000 | auto checkBlock = toAst<Block_t>(blockStr, inExp); | 7500 | auto checkBlock = toAst<Block_t>(blockStr, inExp); |
| 7001 | block->statements.dup(checkBlock->statements); | 7501 | block->statementOrComments.dup(checkBlock->statementOrComments); |
| 7002 | auto body = x->new_ptr<Body_t>(); | 7502 | auto body = x->new_ptr<Body_t>(); |
| 7003 | body->content.set(block); | 7503 | body->content.set(block); |
| 7004 | auto doNode = x->new_ptr<Do_t>(); | 7504 | auto doNode = x->new_ptr<Do_t>(); |
| @@ -7018,16 +7518,16 @@ private: | |||
| 7018 | } else { | 7518 | } else { |
| 7019 | auto arrayCheck = [&](bool exist) { | 7519 | auto arrayCheck = [&](bool exist) { |
| 7020 | auto indexVar = getUnusedName("_index_"); | 7520 | auto indexVar = getUnusedName("_index_"); |
| 7021 | _buf << indent() << "for "sv << indexVar << " = 1, #"sv << checkVar << " do"sv << nll(x); | 7521 | _buf << indent() << "for "sv << indexVar << " = 1, #"sv << checkVar << " do"sv << nl(x); |
| 7022 | incIndentOffset(); | 7522 | incIndentOffset(); |
| 7023 | _buf << indent() << "if "sv << checkVar << '[' << indexVar << "] == "sv << varName << " then"sv << nll(x); | 7523 | _buf << indent() << "if "sv << checkVar << '[' << indexVar << "] == "sv << varName << " then"sv << nl(x); |
| 7024 | incIndentOffset(); | 7524 | incIndentOffset(); |
| 7025 | _buf << indent() << "return "sv << (exist ? "true"sv : "false"sv) << nll(x); | 7525 | _buf << indent() << "return "sv << (exist ? "true"sv : "false"sv) << nl(x); |
| 7026 | decIndentOffset(); | 7526 | decIndentOffset(); |
| 7027 | _buf << indent() << "end"sv << nll(x); | 7527 | _buf << indent() << "end"sv << nl(x); |
| 7028 | decIndentOffset(); | 7528 | decIndentOffset(); |
| 7029 | _buf << indent() << "end"sv << nll(x); | 7529 | _buf << indent() << "end"sv << nl(x); |
| 7030 | _buf << indent() << "return "sv << (exist ? "false"sv : "true"sv) << nll(x); | 7530 | _buf << indent() << "return "sv << (exist ? "false"sv : "true"sv) << nl(x); |
| 7031 | temp.push_back(clearBuf()); | 7531 | temp.push_back(clearBuf()); |
| 7032 | }; | 7532 | }; |
| 7033 | bool useShortCheck = (usage == ExpUsage::Closure) && !varName.empty() && !checkVar.empty() && isLocal(checkVar); | 7533 | bool useShortCheck = (usage == ExpUsage::Closure) && !varName.empty() && !checkVar.empty() && isLocal(checkVar); |
| @@ -7043,7 +7543,7 @@ private: | |||
| 7043 | pushAnonVarArg(); | 7543 | pushAnonVarArg(); |
| 7044 | pushScope(); | 7544 | pushScope(); |
| 7045 | arrayCheck(true); | 7545 | arrayCheck(true); |
| 7046 | temp.push_front("(#"s + checkVar + " > 0 and "s + anonFuncStart() + nll(x)); | 7546 | temp.push_front("(#"s + checkVar + " > 0 and "s + anonFuncStart() + nl(x)); |
| 7047 | popScope(); | 7547 | popScope(); |
| 7048 | temp.push_back(indent() + anonFuncEnd() + ')'); | 7548 | temp.push_back(indent() + anonFuncEnd() + ')'); |
| 7049 | if (unary_exp->inExp->not_) { | 7549 | if (unary_exp->inExp->not_) { |
| @@ -7080,7 +7580,7 @@ private: | |||
| 7080 | arrayCheck(!unary_exp->inExp->not_); | 7580 | arrayCheck(!unary_exp->inExp->not_); |
| 7081 | } else { | 7581 | } else { |
| 7082 | arrayCheck(!unary_exp->inExp->not_); | 7582 | arrayCheck(!unary_exp->inExp->not_); |
| 7083 | temp.push_front(anonFuncStart() + nll(x)); | 7583 | temp.push_front(anonFuncStart() + nl(x)); |
| 7084 | popScope(); | 7584 | popScope(); |
| 7085 | temp.push_back(indent() + anonFuncEnd()); | 7585 | temp.push_back(indent() + anonFuncEnd()); |
| 7086 | popAnonVarArg(); | 7586 | popAnonVarArg(); |
| @@ -7120,7 +7620,7 @@ private: | |||
| 7120 | pushScope(); | 7620 | pushScope(); |
| 7121 | } else if (usage == ExpUsage::Assignment) { | 7621 | } else if (usage == ExpUsage::Assignment) { |
| 7122 | if (isScoped) { | 7622 | if (isScoped) { |
| 7123 | temp.push_back(indent() + "do"s + nll(x)); | 7623 | temp.push_back(indent() + "do"s + nl(x)); |
| 7124 | pushScope(); | 7624 | pushScope(); |
| 7125 | } | 7625 | } |
| 7126 | } | 7626 | } |
| @@ -7160,10 +7660,10 @@ private: | |||
| 7160 | if (unary_exp->inExp->not_) { | 7660 | if (unary_exp->inExp->not_) { |
| 7161 | _buf << ")"sv; | 7661 | _buf << ")"sv; |
| 7162 | } | 7662 | } |
| 7163 | _buf << nll(x); | 7663 | _buf << nl(x); |
| 7164 | temp.push_back(clearBuf()); | 7664 | temp.push_back(clearBuf()); |
| 7165 | if (usage == ExpUsage::Closure) { | 7665 | if (usage == ExpUsage::Closure) { |
| 7166 | temp.push_front(anonFuncStart() + nll(x)); | 7666 | temp.push_front(anonFuncStart() + nl(x)); |
| 7167 | popScope(); | 7667 | popScope(); |
| 7168 | temp.push_back(indent() + anonFuncEnd()); | 7668 | temp.push_back(indent() + anonFuncEnd()); |
| 7169 | out.push_back(join(temp)); | 7669 | out.push_back(join(temp)); |
| @@ -7172,7 +7672,7 @@ private: | |||
| 7172 | } else if (usage == ExpUsage::Assignment) { | 7672 | } else if (usage == ExpUsage::Assignment) { |
| 7173 | if (isScoped) { | 7673 | if (isScoped) { |
| 7174 | popScope(); | 7674 | popScope(); |
| 7175 | temp.push_back(indent() + "end"s + nll(x)); | 7675 | temp.push_back(indent() + "end"s + nl(x)); |
| 7176 | } | 7676 | } |
| 7177 | out.push_back(join(temp)); | 7677 | out.push_back(join(temp)); |
| 7178 | } else { | 7678 | } else { |
| @@ -7206,7 +7706,7 @@ private: | |||
| 7206 | } | 7706 | } |
| 7207 | _buf << ')'; | 7707 | _buf << ')'; |
| 7208 | if (usage == ExpUsage::Assignment || usage == ExpUsage::Return) { | 7708 | if (usage == ExpUsage::Assignment || usage == ExpUsage::Return) { |
| 7209 | _buf << nll(discrete); | 7709 | _buf << nl(discrete); |
| 7210 | } | 7710 | } |
| 7211 | out.push_back(clearBuf()); | 7711 | out.push_back(clearBuf()); |
| 7212 | } | 7712 | } |
| @@ -7326,7 +7826,7 @@ private: | |||
| 7326 | forceAddToScope(tableVar); | 7826 | forceAddToScope(tableVar); |
| 7327 | auto it = values.begin(); | 7827 | auto it = values.begin(); |
| 7328 | if (ast_is<SpreadExp_t, SpreadListExp_t>(*it)) { | 7828 | if (ast_is<SpreadExp_t, SpreadListExp_t>(*it)) { |
| 7329 | temp.push_back(indent() + "local "s + tableVar + " = { }"s + nll(x)); | 7829 | temp.push_back(indent() + "local "s + tableVar + " = { }"s + nl(x)); |
| 7330 | } else { | 7830 | } else { |
| 7331 | auto initialTab = x->new_ptr<TableLit_t>(); | 7831 | auto initialTab = x->new_ptr<TableLit_t>(); |
| 7332 | while (it != values.end() && !ast_is<SpreadExp_t, SpreadListExp_t>(*it)) { | 7832 | while (it != values.end() && !ast_is<SpreadExp_t, SpreadListExp_t>(*it)) { |
| @@ -7334,7 +7834,7 @@ private: | |||
| 7334 | ++it; | 7834 | ++it; |
| 7335 | } | 7835 | } |
| 7336 | transformTable(initialTab->values.objects(), temp); | 7836 | transformTable(initialTab->values.objects(), temp); |
| 7337 | temp.back() = indent() + "local "s + tableVar + " = "s + temp.back() + nll(*it); | 7837 | temp.back() = indent() + "local "s + tableVar + " = "s + temp.back() + nl(*it); |
| 7338 | } | 7838 | } |
| 7339 | for (; it != values.end(); ++it) { | 7839 | for (; it != values.end(); ++it) { |
| 7340 | auto item = *it; | 7840 | auto item = *it; |
| @@ -7354,14 +7854,14 @@ private: | |||
| 7354 | transformAssignment(assignment, temp); | 7854 | transformAssignment(assignment, temp); |
| 7355 | } | 7855 | } |
| 7356 | forceAddToScope(indexVar); | 7856 | forceAddToScope(indexVar); |
| 7357 | temp.push_back(indent() + "local "s + indexVar + " = 1"s + nll(item)); | 7857 | temp.push_back(indent() + "local "s + indexVar + " = 1"s + nl(item)); |
| 7358 | _buf << "for "sv << keyVar << ',' << valueVar << " in pairs "sv << objVar | 7858 | _buf << "for "sv << keyVar << ',' << valueVar << " in pairs "sv << objVar |
| 7359 | << "\n\tif "sv << indexVar << "=="sv << keyVar | 7859 | << "\n\tif "sv << indexVar << "=="sv << keyVar |
| 7360 | << "\n\t\t"sv << tableVar << "[]="sv << valueVar | 7860 | << "\n\t\t"sv << tableVar << "[]="sv << valueVar |
| 7361 | << "\n\t\t"sv << indexVar << "+=1"sv | 7861 | << "\n\t\t"sv << indexVar << "+=1"sv |
| 7362 | << "\n\telse "sv << tableVar << '[' << keyVar << "]="sv << valueVar; | 7862 | << "\n\telse "sv << tableVar << '[' << keyVar << "]="sv << valueVar; |
| 7363 | auto forEach = toAst<ForEach_t>(clearBuf(), item); | 7863 | auto forNode = toAst<For_t>(clearBuf(), item); |
| 7364 | transformForEach(forEach, temp); | 7864 | transformFor(forNode, temp); |
| 7365 | break; | 7865 | break; |
| 7366 | } | 7866 | } |
| 7367 | case id<SpreadListExp_t>(): { | 7867 | case id<SpreadListExp_t>(): { |
| @@ -7378,12 +7878,12 @@ private: | |||
| 7378 | transformAssignment(assignment, temp); | 7878 | transformAssignment(assignment, temp); |
| 7379 | } | 7879 | } |
| 7380 | forceAddToScope(indexVar); | 7880 | forceAddToScope(indexVar); |
| 7381 | temp.push_back(indent() + "local "s + indexVar + " = #"s + tableVar + " + 1"s + nll(item)); | 7881 | temp.push_back(indent() + "local "s + indexVar + " = #"s + tableVar + " + 1"s + nl(item)); |
| 7382 | _buf << "for "sv << valueVar << " in *"sv << objVar | 7882 | _buf << "for "sv << valueVar << " in *"sv << objVar |
| 7383 | << "\n\t"sv << tableVar << '[' << indexVar << "]="sv << valueVar | 7883 | << "\n\t"sv << tableVar << '[' << indexVar << "]="sv << valueVar |
| 7384 | << "\n\t"sv << indexVar << "+=1"sv; | 7884 | << "\n\t"sv << indexVar << "+=1"sv; |
| 7385 | auto forEach = toAst<ForEach_t>(clearBuf(), item); | 7885 | auto forNode = toAst<For_t>(clearBuf(), item); |
| 7386 | transformForEach(forEach, temp); | 7886 | transformFor(forNode, temp); |
| 7387 | break; | 7887 | break; |
| 7388 | } | 7888 | } |
| 7389 | case id<VariablePair_t>(): | 7889 | case id<VariablePair_t>(): |
| @@ -7561,9 +8061,9 @@ private: | |||
| 7561 | break; | 8061 | break; |
| 7562 | case ExpUsage::Closure: { | 8062 | case ExpUsage::Closure: { |
| 7563 | out.push_back(join(temp)); | 8063 | out.push_back(join(temp)); |
| 7564 | out.back().append(indent() + "return "s + tableVar + nlr(x)); | 8064 | out.back().append(indent() + "return "s + tableVar + nl(x)); |
| 7565 | popScope(); | 8065 | popScope(); |
| 7566 | out.back().insert(0, anonFuncStart() + nll(x)); | 8066 | out.back().insert(0, anonFuncStart() + nl(x)); |
| 7567 | out.back().append(indent() + anonFuncEnd()); | 8067 | out.back().append(indent() + anonFuncEnd()); |
| 7568 | popAnonVarArg(); | 8068 | popAnonVarArg(); |
| 7569 | popFunctionScope(); | 8069 | popFunctionScope(); |
| @@ -7579,13 +8079,13 @@ private: | |||
| 7579 | if (extraScope) popScope(); | 8079 | if (extraScope) popScope(); |
| 7580 | out.push_back(join(temp)); | 8080 | out.push_back(join(temp)); |
| 7581 | if (extraScope) { | 8081 | if (extraScope) { |
| 7582 | out.back() = indent() + "do"s + nll(x) + out.back() + indent() + "end"s + nlr(x); | 8082 | out.back() = indent() + "do"s + nl(x) + out.back() + indent() + "end"s + nl(x); |
| 7583 | } | 8083 | } |
| 7584 | break; | 8084 | break; |
| 7585 | } | 8085 | } |
| 7586 | case ExpUsage::Return: | 8086 | case ExpUsage::Return: |
| 7587 | out.push_back(join(temp)); | 8087 | out.push_back(join(temp)); |
| 7588 | out.back().append(indent() + "return "s + tableVar + nlr(x)); | 8088 | out.back().append(indent() + "return "s + tableVar + nl(x)); |
| 7589 | break; | 8089 | break; |
| 7590 | default: | 8090 | default: |
| 7591 | break; | 8091 | break; |
| @@ -7706,11 +8206,11 @@ private: | |||
| 7706 | default: YUEE("AST node mismatch", item); break; | 8206 | default: YUEE("AST node mismatch", item); break; |
| 7707 | } | 8207 | } |
| 7708 | if (!isMetamethod) { | 8208 | if (!isMetamethod) { |
| 7709 | temp.back() = indent() + (value == values.back() ? temp.back() : temp.back() + ',') + nll(value); | 8209 | temp.back() = indent() + (value == values.back() ? temp.back() : temp.back() + ',') + nl(value); |
| 7710 | } | 8210 | } |
| 7711 | } | 8211 | } |
| 7712 | if (metatable->pairs.empty() && !metatableItem) { | 8212 | if (metatable->pairs.empty() && !metatableItem) { |
| 7713 | out.push_back('{' + nll(x) + join(temp)); | 8213 | out.push_back('{' + nl(x) + join(temp)); |
| 7714 | decIndentOffset(); | 8214 | decIndentOffset(); |
| 7715 | out.back() += (indent() + '}'); | 8215 | out.back() += (indent() + '}'); |
| 7716 | } else { | 8216 | } else { |
| @@ -7720,7 +8220,7 @@ private: | |||
| 7720 | decIndentOffset(); | 8220 | decIndentOffset(); |
| 7721 | tabStr += "{ }"sv; | 8221 | tabStr += "{ }"sv; |
| 7722 | } else { | 8222 | } else { |
| 7723 | tabStr += ('{' + nll(x) + join(temp)); | 8223 | tabStr += ('{' + nl(x) + join(temp)); |
| 7724 | decIndentOffset(); | 8224 | decIndentOffset(); |
| 7725 | tabStr += (indent() + '}'); | 8225 | tabStr += (indent() + '}'); |
| 7726 | } | 8226 | } |
| @@ -7764,18 +8264,18 @@ private: | |||
| 7764 | void transformCompCommon(Comprehension_t* comp, str_list& out) { | 8264 | void transformCompCommon(Comprehension_t* comp, str_list& out) { |
| 7765 | str_list temp; | 8265 | str_list temp; |
| 7766 | auto x = comp; | 8266 | auto x = comp; |
| 7767 | auto compInner = static_cast<CompInner_t*>(comp->items.back()); | 8267 | auto compFor = static_cast<CompFor_t*>(comp->items.back()); |
| 7768 | for (auto item : compInner->items.objects()) { | 8268 | for (auto item : compFor->items.objects()) { |
| 7769 | switch (item->get_id()) { | 8269 | switch (item->get_id()) { |
| 7770 | case id<CompForEach_t>(): | 8270 | case id<CompForEach_t>(): |
| 7771 | transformCompForEach(static_cast<CompForEach_t*>(item), temp); | 8271 | transformCompForEach(static_cast<CompForEach_t*>(item), temp); |
| 7772 | break; | 8272 | break; |
| 7773 | case id<CompFor_t>(): | 8273 | case id<CompForNum_t>(): |
| 7774 | transformCompFor(static_cast<CompFor_t*>(item), temp); | 8274 | transformCompForNum(static_cast<CompForNum_t*>(item), temp); |
| 7775 | break; | 8275 | break; |
| 7776 | case id<Exp_t>(): | 8276 | case id<Exp_t>(): |
| 7777 | transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure); | 8277 | transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure); |
| 7778 | temp.back() = indent() + "if "s + temp.back() + " then"s + nll(item); | 8278 | temp.back() = indent() + "if "s + temp.back() + " then"s + nl(item); |
| 7779 | pushScope(); | 8279 | pushScope(); |
| 7780 | break; | 8280 | break; |
| 7781 | default: YUEE("AST node mismatch", item); break; | 8281 | default: YUEE("AST node mismatch", item); break; |
| @@ -7795,16 +8295,16 @@ private: | |||
| 7795 | auto value = std::move(temp.back()); | 8295 | auto value = std::move(temp.back()); |
| 7796 | temp.pop_back(); | 8296 | temp.pop_back(); |
| 7797 | _buf << join(temp) << value; | 8297 | _buf << join(temp) << value; |
| 7798 | for (size_t i = 0; i < compInner->items.objects().size(); ++i) { | 8298 | for (size_t i = 0; i < compFor->items.objects().size(); ++i) { |
| 7799 | popScope(); | 8299 | popScope(); |
| 7800 | _buf << indent() << "end"sv << nll(comp); | 8300 | _buf << indent() << "end"sv << nl(comp); |
| 7801 | } | 8301 | } |
| 7802 | out.push_back(clearBuf()); | 8302 | out.push_back(clearBuf()); |
| 7803 | } | 8303 | } |
| 7804 | 8304 | ||
| 7805 | void transformComprehension(Comprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { | 8305 | void transformComprehension(Comprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { |
| 7806 | auto x = comp; | 8306 | auto x = comp; |
| 7807 | if (comp->items.size() != 2 || !ast_is<CompInner_t>(comp->items.back())) { | 8307 | if (!isListComp(comp)) { |
| 7808 | switch (usage) { | 8308 | switch (usage) { |
| 7809 | case ExpUsage::Assignment: { | 8309 | case ExpUsage::Assignment: { |
| 7810 | auto tableLit = x->new_ptr<TableLit_t>(); | 8310 | auto tableLit = x->new_ptr<TableLit_t>(); |
| @@ -7843,9 +8343,16 @@ private: | |||
| 7843 | } | 8343 | } |
| 7844 | return; | 8344 | return; |
| 7845 | } | 8345 | } |
| 7846 | auto def = ast_cast<NormalDef_t>(comp->items.front()); | 8346 | ast_node* value = nullptr; |
| 7847 | if (!def || def->defVal) { | 8347 | bool isSpread = ast_is<SpreadListExp_t>(comp->items.front()); |
| 7848 | throw CompileError("invalid comprehension expression", comp->items.front()); | 8348 | if (isSpread) { |
| 8349 | value = comp->items.front(); | ||
| 8350 | } else { | ||
| 8351 | auto def = ast_cast<NormalDef_t>(comp->items.front()); | ||
| 8352 | if (!def || def->defVal) { | ||
| 8353 | throw CompileError("invalid comprehension expression", comp->items.front()); | ||
| 8354 | } | ||
| 8355 | value = def->item.get(); | ||
| 7849 | } | 8356 | } |
| 7850 | bool extraScope = false; | 8357 | bool extraScope = false; |
| 7851 | switch (usage) { | 8358 | switch (usage) { |
| @@ -7869,31 +8376,33 @@ private: | |||
| 7869 | default: | 8376 | default: |
| 7870 | break; | 8377 | break; |
| 7871 | } | 8378 | } |
| 7872 | auto value = def->item.get(); | 8379 | auto compFor = static_cast<CompFor_t*>(comp->items.back()); |
| 7873 | auto compInner = static_cast<CompInner_t*>(comp->items.back()); | ||
| 7874 | str_list temp; | 8380 | str_list temp; |
| 7875 | std::string accumVar = getUnusedName("_accum_"sv); | 8381 | std::string accumVar = getUnusedName("_accum_"sv); |
| 7876 | std::string lenVar = getUnusedName("_len_"sv); | ||
| 7877 | addToScope(accumVar); | 8382 | addToScope(accumVar); |
| 7878 | addToScope(lenVar); | 8383 | std::string lenVar; |
| 7879 | for (auto item : compInner->items.objects()) { | 8384 | if (!isSpread) { |
| 8385 | lenVar = getUnusedName("_len_"sv); | ||
| 8386 | addToScope(lenVar); | ||
| 8387 | } | ||
| 8388 | for (auto item : compFor->items.objects()) { | ||
| 7880 | switch (item->get_id()) { | 8389 | switch (item->get_id()) { |
| 7881 | case id<CompForEach_t>(): | 8390 | case id<CompForEach_t>(): |
| 7882 | transformCompForEach(static_cast<CompForEach_t*>(item), temp); | 8391 | transformCompForEach(static_cast<CompForEach_t*>(item), temp); |
| 7883 | break; | 8392 | break; |
| 7884 | case id<CompFor_t>(): | 8393 | case id<CompForNum_t>(): |
| 7885 | transformCompFor(static_cast<CompFor_t*>(item), temp); | 8394 | transformCompForNum(static_cast<CompForNum_t*>(item), temp); |
| 7886 | break; | 8395 | break; |
| 7887 | case id<Exp_t>(): | 8396 | case id<Exp_t>(): |
| 7888 | transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure); | 8397 | transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure); |
| 7889 | temp.back() = indent() + "if "s + temp.back() + " then"s + nll(item); | 8398 | temp.back() = indent() + "if "s + temp.back() + " then"s + nl(item); |
| 7890 | pushScope(); | 8399 | pushScope(); |
| 7891 | break; | 8400 | break; |
| 7892 | default: YUEE("AST node mismatch", item); break; | 8401 | default: YUEE("AST node mismatch", item); break; |
| 7893 | } | 8402 | } |
| 7894 | } | 8403 | } |
| 7895 | { | 8404 | { |
| 7896 | auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); | 8405 | auto assignLeft = toAst<ExpList_t>(accumVar + '[' + (isSpread ? "]"s : lenVar + ']'), x); |
| 7897 | auto assign = x->new_ptr<Assign_t>(); | 8406 | auto assign = x->new_ptr<Assign_t>(); |
| 7898 | assign->values.push_back(value); | 8407 | assign->values.push_back(value); |
| 7899 | auto assignment = x->new_ptr<ExpListAssign_t>(); | 8408 | auto assignment = x->new_ptr<ExpListAssign_t>(); |
| @@ -7903,25 +8412,30 @@ private: | |||
| 7903 | } | 8412 | } |
| 7904 | auto assignStr = std::move(temp.back()); | 8413 | auto assignStr = std::move(temp.back()); |
| 7905 | temp.pop_back(); | 8414 | temp.pop_back(); |
| 7906 | for (size_t i = 0; i < compInner->items.objects().size(); ++i) { | 8415 | for (size_t i = 0; i < compFor->items.objects().size(); ++i) { |
| 7907 | popScope(); | 8416 | popScope(); |
| 7908 | } | 8417 | } |
| 7909 | _buf << indent() << "local "sv << accumVar << " = { }"sv << nll(comp); | 8418 | _buf << indent() << "local "sv << accumVar << " = { }"sv << nl(comp); |
| 7910 | _buf << indent() << "local "sv << lenVar << " = 1"sv << nll(comp); | 8419 | if (isSpread) { |
| 7911 | _buf << join(temp); | 8420 | _buf << join(temp); |
| 7912 | _buf << assignStr; | 8421 | _buf << assignStr; |
| 7913 | _buf << indent(int(temp.size())) << lenVar << " = "sv << lenVar << " + 1"sv << nll(comp); | 8422 | } else { |
| 8423 | _buf << indent() << "local "sv << lenVar << " = 1"sv << nl(comp); | ||
| 8424 | _buf << join(temp); | ||
| 8425 | _buf << assignStr; | ||
| 8426 | _buf << indent(int(temp.size())) << lenVar << " = "sv << lenVar << " + 1"sv << nl(comp); | ||
| 8427 | } | ||
| 7914 | for (int ind = int(temp.size()) - 1; ind > -1; --ind) { | 8428 | for (int ind = int(temp.size()) - 1; ind > -1; --ind) { |
| 7915 | _buf << indent(ind) << "end"sv << nll(comp); | 8429 | _buf << indent(ind) << "end"sv << nl(comp); |
| 7916 | } | 8430 | } |
| 7917 | switch (usage) { | 8431 | switch (usage) { |
| 7918 | case ExpUsage::Common: | 8432 | case ExpUsage::Common: |
| 7919 | break; | 8433 | break; |
| 7920 | case ExpUsage::Closure: { | 8434 | case ExpUsage::Closure: { |
| 7921 | out.push_back(clearBuf()); | 8435 | out.push_back(clearBuf()); |
| 7922 | out.back().append(indent() + "return "s + accumVar + nlr(comp)); | 8436 | out.back().append(indent() + "return "s + accumVar + nl(comp)); |
| 7923 | popScope(); | 8437 | popScope(); |
| 7924 | out.back().insert(0, anonFuncStart() + nll(comp)); | 8438 | out.back().insert(0, anonFuncStart() + nl(comp)); |
| 7925 | out.back().append(indent() + anonFuncEnd()); | 8439 | out.back().append(indent() + anonFuncEnd()); |
| 7926 | popAnonVarArg(); | 8440 | popAnonVarArg(); |
| 7927 | popFunctionScope(); | 8441 | popFunctionScope(); |
| @@ -7938,13 +8452,13 @@ private: | |||
| 7938 | out.back().append(temp.back()); | 8452 | out.back().append(temp.back()); |
| 7939 | if (extraScope) { | 8453 | if (extraScope) { |
| 7940 | popScope(); | 8454 | popScope(); |
| 7941 | out.back() = indent() + "do"s + nll(comp) + out.back() + indent() + "end"s + nlr(comp); | 8455 | out.back() = indent() + "do"s + nl(comp) + out.back() + indent() + "end"s + nl(comp); |
| 7942 | } | 8456 | } |
| 7943 | break; | 8457 | break; |
| 7944 | } | 8458 | } |
| 7945 | case ExpUsage::Return: | 8459 | case ExpUsage::Return: |
| 7946 | out.push_back(clearBuf()); | 8460 | out.push_back(clearBuf()); |
| 7947 | out.back().append(indent() + "return "s + accumVar + nlr(comp)); | 8461 | out.back().append(indent() + "return "s + accumVar + nl(comp)); |
| 7948 | break; | 8462 | break; |
| 7949 | default: | 8463 | default: |
| 7950 | break; | 8464 | break; |
| @@ -7952,6 +8466,11 @@ private: | |||
| 7952 | } | 8466 | } |
| 7953 | 8467 | ||
| 7954 | bool transformForEachHead(AssignableNameList_t* nameList, ast_node* loopTarget, str_list& out, bool inClosure) { | 8468 | bool transformForEachHead(AssignableNameList_t* nameList, ast_node* loopTarget, str_list& out, bool inClosure) { |
| 8469 | enum class NumState { | ||
| 8470 | Unknown, | ||
| 8471 | Positive, | ||
| 8472 | Negtive | ||
| 8473 | }; | ||
| 7955 | auto x = nameList; | 8474 | auto x = nameList; |
| 7956 | str_list temp; | 8475 | str_list temp; |
| 7957 | str_list vars; | 8476 | str_list vars; |
| @@ -7970,13 +8489,8 @@ private: | |||
| 7970 | varConstAfter = vars.back(); | 8489 | varConstAfter = vars.back(); |
| 7971 | } | 8490 | } |
| 7972 | break; | 8491 | break; |
| 7973 | case id<TableLit_t>(): { | 8492 | case id<SimpleTable_t>(): |
| 7974 | auto desVar = getUnusedName("_des_"sv); | 8493 | case id<TableLit_t>(): |
| 7975 | destructPairs.emplace_back(item, toAst<Exp_t>(desVar, x)); | ||
| 7976 | vars.push_back(desVar); | ||
| 7977 | varAfter.push_back(desVar); | ||
| 7978 | break; | ||
| 7979 | } | ||
| 7980 | case id<Comprehension_t>(): { | 8494 | case id<Comprehension_t>(): { |
| 7981 | auto desVar = getUnusedName("_des_"sv); | 8495 | auto desVar = getUnusedName("_des_"sv); |
| 7982 | destructPairs.emplace_back(item, toAst<Exp_t>(desVar, x)); | 8496 | destructPairs.emplace_back(item, toAst<Exp_t>(desVar, x)); |
| @@ -8018,15 +8532,35 @@ private: | |||
| 8018 | for (auto item : chainList) { | 8532 | for (auto item : chainList) { |
| 8019 | chain->items.push_back(item); | 8533 | chain->items.push_back(item); |
| 8020 | } | 8534 | } |
| 8021 | std::string startValue("1"sv); | 8535 | std::string startValue; |
| 8536 | NumState startStatus = NumState::Unknown; | ||
| 8022 | if (auto exp = slice->startValue.as<Exp_t>()) { | 8537 | if (auto exp = slice->startValue.as<Exp_t>()) { |
| 8023 | transformExp(exp, temp, ExpUsage::Closure); | 8538 | transformExp(exp, temp, ExpUsage::Closure); |
| 8539 | if (temp.back().at(0) == '-') { | ||
| 8540 | if (_parser.match<Num_t>(temp.back().substr(1))) { | ||
| 8541 | startStatus = NumState::Negtive; | ||
| 8542 | } | ||
| 8543 | } else { | ||
| 8544 | if (_parser.match<Num_t>(temp.back())) { | ||
| 8545 | startStatus = NumState::Positive; | ||
| 8546 | } | ||
| 8547 | } | ||
| 8024 | startValue = std::move(temp.back()); | 8548 | startValue = std::move(temp.back()); |
| 8025 | temp.pop_back(); | 8549 | temp.pop_back(); |
| 8026 | } | 8550 | } |
| 8027 | std::string stopValue; | 8551 | std::string stopValue; |
| 8552 | NumState stopStatus = NumState::Unknown; | ||
| 8028 | if (auto exp = slice->stopValue.as<Exp_t>()) { | 8553 | if (auto exp = slice->stopValue.as<Exp_t>()) { |
| 8029 | transformExp(exp, temp, ExpUsage::Closure); | 8554 | transformExp(exp, temp, ExpUsage::Closure); |
| 8555 | if (temp.back().at(0) == '-') { | ||
| 8556 | if (_parser.match<Num_t>(temp.back().substr(1))) { | ||
| 8557 | stopStatus = NumState::Negtive; | ||
| 8558 | } | ||
| 8559 | } else { | ||
| 8560 | if (_parser.match<Num_t>(temp.back())) { | ||
| 8561 | stopStatus = NumState::Positive; | ||
| 8562 | } | ||
| 8563 | } | ||
| 8030 | stopValue = std::move(temp.back()); | 8564 | stopValue = std::move(temp.back()); |
| 8031 | temp.pop_back(); | 8565 | temp.pop_back(); |
| 8032 | } | 8566 | } |
| @@ -8040,38 +8574,94 @@ private: | |||
| 8040 | std::string prefix; | 8574 | std::string prefix; |
| 8041 | if (!inClosure && needScope) { | 8575 | if (!inClosure && needScope) { |
| 8042 | extraScope = true; | 8576 | extraScope = true; |
| 8043 | prefix = indent() + "do"s + nll(x); | 8577 | prefix = indent() + "do"s + nl(x); |
| 8044 | pushScope(); | 8578 | pushScope(); |
| 8045 | } | 8579 | } |
| 8046 | listVar = getUnusedName("_list_"sv); | 8580 | listVar = getUnusedName("_list_"sv); |
| 8047 | varBefore.push_back(listVar); | 8581 | varBefore.push_back(listVar); |
| 8048 | transformChainValue(chain, temp, ExpUsage::Closure); | 8582 | transformChainValue(chain, temp, ExpUsage::Closure); |
| 8049 | _buf << prefix << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList); | 8583 | _buf << prefix << indent() << "local "sv << listVar << " = "sv << temp.back() << nl(nameList); |
| 8584 | } | ||
| 8585 | if (startValue.empty()) { | ||
| 8586 | startValue = "1"s; | ||
| 8587 | startStatus = NumState::Positive; | ||
| 8588 | } | ||
| 8589 | std::string minVar; | ||
| 8590 | if (startStatus != NumState::Positive) { | ||
| 8591 | std::string prefix; | ||
| 8592 | if (!extraScope && !inClosure && needScope) { | ||
| 8593 | extraScope = true; | ||
| 8594 | prefix = indent() + "do"s + nl(x); | ||
| 8595 | pushScope(); | ||
| 8596 | } | ||
| 8597 | minVar = getUnusedName("_min_"sv); | ||
| 8598 | varBefore.push_back(minVar); | ||
| 8599 | if (startStatus == NumState::Negtive) { | ||
| 8600 | _buf << prefix << indent() << "local "sv << minVar << " = "sv << "#"sv << listVar << " + "sv << startValue << " + 1"sv << nl(nameList); | ||
| 8601 | } else { | ||
| 8602 | _buf << prefix << indent() << "local "sv << minVar << " = "sv << startValue << nl(nameList); | ||
| 8603 | } | ||
| 8604 | } | ||
| 8605 | bool defaultStop = false; | ||
| 8606 | if (stopValue.empty()) { | ||
| 8607 | stopValue = "#"s + listVar; | ||
| 8608 | defaultStop = true; | ||
| 8050 | } | 8609 | } |
| 8051 | std::string maxVar; | 8610 | std::string maxVar; |
| 8052 | if (!stopValue.empty()) { | 8611 | if (stopStatus != NumState::Positive) { |
| 8053 | std::string prefix; | 8612 | std::string prefix; |
| 8054 | if (!extraScope && !inClosure && needScope) { | 8613 | if (!extraScope && !inClosure && needScope) { |
| 8055 | extraScope = true; | 8614 | extraScope = true; |
| 8056 | prefix = indent() + "do"s + nll(x); | 8615 | prefix = indent() + "do"s + nl(x); |
| 8057 | pushScope(); | 8616 | pushScope(); |
| 8058 | } | 8617 | } |
| 8059 | maxVar = getUnusedName("_max_"sv); | 8618 | maxVar = getUnusedName("_max_"sv); |
| 8060 | varBefore.push_back(maxVar); | 8619 | varBefore.push_back(maxVar); |
| 8061 | _buf << prefix << indent() << "local "sv << maxVar << " = "sv << stopValue << nll(nameList); | 8620 | if (stopStatus == NumState::Negtive) { |
| 8621 | _buf << indent() << "local "sv << maxVar << " = "sv << "#"sv << listVar << " + "sv << stopValue << " + 1"sv << nl(nameList); | ||
| 8622 | } else { | ||
| 8623 | _buf << prefix << indent() << "local "sv << maxVar << " = "sv << stopValue << nl(nameList); | ||
| 8624 | } | ||
| 8625 | } | ||
| 8626 | if (startStatus == NumState::Unknown) { | ||
| 8627 | _buf << indent() << minVar << " = "sv << minVar << " < 0 and #"sv << listVar << " + "sv << minVar << " + 1 or "sv << minVar << nl(nameList); | ||
| 8628 | } | ||
| 8629 | if (!defaultStop && stopStatus == NumState::Unknown) { | ||
| 8630 | _buf << indent() << maxVar << " = "sv << maxVar << " < 0 and #"sv << listVar << " + "sv << maxVar << " + 1 or "sv << maxVar << nl(nameList); | ||
| 8062 | } | 8631 | } |
| 8063 | _buf << indent() << "for "sv << indexVar << " = "sv; | 8632 | _buf << indent() << "for "sv << indexVar << " = "sv; |
| 8064 | _buf << startValue << ", "sv; | 8633 | if (startValue.empty()) { |
| 8634 | _buf << "1"sv; | ||
| 8635 | } else { | ||
| 8636 | switch (startStatus) { | ||
| 8637 | case NumState::Unknown: | ||
| 8638 | case NumState::Negtive: | ||
| 8639 | _buf << minVar; | ||
| 8640 | break; | ||
| 8641 | case NumState::Positive: | ||
| 8642 | _buf << startValue; | ||
| 8643 | break; | ||
| 8644 | } | ||
| 8645 | } | ||
| 8646 | _buf << ", "sv; | ||
| 8065 | if (stopValue.empty()) { | 8647 | if (stopValue.empty()) { |
| 8066 | _buf << "#"sv << listVar; | 8648 | _buf << "#"sv << listVar; |
| 8067 | } else { | 8649 | } else { |
| 8068 | _buf << maxVar << " < 0 and #"sv << listVar << " + "sv << maxVar << " or "sv << maxVar; | 8650 | switch (stopStatus) { |
| 8651 | case NumState::Unknown: | ||
| 8652 | case NumState::Negtive: | ||
| 8653 | _buf << maxVar; | ||
| 8654 | break; | ||
| 8655 | case NumState::Positive: | ||
| 8656 | _buf << stopValue; | ||
| 8657 | break; | ||
| 8658 | } | ||
| 8069 | } | 8659 | } |
| 8070 | if (!stepValue.empty()) { | 8660 | if (!stepValue.empty()) { |
| 8071 | _buf << ", "sv << stepValue; | 8661 | _buf << ", "sv << stepValue; |
| 8072 | } | 8662 | } |
| 8073 | _buf << " do"sv << nlr(loopTarget); | 8663 | _buf << " do"sv << nl(loopTarget); |
| 8074 | _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nll(nameList); | 8664 | _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nl(nameList); |
| 8075 | out.push_back(clearBuf()); | 8665 | out.push_back(clearBuf()); |
| 8076 | BLOCK_END | 8666 | BLOCK_END |
| 8077 | bool newListVal = false; | 8667 | bool newListVal = false; |
| @@ -8082,21 +8672,21 @@ private: | |||
| 8082 | } | 8672 | } |
| 8083 | if (!endWithSlice) { | 8673 | if (!endWithSlice) { |
| 8084 | transformExp(star_exp->value, temp, ExpUsage::Closure); | 8674 | transformExp(star_exp->value, temp, ExpUsage::Closure); |
| 8085 | if (newListVal) _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList); | 8675 | if (newListVal) _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nl(nameList); |
| 8086 | _buf << indent() << "for "sv << indexVar << " = 1, #"sv << listVar << " do"sv << nlr(loopTarget); | 8676 | _buf << indent() << "for "sv << indexVar << " = 1, #"sv << listVar << " do"sv << nl(loopTarget); |
| 8087 | _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nll(nameList); | 8677 | _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nl(nameList); |
| 8088 | out.push_back(clearBuf()); | 8678 | out.push_back(clearBuf()); |
| 8089 | } | 8679 | } |
| 8090 | break; | 8680 | break; |
| 8091 | } | 8681 | } |
| 8092 | case id<Exp_t>(): | 8682 | case id<Exp_t>(): |
| 8093 | transformExp(static_cast<Exp_t*>(loopTarget), temp, ExpUsage::Closure); | 8683 | transformExp(static_cast<Exp_t*>(loopTarget), temp, ExpUsage::Closure); |
| 8094 | _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nlr(loopTarget); | 8684 | _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nl(loopTarget); |
| 8095 | out.push_back(clearBuf()); | 8685 | out.push_back(clearBuf()); |
| 8096 | break; | 8686 | break; |
| 8097 | case id<ExpList_t>(): | 8687 | case id<ExpList_t>(): |
| 8098 | transformExpList(static_cast<ExpList_t*>(loopTarget), temp); | 8688 | transformExpList(static_cast<ExpList_t*>(loopTarget), temp); |
| 8099 | _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nlr(loopTarget); | 8689 | _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nl(loopTarget); |
| 8100 | out.push_back(clearBuf()); | 8690 | out.push_back(clearBuf()); |
| 8101 | break; | 8691 | break; |
| 8102 | default: YUEE("AST node mismatch", loopTarget); break; | 8692 | default: YUEE("AST node mismatch", loopTarget); break; |
| @@ -8109,11 +8699,18 @@ private: | |||
| 8109 | if (!destructPairs.empty()) { | 8699 | if (!destructPairs.empty()) { |
| 8110 | temp.clear(); | 8700 | temp.clear(); |
| 8111 | for (auto& pair : destructPairs) { | 8701 | for (auto& pair : destructPairs) { |
| 8112 | auto sValue = x->new_ptr<SimpleValue_t>(); | ||
| 8113 | sValue->value.set(pair.first); | ||
| 8114 | auto exp = newExp(sValue, x); | ||
| 8115 | auto expList = x->new_ptr<ExpList_t>(); | 8702 | auto expList = x->new_ptr<ExpList_t>(); |
| 8116 | expList->exprs.push_back(exp); | 8703 | if (ast_is<SimpleTable_t>(pair.first)) { |
| 8704 | auto value = x->new_ptr<Value_t>(); | ||
| 8705 | value->item.set(pair.first); | ||
| 8706 | auto exp = newExp(value, x); | ||
| 8707 | expList->exprs.push_back(exp); | ||
| 8708 | } else { | ||
| 8709 | auto sValue = x->new_ptr<SimpleValue_t>(); | ||
| 8710 | sValue->value.set(pair.first); | ||
| 8711 | auto exp = newExp(sValue, x); | ||
| 8712 | expList->exprs.push_back(exp); | ||
| 8713 | } | ||
| 8117 | auto assign = x->new_ptr<Assign_t>(); | 8714 | auto assign = x->new_ptr<Assign_t>(); |
| 8118 | assign->values.push_back(pair.second); | 8715 | assign->values.push_back(pair.second); |
| 8119 | auto assignment = x->new_ptr<ExpListAssign_t>(); | 8716 | auto assignment = x->new_ptr<ExpListAssign_t>(); |
| @@ -8173,7 +8770,7 @@ private: | |||
| 8173 | out.push_back('(' + join(temp, ", "sv) + ')'); | 8770 | out.push_back('(' + join(temp, ", "sv) + ')'); |
| 8174 | } | 8771 | } |
| 8175 | 8772 | ||
| 8176 | void transformForHead(Variable_t* var, Exp_t* startVal, Exp_t* stopVal, ForStepValue_t* stepVal, str_list& out) { | 8773 | void transformForNumHead(Variable_t* var, Exp_t* startVal, Exp_t* stopVal, ForStepValue_t* stepVal, str_list& out) { |
| 8177 | str_list temp; | 8774 | str_list temp; |
| 8178 | std::string varName = variableToString(var); | 8775 | std::string varName = variableToString(var); |
| 8179 | transformExp(startVal, temp, ExpUsage::Closure); | 8776 | transformExp(startVal, temp, ExpUsage::Closure); |
| @@ -8187,15 +8784,15 @@ private: | |||
| 8187 | const auto& start = *it; | 8784 | const auto& start = *it; |
| 8188 | const auto& stop = *(++it); | 8785 | const auto& stop = *(++it); |
| 8189 | const auto& step = *(++it); | 8786 | const auto& step = *(++it); |
| 8190 | _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : ", "s + step) << " do"sv << nll(var); | 8787 | _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : ", "s + step) << " do"sv << nl(var); |
| 8191 | pushScope(); | 8788 | pushScope(); |
| 8192 | forceAddToScope(varName); | 8789 | forceAddToScope(varName); |
| 8193 | markVarLocalConst(varName); | 8790 | markVarLocalConst(varName); |
| 8194 | out.push_back(clearBuf()); | 8791 | out.push_back(clearBuf()); |
| 8195 | } | 8792 | } |
| 8196 | 8793 | ||
| 8197 | void transformForHead(For_t* forNode, str_list& out) { | 8794 | void transformForNumHead(ForNum_t* forNum, str_list& out) { |
| 8198 | transformForHead(forNode->varName, forNode->startValue, forNode->stopValue, forNode->stepValue, out); | 8795 | transformForNumHead(forNum->varName, forNum->startValue, forNum->stopValue, forNum->stepValue, out); |
| 8199 | } | 8796 | } |
| 8200 | 8797 | ||
| 8201 | void transform_plain_body(ast_node* bodyOrStmt, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { | 8798 | void transform_plain_body(ast_node* bodyOrStmt, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { |
| @@ -8205,7 +8802,7 @@ private: | |||
| 8205 | break; | 8802 | break; |
| 8206 | case id<Statement_t>(): { | 8803 | case id<Statement_t>(): { |
| 8207 | auto newBlock = bodyOrStmt->new_ptr<Block_t>(); | 8804 | auto newBlock = bodyOrStmt->new_ptr<Block_t>(); |
| 8208 | newBlock->statements.push_back(bodyOrStmt); | 8805 | newBlock->statementOrComments.push_back(bodyOrStmt); |
| 8209 | transformBlock(newBlock, out, usage, assignList); | 8806 | transformBlock(newBlock, out, usage, assignList); |
| 8210 | break; | 8807 | break; |
| 8211 | } | 8808 | } |
| @@ -8302,9 +8899,9 @@ private: | |||
| 8302 | } | 8899 | } |
| 8303 | 8900 | ||
| 8304 | void addDoToLastLineReturn(ast_node* body) { | 8901 | void addDoToLastLineReturn(ast_node* body) { |
| 8305 | if (auto block = ast_cast<Block_t>(body); block && !block->statements.empty()) { | 8902 | if (auto block = ast_cast<Block_t>(body); block && !block->statementOrComments.empty()) { |
| 8306 | auto last = static_cast<Statement_t*>(block->statements.back()); | 8903 | auto last = lastStatementFrom(block); |
| 8307 | if (last->content.is<Return_t>()) { | 8904 | if (last && last->content.is<Return_t>()) { |
| 8308 | auto doNode = last->new_ptr<Do_t>(); | 8905 | auto doNode = last->new_ptr<Do_t>(); |
| 8309 | auto newBody = last->new_ptr<Body_t>(); | 8906 | auto newBody = last->new_ptr<Body_t>(); |
| 8310 | auto newStmt = last->new_ptr<Statement_t>(); | 8907 | auto newStmt = last->new_ptr<Statement_t>(); |
| @@ -8331,8 +8928,8 @@ private: | |||
| 8331 | if (withContinue) { | 8928 | if (withContinue) { |
| 8332 | if (target < 502) { | 8929 | if (target < 502) { |
| 8333 | if (auto block = ast_cast<Block_t>(body)) { | 8930 | if (auto block = ast_cast<Block_t>(body)) { |
| 8334 | if (!block->statements.empty()) { | 8931 | if (!block->statementOrComments.empty()) { |
| 8335 | auto stmt = static_cast<Statement_t*>(block->statements.back()); | 8932 | auto stmt = lastStatementFrom(block); |
| 8336 | if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { | 8933 | if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { |
| 8337 | extraDo = breakLoop->type.is<Break_t>(); | 8934 | extraDo = breakLoop->type.is<Break_t>(); |
| 8338 | } | 8935 | } |
| @@ -8341,11 +8938,11 @@ private: | |||
| 8341 | auto continueVar = getUnusedName("_continue_"sv); | 8938 | auto continueVar = getUnusedName("_continue_"sv); |
| 8342 | addToScope(continueVar); | 8939 | addToScope(continueVar); |
| 8343 | _continueVars.push({continueVar, nullptr}); | 8940 | _continueVars.push({continueVar, nullptr}); |
| 8344 | _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body); | 8941 | _buf << indent() << "local "sv << continueVar << " = false"sv << nl(body); |
| 8345 | _buf << indent() << "repeat"sv << nll(body); | 8942 | _buf << indent() << "repeat"sv << nl(body); |
| 8346 | pushScope(); | 8943 | pushScope(); |
| 8347 | if (extraDo) { | 8944 | if (extraDo) { |
| 8348 | _buf << indent() << "do"sv << nll(body); | 8945 | _buf << indent() << "do"sv << nl(body); |
| 8349 | pushScope(); | 8946 | pushScope(); |
| 8350 | } | 8947 | } |
| 8351 | temp.push_back(clearBuf()); | 8948 | temp.push_back(clearBuf()); |
| @@ -8365,14 +8962,14 @@ private: | |||
| 8365 | if (target < 502) { | 8962 | if (target < 502) { |
| 8366 | if (extraDo) { | 8963 | if (extraDo) { |
| 8367 | popScope(); | 8964 | popScope(); |
| 8368 | _buf << indent() << "end"sv << nll(body); | 8965 | _buf << indent() << "end"sv << nl(body); |
| 8369 | } | 8966 | } |
| 8370 | _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); | 8967 | _buf << indent() << _continueVars.top().var << " = true"sv << nl(body); |
| 8371 | popScope(); | 8968 | popScope(); |
| 8372 | _buf << indent() << "until true"sv << nlr(body); | 8969 | _buf << indent() << "until true"sv << nl(body); |
| 8373 | _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nlr(body); | 8970 | _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nl(body); |
| 8374 | _buf << indent(1) << "break"sv << nlr(body); | 8971 | _buf << indent(1) << "break"sv << nl(body); |
| 8375 | _buf << indent() << "end"sv << nlr(body); | 8972 | _buf << indent() << "end"sv << nl(body); |
| 8376 | temp.push_back(clearBuf()); | 8973 | temp.push_back(clearBuf()); |
| 8377 | _continueVars.pop(); | 8974 | _continueVars.pop(); |
| 8378 | } else { | 8975 | } else { |
| @@ -8386,7 +8983,7 @@ private: | |||
| 8386 | std::string transformRepeatBody(Repeat_t* repeatNode, str_list& out) { | 8983 | std::string transformRepeatBody(Repeat_t* repeatNode, str_list& out) { |
| 8387 | str_list temp; | 8984 | str_list temp; |
| 8388 | bool extraDo = false; | 8985 | bool extraDo = false; |
| 8389 | auto body = repeatNode->body->content.get(); | 8986 | auto body = repeatNode->body.get(); |
| 8390 | auto breakLoopType = getBreakLoopType(body, Empty); | 8987 | auto breakLoopType = getBreakLoopType(body, Empty); |
| 8391 | bool withContinue = hasContinue(breakLoopType); | 8988 | bool withContinue = hasContinue(breakLoopType); |
| 8392 | std::string conditionVar; | 8989 | std::string conditionVar; |
| @@ -8396,8 +8993,8 @@ private: | |||
| 8396 | if (withContinue) { | 8993 | if (withContinue) { |
| 8397 | if (target < 502) { | 8994 | if (target < 502) { |
| 8398 | if (auto block = ast_cast<Block_t>(body)) { | 8995 | if (auto block = ast_cast<Block_t>(body)) { |
| 8399 | if (!block->statements.empty()) { | 8996 | if (!block->statementOrComments.empty()) { |
| 8400 | auto stmt = static_cast<Statement_t*>(block->statements.back()); | 8997 | auto stmt = lastStatementFrom(block); |
| 8401 | if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { | 8998 | if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { |
| 8402 | extraDo = breakLoop->type.is<Break_t>(); | 8999 | extraDo = breakLoop->type.is<Break_t>(); |
| 8403 | } | 9000 | } |
| @@ -8414,12 +9011,12 @@ private: | |||
| 8414 | assign->values.push_back(repeatNode->condition); | 9011 | assign->values.push_back(repeatNode->condition); |
| 8415 | _continueVars.push({continueVar, assignment.get()}); | 9012 | _continueVars.push({continueVar, assignment.get()}); |
| 8416 | } | 9013 | } |
| 8417 | _buf << indent() << "local "sv << conditionVar << " = false"sv << nll(body); | 9014 | _buf << indent() << "local "sv << conditionVar << " = false"sv << nl(body); |
| 8418 | _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body); | 9015 | _buf << indent() << "local "sv << continueVar << " = false"sv << nl(body); |
| 8419 | _buf << indent() << "repeat"sv << nll(body); | 9016 | _buf << indent() << "repeat"sv << nl(body); |
| 8420 | pushScope(); | 9017 | pushScope(); |
| 8421 | if (extraDo) { | 9018 | if (extraDo) { |
| 8422 | _buf << indent() << "do"sv << nll(body); | 9019 | _buf << indent() << "do"sv << nl(body); |
| 8423 | pushScope(); | 9020 | pushScope(); |
| 8424 | } | 9021 | } |
| 8425 | temp.push_back(clearBuf()); | 9022 | temp.push_back(clearBuf()); |
| @@ -8440,14 +9037,14 @@ private: | |||
| 8440 | transformAssignment(_continueVars.top().condAssign, temp); | 9037 | transformAssignment(_continueVars.top().condAssign, temp); |
| 8441 | if (extraDo) { | 9038 | if (extraDo) { |
| 8442 | popScope(); | 9039 | popScope(); |
| 8443 | _buf << indent() << "end"sv << nll(body); | 9040 | _buf << indent() << "end"sv << nl(body); |
| 8444 | } | 9041 | } |
| 8445 | _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); | 9042 | _buf << indent() << _continueVars.top().var << " = true"sv << nl(body); |
| 8446 | popScope(); | 9043 | popScope(); |
| 8447 | _buf << indent() << "until true"sv << nlr(body); | 9044 | _buf << indent() << "until true"sv << nl(body); |
| 8448 | _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nlr(body); | 9045 | _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nl(body); |
| 8449 | _buf << indent(1) << "break"sv << nlr(body); | 9046 | _buf << indent(1) << "break"sv << nl(body); |
| 8450 | _buf << indent() << "end"sv << nlr(body); | 9047 | _buf << indent() << "end"sv << nl(body); |
| 8451 | temp.push_back(clearBuf()); | 9048 | temp.push_back(clearBuf()); |
| 8452 | _continueVars.pop(); | 9049 | _continueVars.pop(); |
| 8453 | } else { | 9050 | } else { |
| @@ -8459,46 +9056,48 @@ private: | |||
| 8459 | return conditionVar; | 9056 | return conditionVar; |
| 8460 | } | 9057 | } |
| 8461 | 9058 | ||
| 8462 | void transformFor(For_t* forNode, str_list& out) { | 9059 | void transformForNum(ForNum_t* forNum, str_list& out) { |
| 8463 | str_list temp; | 9060 | str_list temp; |
| 8464 | transformForHead(forNode, temp); | 9061 | transformForNumHead(forNum, temp); |
| 8465 | auto breakLoopType = getBreakLoopType(forNode->body, Empty); | 9062 | auto breakLoopType = getBreakLoopType(forNum->body, Empty); |
| 8466 | transformLoopBody(forNode->body, temp, breakLoopType, ExpUsage::Common); | 9063 | transformLoopBody(forNum->body, temp, breakLoopType, ExpUsage::Common); |
| 8467 | popScope(); | 9064 | popScope(); |
| 8468 | out.push_back(join(temp) + indent() + "end"s + nlr(forNode)); | 9065 | out.push_back(join(temp) + indent() + "end"s + nl(forNum)); |
| 8469 | } | 9066 | } |
| 8470 | 9067 | ||
| 8471 | std::string transformForInner(For_t* forNode, str_list& out) { | 9068 | std::string transformForNumInner(ForNum_t* forNum, str_list& out) { |
| 8472 | auto x = forNode; | 9069 | auto x = forNum; |
| 8473 | std::string accum = getUnusedName("_accum_"sv); | 9070 | std::string accum = getUnusedName("_accum_"sv); |
| 8474 | addToScope(accum); | 9071 | addToScope(accum); |
| 8475 | std::string len = getUnusedName("_len_"sv); | 9072 | std::string len = getUnusedName("_len_"sv); |
| 8476 | addToScope(len); | 9073 | addToScope(len); |
| 8477 | auto breakLoopType = getBreakLoopType(forNode->body, accum); | 9074 | auto breakLoopType = getBreakLoopType(forNum->body, accum); |
| 8478 | _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(forNode); | 9075 | _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(forNum); |
| 8479 | out.emplace_back(clearBuf()); | 9076 | out.emplace_back(clearBuf()); |
| 8480 | _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode); | 9077 | _buf << indent() << "local "sv << len << " = 1"sv << nl(forNum); |
| 8481 | auto& lenAssign = out.emplace_back(clearBuf()); | 9078 | auto& lenAssign = out.emplace_back(clearBuf()); |
| 8482 | transformForHead(forNode, out); | 9079 | transformForNumHead(forNum, out); |
| 8483 | if (hasBreakWithValue(breakLoopType)) { | 9080 | if (hasBreakWithValue(breakLoopType)) { |
| 8484 | lenAssign.clear(); | 9081 | lenAssign.clear(); |
| 8485 | transformLoopBody(forNode->body, out, breakLoopType, ExpUsage::Common); | 9082 | transformLoopBody(forNum->body, out, breakLoopType, ExpUsage::Common); |
| 8486 | } else { | 9083 | } else { |
| 8487 | auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); | 9084 | auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); |
| 8488 | auto followStmt = toAst<Statement_t>(len + "+=1"s, forNode->body); | 9085 | auto followStmt = toAst<Statement_t>(len + "+=1"s, forNum->body); |
| 8489 | expList->followStmt = followStmt.get(); | 9086 | expList->followStmt = followStmt.get(); |
| 8490 | transformLoopBody(forNode->body, out, breakLoopType, ExpUsage::Assignment, expList); | 9087 | transformLoopBody(forNum->body, out, breakLoopType, ExpUsage::Assignment, expList); |
| 8491 | if (!expList->followStmtProcessed) { | 9088 | if (!expList->followStmtProcessed) { |
| 8492 | lenAssign.clear(); | 9089 | lenAssign.clear(); |
| 8493 | } | 9090 | } |
| 8494 | } | 9091 | } |
| 8495 | popScope(); | 9092 | popScope(); |
| 8496 | out.push_back(indent() + "end"s + nlr(forNode)); | 9093 | out.push_back(indent() + "end"s + nl(forNum)); |
| 8497 | return accum; | 9094 | return accum; |
| 8498 | } | 9095 | } |
| 8499 | 9096 | ||
| 8500 | void transformForClosure(For_t* forNode, str_list& out) { | 9097 | void transformForNumClosure(ForNum_t* forNum, str_list& out) { |
| 8501 | auto simpleValue = forNode->new_ptr<SimpleValue_t>(); | 9098 | auto forNode = forNum->new_ptr<For_t>(); |
| 9099 | forNode->forLoop.set(forNum); | ||
| 9100 | auto simpleValue = forNum->new_ptr<SimpleValue_t>(); | ||
| 8502 | simpleValue->value.set(forNode); | 9101 | simpleValue->value.set(forNode); |
| 8503 | if (transformAsUpValueFunc(newExp(simpleValue, forNode), out)) { | 9102 | if (transformAsUpValueFunc(newExp(simpleValue, forNode), out)) { |
| 8504 | return; | 9103 | return; |
| @@ -8508,26 +9107,26 @@ private: | |||
| 8508 | pushAnonVarArg(); | 9107 | pushAnonVarArg(); |
| 8509 | std::string& funcStart = temp.emplace_back(); | 9108 | std::string& funcStart = temp.emplace_back(); |
| 8510 | pushScope(); | 9109 | pushScope(); |
| 8511 | auto accum = transformForInner(forNode, temp); | 9110 | auto accum = transformForNumInner(forNum, temp); |
| 8512 | temp.push_back(indent() + "return "s + accum + nlr(forNode)); | 9111 | temp.push_back(indent() + "return "s + accum + nl(forNum)); |
| 8513 | popScope(); | 9112 | popScope(); |
| 8514 | funcStart = anonFuncStart() + nll(forNode); | 9113 | funcStart = anonFuncStart() + nl(forNum); |
| 8515 | temp.push_back(indent() + anonFuncEnd()); | 9114 | temp.push_back(indent() + anonFuncEnd()); |
| 8516 | popAnonVarArg(); | 9115 | popAnonVarArg(); |
| 8517 | popFunctionScope(); | 9116 | popFunctionScope(); |
| 8518 | out.push_back(join(temp)); | 9117 | out.push_back(join(temp)); |
| 8519 | } | 9118 | } |
| 8520 | 9119 | ||
| 8521 | void transformForInPlace(For_t* forNode, str_list& out, ExpList_t* assignExpList = nullptr) { | 9120 | void transformForNumInPlace(ForNum_t* forNum, str_list& out, ExpList_t* assignExpList) { |
| 8522 | auto x = forNode; | 9121 | auto x = forNum; |
| 8523 | str_list temp; | 9122 | str_list temp; |
| 8524 | bool isScoped = !currentScope().lastStatement; | 9123 | bool isScoped = !currentScope().lastStatement; |
| 8525 | if (assignExpList) { | 9124 | if (assignExpList) { |
| 8526 | if (isScoped) { | 9125 | if (isScoped) { |
| 8527 | _buf << indent() << "do"sv << nll(forNode); | 9126 | _buf << indent() << "do"sv << nl(forNum); |
| 8528 | pushScope(); | 9127 | pushScope(); |
| 8529 | } | 9128 | } |
| 8530 | auto accum = transformForInner(forNode, temp); | 9129 | auto accum = transformForNumInner(forNum, temp); |
| 8531 | auto assign = x->new_ptr<Assign_t>(); | 9130 | auto assign = x->new_ptr<Assign_t>(); |
| 8532 | assign->values.push_back(toAst<Exp_t>(accum, x)); | 9131 | assign->values.push_back(toAst<Exp_t>(accum, x)); |
| 8533 | auto assignment = x->new_ptr<ExpListAssign_t>(); | 9132 | auto assignment = x->new_ptr<ExpListAssign_t>(); |
| @@ -8536,10 +9135,10 @@ private: | |||
| 8536 | transformAssignment(assignment, temp); | 9135 | transformAssignment(assignment, temp); |
| 8537 | if (isScoped) { | 9136 | if (isScoped) { |
| 8538 | popScope(); | 9137 | popScope(); |
| 8539 | temp.push_back(indent() + "end"s + nlr(forNode)); | 9138 | temp.push_back(indent() + "end"s + nl(forNum)); |
| 8540 | } | 9139 | } |
| 8541 | } else { | 9140 | } else { |
| 8542 | auto accum = transformForInner(forNode, temp); | 9141 | auto accum = transformForNumInner(forNum, temp); |
| 8543 | auto returnNode = x->new_ptr<Return_t>(); | 9142 | auto returnNode = x->new_ptr<Return_t>(); |
| 8544 | returnNode->explicitReturn = false; | 9143 | returnNode->explicitReturn = false; |
| 8545 | auto expListLow = toAst<ExpListLow_t>(accum, x); | 9144 | auto expListLow = toAst<ExpListLow_t>(accum, x); |
| @@ -8573,10 +9172,10 @@ private: | |||
| 8573 | auto breakLoopType = getBreakLoopType(forEach->body, Empty); | 9172 | auto breakLoopType = getBreakLoopType(forEach->body, Empty); |
| 8574 | transformLoopBody(forEach->body, temp, breakLoopType, ExpUsage::Common); | 9173 | transformLoopBody(forEach->body, temp, breakLoopType, ExpUsage::Common); |
| 8575 | popScope(); | 9174 | popScope(); |
| 8576 | out.push_back(temp.front() + temp.back() + indent() + "end"s + nlr(forEach)); | 9175 | out.push_back(temp.front() + temp.back() + indent() + "end"s + nl(forEach)); |
| 8577 | if (extraScoped) { | 9176 | if (extraScoped) { |
| 8578 | popScope(); | 9177 | popScope(); |
| 8579 | out.back().append(indent() + "end"s + nlr(forEach)); | 9178 | out.back().append(indent() + "end"s + nl(forEach)); |
| 8580 | } | 9179 | } |
| 8581 | } | 9180 | } |
| 8582 | 9181 | ||
| @@ -8587,9 +9186,9 @@ private: | |||
| 8587 | std::string len = getUnusedName("_len_"sv); | 9186 | std::string len = getUnusedName("_len_"sv); |
| 8588 | addToScope(len); | 9187 | addToScope(len); |
| 8589 | auto breakLoopType = getBreakLoopType(forEach->body, accum); | 9188 | auto breakLoopType = getBreakLoopType(forEach->body, accum); |
| 8590 | _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(forEach); | 9189 | _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(forEach); |
| 8591 | out.emplace_back(clearBuf()); | 9190 | out.emplace_back(clearBuf()); |
| 8592 | _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach); | 9191 | _buf << indent() << "local "sv << len << " = 1"sv << nl(forEach); |
| 8593 | auto& lenAssign = out.emplace_back(clearBuf()); | 9192 | auto& lenAssign = out.emplace_back(clearBuf()); |
| 8594 | transformForEachHead(forEach->nameList, forEach->loopValue, out, true); | 9193 | transformForEachHead(forEach->nameList, forEach->loopValue, out, true); |
| 8595 | if (hasBreakWithValue(breakLoopType)) { | 9194 | if (hasBreakWithValue(breakLoopType)) { |
| @@ -8605,14 +9204,16 @@ private: | |||
| 8605 | } | 9204 | } |
| 8606 | } | 9205 | } |
| 8607 | popScope(); | 9206 | popScope(); |
| 8608 | out.push_back(indent() + "end"s + nlr(forEach)); | 9207 | out.push_back(indent() + "end"s + nl(forEach)); |
| 8609 | return accum; | 9208 | return accum; |
| 8610 | } | 9209 | } |
| 8611 | 9210 | ||
| 8612 | void transformForEachClosure(ForEach_t* forEach, str_list& out) { | 9211 | void transformForEachClosure(ForEach_t* forEach, str_list& out) { |
| 9212 | auto forNode = forEach->new_ptr<For_t>(); | ||
| 9213 | forNode->forLoop.set(forEach); | ||
| 8613 | auto simpleValue = forEach->new_ptr<SimpleValue_t>(); | 9214 | auto simpleValue = forEach->new_ptr<SimpleValue_t>(); |
| 8614 | simpleValue->value.set(forEach); | 9215 | simpleValue->value.set(forNode); |
| 8615 | if (transformAsUpValueFunc(newExp(simpleValue, forEach), out)) { | 9216 | if (transformAsUpValueFunc(newExp(simpleValue, forNode), out)) { |
| 8616 | return; | 9217 | return; |
| 8617 | } | 9218 | } |
| 8618 | str_list temp; | 9219 | str_list temp; |
| @@ -8621,22 +9222,22 @@ private: | |||
| 8621 | std::string& funcStart = temp.emplace_back(); | 9222 | std::string& funcStart = temp.emplace_back(); |
| 8622 | pushScope(); | 9223 | pushScope(); |
| 8623 | auto accum = transformForEachInner(forEach, temp); | 9224 | auto accum = transformForEachInner(forEach, temp); |
| 8624 | temp.push_back(indent() + "return "s + accum + nlr(forEach)); | 9225 | temp.push_back(indent() + "return "s + accum + nl(forEach)); |
| 8625 | popScope(); | 9226 | popScope(); |
| 8626 | funcStart = anonFuncStart() + nll(forEach); | 9227 | funcStart = anonFuncStart() + nl(forEach); |
| 8627 | temp.push_back(indent() + anonFuncEnd()); | 9228 | temp.push_back(indent() + anonFuncEnd()); |
| 8628 | popAnonVarArg(); | 9229 | popAnonVarArg(); |
| 8629 | popFunctionScope(); | 9230 | popFunctionScope(); |
| 8630 | out.push_back(join(temp)); | 9231 | out.push_back(join(temp)); |
| 8631 | } | 9232 | } |
| 8632 | 9233 | ||
| 8633 | void transformForEachInPlace(ForEach_t* forEach, str_list& out, ExpList_t* assignExpList = nullptr) { | 9234 | void transformForEachInPlace(ForEach_t* forEach, str_list& out, ExpList_t* assignExpList) { |
| 8634 | auto x = forEach; | 9235 | auto x = forEach; |
| 8635 | str_list temp; | 9236 | str_list temp; |
| 8636 | bool isScoped = !currentScope().lastStatement; | 9237 | bool isScoped = !currentScope().lastStatement; |
| 8637 | if (assignExpList) { | 9238 | if (assignExpList) { |
| 8638 | if (isScoped) { | 9239 | if (isScoped) { |
| 8639 | _buf << indent() << "do"sv << nll(forEach); | 9240 | _buf << indent() << "do"sv << nl(forEach); |
| 8640 | pushScope(); | 9241 | pushScope(); |
| 8641 | } | 9242 | } |
| 8642 | auto accum = transformForEachInner(forEach, temp); | 9243 | auto accum = transformForEachInner(forEach, temp); |
| @@ -8648,7 +9249,7 @@ private: | |||
| 8648 | transformAssignment(assignment, temp); | 9249 | transformAssignment(assignment, temp); |
| 8649 | if (isScoped) { | 9250 | if (isScoped) { |
| 8650 | popScope(); | 9251 | popScope(); |
| 8651 | temp.push_back(indent() + "end"s + nlr(forEach)); | 9252 | temp.push_back(indent() + "end"s + nl(forEach)); |
| 8652 | } | 9253 | } |
| 8653 | } else { | 9254 | } else { |
| 8654 | auto accum = transformForEachInner(forEach, temp); | 9255 | auto accum = transformForEachInner(forEach, temp); |
| @@ -8661,6 +9262,48 @@ private: | |||
| 8661 | out.push_back(join(temp)); | 9262 | out.push_back(join(temp)); |
| 8662 | } | 9263 | } |
| 8663 | 9264 | ||
| 9265 | void transformFor(For_t* forNode, str_list& out) { | ||
| 9266 | switch (forNode->forLoop->get_id()) { | ||
| 9267 | case id<ForNum_t>(): | ||
| 9268 | transformForNum(static_cast<ForNum_t*>(forNode->forLoop.get()), out); | ||
| 9269 | break; | ||
| 9270 | case id<ForEach_t>(): | ||
| 9271 | transformForEach(static_cast<ForEach_t*>(forNode->forLoop.get()), out); | ||
| 9272 | break; | ||
| 9273 | default: | ||
| 9274 | YUEE("AST node mismatch", forNode->forLoop.get()); | ||
| 9275 | break; | ||
| 9276 | } | ||
| 9277 | } | ||
| 9278 | |||
| 9279 | void transformForClosure(For_t* forNode, str_list& out) { | ||
| 9280 | switch (forNode->forLoop->get_id()) { | ||
| 9281 | case id<ForNum_t>(): | ||
| 9282 | transformForNumClosure(static_cast<ForNum_t*>(forNode->forLoop.get()), out); | ||
| 9283 | break; | ||
| 9284 | case id<ForEach_t>(): | ||
| 9285 | transformForEachClosure(static_cast<ForEach_t*>(forNode->forLoop.get()), out); | ||
| 9286 | break; | ||
| 9287 | default: | ||
| 9288 | YUEE("AST node mismatch", forNode->forLoop.get()); | ||
| 9289 | break; | ||
| 9290 | } | ||
| 9291 | } | ||
| 9292 | |||
| 9293 | void transformForInPlace(For_t* forNode, str_list& out, ExpList_t* assignExpList) { | ||
| 9294 | switch (forNode->forLoop->get_id()) { | ||
| 9295 | case id<ForNum_t>(): | ||
| 9296 | transformForNumInPlace(static_cast<ForNum_t*>(forNode->forLoop.get()), out, assignExpList); | ||
| 9297 | break; | ||
| 9298 | case id<ForEach_t>(): | ||
| 9299 | transformForEachInPlace(static_cast<ForEach_t*>(forNode->forLoop.get()), out, assignExpList); | ||
| 9300 | break; | ||
| 9301 | default: | ||
| 9302 | YUEE("AST node mismatch", forNode->forLoop.get()); | ||
| 9303 | break; | ||
| 9304 | } | ||
| 9305 | } | ||
| 9306 | |||
| 8664 | void transform_variable_pair(VariablePair_t* pair, str_list& out) { | 9307 | void transform_variable_pair(VariablePair_t* pair, str_list& out) { |
| 8665 | auto name = _parser.toString(pair->name); | 9308 | auto name = _parser.toString(pair->name); |
| 8666 | if (pair->name->name.is<UnicodeName_t>()) { | 9309 | if (pair->name->name.is<UnicodeName_t>()) { |
| @@ -8672,8 +9315,8 @@ private: | |||
| 8672 | } | 9315 | } |
| 8673 | if (_config.lintGlobalVariable && !isLocal(name)) { | 9316 | if (_config.lintGlobalVariable && !isLocal(name)) { |
| 8674 | auto key = name + ':' + std::to_string(pair->name->m_begin.m_line) + ':' + std::to_string(pair->name->m_begin.m_col); | 9317 | auto key = name + ':' + std::to_string(pair->name->m_begin.m_line) + ':' + std::to_string(pair->name->m_begin.m_col); |
| 8675 | if (_globals.find(key) != _globals.end()) { | 9318 | if (_globals.find(key) == _globals.end()) { |
| 8676 | _globals[key] = {name, pair->name->m_begin.m_line, pair->name->m_begin.m_col, _funcLevel > 1 ? AccessType::Capture : AccessType::Read}; | 9319 | _globals[key] = {name, pair->name->m_begin.m_line, pair->name->m_begin.m_col, _funcLevel > 1 ? AccessType::Capture : AccessType::Read, isSolidDefined(name)}; |
| 8677 | } | 9320 | } |
| 8678 | } | 9321 | } |
| 8679 | } | 9322 | } |
| @@ -8787,12 +9430,64 @@ private: | |||
| 8787 | out.push_back(temp.empty() ? "\"\""s : join(temp, " .. "sv)); | 9430 | out.push_back(temp.empty() ? "\"\""s : join(temp, " .. "sv)); |
| 8788 | } | 9431 | } |
| 8789 | 9432 | ||
| 9433 | void transformYAMLMultiline(YAMLMultiline_t* multiline, str_list& out) { | ||
| 9434 | std::optional<std::string> indent; | ||
| 9435 | str_list temp; | ||
| 9436 | for (auto line_ : multiline->lines.objects()) { | ||
| 9437 | auto line = static_cast<YAMLLine_t*>(line_); | ||
| 9438 | auto indentStr = _parser.toString(line->indent); | ||
| 9439 | if (!indent) { | ||
| 9440 | indent = indentStr; | ||
| 9441 | } | ||
| 9442 | if (std::string_view{indentStr.c_str(), indent.value().size()} != indent.value()) { | ||
| 9443 | throw CompileError("inconsistent indent"sv, line); | ||
| 9444 | } | ||
| 9445 | indentStr = indentStr.substr(indent.value().size()); | ||
| 9446 | str_list segs; | ||
| 9447 | bool firstSeg = true; | ||
| 9448 | for (auto seg_ : line->segments.objects()) { | ||
| 9449 | auto content = static_cast<YAMLLineContent_t*>(seg_)->content.get(); | ||
| 9450 | switch (content->get_id()) { | ||
| 9451 | case id<YAMLLineInner_t>(): { | ||
| 9452 | auto seqStr = _parser.toString(content); | ||
| 9453 | Utils::replace(seqStr, "\\#"sv, "#"sv); | ||
| 9454 | if (firstSeg) { | ||
| 9455 | firstSeg = false; | ||
| 9456 | seqStr.insert(0, indentStr); | ||
| 9457 | } | ||
| 9458 | segs.push_back(Utils::toLuaDoubleString(seqStr)); | ||
| 9459 | break; | ||
| 9460 | } | ||
| 9461 | case id<Exp_t>(): { | ||
| 9462 | if (firstSeg) { | ||
| 9463 | firstSeg = false; | ||
| 9464 | if (!indentStr.empty()) { | ||
| 9465 | segs.push_back(Utils::toLuaDoubleString(indentStr)); | ||
| 9466 | } | ||
| 9467 | } | ||
| 9468 | transformExp(static_cast<Exp_t*>(content), segs, ExpUsage::Closure); | ||
| 9469 | segs.back() = globalVar("tostring"sv, content, AccessType::Read) + '(' + segs.back() + ')'; | ||
| 9470 | break; | ||
| 9471 | } | ||
| 9472 | default: YUEE("AST node mismatch", content); break; | ||
| 9473 | } | ||
| 9474 | } | ||
| 9475 | temp.push_back(join(segs, " .. "sv)); | ||
| 9476 | } | ||
| 9477 | auto str = join(temp, " .. '\\n' .. "sv); | ||
| 9478 | Utils::replace(str, "\" .. '\\n' .. \""sv, "\\n"sv); | ||
| 9479 | Utils::replace(str, "\" .. '\\n'"sv, "\\n\""sv); | ||
| 9480 | Utils::replace(str, "'\\n' .. \""sv, "\"\\n"sv); | ||
| 9481 | out.push_back(str); | ||
| 9482 | } | ||
| 9483 | |||
| 8790 | void transformString(String_t* string, str_list& out) { | 9484 | void transformString(String_t* string, str_list& out) { |
| 8791 | auto str = string->str.get(); | 9485 | auto str = string->str.get(); |
| 8792 | switch (str->get_id()) { | 9486 | switch (str->get_id()) { |
| 8793 | case id<SingleString_t>(): transformSingleString(static_cast<SingleString_t*>(str), out); break; | 9487 | case id<SingleString_t>(): transformSingleString(static_cast<SingleString_t*>(str), out); break; |
| 8794 | case id<DoubleString_t>(): transformDoubleString(static_cast<DoubleString_t*>(str), out); break; | 9488 | case id<DoubleString_t>(): transformDoubleString(static_cast<DoubleString_t*>(str), out); break; |
| 8795 | case id<LuaString_t>(): transformLuaString(static_cast<LuaString_t*>(str), out); break; | 9489 | case id<LuaString_t>(): transformLuaString(static_cast<LuaString_t*>(str), out); break; |
| 9490 | case id<YAMLMultiline_t>(): transformYAMLMultiline(static_cast<YAMLMultiline_t*>(str), out); break; | ||
| 8796 | default: YUEE("AST node mismatch", str); break; | 9491 | default: YUEE("AST node mismatch", str); break; |
| 8797 | } | 9492 | } |
| 8798 | } | 9493 | } |
| @@ -8823,7 +9518,7 @@ private: | |||
| 8823 | pushScope(); | 9518 | pushScope(); |
| 8824 | transformClassDecl(classDecl, temp, ExpUsage::Return); | 9519 | transformClassDecl(classDecl, temp, ExpUsage::Return); |
| 8825 | popScope(); | 9520 | popScope(); |
| 8826 | funcStart = anonFuncStart() + nll(classDecl); | 9521 | funcStart = anonFuncStart() + nl(classDecl); |
| 8827 | temp.push_back(indent() + anonFuncEnd()); | 9522 | temp.push_back(indent() + anonFuncEnd()); |
| 8828 | popAnonVarArg(); | 9523 | popAnonVarArg(); |
| 8829 | popFunctionScope(); | 9524 | popFunctionScope(); |
| @@ -8847,7 +9542,7 @@ private: | |||
| 8847 | bool newDefined = false; | 9542 | bool newDefined = false; |
| 8848 | std::tie(className, newDefined, classTextName) = defineClassVariable(assignable); | 9543 | std::tie(className, newDefined, classTextName) = defineClassVariable(assignable); |
| 8849 | if (newDefined) { | 9544 | if (newDefined) { |
| 8850 | temp.push_back(indent() + "local "s + className + nll(classDecl)); | 9545 | temp.push_back(indent() + "local "s + className + nl(classDecl)); |
| 8851 | } | 9546 | } |
| 8852 | if (classTextName.empty()) { | 9547 | if (classTextName.empty()) { |
| 8853 | if (auto chain = ast_cast<AssignableChain_t>(assignable->item)) { | 9548 | if (auto chain = ast_cast<AssignableChain_t>(assignable->item)) { |
| @@ -8884,12 +9579,12 @@ private: | |||
| 8884 | } | 9579 | } |
| 8885 | } | 9580 | } |
| 8886 | if (isScoped) { | 9581 | if (isScoped) { |
| 8887 | temp.push_back(indent() + "do"s + nll(classDecl)); | 9582 | temp.push_back(indent() + "do"s + nl(classDecl)); |
| 8888 | pushScope(); | 9583 | pushScope(); |
| 8889 | } | 9584 | } |
| 8890 | auto classVar = getUnusedName("_class_"sv); | 9585 | auto classVar = getUnusedName("_class_"sv); |
| 8891 | addToScope(classVar); | 9586 | addToScope(classVar); |
| 8892 | temp.push_back(indent() + "local "s + classVar + nll(classDecl)); | 9587 | temp.push_back(indent() + "local "s + classVar + nl(classDecl)); |
| 8893 | auto block = classDecl->new_ptr<Block_t>(); | 9588 | auto block = classDecl->new_ptr<Block_t>(); |
| 8894 | str_list classConstVars; | 9589 | str_list classConstVars; |
| 8895 | if (body) { | 9590 | if (body) { |
| @@ -8898,7 +9593,7 @@ private: | |||
| 8898 | if (auto statement = ast_cast<Statement_t>(item)) { | 9593 | if (auto statement = ast_cast<Statement_t>(item)) { |
| 8899 | ClassDecl_t* clsDecl = nullptr; | 9594 | ClassDecl_t* clsDecl = nullptr; |
| 8900 | if (auto assignment = assignmentFrom(statement)) { | 9595 | if (auto assignment = assignmentFrom(statement)) { |
| 8901 | block->statements.push_back(statement); | 9596 | block->statementOrComments.push_back(statement); |
| 8902 | auto names = transformAssignDefs(assignment->expList.get(), DefOp::Mark); | 9597 | auto names = transformAssignDefs(assignment->expList.get(), DefOp::Mark); |
| 8903 | for (const auto& name : names) { | 9598 | for (const auto& name : names) { |
| 8904 | varDefs.push_back(name.first); | 9599 | varDefs.push_back(name.first); |
| @@ -8928,12 +9623,12 @@ private: | |||
| 8928 | clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>(); | 9623 | clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>(); |
| 8929 | BLOCK_END | 9624 | BLOCK_END |
| 8930 | } else if (auto expList = expListFrom(statement)) { | 9625 | } else if (auto expList = expListFrom(statement)) { |
| 8931 | block->statements.push_back(statement); | 9626 | block->statementOrComments.push_back(statement); |
| 8932 | if (auto value = singleValueFrom(expList)) { | 9627 | if (auto value = singleValueFrom(expList)) { |
| 8933 | clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>(); | 9628 | clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>(); |
| 8934 | } | 9629 | } |
| 8935 | } else if (auto local = statement->content.as<Local_t>()) { | 9630 | } else if (auto local = statement->content.as<Local_t>()) { |
| 8936 | block->statements.push_back(statement); | 9631 | block->statementOrComments.push_back(statement); |
| 8937 | if (auto values = local->item.as<LocalValues_t>()) { | 9632 | if (auto values = local->item.as<LocalValues_t>()) { |
| 8938 | for (auto name : values->nameList->names.objects()) { | 9633 | for (auto name : values->nameList->names.objects()) { |
| 8939 | auto varName = variableToString(static_cast<Variable_t*>(name)); | 9634 | auto varName = variableToString(static_cast<Variable_t*>(name)); |
| @@ -8996,7 +9691,6 @@ private: | |||
| 8996 | } | 9691 | } |
| 8997 | } | 9692 | } |
| 8998 | auto stmt = statement->new_ptr<Statement_t>(); | 9693 | auto stmt = statement->new_ptr<Statement_t>(); |
| 8999 | stmt->comments.dup(statement->comments); | ||
| 9000 | auto newAttrib = localAttrib->new_ptr<LocalAttrib_t>(); | 9694 | auto newAttrib = localAttrib->new_ptr<LocalAttrib_t>(); |
| 9001 | newAttrib->attrib.set(localAttrib->attrib); | 9695 | newAttrib->attrib.set(localAttrib->attrib); |
| 9002 | newAttrib->leftList.dup(localAttrib->leftList); | 9696 | newAttrib->leftList.dup(localAttrib->leftList); |
| @@ -9004,7 +9698,7 @@ private: | |||
| 9004 | newAttrib->forceLocal = false; | 9698 | newAttrib->forceLocal = false; |
| 9005 | stmt->content.set(newAttrib); | 9699 | stmt->content.set(newAttrib); |
| 9006 | stmt->appendix.set(statement->appendix); | 9700 | stmt->appendix.set(statement->appendix); |
| 9007 | block->statements.push_back(stmt); | 9701 | block->statementOrComments.push_back(stmt); |
| 9008 | } else if (statement->content.is<Global_t>()) { | 9702 | } else if (statement->content.is<Global_t>()) { |
| 9009 | throw CompileError("global statement is not allowed here"sv, statement->content); | 9703 | throw CompileError("global statement is not allowed here"sv, statement->content); |
| 9010 | } | 9704 | } |
| @@ -9018,7 +9712,7 @@ private: | |||
| 9018 | } | 9712 | } |
| 9019 | } | 9713 | } |
| 9020 | if (!varDefs.empty()) { | 9714 | if (!varDefs.empty()) { |
| 9021 | temp.push_back(indent() + "local "s + join(varDefs, ", "sv) + nll(body)); | 9715 | temp.push_back(indent() + "local "s + join(varDefs, ", "sv) + nl(body)); |
| 9022 | } | 9716 | } |
| 9023 | } | 9717 | } |
| 9024 | std::string parent, parentVar; | 9718 | std::string parent, parentVar; |
| @@ -9028,7 +9722,7 @@ private: | |||
| 9028 | transformExp(extend, temp, ExpUsage::Closure); | 9722 | transformExp(extend, temp, ExpUsage::Closure); |
| 9029 | parent = std::move(temp.back()); | 9723 | parent = std::move(temp.back()); |
| 9030 | temp.pop_back(); | 9724 | temp.pop_back(); |
| 9031 | temp.push_back(indent() + "local "s + parentVar + " = "s + parent + nll(classDecl)); | 9725 | temp.push_back(indent() + "local "s + parentVar + " = "s + parent + nl(classDecl)); |
| 9032 | } | 9726 | } |
| 9033 | auto baseVar = getUnusedName("_base_"sv); | 9727 | auto baseVar = getUnusedName("_base_"sv); |
| 9034 | addToScope(baseVar); | 9728 | addToScope(baseVar); |
| @@ -9047,7 +9741,7 @@ private: | |||
| 9047 | for (; it != members.end(); ++it) { | 9741 | for (; it != members.end(); ++it) { |
| 9048 | auto& member = *it; | 9742 | auto& member = *it; |
| 9049 | if (member.type == MemType::Property) { | 9743 | if (member.type == MemType::Property) { |
| 9050 | statements.push_back(indent() + member.item + nll(content)); | 9744 | statements.push_back(indent() + member.item + nl(content)); |
| 9051 | } else { | 9745 | } else { |
| 9052 | member.item = indent(1) + member.item; | 9746 | member.item = indent(1) + member.item; |
| 9053 | } | 9747 | } |
| @@ -9059,32 +9753,34 @@ private: | |||
| 9059 | } | 9753 | } |
| 9060 | } | 9754 | } |
| 9061 | for (const auto& classVar : classConstVars) { | 9755 | for (const auto& classVar : classConstVars) { |
| 9062 | auto& scope = _scopes.back(); | 9756 | forceAddToScope(classVar); |
| 9063 | scope.vars->insert_or_assign(classVar, VarType::Local); | ||
| 9064 | } | 9757 | } |
| 9065 | for (auto stmt_ : block->statements.objects()) { | 9758 | forceAddToScope("self"s); |
| 9066 | transformStatement(static_cast<Statement_t*>(stmt_), statements); | 9759 | for (auto stmt_ : block->statementOrComments.objects()) { |
| 9760 | if (auto stmt = ast_cast<Statement_t>(stmt_)) { | ||
| 9761 | transformStatement(stmt, statements); | ||
| 9762 | } | ||
| 9067 | } | 9763 | } |
| 9068 | for (auto& member : members) { | 9764 | for (auto& member : members) { |
| 9069 | switch (member.type) { | 9765 | switch (member.type) { |
| 9070 | case MemType::Common: | 9766 | case MemType::Common: |
| 9071 | commons.push_back((commons.empty() ? Empty : ',' + nll(member.node)) + member.item); | 9767 | commons.push_back((commons.empty() ? Empty : ',' + nl(member.node)) + member.item); |
| 9072 | break; | 9768 | break; |
| 9073 | case MemType::Builtin: | 9769 | case MemType::Builtin: |
| 9074 | builtins.push_back((builtins.empty() ? Empty : ',' + nll(member.node)) + member.item); | 9770 | builtins.push_back((builtins.empty() ? Empty : ',' + nl(member.node)) + member.item); |
| 9075 | break; | 9771 | break; |
| 9076 | default: break; | 9772 | default: break; |
| 9077 | } | 9773 | } |
| 9078 | } | 9774 | } |
| 9079 | if (!commons.empty()) { | 9775 | if (!commons.empty()) { |
| 9080 | temp.back() += '{' + nll(body); | 9776 | temp.back() += '{' + nl(body); |
| 9081 | temp.push_back(join(commons) + nll(body)); | 9777 | temp.push_back(join(commons) + nl(body)); |
| 9082 | temp.push_back(indent() + '}' + nll(body)); | 9778 | temp.push_back(indent() + '}' + nl(body)); |
| 9083 | } else { | 9779 | } else { |
| 9084 | temp.back() += "{ }"s + nll(body); | 9780 | temp.back() += "{ }"s + nl(body); |
| 9085 | } | 9781 | } |
| 9086 | } else { | 9782 | } else { |
| 9087 | temp.back() += "{ }"s + nll(classDecl); | 9783 | temp.back() += "{ }"s + nl(classDecl); |
| 9088 | } | 9784 | } |
| 9089 | if (classDecl->mixes) { | 9785 | if (classDecl->mixes) { |
| 9090 | auto item = getUnusedName("_item_"sv); | 9786 | auto item = getUnusedName("_item_"sv); |
| @@ -9117,72 +9813,72 @@ private: | |||
| 9117 | transformAssignment(assignment, tmp); | 9813 | transformAssignment(assignment, tmp); |
| 9118 | } | 9814 | } |
| 9119 | if (extend) { | 9815 | if (extend) { |
| 9120 | _buf << indent() << "setmetatable("sv << baseVar << ", "sv << parentVar << ".__base)"sv << nll(classDecl); | 9816 | _buf << indent() << "setmetatable("sv << baseVar << ", "sv << parentVar << ".__base)"sv << nl(classDecl); |
| 9121 | } | 9817 | } |
| 9122 | _buf << indent() << classVar << " = "sv << globalVar("setmetatable"sv, classDecl, AccessType::Read) << "({"sv << nll(classDecl); | 9818 | _buf << indent() << classVar << " = "sv << globalVar("setmetatable"sv, classDecl, AccessType::Read) << "({"sv << nl(classDecl); |
| 9123 | if (!builtins.empty()) { | 9819 | if (!builtins.empty()) { |
| 9124 | _buf << join(builtins) << ',' << nll(classDecl); | 9820 | _buf << join(builtins) << ',' << nl(classDecl); |
| 9125 | } else { | 9821 | } else { |
| 9126 | if (extend) { | 9822 | if (extend) { |
| 9127 | _buf << indent(1) << "__init = function(self, ...)"sv << nll(classDecl); | 9823 | _buf << indent(1) << "__init = function(self, ...)"sv << nl(classDecl); |
| 9128 | _buf << indent(2) << "return "sv << classVar << ".__parent.__init(self, ...)"sv << nll(classDecl); | 9824 | _buf << indent(2) << "return "sv << classVar << ".__parent.__init(self, ...)"sv << nl(classDecl); |
| 9129 | _buf << indent(1) << "end,"sv << nll(classDecl); | 9825 | _buf << indent(1) << "end,"sv << nl(classDecl); |
| 9130 | } else { | 9826 | } else { |
| 9131 | _buf << indent(1) << "__init = function() end,"sv << nll(classDecl); | 9827 | _buf << indent(1) << "__init = function() end,"sv << nl(classDecl); |
| 9132 | } | 9828 | } |
| 9133 | } | 9829 | } |
| 9134 | _buf << indent(1) << "__base = "sv << baseVar; | 9830 | _buf << indent(1) << "__base = "sv << baseVar; |
| 9135 | if (!classTextName.empty()) { | 9831 | if (!classTextName.empty()) { |
| 9136 | _buf << ","sv << nll(classDecl); | 9832 | _buf << ","sv << nl(classDecl); |
| 9137 | _buf << indent(1) << "__name = "sv << classTextName; | 9833 | _buf << indent(1) << "__name = "sv << classTextName; |
| 9138 | } | 9834 | } |
| 9139 | if (extend) { | 9835 | if (extend) { |
| 9140 | _buf << ","sv << nll(classDecl); | 9836 | _buf << ","sv << nl(classDecl); |
| 9141 | _buf << indent(1) << "__parent = "sv << parentVar; | 9837 | _buf << indent(1) << "__parent = "sv << parentVar; |
| 9142 | } | 9838 | } |
| 9143 | _buf << nll(classDecl); | 9839 | _buf << nl(classDecl); |
| 9144 | _buf << indent() << "}, {"sv << nll(classDecl); | 9840 | _buf << indent() << "}, {"sv << nl(classDecl); |
| 9145 | if (extend) { | 9841 | if (extend) { |
| 9146 | _buf << indent(1) << "__index = function(cls, name)"sv << nll(classDecl); | 9842 | _buf << indent(1) << "__index = function(cls, name)"sv << nl(classDecl); |
| 9147 | _buf << indent(2) << "local val = rawget("sv << baseVar << ", name)"sv << nll(classDecl); | 9843 | _buf << indent(2) << "local val = rawget("sv << baseVar << ", name)"sv << nl(classDecl); |
| 9148 | _buf << indent(2) << "if val == nil then"sv << nll(classDecl); | 9844 | _buf << indent(2) << "if val == nil then"sv << nl(classDecl); |
| 9149 | _buf << indent(3) << "local parent = rawget(cls, \"__parent\")"sv << nll(classDecl); | 9845 | _buf << indent(3) << "local parent = rawget(cls, \"__parent\")"sv << nl(classDecl); |
| 9150 | _buf << indent(3) << "if parent then"sv << nll(classDecl); | 9846 | _buf << indent(3) << "if parent then"sv << nl(classDecl); |
| 9151 | _buf << indent(4) << "return parent[name]"sv << nll(classDecl); | 9847 | _buf << indent(4) << "return parent[name]"sv << nl(classDecl); |
| 9152 | _buf << indent(3) << "end"sv << nll(classDecl); | 9848 | _buf << indent(3) << "end"sv << nl(classDecl); |
| 9153 | _buf << indent(2) << "else"sv << nll(classDecl); | 9849 | _buf << indent(2) << "else"sv << nl(classDecl); |
| 9154 | _buf << indent(3) << "return val"sv << nll(classDecl); | 9850 | _buf << indent(3) << "return val"sv << nl(classDecl); |
| 9155 | _buf << indent(2) << "end"sv << nll(classDecl); | 9851 | _buf << indent(2) << "end"sv << nl(classDecl); |
| 9156 | _buf << indent(1) << "end,"sv << nll(classDecl); | 9852 | _buf << indent(1) << "end,"sv << nl(classDecl); |
| 9157 | } else { | 9853 | } else { |
| 9158 | _buf << indent(1) << "__index = "sv << baseVar << ","sv << nll(classDecl); | 9854 | _buf << indent(1) << "__index = "sv << baseVar << ","sv << nl(classDecl); |
| 9159 | } | 9855 | } |
| 9160 | _buf << indent(1) << "__call = function(cls, ...)"sv << nll(classDecl); | 9856 | _buf << indent(1) << "__call = function(cls, ...)"sv << nl(classDecl); |
| 9161 | pushScope(); | 9857 | pushScope(); |
| 9162 | auto selfVar = getUnusedName("_self_"sv); | 9858 | auto selfVar = getUnusedName("_self_"sv); |
| 9163 | addToScope(selfVar); | 9859 | addToScope(selfVar); |
| 9164 | _buf << indent(1) << "local "sv << selfVar << " = setmetatable({ }, "sv << baseVar << ")"sv << nll(classDecl); | 9860 | _buf << indent(1) << "local "sv << selfVar << " = setmetatable({ }, "sv << baseVar << ")"sv << nl(classDecl); |
| 9165 | _buf << indent(1) << "cls.__init("sv << selfVar << ", ...)"sv << nll(classDecl); | 9861 | _buf << indent(1) << "cls.__init("sv << selfVar << ", ...)"sv << nl(classDecl); |
| 9166 | _buf << indent(1) << "return "sv << selfVar << nll(classDecl); | 9862 | _buf << indent(1) << "return "sv << selfVar << nl(classDecl); |
| 9167 | popScope(); | 9863 | popScope(); |
| 9168 | _buf << indent(1) << "end"sv << nll(classDecl); | 9864 | _buf << indent(1) << "end"sv << nl(classDecl); |
| 9169 | _buf << indent() << "})"sv << nll(classDecl); | 9865 | _buf << indent() << "})"sv << nl(classDecl); |
| 9170 | _buf << indent() << baseVar << ".__class = "sv << classVar << nll(classDecl); | 9866 | _buf << indent() << baseVar << ".__class = "sv << classVar << nl(classDecl); |
| 9171 | if (!statements.empty()) { | 9867 | if (!statements.empty()) { |
| 9172 | _buf << indent() << "local self = "sv << classVar << ';' << nll(classDecl); | 9868 | _buf << indent() << "local self = "sv << classVar << ';' << nl(classDecl); |
| 9173 | } | 9869 | } |
| 9174 | _buf << join(statements); | 9870 | _buf << join(statements); |
| 9175 | if (extend) { | 9871 | if (extend) { |
| 9176 | _buf << indent() << "if "sv << parentVar << ".__inherited then"sv << nll(classDecl); | 9872 | _buf << indent() << "if "sv << parentVar << ".__inherited then"sv << nl(classDecl); |
| 9177 | _buf << indent(1) << parentVar << ".__inherited("sv << parentVar << ", "sv << classVar << ")"sv << nll(classDecl); | 9873 | _buf << indent(1) << parentVar << ".__inherited("sv << parentVar << ", "sv << classVar << ")"sv << nl(classDecl); |
| 9178 | _buf << indent() << "end"sv << nll(classDecl); | 9874 | _buf << indent() << "end"sv << nl(classDecl); |
| 9179 | } | 9875 | } |
| 9180 | if (!assignItem.empty()) { | 9876 | if (!assignItem.empty()) { |
| 9181 | _buf << indent() << assignItem << " = "sv << classVar << nll(classDecl); | 9877 | _buf << indent() << assignItem << " = "sv << classVar << nl(classDecl); |
| 9182 | } | 9878 | } |
| 9183 | switch (usage) { | 9879 | switch (usage) { |
| 9184 | case ExpUsage::Return: { | 9880 | case ExpUsage::Return: { |
| 9185 | _buf << indent() << "return "sv << classVar << nlr(classDecl); | 9881 | _buf << indent() << "return "sv << classVar << nl(classDecl); |
| 9186 | break; | 9882 | break; |
| 9187 | } | 9883 | } |
| 9188 | case ExpUsage::Assignment: { | 9884 | case ExpUsage::Assignment: { |
| @@ -9194,7 +9890,7 @@ private: | |||
| 9194 | temp.push_back(clearBuf()); | 9890 | temp.push_back(clearBuf()); |
| 9195 | if (isScoped) { | 9891 | if (isScoped) { |
| 9196 | popScope(); | 9892 | popScope(); |
| 9197 | temp.push_back(indent() + "end"s + nlr(classDecl)); | 9893 | temp.push_back(indent() + "end"s + nl(classDecl)); |
| 9198 | } | 9894 | } |
| 9199 | out.push_back(join(temp)); | 9895 | out.push_back(join(temp)); |
| 9200 | } | 9896 | } |
| @@ -9357,7 +10053,7 @@ private: | |||
| 9357 | pushScope(); | 10053 | pushScope(); |
| 9358 | transformWith(with, temp, nullptr, true); | 10054 | transformWith(with, temp, nullptr, true); |
| 9359 | popScope(); | 10055 | popScope(); |
| 9360 | funcStart = anonFuncStart() + nll(with); | 10056 | funcStart = anonFuncStart() + nl(with); |
| 9361 | temp.push_back(indent() + anonFuncEnd()); | 10057 | temp.push_back(indent() + anonFuncEnd()); |
| 9362 | popAnonVarArg(); | 10058 | popAnonVarArg(); |
| 9363 | popFunctionScope(); | 10059 | popFunctionScope(); |
| @@ -9370,11 +10066,11 @@ private: | |||
| 9370 | std::string withVar; | 10066 | std::string withVar; |
| 9371 | bool needScope = !currentScope().lastStatement && !returnValue; | 10067 | bool needScope = !currentScope().lastStatement && !returnValue; |
| 9372 | bool extraScope = false; | 10068 | bool extraScope = false; |
| 9373 | if (with->assigns) { | 10069 | if (with->assign) { |
| 9374 | auto vars = getAssignVars(with); | 10070 | auto vars = getAssignVars(with); |
| 9375 | if (vars.front().empty() || isDeclaredAsGlobal(vars.front())) { | 10071 | if (vars.front().empty() || isDeclaredAsGlobal(vars.front())) { |
| 9376 | if (with->assigns->values.objects().size() == 1) { | 10072 | if (with->assign->values.objects().size() == 1) { |
| 9377 | auto var = singleVariableFrom(with->assigns->values.objects().front(), AccessType::Read); | 10073 | auto var = singleVariableFrom(with->assign->values.objects().front(), AccessType::Read); |
| 9378 | if (!var.empty() && isLocal(var)) { | 10074 | if (!var.empty() && isLocal(var)) { |
| 9379 | withVar = var; | 10075 | withVar = var; |
| 9380 | } | 10076 | } |
| @@ -9384,11 +10080,11 @@ private: | |||
| 9384 | auto assignment = x->new_ptr<ExpListAssign_t>(); | 10080 | auto assignment = x->new_ptr<ExpListAssign_t>(); |
| 9385 | assignment->expList.set(toAst<ExpList_t>(withVar, x)); | 10081 | assignment->expList.set(toAst<ExpList_t>(withVar, x)); |
| 9386 | auto assign = x->new_ptr<Assign_t>(); | 10082 | auto assign = x->new_ptr<Assign_t>(); |
| 9387 | assign->values.push_back(with->assigns->values.objects().front()); | 10083 | assign->values.push_back(with->assign->values.objects().front()); |
| 9388 | assignment->action.set(assign); | 10084 | assignment->action.set(assign); |
| 9389 | if (needScope) { | 10085 | if (needScope) { |
| 9390 | extraScope = true; | 10086 | extraScope = true; |
| 9391 | temp.push_back(indent() + "do"s + nll(with)); | 10087 | temp.push_back(indent() + "do"s + nl(with)); |
| 9392 | pushScope(); | 10088 | pushScope(); |
| 9393 | } | 10089 | } |
| 9394 | transformAssignment(assignment, temp); | 10090 | transformAssignment(assignment, temp); |
| @@ -9398,7 +10094,7 @@ private: | |||
| 9398 | auto assign = x->new_ptr<Assign_t>(); | 10094 | auto assign = x->new_ptr<Assign_t>(); |
| 9399 | assign->values.push_back(toAst<Exp_t>(withVar, x)); | 10095 | assign->values.push_back(toAst<Exp_t>(withVar, x)); |
| 9400 | bool skipFirst = true; | 10096 | bool skipFirst = true; |
| 9401 | for (auto value : with->assigns->values.objects()) { | 10097 | for (auto value : with->assign->values.objects()) { |
| 9402 | if (skipFirst) { | 10098 | if (skipFirst) { |
| 9403 | skipFirst = false; | 10099 | skipFirst = false; |
| 9404 | continue; | 10100 | continue; |
| @@ -9411,10 +10107,10 @@ private: | |||
| 9411 | withVar = vars.front(); | 10107 | withVar = vars.front(); |
| 9412 | auto assignment = x->new_ptr<ExpListAssign_t>(); | 10108 | auto assignment = x->new_ptr<ExpListAssign_t>(); |
| 9413 | assignment->expList.set(with->valueList); | 10109 | assignment->expList.set(with->valueList); |
| 9414 | assignment->action.set(with->assigns); | 10110 | assignment->action.set(with->assign); |
| 9415 | if (needScope) { | 10111 | if (needScope) { |
| 9416 | extraScope = true; | 10112 | extraScope = true; |
| 9417 | temp.push_back(indent() + "do"s + nll(with)); | 10113 | temp.push_back(indent() + "do"s + nl(with)); |
| 9418 | pushScope(); | 10114 | pushScope(); |
| 9419 | } | 10115 | } |
| 9420 | transformAssignment(assignment, temp); | 10116 | transformAssignment(assignment, temp); |
| @@ -9430,7 +10126,7 @@ private: | |||
| 9430 | assignment->action.set(assign); | 10126 | assignment->action.set(assign); |
| 9431 | if (needScope) { | 10127 | if (needScope) { |
| 9432 | extraScope = true; | 10128 | extraScope = true; |
| 9433 | temp.push_back(indent() + "do"s + nll(with)); | 10129 | temp.push_back(indent() + "do"s + nl(with)); |
| 9434 | pushScope(); | 10130 | pushScope(); |
| 9435 | } | 10131 | } |
| 9436 | transformAssignment(assignment, temp); | 10132 | transformAssignment(assignment, temp); |
| @@ -9484,7 +10180,7 @@ private: | |||
| 9484 | }); | 10180 | }); |
| 9485 | popScope(); | 10181 | popScope(); |
| 9486 | if (extraScope) { | 10182 | if (extraScope) { |
| 9487 | temp.push_back(indent() + "do"s + nll(with)); | 10183 | temp.push_back(indent() + "do"s + nl(with)); |
| 9488 | pushScope(); | 10184 | pushScope(); |
| 9489 | } | 10185 | } |
| 9490 | } | 10186 | } |
| @@ -9513,49 +10209,40 @@ private: | |||
| 9513 | expListAssign->expList.set(expList); | 10209 | expListAssign->expList.set(expList); |
| 9514 | auto stmt = x->new_ptr<Statement_t>(); | 10210 | auto stmt = x->new_ptr<Statement_t>(); |
| 9515 | stmt->content.set(expListAssign); | 10211 | stmt->content.set(expListAssign); |
| 9516 | auto whileNode = toAst<While_t>("while true do break"s, x); | 10212 | auto repeatNode = toAst<Repeat_t>("repeat\n\t--\nuntil true"s, x); |
| 9517 | auto block = x->new_ptr<Block_t>(); | 10213 | auto block = x->new_ptr<Block_t>(); |
| 9518 | block->statements.push_back(stmt); | 10214 | block->statementOrComments.push_back(stmt); |
| 9519 | block->statements.push_back(whileNode->body); | 10215 | repeatNode->body.set(block); |
| 9520 | auto body = x->new_ptr<Body_t>(); | ||
| 9521 | body->content.set(block); | ||
| 9522 | whileNode->body.set(block); | ||
| 9523 | auto sVal = x->new_ptr<SimpleValue_t>(); | 10216 | auto sVal = x->new_ptr<SimpleValue_t>(); |
| 9524 | sVal->value.set(whileNode); | 10217 | sVal->value.set(repeatNode); |
| 9525 | auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x); | 10218 | auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x); |
| 9526 | transformAssignment(asmt, temp); | 10219 | transformAssignment(asmt, temp); |
| 9527 | } | 10220 | } |
| 9528 | } else { | 10221 | } else { |
| 9529 | bool transformed = false; | 10222 | bool transformed = false; |
| 9530 | if (!breakWithVar.empty()) { | 10223 | if (!breakWithVar.empty()) { |
| 9531 | auto whileNode = toAst<While_t>("while true do break"s, x); | 10224 | auto repeatNode = toAst<Repeat_t>("repeat\n\t--\nuntil true"s, x); |
| 9532 | auto block = x->new_ptr<Block_t>(); | 10225 | auto block = x->new_ptr<Block_t>(); |
| 9533 | if (auto blk = with->body.as<Block_t>()) { | 10226 | if (auto blk = with->body.as<Block_t>()) { |
| 9534 | block->statements.dup(blk->statements); | 10227 | block->statementOrComments.dup(blk->statementOrComments); |
| 9535 | } else { | 10228 | } else { |
| 9536 | auto stmt = with->body.to<Statement_t>(); | 10229 | auto stmt = with->body.to<Statement_t>(); |
| 9537 | block->statements.push_back(stmt); | 10230 | block->statementOrComments.push_back(stmt); |
| 9538 | } | ||
| 9539 | auto breakLoop = whileNode->body.to<Statement_t>()->content.as<BreakLoop_t>(); | ||
| 9540 | if (!(breakLoop && breakLoop->type.is<Break_t>())) { | ||
| 9541 | block->statements.push_back(whileNode->body); | ||
| 9542 | } | 10231 | } |
| 9543 | auto body = x->new_ptr<Body_t>(); | 10232 | repeatNode->body.set(block); |
| 9544 | body->content.set(block); | ||
| 9545 | whileNode->body.set(block); | ||
| 9546 | auto sVal = x->new_ptr<SimpleValue_t>(); | 10233 | auto sVal = x->new_ptr<SimpleValue_t>(); |
| 9547 | sVal->value.set(whileNode); | 10234 | sVal->value.set(repeatNode); |
| 9548 | auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x); | 10235 | auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x); |
| 9549 | transformAssignment(asmt, temp); | 10236 | transformAssignment(asmt, temp); |
| 9550 | transformed = true; | 10237 | transformed = true; |
| 9551 | } else if (!extraScope && assignList) { | 10238 | } else if (!extraScope && assignList) { |
| 9552 | if (auto block = with->body.as<Block_t>()) { | 10239 | if (auto block = with->body.as<Block_t>()) { |
| 9553 | if (!block->statements.empty()) { | 10240 | if (!block->statementOrComments.empty()) { |
| 9554 | Statement_t* stmt = static_cast<Statement_t*>(block->statements.back()); | 10241 | Statement_t* stmt = lastStatementFrom(block); |
| 9555 | if (stmt->content.is<Return_t>()) { | 10242 | if (stmt && stmt->content.is<Return_t>()) { |
| 9556 | auto newBlock = with->body->new_ptr<Block_t>(); | 10243 | auto newBlock = with->body->new_ptr<Block_t>(); |
| 9557 | newBlock->statements.dup(block->statements); | 10244 | newBlock->statementOrComments.dup(block->statementOrComments); |
| 9558 | newBlock->statements.pop_back(); | 10245 | newBlock->statementOrComments.pop_back(); |
| 9559 | transform_plain_body(newBlock, temp, ExpUsage::Common); | 10246 | transform_plain_body(newBlock, temp, ExpUsage::Common); |
| 9560 | auto newBody = stmt->new_ptr<Body_t>(); | 10247 | auto newBody = stmt->new_ptr<Body_t>(); |
| 9561 | newBody->content.set(stmt); | 10248 | newBody->content.set(stmt); |
| @@ -9593,12 +10280,12 @@ private: | |||
| 9593 | if (returnValue) { | 10280 | if (returnValue) { |
| 9594 | auto last = lastStatementFrom(with->body); | 10281 | auto last = lastStatementFrom(with->body); |
| 9595 | if (last && !last->content.is<Return_t>()) { | 10282 | if (last && !last->content.is<Return_t>()) { |
| 9596 | temp.push_back(indent() + "return "s + withVar + nll(with)); | 10283 | temp.push_back(indent() + "return "s + withVar + nl(with)); |
| 9597 | } | 10284 | } |
| 9598 | } | 10285 | } |
| 9599 | if (extraScope) { | 10286 | if (extraScope) { |
| 9600 | popScope(); | 10287 | popScope(); |
| 9601 | temp.push_back(indent() + "end"s + nll(with)); | 10288 | temp.push_back(indent() + "end"s + nl(with)); |
| 9602 | } | 10289 | } |
| 9603 | out.push_back(join(temp)); | 10290 | out.push_back(join(temp)); |
| 9604 | } | 10291 | } |
| @@ -9808,7 +10495,7 @@ private: | |||
| 9808 | } | 10495 | } |
| 9809 | } | 10496 | } |
| 9810 | if (_info.exportDefault) { | 10497 | if (_info.exportDefault) { |
| 9811 | out.back().append(indent() + _info.moduleName + " = "s + names.back().first + nlr(exportNode)); | 10498 | out.back().append(indent() + _info.moduleName + " = "s + names.back().first + nl(exportNode)); |
| 9812 | } else { | 10499 | } else { |
| 9813 | str_list lefts, rights; | 10500 | str_list lefts, rights; |
| 9814 | for (const auto& name : names) { | 10501 | for (const auto& name : names) { |
| @@ -9821,7 +10508,7 @@ private: | |||
| 9821 | lefts.push_back(_info.moduleName + "[\""s + realName + "\"]"s); | 10508 | lefts.push_back(_info.moduleName + "[\""s + realName + "\"]"s); |
| 9822 | rights.push_back(name.first); | 10509 | rights.push_back(name.first); |
| 9823 | } | 10510 | } |
| 9824 | out.back().append(indent() + join(lefts, ", "sv) + " = "s + join(rights, ", "sv) + nlr(exportNode)); | 10511 | out.back().append(indent() + join(lefts, ", "sv) + " = "s + join(rights, ", "sv) + nl(exportNode)); |
| 9825 | } | 10512 | } |
| 9826 | } | 10513 | } |
| 9827 | } else { | 10514 | } else { |
| @@ -9905,12 +10592,12 @@ private: | |||
| 9905 | case id<CompForEach_t>(): | 10592 | case id<CompForEach_t>(): |
| 9906 | transformCompForEach(static_cast<CompForEach_t*>(item), temp); | 10593 | transformCompForEach(static_cast<CompForEach_t*>(item), temp); |
| 9907 | break; | 10594 | break; |
| 9908 | case id<CompFor_t>(): | 10595 | case id<CompForNum_t>(): |
| 9909 | transformCompFor(static_cast<CompFor_t*>(item), temp); | 10596 | transformCompForNum(static_cast<CompForNum_t*>(item), temp); |
| 9910 | break; | 10597 | break; |
| 9911 | case id<Exp_t>(): | 10598 | case id<Exp_t>(): |
| 9912 | transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure); | 10599 | transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure); |
| 9913 | temp.back() = indent() + "if "s + temp.back() + " then"s + nll(item); | 10600 | temp.back() = indent() + "if "s + temp.back() + " then"s + nl(item); |
| 9914 | pushScope(); | 10601 | pushScope(); |
| 9915 | break; | 10602 | break; |
| 9916 | default: YUEE("AST node mismatch", item); break; | 10603 | default: YUEE("AST node mismatch", item); break; |
| @@ -9923,27 +10610,27 @@ private: | |||
| 9923 | for (size_t i = 0; i < compInner->items.objects().size(); ++i) { | 10610 | for (size_t i = 0; i < compInner->items.objects().size(); ++i) { |
| 9924 | popScope(); | 10611 | popScope(); |
| 9925 | } | 10612 | } |
| 9926 | _buf << indent() << "local "sv << tbl << " = { }"sv << nll(comp); | 10613 | _buf << indent() << "local "sv << tbl << " = { }"sv << nl(comp); |
| 9927 | _buf << join(temp); | 10614 | _buf << join(temp); |
| 9928 | pushScope(); | 10615 | pushScope(); |
| 9929 | if (!comp->value) { | 10616 | if (!comp->value) { |
| 9930 | auto keyVar = getUnusedName("_key_"sv); | 10617 | auto keyVar = getUnusedName("_key_"sv); |
| 9931 | auto valVar = getUnusedName("_val_"sv); | 10618 | auto valVar = getUnusedName("_val_"sv); |
| 9932 | _buf << indent(int(temp.size()) - 1) << "local "sv << keyVar << ", "sv << valVar << " = "sv << kv.front() << nll(comp); | 10619 | _buf << indent(int(temp.size()) - 1) << "local "sv << keyVar << ", "sv << valVar << " = "sv << kv.front() << nl(comp); |
| 9933 | kv.front() = keyVar; | 10620 | kv.front() = keyVar; |
| 9934 | kv.push_back(valVar); | 10621 | kv.push_back(valVar); |
| 9935 | } | 10622 | } |
| 9936 | _buf << indent(int(temp.size()) - 1) << tbl << "["sv << kv.front() << "] = "sv << kv.back() << nll(comp); | 10623 | _buf << indent(int(temp.size()) - 1) << tbl << "["sv << kv.front() << "] = "sv << kv.back() << nl(comp); |
| 9937 | for (int ind = int(temp.size()) - 2; ind > -1; --ind) { | 10624 | for (int ind = int(temp.size()) - 2; ind > -1; --ind) { |
| 9938 | _buf << indent(ind) << "end"sv << nll(comp); | 10625 | _buf << indent(ind) << "end"sv << nl(comp); |
| 9939 | } | 10626 | } |
| 9940 | popScope(); | 10627 | popScope(); |
| 9941 | _buf << indent() << "end"sv << nll(comp); | 10628 | _buf << indent() << "end"sv << nl(comp); |
| 9942 | switch (usage) { | 10629 | switch (usage) { |
| 9943 | case ExpUsage::Closure: | 10630 | case ExpUsage::Closure: |
| 9944 | out.push_back(clearBuf() + indent() + "return "s + tbl + nlr(comp)); | 10631 | out.push_back(clearBuf() + indent() + "return "s + tbl + nl(comp)); |
| 9945 | popScope(); | 10632 | popScope(); |
| 9946 | out.back().insert(0, anonFuncStart() + nll(comp)); | 10633 | out.back().insert(0, anonFuncStart() + nl(comp)); |
| 9947 | out.back().append(indent() + anonFuncEnd()); | 10634 | out.back().append(indent() + anonFuncEnd()); |
| 9948 | popAnonVarArg(); | 10635 | popAnonVarArg(); |
| 9949 | popFunctionScope(); | 10636 | popFunctionScope(); |
| @@ -9959,21 +10646,21 @@ private: | |||
| 9959 | out.back().append(temp.back()); | 10646 | out.back().append(temp.back()); |
| 9960 | if (extraScope) { | 10647 | if (extraScope) { |
| 9961 | popScope(); | 10648 | popScope(); |
| 9962 | out.back().insert(0, indent() + "do"s + nll(comp)); | 10649 | out.back().insert(0, indent() + "do"s + nl(comp)); |
| 9963 | out.back().append(indent() + "end"s + nlr(comp)); | 10650 | out.back().append(indent() + "end"s + nl(comp)); |
| 9964 | } | 10651 | } |
| 9965 | break; | 10652 | break; |
| 9966 | } | 10653 | } |
| 9967 | case ExpUsage::Return: | 10654 | case ExpUsage::Return: |
| 9968 | out.push_back(clearBuf() + indent() + "return "s + tbl + nlr(comp)); | 10655 | out.push_back(clearBuf() + indent() + "return "s + tbl + nl(comp)); |
| 9969 | break; | 10656 | break; |
| 9970 | default: | 10657 | default: |
| 9971 | break; | 10658 | break; |
| 9972 | } | 10659 | } |
| 9973 | } | 10660 | } |
| 9974 | 10661 | ||
| 9975 | void transformCompFor(CompFor_t* comp, str_list& out) { | 10662 | void transformCompForNum(CompForNum_t* comp, str_list& out) { |
| 9976 | transformForHead(comp->varName, comp->startValue, comp->stopValue, comp->stepValue, out); | 10663 | transformForNumHead(comp->varName, comp->startValue, comp->stopValue, comp->stepValue, out); |
| 9977 | } | 10664 | } |
| 9978 | 10665 | ||
| 9979 | void transformTableBlockIndent(TableBlockIndent_t* table, str_list& out) { | 10666 | void transformTableBlockIndent(TableBlockIndent_t* table, str_list& out) { |
| @@ -10003,25 +10690,64 @@ private: | |||
| 10003 | funcStart = &temp.emplace_back(); | 10690 | funcStart = &temp.emplace_back(); |
| 10004 | pushScope(); | 10691 | pushScope(); |
| 10005 | } else { | 10692 | } else { |
| 10006 | temp.push_back(indent() + "do"s + nll(doNode)); | 10693 | temp.push_back(indent() + "do"s + nl(doNode)); |
| 10007 | pushScope(); | 10694 | pushScope(); |
| 10008 | } | 10695 | } |
| 10009 | transformBody(doNode->body, temp, usage, assignList); | 10696 | transformBody(doNode->body, temp, usage, assignList); |
| 10010 | if (usage == ExpUsage::Closure) { | 10697 | if (usage == ExpUsage::Closure) { |
| 10011 | popScope(); | 10698 | popScope(); |
| 10012 | *funcStart = anonFuncStart() + nll(doNode); | 10699 | *funcStart = anonFuncStart() + nl(doNode); |
| 10013 | temp.push_back(indent() + anonFuncEnd()); | 10700 | temp.push_back(indent() + anonFuncEnd()); |
| 10014 | popAnonVarArg(); | 10701 | popAnonVarArg(); |
| 10015 | popFunctionScope(); | 10702 | popFunctionScope(); |
| 10016 | } else { | 10703 | } else { |
| 10017 | popScope(); | 10704 | popScope(); |
| 10018 | temp.push_back(indent() + "end"s + nlr(doNode)); | 10705 | temp.push_back(indent() + "end"s + nl(doNode)); |
| 10019 | } | 10706 | } |
| 10020 | out.push_back(join(temp)); | 10707 | out.push_back(join(temp)); |
| 10021 | } | 10708 | } |
| 10022 | 10709 | ||
| 10023 | void transformTry(Try_t* tryNode, str_list& out, ExpUsage usage) { | 10710 | void transformTry(Try_t* tryNode, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { |
| 10024 | auto x = tryNode; | 10711 | auto x = tryNode; |
| 10712 | if (tryNode->eop && usage == ExpUsage::Assignment) { | ||
| 10713 | str_list rets; | ||
| 10714 | pushScope(); | ||
| 10715 | auto okVar = getUnusedName("_ok_"sv); | ||
| 10716 | for (size_t i = 0; i < assignList->exprs.size(); i++) { | ||
| 10717 | auto retVar = getUnusedName("_ret_"sv); | ||
| 10718 | rets.emplace_back(retVar); | ||
| 10719 | addToScope(retVar); | ||
| 10720 | } | ||
| 10721 | popScope(); | ||
| 10722 | auto varList = join(rets, ","sv); | ||
| 10723 | auto ifNode = toAst<If_t>("if "s + okVar + ',' + varList + ":=try nil then "s + varList, x); | ||
| 10724 | auto exp = ast_to<IfCond_t>(ifNode->nodes.front())->assignment->assign->values.front(); | ||
| 10725 | auto sVal = simpleSingleValueFrom(exp); | ||
| 10726 | auto newTry = sVal->value.to<Try_t>(); | ||
| 10727 | newTry->func.set(tryNode->func); | ||
| 10728 | newTry->catchBlock.set(tryNode->catchBlock); | ||
| 10729 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
| 10730 | assignment->expList.set(assignList); | ||
| 10731 | auto assign = x->new_ptr<Assign_t>(); | ||
| 10732 | assign->values.push_back(ifNode); | ||
| 10733 | assignment->action.set(assign); | ||
| 10734 | transformAssignment(assignment, out); | ||
| 10735 | return; | ||
| 10736 | } | ||
| 10737 | if (tryNode->eop && usage != ExpUsage::Common) { | ||
| 10738 | auto okVar = getUnusedName("_ok_"sv); | ||
| 10739 | auto code = "do\n\t"s + okVar + ", ... = try nil\n\t... if "s + okVar; | ||
| 10740 | auto doNode = toAst<Do_t>(code, x); | ||
| 10741 | auto block = doNode->body->content.to<Block_t>(); | ||
| 10742 | auto asmt = static_cast<Statement_t*>(block->statementOrComments.front())->content.to<ExpListAssign_t>(); | ||
| 10743 | auto assign = asmt->action.to<Assign_t>(); | ||
| 10744 | auto sVal = simpleSingleValueFrom(assign->values.back()); | ||
| 10745 | auto newTry = sVal->value.to<Try_t>(); | ||
| 10746 | newTry->func.set(tryNode->func); | ||
| 10747 | newTry->catchBlock.set(tryNode->catchBlock); | ||
| 10748 | transformDo(doNode, out, usage); | ||
| 10749 | return; | ||
| 10750 | } | ||
| 10025 | ast_ptr<true, Exp_t> errHandler; | 10751 | ast_ptr<true, Exp_t> errHandler; |
| 10026 | if (tryNode->catchBlock) { | 10752 | if (tryNode->catchBlock) { |
| 10027 | auto catchBlock = tryNode->catchBlock.get(); | 10753 | auto catchBlock = tryNode->catchBlock.get(); |
| @@ -10037,8 +10763,8 @@ private: | |||
| 10037 | tryFunc.set(tryNode->func); | 10763 | tryFunc.set(tryNode->func); |
| 10038 | if (auto tryBlock = tryFunc.as<Block_t>()) { | 10764 | if (auto tryBlock = tryFunc.as<Block_t>()) { |
| 10039 | BLOCK_START | 10765 | BLOCK_START |
| 10040 | BREAK_IF(tryBlock->statements.size() != 1); | 10766 | BREAK_IF(countStatementFrom(tryBlock) != 1); |
| 10041 | auto stmt = static_cast<Statement_t*>(tryBlock->statements.front()); | 10767 | auto stmt = firstStatementFrom(tryBlock); |
| 10042 | auto expListAssign = stmt->content.as<ExpListAssign_t>(); | 10768 | auto expListAssign = stmt->content.as<ExpListAssign_t>(); |
| 10043 | BREAK_IF(!expListAssign); | 10769 | BREAK_IF(!expListAssign); |
| 10044 | BREAK_IF(expListAssign->action); | 10770 | BREAK_IF(expListAssign->action); |
| @@ -10102,7 +10828,7 @@ private: | |||
| 10102 | auto stmt = x->new_ptr<Statement_t>(); | 10828 | auto stmt = x->new_ptr<Statement_t>(); |
| 10103 | stmt->content.set(expListAssign); | 10829 | stmt->content.set(expListAssign); |
| 10104 | auto block = x->new_ptr<Block_t>(); | 10830 | auto block = x->new_ptr<Block_t>(); |
| 10105 | block->statements.push_back(stmt); | 10831 | block->statementOrComments.push_back(stmt); |
| 10106 | tryFunc.set(block); | 10832 | tryFunc.set(block); |
| 10107 | } | 10833 | } |
| 10108 | } | 10834 | } |
| @@ -10130,7 +10856,7 @@ private: | |||
| 10130 | } | 10856 | } |
| 10131 | if (usage == ExpUsage::Common) { | 10857 | if (usage == ExpUsage::Common) { |
| 10132 | out.back().insert(0, indent()); | 10858 | out.back().insert(0, indent()); |
| 10133 | out.back().append(nlr(x)); | 10859 | out.back().append(nl(x)); |
| 10134 | } | 10860 | } |
| 10135 | return; | 10861 | return; |
| 10136 | } | 10862 | } |
| @@ -10155,7 +10881,7 @@ private: | |||
| 10155 | } | 10881 | } |
| 10156 | if (usage == ExpUsage::Common) { | 10882 | if (usage == ExpUsage::Common) { |
| 10157 | out.back().insert(0, indent()); | 10883 | out.back().insert(0, indent()); |
| 10158 | out.back().append(nlr(x)); | 10884 | out.back().append(nl(x)); |
| 10159 | } | 10885 | } |
| 10160 | return; | 10886 | return; |
| 10161 | } else if (auto value = singleValueFrom(tryFunc)) { | 10887 | } else if (auto value = singleValueFrom(tryFunc)) { |
| @@ -10216,7 +10942,7 @@ private: | |||
| 10216 | } | 10942 | } |
| 10217 | if (usage == ExpUsage::Common) { | 10943 | if (usage == ExpUsage::Common) { |
| 10218 | out.back().insert(0, indent()); | 10944 | out.back().insert(0, indent()); |
| 10219 | out.back().append(nlr(x)); | 10945 | out.back().append(nl(x)); |
| 10220 | } | 10946 | } |
| 10221 | return; | 10947 | return; |
| 10222 | BLOCK_END | 10948 | BLOCK_END |
| @@ -10235,13 +10961,13 @@ private: | |||
| 10235 | } | 10961 | } |
| 10236 | if (usage == ExpUsage::Common) { | 10962 | if (usage == ExpUsage::Common) { |
| 10237 | out.back().insert(0, indent()); | 10963 | out.back().insert(0, indent()); |
| 10238 | out.back().append(nlr(x)); | 10964 | out.back().append(nl(x)); |
| 10239 | } | 10965 | } |
| 10240 | } | 10966 | } |
| 10241 | 10967 | ||
| 10242 | void transformImportFrom(ImportFrom_t* importNode, str_list& out) { | 10968 | void transformImportFrom(ImportFrom_t* importNode, str_list& out) { |
| 10243 | str_list temp; | 10969 | str_list temp; |
| 10244 | auto x = importNode; | 10970 | auto x = importNode->item.get(); |
| 10245 | auto objVar = singleVariableFrom(importNode->item, AccessType::Read); | 10971 | auto objVar = singleVariableFrom(importNode->item, AccessType::Read); |
| 10246 | ast_ptr<false, ExpListAssign_t> objAssign; | 10972 | ast_ptr<false, ExpListAssign_t> objAssign; |
| 10247 | if (objVar.empty()) { | 10973 | if (objVar.empty()) { |
| @@ -10311,11 +11037,11 @@ private: | |||
| 10311 | if (objAssign) { | 11037 | if (objAssign) { |
| 10312 | auto preDef = toLocalDecl(transformAssignDefs(expList, DefOp::Mark)); | 11038 | auto preDef = toLocalDecl(transformAssignDefs(expList, DefOp::Mark)); |
| 10313 | if (!preDef.empty()) { | 11039 | if (!preDef.empty()) { |
| 10314 | temp.push_back(preDef + nll(importNode)); | 11040 | temp.push_back(preDef + nl(importNode)); |
| 10315 | } | 11041 | } |
| 10316 | if (!currentScope().lastStatement) { | 11042 | if (!currentScope().lastStatement) { |
| 10317 | extraScope = true; | 11043 | extraScope = true; |
| 10318 | temp.push_back(indent() + "do"s + nll(importNode)); | 11044 | temp.push_back(indent() + "do"s + nl(importNode)); |
| 10319 | pushScope(); | 11045 | pushScope(); |
| 10320 | } | 11046 | } |
| 10321 | transformAssignment(objAssign, temp); | 11047 | transformAssignment(objAssign, temp); |
| @@ -10327,7 +11053,7 @@ private: | |||
| 10327 | if (objAssign) { | 11053 | if (objAssign) { |
| 10328 | if (extraScope) { | 11054 | if (extraScope) { |
| 10329 | popScope(); | 11055 | popScope(); |
| 10330 | temp.push_back(indent() + "end"s + nlr(importNode)); | 11056 | temp.push_back(indent() + "end"s + nl(importNode)); |
| 10331 | } | 11057 | } |
| 10332 | } | 11058 | } |
| 10333 | out.push_back(join(temp)); | 11059 | out.push_back(join(temp)); |
| @@ -10567,6 +11293,30 @@ private: | |||
| 10567 | } | 11293 | } |
| 10568 | } | 11294 | } |
| 10569 | 11295 | ||
| 11296 | void transformImportGlobal(ImportGlobal_t* importNode, str_list& out) { | ||
| 11297 | auto uname = static_cast<UnicodeName_t*>(importNode->segs.front()); | ||
| 11298 | auto var = _parser.toString(uname); | ||
| 11299 | auto isNormal = _parser.match<Name_t>(var) && _parser.match<Variable_t>(var); | ||
| 11300 | auto varName = unicodeVariableFrom(uname); | ||
| 11301 | str_list temp; | ||
| 11302 | auto it = ++importNode->segs.objects().begin(); | ||
| 11303 | for (; it != importNode->segs.objects().end(); ++it) { | ||
| 11304 | temp.emplace_back(_parser.toString(*it)); | ||
| 11305 | } | ||
| 11306 | temp.emplace_front(var); | ||
| 11307 | if (isLocal(varName) || !isNormal) { | ||
| 11308 | temp.emplace_front("_G"s); | ||
| 11309 | } | ||
| 11310 | std::string stmt; | ||
| 11311 | if (importNode->target) { | ||
| 11312 | stmt = "const "s + _parser.toString(importNode->target) + '=' + join(temp, "."sv); | ||
| 11313 | } else { | ||
| 11314 | stmt = "const "s + temp.back() + '=' + join(temp, "."sv); | ||
| 11315 | } | ||
| 11316 | auto localAttrib = toAst<LocalAttrib_t>(stmt, importNode); | ||
| 11317 | transformLocalAttrib(localAttrib, out); | ||
| 11318 | } | ||
| 11319 | |||
| 10570 | void transformImport(Import_t* import, str_list& out) { | 11320 | void transformImport(Import_t* import, str_list& out) { |
| 10571 | auto content = import->content.get(); | 11321 | auto content = import->content.get(); |
| 10572 | switch (content->get_id()) { | 11322 | switch (content->get_id()) { |
| @@ -10579,6 +11329,9 @@ private: | |||
| 10579 | case id<FromImport_t>(): | 11329 | case id<FromImport_t>(): |
| 10580 | transformFromImport(static_cast<FromImport_t*>(content), out); | 11330 | transformFromImport(static_cast<FromImport_t*>(content), out); |
| 10581 | break; | 11331 | break; |
| 11332 | case id<ImportGlobal_t>(): | ||
| 11333 | transformImportGlobal(static_cast<ImportGlobal_t*>(content), out); | ||
| 11334 | break; | ||
| 10582 | default: YUEE("AST node mismatch", content); break; | 11335 | default: YUEE("AST node mismatch", content); break; |
| 10583 | } | 11336 | } |
| 10584 | } | 11337 | } |
| @@ -10590,7 +11343,7 @@ private: | |||
| 10590 | if (expList) { | 11343 | if (expList) { |
| 10591 | if (!currentScope().lastStatement) { | 11344 | if (!currentScope().lastStatement) { |
| 10592 | extraScope = true; | 11345 | extraScope = true; |
| 10593 | temp.push_back(indent() + "do"s + nll(whileNode)); | 11346 | temp.push_back(indent() + "do"s + nl(whileNode)); |
| 10594 | pushScope(); | 11347 | pushScope(); |
| 10595 | } | 11348 | } |
| 10596 | } | 11349 | } |
| @@ -10599,13 +11352,13 @@ private: | |||
| 10599 | auto lenVar = getUnusedName("_len_"sv); | 11352 | auto lenVar = getUnusedName("_len_"sv); |
| 10600 | addToScope(lenVar); | 11353 | addToScope(lenVar); |
| 10601 | auto breakLoopType = getBreakLoopType(whileNode->body, accumVar); | 11354 | auto breakLoopType = getBreakLoopType(whileNode->body, accumVar); |
| 10602 | _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(whileNode); | 11355 | _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(whileNode); |
| 10603 | temp.emplace_back(clearBuf()); | 11356 | temp.emplace_back(clearBuf()); |
| 10604 | _buf << indent() << "local "s << lenVar << " = 1"s << nll(whileNode); | 11357 | _buf << indent() << "local "s << lenVar << " = 1"s << nl(whileNode); |
| 10605 | auto& lenAssign = temp.emplace_back(clearBuf()); | 11358 | auto& lenAssign = temp.emplace_back(clearBuf()); |
| 10606 | bool isUntil = _parser.toString(whileNode->type) == "until"sv; | 11359 | bool isUntil = _parser.toString(whileNode->type) == "until"sv; |
| 10607 | auto condStr = transformCondExp(whileNode->condition, isUntil); | 11360 | auto condStr = transformCondExp(whileNode->condition, isUntil); |
| 10608 | temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); | 11361 | temp.push_back(indent() + "while "s + condStr + " do"s + nl(whileNode)); |
| 10609 | pushScope(); | 11362 | pushScope(); |
| 10610 | if (hasBreakWithValue(breakLoopType)) { | 11363 | if (hasBreakWithValue(breakLoopType)) { |
| 10611 | lenAssign.clear(); | 11364 | lenAssign.clear(); |
| @@ -10620,7 +11373,7 @@ private: | |||
| 10620 | } | 11373 | } |
| 10621 | } | 11374 | } |
| 10622 | popScope(); | 11375 | popScope(); |
| 10623 | temp.push_back(indent() + "end"s + nlr(whileNode)); | 11376 | temp.push_back(indent() + "end"s + nl(whileNode)); |
| 10624 | if (expList) { | 11377 | if (expList) { |
| 10625 | auto assign = x->new_ptr<Assign_t>(); | 11378 | auto assign = x->new_ptr<Assign_t>(); |
| 10626 | assign->values.push_back(toAst<Exp_t>(accumVar, x)); | 11379 | assign->values.push_back(toAst<Exp_t>(accumVar, x)); |
| @@ -10630,10 +11383,10 @@ private: | |||
| 10630 | transformAssignment(assignment, temp); | 11383 | transformAssignment(assignment, temp); |
| 10631 | if (extraScope) popScope(); | 11384 | if (extraScope) popScope(); |
| 10632 | } else { | 11385 | } else { |
| 10633 | temp.push_back(indent() + "return "s + accumVar + nlr(whileNode)); | 11386 | temp.push_back(indent() + "return "s + accumVar + nl(whileNode)); |
| 10634 | } | 11387 | } |
| 10635 | if (expList && extraScope) { | 11388 | if (expList && extraScope) { |
| 10636 | temp.push_back(indent() + "end"s + nlr(whileNode)); | 11389 | temp.push_back(indent() + "end"s + nl(whileNode)); |
| 10637 | } | 11390 | } |
| 10638 | out.push_back(join(temp)); | 11391 | out.push_back(join(temp)); |
| 10639 | } | 11392 | } |
| @@ -10655,12 +11408,12 @@ private: | |||
| 10655 | auto lenVar = getUnusedName("_len_"sv); | 11408 | auto lenVar = getUnusedName("_len_"sv); |
| 10656 | addToScope(lenVar); | 11409 | addToScope(lenVar); |
| 10657 | auto breakLoopType = getBreakLoopType(whileNode->body, accumVar); | 11410 | auto breakLoopType = getBreakLoopType(whileNode->body, accumVar); |
| 10658 | _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(whileNode); | 11411 | _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(whileNode); |
| 10659 | temp.emplace_back(clearBuf()); | 11412 | temp.emplace_back(clearBuf()); |
| 10660 | auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nll(whileNode)); | 11413 | auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nl(whileNode)); |
| 10661 | bool isUntil = _parser.toString(whileNode->type) == "until"sv; | 11414 | bool isUntil = _parser.toString(whileNode->type) == "until"sv; |
| 10662 | auto condStr = transformCondExp(whileNode->condition, isUntil); | 11415 | auto condStr = transformCondExp(whileNode->condition, isUntil); |
| 10663 | temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); | 11416 | temp.push_back(indent() + "while "s + condStr + " do"s + nl(whileNode)); |
| 10664 | pushScope(); | 11417 | pushScope(); |
| 10665 | if (hasBreakWithValue(breakLoopType)) { | 11418 | if (hasBreakWithValue(breakLoopType)) { |
| 10666 | lenAssign.clear(); | 11419 | lenAssign.clear(); |
| @@ -10675,10 +11428,10 @@ private: | |||
| 10675 | } | 11428 | } |
| 10676 | } | 11429 | } |
| 10677 | popScope(); | 11430 | popScope(); |
| 10678 | temp.push_back(indent() + "end"s + nlr(whileNode)); | 11431 | temp.push_back(indent() + "end"s + nl(whileNode)); |
| 10679 | temp.push_back(indent() + "return "s + accumVar + nlr(whileNode)); | 11432 | temp.push_back(indent() + "return "s + accumVar + nl(whileNode)); |
| 10680 | popScope(); | 11433 | popScope(); |
| 10681 | funcStart = anonFuncStart() + nll(whileNode); | 11434 | funcStart = anonFuncStart() + nl(whileNode); |
| 10682 | temp.push_back(indent() + anonFuncEnd()); | 11435 | temp.push_back(indent() + anonFuncEnd()); |
| 10683 | popAnonVarArg(); | 11436 | popAnonVarArg(); |
| 10684 | popFunctionScope(); | 11437 | popFunctionScope(); |
| @@ -10708,9 +11461,7 @@ private: | |||
| 10708 | expListAssign->expList.set(expList); | 11461 | expListAssign->expList.set(expList); |
| 10709 | auto stmt = x->new_ptr<Statement_t>(); | 11462 | auto stmt = x->new_ptr<Statement_t>(); |
| 10710 | stmt->content.set(expListAssign); | 11463 | stmt->content.set(expListAssign); |
| 10711 | auto body = x->new_ptr<Body_t>(); | 11464 | repeat->body.set(stmt); |
| 10712 | body->content.set(stmt); | ||
| 10713 | repeat->body.set(body); | ||
| 10714 | transformRepeat(repeat, out); | 11465 | transformRepeat(repeat, out); |
| 10715 | return; | 11466 | return; |
| 10716 | } | 11467 | } |
| @@ -10721,12 +11472,112 @@ private: | |||
| 10721 | auto breakLoopType = getBreakLoopType(whileNode->body, Empty); | 11472 | auto breakLoopType = getBreakLoopType(whileNode->body, Empty); |
| 10722 | transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common); | 11473 | transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common); |
| 10723 | popScope(); | 11474 | popScope(); |
| 10724 | _buf << indent() << "while "sv << condStr << " do"sv << nll(whileNode); | 11475 | _buf << indent() << "while "sv << condStr << " do"sv << nl(whileNode); |
| 10725 | _buf << temp.back(); | 11476 | _buf << temp.back(); |
| 10726 | _buf << indent() << "end"sv << nlr(whileNode); | 11477 | _buf << indent() << "end"sv << nl(whileNode); |
| 10727 | out.push_back(clearBuf()); | 11478 | out.push_back(clearBuf()); |
| 10728 | } | 11479 | } |
| 10729 | 11480 | ||
| 11481 | void transformRepeatInPlace(Repeat_t* repeatNode, str_list& out, ExpList_t* expList = nullptr) { | ||
| 11482 | auto x = repeatNode; | ||
| 11483 | str_list temp; | ||
| 11484 | bool extraScope = false; | ||
| 11485 | if (expList) { | ||
| 11486 | if (!currentScope().lastStatement) { | ||
| 11487 | extraScope = true; | ||
| 11488 | temp.push_back(indent() + "do"s + nl(repeatNode)); | ||
| 11489 | pushScope(); | ||
| 11490 | } | ||
| 11491 | } | ||
| 11492 | auto accumVar = getUnusedName("_accum_"sv); | ||
| 11493 | addToScope(accumVar); | ||
| 11494 | auto lenVar = getUnusedName("_len_"sv); | ||
| 11495 | addToScope(lenVar); | ||
| 11496 | auto breakLoopType = getBreakLoopType(repeatNode->body, accumVar); | ||
| 11497 | _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(repeatNode); | ||
| 11498 | temp.emplace_back(clearBuf()); | ||
| 11499 | _buf << indent() << "local "s << lenVar << " = 1"s << nl(repeatNode); | ||
| 11500 | auto& lenAssign = temp.emplace_back(clearBuf()); | ||
| 11501 | auto condStr = transformCondExp(repeatNode->condition, false); | ||
| 11502 | temp.push_back(indent() + "repeat"s + nl(repeatNode)); | ||
| 11503 | pushScope(); | ||
| 11504 | if (hasBreakWithValue(breakLoopType)) { | ||
| 11505 | lenAssign.clear(); | ||
| 11506 | transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Common); | ||
| 11507 | } else { | ||
| 11508 | auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); | ||
| 11509 | auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, repeatNode); | ||
| 11510 | assignLeft->followStmt = followStmt.get(); | ||
| 11511 | transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft); | ||
| 11512 | if (!assignLeft->followStmtProcessed) { | ||
| 11513 | lenAssign.clear(); | ||
| 11514 | } | ||
| 11515 | } | ||
| 11516 | popScope(); | ||
| 11517 | temp.push_back(indent() + "until "s + condStr + nl(repeatNode)); | ||
| 11518 | if (expList) { | ||
| 11519 | auto assign = x->new_ptr<Assign_t>(); | ||
| 11520 | assign->values.push_back(toAst<Exp_t>(accumVar, x)); | ||
| 11521 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
| 11522 | assignment->expList.set(expList); | ||
| 11523 | assignment->action.set(assign); | ||
| 11524 | transformAssignment(assignment, temp); | ||
| 11525 | if (extraScope) popScope(); | ||
| 11526 | } else { | ||
| 11527 | temp.push_back(indent() + "return "s + accumVar + nl(repeatNode)); | ||
| 11528 | } | ||
| 11529 | if (expList && extraScope) { | ||
| 11530 | temp.push_back(indent() + "end"s + nl(repeatNode)); | ||
| 11531 | } | ||
| 11532 | out.push_back(join(temp)); | ||
| 11533 | } | ||
| 11534 | |||
| 11535 | void transformRepeatClosure(Repeat_t* repeatNode, str_list& out) { | ||
| 11536 | auto x = repeatNode; | ||
| 11537 | auto simpleValue = x->new_ptr<SimpleValue_t>(); | ||
| 11538 | simpleValue->value.set(repeatNode); | ||
| 11539 | if (transformAsUpValueFunc(newExp(simpleValue, x), out)) { | ||
| 11540 | return; | ||
| 11541 | } | ||
| 11542 | str_list temp; | ||
| 11543 | pushAnonFunctionScope(); | ||
| 11544 | pushAnonVarArg(); | ||
| 11545 | std::string& funcStart = temp.emplace_back(); | ||
| 11546 | pushScope(); | ||
| 11547 | auto accumVar = getUnusedName("_accum_"sv); | ||
| 11548 | addToScope(accumVar); | ||
| 11549 | auto lenVar = getUnusedName("_len_"sv); | ||
| 11550 | addToScope(lenVar); | ||
| 11551 | auto breakLoopType = getBreakLoopType(repeatNode->body, accumVar); | ||
| 11552 | _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(repeatNode); | ||
| 11553 | temp.emplace_back(clearBuf()); | ||
| 11554 | auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nl(repeatNode)); | ||
| 11555 | auto condStr = transformCondExp(repeatNode->condition, false); | ||
| 11556 | temp.push_back(indent() + "repeat"s + nl(repeatNode)); | ||
| 11557 | pushScope(); | ||
| 11558 | if (hasBreakWithValue(breakLoopType)) { | ||
| 11559 | lenAssign.clear(); | ||
| 11560 | transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Common); | ||
| 11561 | } else { | ||
| 11562 | auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); | ||
| 11563 | auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, repeatNode); | ||
| 11564 | assignLeft->followStmt = followStmt.get(); | ||
| 11565 | transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft); | ||
| 11566 | if (!assignLeft->followStmtProcessed) { | ||
| 11567 | lenAssign.clear(); | ||
| 11568 | } | ||
| 11569 | } | ||
| 11570 | popScope(); | ||
| 11571 | temp.push_back(indent() + "until "s + condStr + nl(repeatNode)); | ||
| 11572 | temp.push_back(indent() + "return "s + accumVar + nl(repeatNode)); | ||
| 11573 | popScope(); | ||
| 11574 | funcStart = anonFuncStart() + nl(repeatNode); | ||
| 11575 | temp.push_back(indent() + anonFuncEnd()); | ||
| 11576 | popAnonVarArg(); | ||
| 11577 | popFunctionScope(); | ||
| 11578 | out.push_back(join(temp)); | ||
| 11579 | } | ||
| 11580 | |||
| 10730 | void transformRepeat(Repeat_t* repeat, str_list& out) { | 11581 | void transformRepeat(Repeat_t* repeat, str_list& out) { |
| 10731 | str_list temp; | 11582 | str_list temp; |
| 10732 | pushScope(); | 11583 | pushScope(); |
| @@ -10737,9 +11588,9 @@ private: | |||
| 10737 | temp.push_back(condVar); | 11588 | temp.push_back(condVar); |
| 10738 | } | 11589 | } |
| 10739 | popScope(); | 11590 | popScope(); |
| 10740 | _buf << indent() << "repeat"sv << nll(repeat); | 11591 | _buf << indent() << "repeat"sv << nl(repeat); |
| 10741 | _buf << temp.front(); | 11592 | _buf << temp.front(); |
| 10742 | _buf << indent() << "until "sv << temp.back() << nlr(repeat); | 11593 | _buf << indent() << "until "sv << temp.back() << nl(repeat); |
| 10743 | out.push_back(clearBuf()); | 11594 | out.push_back(clearBuf()); |
| 10744 | } | 11595 | } |
| 10745 | 11596 | ||
| @@ -10760,12 +11611,28 @@ private: | |||
| 10760 | pushScope(); | 11611 | pushScope(); |
| 10761 | } | 11612 | } |
| 10762 | bool extraScope = false; | 11613 | bool extraScope = false; |
| 11614 | if (switchNode->assignment) { | ||
| 11615 | if (needScope) { | ||
| 11616 | extraScope = true; | ||
| 11617 | temp.push_back(indent() + "do"s + nl(x)); | ||
| 11618 | pushScope(); | ||
| 11619 | } | ||
| 11620 | auto asmt = x->new_ptr<ExpListAssign_t>(); | ||
| 11621 | auto expList = x->new_ptr<ExpList_t>(); | ||
| 11622 | expList->exprs.push_back(switchNode->target); | ||
| 11623 | if (switchNode->assignment->expList) { | ||
| 11624 | expList->exprs.dup(switchNode->assignment->expList->exprs); | ||
| 11625 | } | ||
| 11626 | asmt->expList.set(expList); | ||
| 11627 | asmt->action.set(switchNode->assignment->assign); | ||
| 11628 | transformAssignment(asmt, temp); | ||
| 11629 | } | ||
| 10763 | auto objVar = singleVariableFrom(switchNode->target, AccessType::Read); | 11630 | auto objVar = singleVariableFrom(switchNode->target, AccessType::Read); |
| 10764 | if (objVar.empty() || !isLocal(objVar)) { | 11631 | if (objVar.empty() || !isLocal(objVar)) { |
| 10765 | if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) { | 11632 | if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) { |
| 10766 | if (needScope) { | 11633 | if (needScope && !extraScope) { |
| 10767 | extraScope = true; | 11634 | extraScope = true; |
| 10768 | temp.push_back(indent() + "do"s + nll(x)); | 11635 | temp.push_back(indent() + "do"s + nl(x)); |
| 10769 | pushScope(); | 11636 | pushScope(); |
| 10770 | } | 11637 | } |
| 10771 | } | 11638 | } |
| @@ -10795,13 +11662,13 @@ private: | |||
| 10795 | } | 11662 | } |
| 10796 | if (tableMatching) { | 11663 | if (tableMatching) { |
| 10797 | if (!firstBranch) { | 11664 | if (!firstBranch) { |
| 10798 | temp.push_back(indent() + "else"s + nll(branch)); | 11665 | temp.push_back(indent() + "else"s + nl(branch)); |
| 10799 | pushScope(); | 11666 | pushScope(); |
| 10800 | addScope++; | 11667 | addScope++; |
| 10801 | } | 11668 | } |
| 10802 | if (tabCheckVar.empty()) { | 11669 | if (tabCheckVar.empty()) { |
| 10803 | if (!extraScope && needScope) { | 11670 | if (!extraScope && needScope) { |
| 10804 | temp.push_back(indent() + "do"s + nll(branch)); | 11671 | temp.push_back(indent() + "do"s + nl(branch)); |
| 10805 | pushScope(); | 11672 | pushScope(); |
| 10806 | extraScope = true; | 11673 | extraScope = true; |
| 10807 | } | 11674 | } |
| @@ -10809,17 +11676,17 @@ private: | |||
| 10809 | forceAddToScope(typeVar); | 11676 | forceAddToScope(typeVar); |
| 10810 | tabCheckVar = getUnusedName("_tab_"sv); | 11677 | tabCheckVar = getUnusedName("_tab_"sv); |
| 10811 | forceAddToScope(tabCheckVar); | 11678 | forceAddToScope(tabCheckVar); |
| 10812 | temp.push_back(indent() + "local "s + typeVar + " = "s + globalVar("type"sv, branch, AccessType::Read) + '(' + objVar + ')' + nll(branch)); | 11679 | temp.push_back(indent() + "local "s + typeVar + " = "s + globalVar("type"sv, branch, AccessType::Read) + '(' + objVar + ')' + nl(branch)); |
| 10813 | temp.push_back(indent() + "local "s + tabCheckVar + " = \"table\" == "s + typeVar + " or \"userdata\" == "s + typeVar + nll(branch)); | 11680 | temp.push_back(indent() + "local "s + tabCheckVar + " = \"table\" == "s + typeVar + " or \"userdata\" == "s + typeVar + nl(branch)); |
| 10814 | } | 11681 | } |
| 10815 | std::string matchVar; | 11682 | std::string matchVar; |
| 10816 | bool lastBranch = branches.back() == branch_ && !switchNode->lastBranch; | 11683 | bool lastBranch = branches.back() == branch_ && !switchNode->lastBranch; |
| 10817 | if (!lastBranch) { | 11684 | if (!lastBranch) { |
| 10818 | matchVar = getUnusedName("_match_"sv); | 11685 | matchVar = getUnusedName("_match_"sv); |
| 10819 | forceAddToScope(matchVar); | 11686 | forceAddToScope(matchVar); |
| 10820 | temp.push_back(indent() + "local "s + matchVar + " = false"s + nll(branch)); | 11687 | temp.push_back(indent() + "local "s + matchVar + " = false"s + nl(branch)); |
| 10821 | } | 11688 | } |
| 10822 | temp.back().append(indent() + "if "s + tabCheckVar + " then"s + nll(branch)); | 11689 | temp.back().append(indent() + "if "s + tabCheckVar + " then"s + nl(branch)); |
| 10823 | pushScope(); | 11690 | pushScope(); |
| 10824 | auto chainValue = toAst<ChainValue_t>(objVar, branch); | 11691 | auto chainValue = toAst<ChainValue_t>(objVar, branch); |
| 10825 | auto assignment = assignmentFrom(static_cast<Exp_t*>(valueList->exprs.front()), newExp(chainValue, branch), branch); | 11692 | auto assignment = assignmentFrom(static_cast<Exp_t*>(valueList->exprs.front()), newExp(chainValue, branch), branch); |
| @@ -10862,21 +11729,21 @@ private: | |||
| 10862 | } | 11729 | } |
| 10863 | } | 11730 | } |
| 10864 | if (!conds.empty()) { | 11731 | if (!conds.empty()) { |
| 10865 | temp.push_back(indent() + "if "s + join(conds, " and "sv) + " then"s + nll(branch)); | 11732 | temp.push_back(indent() + "if "s + join(conds, " and "sv) + " then"s + nl(branch)); |
| 10866 | pushScope(); | 11733 | pushScope(); |
| 10867 | } | 11734 | } |
| 10868 | if (!lastBranch) { | 11735 | if (!lastBranch) { |
| 10869 | temp.push_back(indent() + matchVar + " = true"s + nll(branch)); | 11736 | temp.push_back(indent() + matchVar + " = true"s + nl(branch)); |
| 10870 | } | 11737 | } |
| 10871 | transform_plain_body(branch->body, temp, usage, assignList); | 11738 | transform_plain_body(branch->body, temp, usage, assignList); |
| 10872 | if (!conds.empty()) { | 11739 | if (!conds.empty()) { |
| 10873 | popScope(); | 11740 | popScope(); |
| 10874 | temp.push_back(indent() + "end"s + nll(branch)); | 11741 | temp.push_back(indent() + "end"s + nl(branch)); |
| 10875 | } | 11742 | } |
| 10876 | if (!lastBranch) { | 11743 | if (!lastBranch) { |
| 10877 | popScope(); | 11744 | popScope(); |
| 10878 | temp.push_back(indent() + "end"s + nll(branch)); | 11745 | temp.push_back(indent() + "end"s + nl(branch)); |
| 10879 | temp.push_back(indent() + "if not "s + matchVar + " then"s + nll(branch)); | 11746 | temp.push_back(indent() + "if not "s + matchVar + " then"s + nl(branch)); |
| 10880 | pushScope(); | 11747 | pushScope(); |
| 10881 | addScope++; | 11748 | addScope++; |
| 10882 | } else { | 11749 | } else { |
| @@ -10896,7 +11763,7 @@ private: | |||
| 10896 | } | 11763 | } |
| 10897 | temp.back().append(' ' + tmp.back() + " == "s + (exp == exprs.back() ? objVar : objVar + " or"s)); | 11764 | temp.back().append(' ' + tmp.back() + " == "s + (exp == exprs.back() ? objVar : objVar + " or"s)); |
| 10898 | } | 11765 | } |
| 10899 | temp.back().append(" then"s + nll(branch)); | 11766 | temp.back().append(" then"s + nl(branch)); |
| 10900 | pushScope(); | 11767 | pushScope(); |
| 10901 | transform_plain_body(branch->body, temp, usage, assignList); | 11768 | transform_plain_body(branch->body, temp, usage, assignList); |
| 10902 | popScope(); | 11769 | popScope(); |
| @@ -10904,7 +11771,7 @@ private: | |||
| 10904 | } | 11771 | } |
| 10905 | if (switchNode->lastBranch) { | 11772 | if (switchNode->lastBranch) { |
| 10906 | if (!firstBranch) { | 11773 | if (!firstBranch) { |
| 10907 | temp.push_back(indent() + "else"s + nll(switchNode->lastBranch)); | 11774 | temp.push_back(indent() + "else"s + nl(switchNode->lastBranch)); |
| 10908 | pushScope(); | 11775 | pushScope(); |
| 10909 | } else { | 11776 | } else { |
| 10910 | addScope--; | 11777 | addScope--; |
| @@ -10914,20 +11781,20 @@ private: | |||
| 10914 | } | 11781 | } |
| 10915 | while (addScope > 0) { | 11782 | while (addScope > 0) { |
| 10916 | addScope--; | 11783 | addScope--; |
| 10917 | temp.push_back(indent() + "end"s + nlr(switchNode)); | 11784 | temp.push_back(indent() + "end"s + nl(switchNode)); |
| 10918 | popScope(); | 11785 | popScope(); |
| 10919 | } | 11786 | } |
| 10920 | temp.push_back(indent() + "end"s + nlr(switchNode)); | 11787 | temp.push_back(indent() + "end"s + nl(switchNode)); |
| 10921 | if (usage == ExpUsage::Closure) { | 11788 | if (usage == ExpUsage::Closure) { |
| 10922 | popFunctionScope(); | 11789 | popFunctionScope(); |
| 10923 | popScope(); | 11790 | popScope(); |
| 10924 | *funcStart = anonFuncStart() + nll(switchNode); | 11791 | *funcStart = anonFuncStart() + nl(switchNode); |
| 10925 | temp.push_back(indent() + anonFuncEnd()); | 11792 | temp.push_back(indent() + anonFuncEnd()); |
| 10926 | popAnonVarArg(); | 11793 | popAnonVarArg(); |
| 10927 | } | 11794 | } |
| 10928 | if (extraScope) { | 11795 | if (extraScope) { |
| 10929 | popScope(); | 11796 | popScope(); |
| 10930 | temp.push_back(indent() + "end"s + nlr(switchNode)); | 11797 | temp.push_back(indent() + "end"s + nl(switchNode)); |
| 10931 | } | 11798 | } |
| 10932 | out.push_back(join(temp)); | 11799 | out.push_back(join(temp)); |
| 10933 | } | 11800 | } |
| @@ -10946,7 +11813,7 @@ private: | |||
| 10946 | } | 11813 | } |
| 10947 | auto preDefine = toLocalDecl(defs); | 11814 | auto preDefine = toLocalDecl(defs); |
| 10948 | if (!preDefine.empty()) { | 11815 | if (!preDefine.empty()) { |
| 10949 | out.push_back(preDefine + nll(local)); | 11816 | out.push_back(preDefine + nl(local)); |
| 10950 | } | 11817 | } |
| 10951 | } | 11818 | } |
| 10952 | } | 11819 | } |
| @@ -11151,7 +12018,7 @@ private: | |||
| 11151 | } | 12018 | } |
| 11152 | str_list temp; | 12019 | str_list temp; |
| 11153 | if (localAttrib->forceLocal) { | 12020 | if (localAttrib->forceLocal) { |
| 11154 | temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x)); | 12021 | temp.push_back(indent() + "local "s + join(vars, ", "sv) + nl(x)); |
| 11155 | } | 12022 | } |
| 11156 | transformAssignment(assignment, temp); | 12023 | transformAssignment(assignment, temp); |
| 11157 | for (const auto& name : vars) { | 12024 | for (const auto& name : vars) { |
| @@ -11197,13 +12064,13 @@ private: | |||
| 11197 | auto rit = items.begin(); | 12064 | auto rit = items.begin(); |
| 11198 | str_list tmp; | 12065 | str_list tmp; |
| 11199 | while (lit != vars.end()) { | 12066 | while (lit != vars.end()) { |
| 11200 | tmp.push_back(indent() + "local "s + *lit + (target >= 504 ? " <close> = "s : " = "s) + *rit + nll(x)); | 12067 | tmp.push_back(indent() + "local "s + *lit + (target >= 504 ? " <close> = "s : " = "s) + *rit + nl(x)); |
| 11201 | lit++; | 12068 | lit++; |
| 11202 | rit++; | 12069 | rit++; |
| 11203 | } | 12070 | } |
| 11204 | temp.push_back(join(tmp)); | 12071 | temp.push_back(join(tmp)); |
| 11205 | } else { | 12072 | } else { |
| 11206 | temp.push_back(indent() + "local "s + join(vars, ", "sv) + " = "s + join(items, ", "sv) + nll(x)); | 12073 | temp.push_back(indent() + "local "s + join(vars, ", "sv) + " = "s + join(items, ", "sv) + nl(x)); |
| 11207 | str_list leftVars; | 12074 | str_list leftVars; |
| 11208 | pushScope(); | 12075 | pushScope(); |
| 11209 | for (size_t i = 0; i < vars.size(); i++) { | 12076 | for (size_t i = 0; i < vars.size(); i++) { |
| @@ -11224,7 +12091,7 @@ private: | |||
| 11224 | for (auto item : assignA->values.objects()) { | 12091 | for (auto item : assignA->values.objects()) { |
| 11225 | transformAssignItem(item, items); | 12092 | transformAssignItem(item, items); |
| 11226 | } | 12093 | } |
| 11227 | temp.push_back(indent() + "local "s + join(leftVars, ", "sv) + " = "s + join(items, ", "sv) + nll(x)); | 12094 | temp.push_back(indent() + "local "s + join(leftVars, ", "sv) + " = "s + join(items, ", "sv) + nl(x)); |
| 11228 | } | 12095 | } |
| 11229 | for (const auto& var : vars) { | 12096 | for (const auto& var : vars) { |
| 11230 | markVarLocalConst(var); | 12097 | markVarLocalConst(var); |
| @@ -11249,7 +12116,7 @@ private: | |||
| 11249 | vars.push_back(item.targetVar); | 12116 | vars.push_back(item.targetVar); |
| 11250 | } | 12117 | } |
| 11251 | } | 12118 | } |
| 11252 | temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x)); | 12119 | temp.push_back(indent() + "local "s + join(vars, ", "sv) + nl(x)); |
| 11253 | transformAssignment(assignment, temp); | 12120 | transformAssignment(assignment, temp); |
| 11254 | for (const auto& name : vars) { | 12121 | for (const auto& name : vars) { |
| 11255 | markVarLocalConst(name); | 12122 | markVarLocalConst(name); |
| @@ -11270,7 +12137,7 @@ private: | |||
| 11270 | auto assignment = assignmentFrom(exp, breakLoop->value, breakLoop); | 12137 | auto assignment = assignmentFrom(exp, breakLoop->value, breakLoop); |
| 11271 | transformAssignment(assignment, out); | 12138 | transformAssignment(assignment, out); |
| 11272 | } | 12139 | } |
| 11273 | out.push_back(indent() + keyword + nll(breakLoop)); | 12140 | out.push_back(indent() + keyword + nl(breakLoop)); |
| 11274 | return; | 12141 | return; |
| 11275 | } | 12142 | } |
| 11276 | if (_continueVars.empty()) throw CompileError("continue is not inside a loop"sv, breakLoop); | 12143 | if (_continueVars.empty()) throw CompileError("continue is not inside a loop"sv, breakLoop); |
| @@ -11283,8 +12150,8 @@ private: | |||
| 11283 | if (!temp.empty()) { | 12150 | if (!temp.empty()) { |
| 11284 | _buf << temp.back(); | 12151 | _buf << temp.back(); |
| 11285 | } | 12152 | } |
| 11286 | _buf << indent() << item.var << " = true"sv << nll(breakLoop); | 12153 | _buf << indent() << item.var << " = true"sv << nl(breakLoop); |
| 11287 | _buf << indent() << "break"sv << nll(breakLoop); | 12154 | _buf << indent() << "break"sv << nl(breakLoop); |
| 11288 | out.push_back(clearBuf()); | 12155 | out.push_back(clearBuf()); |
| 11289 | } else { | 12156 | } else { |
| 11290 | transformGoto(toAst<Goto_t>("goto "s + item.var, breakLoop), temp); | 12157 | transformGoto(toAst<Goto_t>("goto "s + item.var, breakLoop), temp); |
| @@ -11296,7 +12163,7 @@ private: | |||
| 11296 | if (getLuaTarget(label) < 502) { | 12163 | if (getLuaTarget(label) < 502) { |
| 11297 | throw CompileError("label statement is not available when not targeting Lua version 5.2 or higher"sv, label); | 12164 | throw CompileError("label statement is not available when not targeting Lua version 5.2 or higher"sv, label); |
| 11298 | } | 12165 | } |
| 11299 | auto labelStr = unicodeVariableFrom(label->label->name); | 12166 | auto labelStr = unicodeVariableFrom(label->label); |
| 11300 | int currentScope = _gotoScopes.top(); | 12167 | int currentScope = _gotoScopes.top(); |
| 11301 | if (static_cast<int>(_labels.size()) <= currentScope) { | 12168 | if (static_cast<int>(_labels.size()) <= currentScope) { |
| 11302 | _labels.resize(currentScope + 1, std::nullopt); | 12169 | _labels.resize(currentScope + 1, std::nullopt); |
| @@ -11310,16 +12177,16 @@ private: | |||
| 11310 | throw CompileError("label '"s + labelStr + "' already defined at line "s + std::to_string(it->second.line), label); | 12177 | throw CompileError("label '"s + labelStr + "' already defined at line "s + std::to_string(it->second.line), label); |
| 11311 | } | 12178 | } |
| 11312 | scope[labelStr] = {label->m_begin.m_line, static_cast<int>(_scopes.size())}; | 12179 | scope[labelStr] = {label->m_begin.m_line, static_cast<int>(_scopes.size())}; |
| 11313 | out.push_back(indent() + "::"s + labelStr + "::"s + nll(label)); | 12180 | out.push_back(indent() + "::"s + labelStr + "::"s + nl(label)); |
| 11314 | } | 12181 | } |
| 11315 | 12182 | ||
| 11316 | void transformGoto(Goto_t* gotoNode, str_list& out) { | 12183 | void transformGoto(Goto_t* gotoNode, str_list& out) { |
| 11317 | if (getLuaTarget(gotoNode) < 502) { | 12184 | if (getLuaTarget(gotoNode) < 502) { |
| 11318 | throw CompileError("goto statement is not available when not targeting Lua version 5.2 or higher"sv, gotoNode); | 12185 | throw CompileError("goto statement is not available when not targeting Lua version 5.2 or higher"sv, gotoNode); |
| 11319 | } | 12186 | } |
| 11320 | auto labelStr = unicodeVariableFrom(gotoNode->label->name); | 12187 | auto labelStr = unicodeVariableFrom(gotoNode->label); |
| 11321 | gotos.push_back({gotoNode, labelStr, _gotoScopes.top(), static_cast<int>(_scopes.size())}); | 12188 | gotos.push_back({gotoNode, labelStr, _gotoScopes.top(), static_cast<int>(_scopes.size())}); |
| 11322 | out.push_back(indent() + "goto "s + labelStr + nll(gotoNode)); | 12189 | out.push_back(indent() + "goto "s + labelStr + nl(gotoNode)); |
| 11323 | } | 12190 | } |
| 11324 | 12191 | ||
| 11325 | void transformShortTabAppending(ShortTabAppending_t* tab, str_list& out) { | 12192 | void transformShortTabAppending(ShortTabAppending_t* tab, str_list& out) { |
| @@ -11383,13 +12250,13 @@ private: | |||
| 11383 | temp.push_back(getPreDefineLine(assignment)); | 12250 | temp.push_back(getPreDefineLine(assignment)); |
| 11384 | } | 12251 | } |
| 11385 | assignments.push_front(assignmentFrom(newValue, value, value)); | 12252 | assignments.push_front(assignmentFrom(newValue, value, value)); |
| 11386 | temp.push_back(indent() + "do"s + nll(x)); | 12253 | temp.push_back(indent() + "do"s + nl(x)); |
| 11387 | pushScope(); | 12254 | pushScope(); |
| 11388 | for (auto item : assignments.objects()) { | 12255 | for (auto item : assignments.objects()) { |
| 11389 | transformAssignment(static_cast<ExpListAssign_t*>(item), temp); | 12256 | transformAssignment(static_cast<ExpListAssign_t*>(item), temp); |
| 11390 | } | 12257 | } |
| 11391 | popScope(); | 12258 | popScope(); |
| 11392 | temp.push_back(indent() + "end"s + nll(x)); | 12259 | temp.push_back(indent() + "end"s + nl(x)); |
| 11393 | out.push_back(join(temp)); | 12260 | out.push_back(join(temp)); |
| 11394 | } | 12261 | } |
| 11395 | }; | 12262 | }; |
diff --git a/src/yuescript/yue_compiler.h b/src/yuescript/yue_compiler.h index d352636..eb5fb16 100644 --- a/src/yuescript/yue_compiler.h +++ b/src/yuescript/yue_compiler.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> | 1 | /* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com> |
| 2 | 2 | ||
| 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
| 4 | 4 | ||
| @@ -31,6 +31,7 @@ struct YueConfig { | |||
| 31 | bool reserveLineNumber = true; | 31 | bool reserveLineNumber = true; |
| 32 | bool useSpaceOverTab = false; | 32 | bool useSpaceOverTab = false; |
| 33 | bool reserveComment = false; | 33 | bool reserveComment = false; |
| 34 | bool lax = false; | ||
| 34 | // internal options | 35 | // internal options |
| 35 | bool exporting = false; | 36 | bool exporting = false; |
| 36 | bool profiling = false; | 37 | bool profiling = false; |
| @@ -51,6 +52,7 @@ struct GlobalVar { | |||
| 51 | int line; | 52 | int line; |
| 52 | int col; | 53 | int col; |
| 53 | AccessType accessType; | 54 | AccessType accessType; |
| 55 | bool defined; | ||
| 54 | }; | 56 | }; |
| 55 | 57 | ||
| 56 | using GlobalVars = std::vector<GlobalVar>; | 58 | using GlobalVars = std::vector<GlobalVar>; |
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index cd1fd48..1dfe978 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> | 1 | /* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com> |
| 2 | 2 | ||
| 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
| 4 | 4 | ||
| @@ -41,6 +41,24 @@ public: | |||
| 41 | int col; | 41 | int col; |
| 42 | }; | 42 | }; |
| 43 | 43 | ||
| 44 | #define RaiseError(msg, item) \ | ||
| 45 | do { \ | ||
| 46 | if (reinterpret_cast<State*>(item.user_data)->lax) { \ | ||
| 47 | return false; \ | ||
| 48 | } else { \ | ||
| 49 | throw ParserError(msg, item.begin); \ | ||
| 50 | } \ | ||
| 51 | } while (false) | ||
| 52 | |||
| 53 | #define RaiseErrorI(msg, item) \ | ||
| 54 | do { \ | ||
| 55 | if (reinterpret_cast<State*>(item.user_data)->lax) { \ | ||
| 56 | return -1; \ | ||
| 57 | } else { \ | ||
| 58 | throw ParserError(msg, item.begin); \ | ||
| 59 | } \ | ||
| 60 | } while (false) | ||
| 61 | |||
| 44 | // clang-format off | 62 | // clang-format off |
| 45 | YueParser::YueParser() { | 63 | YueParser::YueParser() { |
| 46 | plain_space = *set(" \t"); | 64 | plain_space = *set(" \t"); |
| @@ -57,18 +75,20 @@ YueParser::YueParser() { | |||
| 57 | space = -(and_(set(" \t-\\")) >> *space_one >> -comment); | 75 | space = -(and_(set(" \t-\\")) >> *space_one >> -comment); |
| 58 | space_break = space >> line_break; | 76 | space_break = space >> line_break; |
| 59 | white = space >> *(line_break >> space); | 77 | white = space >> *(line_break >> space); |
| 78 | plain_white = plain_space >> *(line_break >> plain_space); | ||
| 60 | alpha_num = range('a', 'z') | range('A', 'Z') | range('0', '9') | '_'; | 79 | alpha_num = range('a', 'z') | range('A', 'Z') | range('0', '9') | '_'; |
| 61 | not_alpha_num = not_(alpha_num); | 80 | not_alpha_num = not_(alpha_num); |
| 62 | Name = (range('a', 'z') | range('A', 'Z') | '_') >> *alpha_num >> not_(larger(255)); | 81 | Name = (range('a', 'z') | range('A', 'Z') | '_') >> *alpha_num >> not_(larger(255)); |
| 63 | UnicodeName = (range('a', 'z') | range('A', 'Z') | '_' | larger(255)) >> *(larger(255) | alpha_num); | 82 | UnicodeName = (range('a', 'z') | range('A', 'Z') | '_' | larger(255)) >> *(larger(255) | alpha_num); |
| 64 | num_expo = set("eE") >> -set("+-") >> num_char; | 83 | must_num_char = num_char | invalid_number_literal_error; |
| 65 | num_expo_hex = set("pP") >> -set("+-") >> num_char; | 84 | num_expo = set("eE") >> -set("+-") >> must_num_char; |
| 85 | num_expo_hex = set("pP") >> -set("+-") >> must_num_char; | ||
| 66 | lj_num = -set("uU") >> set("lL") >> set("lL"); | 86 | lj_num = -set("uU") >> set("lL") >> set("lL"); |
| 67 | num_char = range('0', '9') >> *(range('0', '9') | '_' >> and_(range('0', '9'))); | 87 | num_char = range('0', '9') >> *(range('0', '9') | '_' >> and_(range('0', '9'))); |
| 68 | num_char_hex = range('0', '9') | range('a', 'f') | range('A', 'F'); | 88 | num_char_hex = range('0', '9') | range('a', 'f') | range('A', 'F'); |
| 69 | num_lit = num_char_hex >> *(num_char_hex | '_' >> and_(num_char_hex)); | 89 | num_lit = num_char_hex >> *(num_char_hex | '_' >> and_(num_char_hex)); |
| 70 | num_bin_lit = set("01") >> *(set("01") | '_' >> and_(set("01"))); | 90 | num_bin_lit = set("01") >> *(set("01") | '_' >> and_(set("01"))); |
| 71 | Num = | 91 | Num = ( |
| 72 | '0' >> ( | 92 | '0' >> ( |
| 73 | set("xX") >> ( | 93 | set("xX") >> ( |
| 74 | num_lit >> ( | 94 | num_lit >> ( |
| @@ -78,50 +98,122 @@ YueParser::YueParser() { | |||
| 78 | true_() | 98 | true_() |
| 79 | ) | ( | 99 | ) | ( |
| 80 | '.' >> num_lit >> -num_expo_hex | 100 | '.' >> num_lit >> -num_expo_hex |
| 81 | ) | 101 | ) | invalid_number_literal_error |
| 82 | ) | | 102 | ) | |
| 83 | set("bB") >> num_bin_lit | 103 | set("bB") >> (num_bin_lit | invalid_number_literal_error) |
| 84 | ) | | 104 | ) | |
| 85 | num_char >> ( | 105 | num_char >> ( |
| 86 | '.' >> num_char >> -num_expo | | 106 | '.' >> must_num_char >> -num_expo | |
| 87 | num_expo | | 107 | num_expo | |
| 88 | lj_num | | 108 | lj_num | |
| 89 | true_() | 109 | true_() |
| 90 | ) | | 110 | ) |
| 91 | '.' >> num_char >> -num_expo; | 111 | ) >> -(and_(alpha_num) >> invalid_number_literal_error) | |
| 112 | '.' >> num_char >> -num_expo >> -(and_(alpha_num) >> invalid_number_literal_error); | ||
| 92 | 113 | ||
| 93 | cut = false_(); | 114 | cut = false_(); |
| 94 | Seperator = true_(); | 115 | Seperator = true_(); |
| 95 | 116 | ||
| 96 | empty_block_error = pl::user(true_(), [](const item_t& item) { | 117 | auto expect_error = [](std::string_view msg) { |
| 97 | throw ParserError("must be followed by a statement or an indented block"sv, item.begin); | 118 | return pl::user(true_(), [msg](const item_t& item) { |
| 98 | return false; | 119 | RaiseError(msg, item); |
| 99 | }); | 120 | return false; |
| 100 | 121 | }); | |
| 101 | export_expression_error = pl::user(true_(), [](const item_t& item) { | 122 | }; |
| 102 | throw ParserError("invalid export expression"sv, item.begin); | ||
| 103 | return false; | ||
| 104 | }); | ||
| 105 | 123 | ||
| 106 | invalid_interpolation_error = pl::user(true_(), [](const item_t& item) { | 124 | empty_block_error = expect_error( |
| 107 | throw ParserError("invalid string interpolation"sv, item.begin); | 125 | "expected a valid statement or indented block"sv |
| 108 | return false; | 126 | ); |
| 109 | }); | 127 | export_expression_error = expect_error( |
| 110 | 128 | "invalid export expression"sv | |
| 111 | confusing_unary_not_error = pl::user(true_(), [](const item_t& item) { | 129 | ); |
| 112 | throw ParserError("deprecated use for unary operator 'not' to be here"sv, item.begin); | 130 | invalid_interpolation_error = expect_error( |
| 113 | return false; | 131 | "invalid string interpolation"sv |
| 114 | }); | 132 | ); |
| 115 | 133 | confusing_unary_not_error = expect_error( | |
| 116 | table_key_pair_error = pl::user(true_(), [](const item_t& item) { | 134 | "deprecated use for unary operator 'not' to be here"sv |
| 117 | throw ParserError("can not put hash pair in a list"sv, item.begin); | 135 | ); |
| 118 | return false; | 136 | table_key_pair_error = expect_error( |
| 119 | }); | 137 | "can not put hash pair in a list"sv |
| 120 | 138 | ); | |
| 121 | if_assignment_syntax_error = pl::user(true_(), [](const item_t& item) { | 139 | assignment_expression_syntax_error = expect_error( |
| 122 | throw ParserError("use := for if-assignment expression"sv, item.begin); | 140 | "use := for assignment expression"sv |
| 123 | return false; | 141 | ); |
| 124 | }); | 142 | braces_expression_error = expect_error( |
| 143 | "syntax error in brace expression"sv | ||
| 144 | ); | ||
| 145 | brackets_expression_error = expect_error( | ||
| 146 | "unclosed bracket expression"sv | ||
| 147 | ); | ||
| 148 | slice_expression_error = expect_error( | ||
| 149 | "syntax error in slice expression"sv | ||
| 150 | ); | ||
| 151 | unclosed_single_string_error = expect_error( | ||
| 152 | "unclosed single-quoted string"sv | ||
| 153 | ); | ||
| 154 | unclosed_double_string_error = expect_error( | ||
| 155 | "unclosed double-quoted string"sv | ||
| 156 | ); | ||
| 157 | unclosed_lua_string_error = expect_error( | ||
| 158 | "unclosed Lua string"sv | ||
| 159 | ); | ||
| 160 | unexpected_comma_error = expect_error( | ||
| 161 | "got unexpected comma"sv | ||
| 162 | ); | ||
| 163 | parenthesis_error = expect_error( | ||
| 164 | "expected only one expression in parenthesis"sv | ||
| 165 | ); | ||
| 166 | dangling_clause_error = expect_error( | ||
| 167 | "dangling control clause"sv | ||
| 168 | ); | ||
| 169 | keyword_as_label_error = expect_error( | ||
| 170 | "keyword cannot be used as a label name"sv | ||
| 171 | ); | ||
| 172 | vararg_position_error = expect_error( | ||
| 173 | "vararg '...' must be the last parameter in function argument list"sv | ||
| 174 | ); | ||
| 175 | invalid_import_syntax_error = expect_error( | ||
| 176 | "invalid import syntax, expected `import \"X.mod\"`, `import \"X.mod\" as {:name}`, `from mod import name` or `import mod.name`"sv | ||
| 177 | ); | ||
| 178 | invalid_import_as_syntax_error = expect_error( | ||
| 179 | "invalid import syntax, expected `import \"X.mod\" as modname` or `import \"X.mod\" as {:name}`"sv | ||
| 180 | ); | ||
| 181 | expected_expression_error = expect_error( | ||
| 182 | "expected valid expression"sv | ||
| 183 | ); | ||
| 184 | invalid_from_import_error = expect_error( | ||
| 185 | "invalid import syntax, expected `from \"X.mod\" import name` or `from mod import name`"sv | ||
| 186 | ); | ||
| 187 | invalid_export_syntax_error = expect_error( | ||
| 188 | "invalid export syntax, expected `export item`, `export item = x`, `export.item = x` or `export default item`"sv | ||
| 189 | ); | ||
| 190 | invalid_macro_definition_error = expect_error( | ||
| 191 | "invalid macro definition, expected `macro Name = -> body` or `macro Name = $Name(...)`"sv | ||
| 192 | ); | ||
| 193 | invalid_global_declaration_error = expect_error( | ||
| 194 | "invalid global declaration, expected `global name`, `global name = ...`, `global *`, `global ^` or `global class ...`"sv | ||
| 195 | ); | ||
| 196 | invalid_local_declaration_error = expect_error( | ||
| 197 | "invalid local declaration, expected `local name`, `local name = ...`, `local *` or `local ^`"sv | ||
| 198 | ); | ||
| 199 | invalid_with_syntax_error = expect_error( | ||
| 200 | "invalid 'with' statement"sv | ||
| 201 | ); | ||
| 202 | invalid_try_syntax_error = expect_error( | ||
| 203 | "invalid 'try' expression, expected `try expr` or `try block` optionally followed by `catch err` with a handling block"sv | ||
| 204 | ); | ||
| 205 | keyword_as_identifier_syntax_error = expect_error( | ||
| 206 | "can not use keyword as identifier"sv | ||
| 207 | ); | ||
| 208 | invalid_number_literal_error = expect_error( | ||
| 209 | "invalid numeric literal"sv | ||
| 210 | ); | ||
| 211 | invalid_import_literal_error = expect_error( | ||
| 212 | "invalid import path literal, expected a dotted path like X.Y.Z"sv | ||
| 213 | ); | ||
| 214 | expected_indentifier_error = expect_error( | ||
| 215 | "expected valid identifer"sv | ||
| 216 | ); | ||
| 125 | 217 | ||
| 126 | #define ensure(patt, finally) ((patt) >> (finally) | (finally) >> cut) | 218 | #define ensure(patt, finally) ((patt) >> (finally) | (finally) >> cut) |
| 127 | 219 | ||
| @@ -162,6 +254,13 @@ YueParser::YueParser() { | |||
| 162 | ) \ | 254 | ) \ |
| 163 | ) | 255 | ) |
| 164 | 256 | ||
| 257 | #define disable_until_rule(patt) ( \ | ||
| 258 | disable_until >> ( \ | ||
| 259 | (patt) >> enable_until | \ | ||
| 260 | enable_until >> cut \ | ||
| 261 | ) \ | ||
| 262 | ) | ||
| 263 | |||
| 165 | #define body_with(str) ( \ | 264 | #define body_with(str) ( \ |
| 166 | key(str) >> space >> (in_block | Statement) | \ | 265 | key(str) >> space >> (in_block | Statement) | \ |
| 167 | in_block | \ | 266 | in_block | \ |
| @@ -194,20 +293,6 @@ YueParser::YueParser() { | |||
| 194 | return isValid; | 293 | return isValid; |
| 195 | }); | 294 | }); |
| 196 | 295 | ||
| 197 | LabelName = pl::user(UnicodeName, [](const item_t& item) { | ||
| 198 | State* st = reinterpret_cast<State*>(item.user_data); | ||
| 199 | for (auto it = item.begin->m_it; it != item.end->m_it; ++it) { | ||
| 200 | if (*it > 255) { | ||
| 201 | st->buffer.clear(); | ||
| 202 | return true; | ||
| 203 | } | ||
| 204 | st->buffer += static_cast<char>(*it); | ||
| 205 | } | ||
| 206 | auto isValid = LuaKeywords.find(st->buffer) == LuaKeywords.end(); | ||
| 207 | st->buffer.clear(); | ||
| 208 | return isValid; | ||
| 209 | }); | ||
| 210 | |||
| 211 | LuaKeyword = pl::user(Name, [](const item_t& item) { | 296 | LuaKeyword = pl::user(Name, [](const item_t& item) { |
| 212 | State* st = reinterpret_cast<State*>(item.user_data); | 297 | State* st = reinterpret_cast<State*>(item.user_data); |
| 213 | for (auto it = item.begin->m_it; it != item.end->m_it; ++it) st->buffer += static_cast<char>(*it); | 298 | for (auto it = item.begin->m_it; it != item.end->m_it; ++it) st->buffer += static_cast<char>(*it); |
| @@ -223,29 +308,46 @@ YueParser::YueParser() { | |||
| 223 | 308 | ||
| 224 | SelfItem = SelfClassName | SelfClass | SelfName | Self; | 309 | SelfItem = SelfClassName | SelfClass | SelfName | Self; |
| 225 | KeyName = SelfItem | Name | UnicodeName; | 310 | KeyName = SelfItem | Name | UnicodeName; |
| 311 | VarArgDef = "..." >> -(space >> Variable); | ||
| 226 | VarArg = "..."; | 312 | VarArg = "..."; |
| 227 | 313 | ||
| 228 | check_indent = pl::user(plain_space, [](const item_t& item) { | 314 | auto getIndent = [](const item_t& item) -> int { |
| 315 | if (item.begin->m_it == item.end->m_it) return 0; | ||
| 316 | State* st = reinterpret_cast<State*>(item.user_data); | ||
| 317 | bool useTab = false; | ||
| 318 | if (st->useTab) { | ||
| 319 | useTab = st->useTab.value(); | ||
| 320 | } else { | ||
| 321 | useTab = *item.begin->m_it == '\t'; | ||
| 322 | st->useTab = useTab; | ||
| 323 | } | ||
| 229 | int indent = 0; | 324 | int indent = 0; |
| 230 | for (input_it i = item.begin->m_it; i != item.end->m_it; ++i) { | 325 | if (useTab) { |
| 231 | switch (*i) { | 326 | for (input_it i = item.begin->m_it; i != item.end->m_it; ++i) { |
| 232 | case ' ': indent++; break; | 327 | switch (*i) { |
| 233 | case '\t': indent += 4; break; | 328 | case '\t': indent += 4; break; |
| 329 | default: RaiseErrorI("can not mix the use of tabs and spaces as indents"sv, item); break; | ||
| 330 | } | ||
| 331 | } | ||
| 332 | } else { | ||
| 333 | for (input_it i = item.begin->m_it; i != item.end->m_it; ++i) { | ||
| 334 | switch (*i) { | ||
| 335 | case ' ': indent++; break; | ||
| 336 | default: RaiseErrorI("can not mix the use of tabs and spaces as indents"sv, item); break; | ||
| 337 | } | ||
| 234 | } | 338 | } |
| 235 | } | 339 | } |
| 340 | return indent; | ||
| 341 | }; | ||
| 342 | |||
| 343 | check_indent = pl::user(plain_space, [getIndent](const item_t& item) { | ||
| 236 | State* st = reinterpret_cast<State*>(item.user_data); | 344 | State* st = reinterpret_cast<State*>(item.user_data); |
| 237 | return st->indents.top() == indent; | 345 | return st->indents.top() == getIndent(item); |
| 238 | }); | 346 | }); |
| 239 | check_indent_match = and_(check_indent); | 347 | check_indent_match = and_(check_indent); |
| 240 | 348 | ||
| 241 | advance = pl::user(plain_space, [](const item_t& item) { | 349 | advance = pl::user(plain_space, [getIndent](const item_t& item) { |
| 242 | int indent = 0; | 350 | int indent = getIndent(item); |
| 243 | for (input_it i = item.begin->m_it; i != item.end->m_it; ++i) { | ||
| 244 | switch (*i) { | ||
| 245 | case ' ': indent++; break; | ||
| 246 | case '\t': indent += 4; break; | ||
| 247 | } | ||
| 248 | } | ||
| 249 | State* st = reinterpret_cast<State*>(item.user_data); | 351 | State* st = reinterpret_cast<State*>(item.user_data); |
| 250 | int top = st->indents.top(); | 352 | int top = st->indents.top(); |
| 251 | if (top != -1 && indent > top) { | 353 | if (top != -1 && indent > top) { |
| @@ -265,6 +367,12 @@ YueParser::YueParser() { | |||
| 265 | } | 367 | } |
| 266 | } | 368 | } |
| 267 | State* st = reinterpret_cast<State*>(item.user_data); | 369 | State* st = reinterpret_cast<State*>(item.user_data); |
| 370 | if (st->indents.empty()) { | ||
| 371 | RaiseError("unknown indent level"sv, item); | ||
| 372 | } | ||
| 373 | if (st->indents.top() > indent) { | ||
| 374 | RaiseError("unexpected dedent"sv, item); | ||
| 375 | } | ||
| 268 | st->indents.push(indent); | 376 | st->indents.push(indent); |
| 269 | return true; | 377 | return true; |
| 270 | }); | 378 | }); |
| @@ -285,31 +393,41 @@ YueParser::YueParser() { | |||
| 285 | in_block = space_break >> *(*set(" \t") >> line_break) >> advance_match >> ensure(Block, pop_indent); | 393 | in_block = space_break >> *(*set(" \t") >> line_break) >> advance_match >> ensure(Block, pop_indent); |
| 286 | 394 | ||
| 287 | LocalFlag = expr('*') | '^'; | 395 | LocalFlag = expr('*') | '^'; |
| 288 | LocalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpListLow)); | 396 | LocalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpListLow | expected_expression_error)); |
| 289 | Local = key("local") >> space >> (LocalFlag | LocalValues); | 397 | Local = key("local") >> space >> (LocalFlag | LocalValues | invalid_local_declaration_error); |
| 290 | 398 | ||
| 291 | ConstAttrib = key("const"); | 399 | ConstAttrib = key("const"); |
| 292 | CloseAttrib = key("close"); | 400 | CloseAttrib = key("close"); |
| 293 | local_const_item = Variable | SimpleTable | TableLit | Comprehension; | 401 | local_const_item = Variable | SimpleTable | TableLit | Comprehension; |
| 294 | LocalAttrib = ( | 402 | LocalAttrib = ( |
| 295 | ConstAttrib >> Seperator >> space >> local_const_item >> *(space >> ',' >> space >> local_const_item) | | 403 | ConstAttrib >> Seperator >> space >> local_const_item >> *(space >> ',' >> space >> local_const_item) | |
| 296 | CloseAttrib >> Seperator >> space >> Variable >> *(space >> ',' >> space >> Variable) | 404 | CloseAttrib >> Seperator >> space >> must_variable >> *(space >> ',' >> space >> must_variable) |
| 297 | ) >> space >> Assign; | 405 | ) >> space >> Assign; |
| 298 | 406 | ||
| 299 | ColonImportName = '\\' >> space >> Variable; | 407 | ColonImportName = '\\' >> must_variable; |
| 300 | import_name = ColonImportName | Variable; | 408 | import_name = not_(key("from")) >> (ColonImportName | must_variable); |
| 301 | import_name_list = Seperator >> *space_break >> space >> import_name >> *((+space_break | space >> ',' >> *space_break) >> space >> import_name); | 409 | import_name_list = Seperator >> *space_break >> space >> import_name >> *( |
| 302 | ImportFrom = import_name_list >> *space_break >> space >> key("from") >> space >> (ImportLiteral | not_(String) >> Exp); | 410 | (+space_break | space >> ',' >> *space_break) >> space >> import_name |
| 303 | from_import_name_list_line = import_name >> *(space >> ',' >> space >> import_name); | 411 | ); |
| 412 | ImportFrom = import_name_list >> *space_break >> space >> key("from") >> space >> (ImportLiteral | not_(String) >> must_exp); | ||
| 413 | from_import_name_list_line = import_name >> *(space >> ',' >> space >> not_(line_break) >> import_name); | ||
| 304 | from_import_name_in_block = +space_break >> advance_match >> ensure(space >> from_import_name_list_line >> *(-(space >> ',') >> +space_break >> check_indent_match >> space >> from_import_name_list_line), pop_indent); | 414 | from_import_name_in_block = +space_break >> advance_match >> ensure(space >> from_import_name_list_line >> *(-(space >> ',') >> +space_break >> check_indent_match >> space >> from_import_name_list_line), pop_indent); |
| 305 | FromImport = key("from") >> space >> (ImportLiteral | not_(String) >> Exp) >> *space_break >> space >> key("import") >> space >> Seperator >> (from_import_name_list_line >> -(space >> ',') >> -from_import_name_in_block | from_import_name_in_block); | 415 | FromImport = key("from") >> space >> ( |
| 416 | ImportLiteral | not_(String) >> Exp | invalid_from_import_error | ||
| 417 | ) >> *space_break >> space >> ( | ||
| 418 | key("import") | invalid_from_import_error | ||
| 419 | ) >> space >> Seperator >> ( | ||
| 420 | from_import_name_in_block | | ||
| 421 | from_import_name_list_line >> -(space >> ',') >> -from_import_name_in_block | | ||
| 422 | invalid_from_import_error | ||
| 423 | ); | ||
| 306 | 424 | ||
| 307 | ImportLiteralInner = (range('a', 'z') | range('A', 'Z') | set("_-") | larger(255)) >> *(alpha_num | '-' | larger(255)); | 425 | ImportLiteralInner = (range('a', 'z') | range('A', 'Z') | set("_-") | larger(255)) >> *(alpha_num | '-' | larger(255)); |
| 308 | import_literal_chain = Seperator >> ImportLiteralInner >> *('.' >> ImportLiteralInner); | 426 | import_literal_chain = Seperator >> ImportLiteralInner >> *('.' >> ImportLiteralInner); |
| 309 | ImportLiteral = ( | 427 | ImportLiteral = ( |
| 310 | '\'' >> import_literal_chain >> '\'' | 428 | '\'' >> import_literal_chain >> -(not_('\'') >> invalid_import_literal_error) >> '\'' |
| 311 | ) | ( | 429 | ) | ( |
| 312 | '"' >> import_literal_chain >> '"' | 430 | '"' >> import_literal_chain >> -(not_('"') >> invalid_import_literal_error) >> '"' |
| 313 | ); | 431 | ); |
| 314 | 432 | ||
| 315 | MacroNamePair = MacroName >> ':' >> space >> MacroName; | 433 | MacroNamePair = MacroName >> ':' >> space >> MacroName; |
| @@ -325,7 +443,7 @@ YueParser::YueParser() { | |||
| 325 | Exp; | 443 | Exp; |
| 326 | import_tab_list = import_tab_item >> *(space >> ',' >> space >> import_tab_item); | 444 | import_tab_list = import_tab_item >> *(space >> ',' >> space >> import_tab_item); |
| 327 | import_tab_line = ( | 445 | import_tab_line = ( |
| 328 | push_indent_match >> (space >> import_tab_list >> pop_indent | pop_indent) | 446 | push_indent_match >> ensure(space >> import_tab_list, pop_indent) |
| 329 | ) | space; | 447 | ) | space; |
| 330 | import_tab_lines = space_break >> import_tab_line >> *(-(space >> ',') >> space_break >> import_tab_line) >> -(space >> ','); | 448 | import_tab_lines = space_break >> import_tab_line >> *(-(space >> ',') >> space_break >> import_tab_line) >> -(space >> ','); |
| 331 | import_tab_key_value = key_value | ':' >> MacroName | MacroNamePair | ImportAllMacro; | 449 | import_tab_key_value = key_value | ':' >> MacroName | MacroNamePair | ImportAllMacro; |
| @@ -335,18 +453,22 @@ YueParser::YueParser() { | |||
| 335 | -(space >> ',') >> | 453 | -(space >> ',') >> |
| 336 | -import_tab_lines >> | 454 | -import_tab_lines >> |
| 337 | white >> | 455 | white >> |
| 338 | '}' | 456 | end_braces_expression |
| 339 | ) | ( | 457 | ) | ( |
| 340 | Seperator >> import_tab_key_value >> *(space >> ',' >> space >> import_tab_key_value) | 458 | Seperator >> import_tab_key_value >> *(space >> ',' >> space >> import_tab_key_value) |
| 341 | ); | 459 | ); |
| 342 | 460 | ||
| 343 | ImportAs = ImportLiteral >> -(space >> key("as") >> space >> (ImportTabLit | Variable | ImportAllMacro)); | 461 | ImportAs = ImportLiteral >> -(space >> key("as") >> space >> ( |
| 462 | ImportTabLit | Variable | ImportAllMacro | invalid_import_as_syntax_error | ||
| 463 | )); | ||
| 464 | |||
| 465 | ImportGlobal = Seperator >> UnicodeName >> *('.' >> UnicodeName) >> space >> not_(',' | key("from")) >> -(key("as") >> space >> must_variable); | ||
| 344 | 466 | ||
| 345 | Import = key("import") >> space >> (ImportAs | ImportFrom) | FromImport; | 467 | Import = key("import") >> space >> (ImportGlobal | ImportAs | ImportFrom | invalid_import_syntax_error) | FromImport; |
| 346 | 468 | ||
| 347 | Label = "::" >> LabelName >> "::"; | 469 | Label = "::" >> (and_(LuaKeyword >> "::") >> keyword_as_label_error | UnicodeName >> "::"); |
| 348 | 470 | ||
| 349 | Goto = key("goto") >> space >> LabelName; | 471 | Goto = key("goto") >> space >> (and_(LuaKeyword >> not_alpha_num) >> keyword_as_label_error | UnicodeName); |
| 350 | 472 | ||
| 351 | ShortTabAppending = "[]" >> space >> Assign; | 473 | ShortTabAppending = "[]" >> space >> Assign; |
| 352 | 474 | ||
| @@ -356,9 +478,14 @@ YueParser::YueParser() { | |||
| 356 | 478 | ||
| 357 | Return = key("return") >> -(space >> (TableBlock | ExpListLow)); | 479 | Return = key("return") >> -(space >> (TableBlock | ExpListLow)); |
| 358 | 480 | ||
| 359 | with_exp = ExpList >> -(space >> Assign); | 481 | must_exp = Exp | expected_expression_error; |
| 360 | 482 | ||
| 361 | With = key("with") >> -ExistentialOp >> space >> disable_do_chain_arg_table_block_rule(with_exp) >> space >> body_with("do"); | 483 | with_exp = ExpList >> -(space >> (':' >> Assign | and_('=') >> assignment_expression_syntax_error)) | expected_expression_error; |
| 484 | |||
| 485 | With = key("with") >> -ExistentialOp >> space >> ( | ||
| 486 | disable_do_chain_arg_table_block_rule(with_exp) >> space >> body_with("do") | | ||
| 487 | invalid_with_syntax_error | ||
| 488 | ); | ||
| 362 | SwitchCase = key("when") >> space >> disable_chain_rule(disable_arg_table_block_rule(SwitchList)) >> space >> body_with("then"); | 489 | SwitchCase = key("when") >> space >> disable_chain_rule(disable_arg_table_block_rule(SwitchList)) >> space >> body_with("then"); |
| 363 | switch_else = key("else") >> space >> body; | 490 | switch_else = key("else") >> space >> body; |
| 364 | 491 | ||
| @@ -370,9 +497,11 @@ YueParser::YueParser() { | |||
| 370 | 497 | ||
| 371 | SwitchList = Seperator >> ( | 498 | SwitchList = Seperator >> ( |
| 372 | and_(SimpleTable | TableLit) >> Exp | | 499 | and_(SimpleTable | TableLit) >> Exp | |
| 373 | exp_not_tab >> *(space >> ',' >> space >> exp_not_tab) | 500 | exp_not_tab >> *(space >> ',' >> space >> exp_not_tab) | |
| 501 | expected_expression_error | ||
| 374 | ); | 502 | ); |
| 375 | Switch = key("switch") >> space >> Exp >> | 503 | Switch = key("switch") >> space >> |
| 504 | must_exp >> -(space >> Assignment) >> | ||
| 376 | space >> Seperator >> ( | 505 | space >> Seperator >> ( |
| 377 | SwitchCase >> space >> ( | 506 | SwitchCase >> space >> ( |
| 378 | switch_block | | 507 | switch_block | |
| @@ -381,45 +510,53 @@ YueParser::YueParser() { | |||
| 381 | +space_break >> advance_match >> space >> SwitchCase >> switch_block >> pop_indent | 510 | +space_break >> advance_match >> space >> SwitchCase >> switch_block >> pop_indent |
| 382 | ); | 511 | ); |
| 383 | 512 | ||
| 384 | Assignment = -(',' >> space >> ExpList >> space) >> (':' >> Assign | and_('=') >> if_assignment_syntax_error); | 513 | Assignment = -(',' >> space >> ExpList >> space) >> (':' >> Assign | and_('=') >> assignment_expression_syntax_error); |
| 385 | IfCond = disable_chain_rule(disable_arg_table_block_rule(Exp >> -(space >> Assignment))); | 514 | IfCond = disable_chain_rule(disable_arg_table_block_rule(Exp >> -(space >> Assignment))) | expected_expression_error; |
| 386 | if_else_if = -(line_break >> *space_break >> check_indent_match) >> space >> key("elseif") >> space >> IfCond >> space >> body_with("then"); | 515 | if_else_if = -(line_break >> *space_break >> check_indent_match) >> space >> key("elseif") >> space >> IfCond >> space >> body_with("then"); |
| 387 | if_else = -(line_break >> *space_break >> check_indent_match) >> space >> key("else") >> space >> body; | 516 | if_else = -(line_break >> *space_break >> check_indent_match) >> space >> key("else") >> space >> body; |
| 388 | IfType = (expr("if") | "unless") >> not_alpha_num; | 517 | IfType = (expr("if") | "unless") >> not_alpha_num; |
| 389 | If = IfType >> space >> IfCond >> space >> opt_body_with("then") >> *if_else_if >> -if_else; | 518 | If = IfType >> space >> IfCond >> space >> opt_body_with("then") >> *if_else_if >> -if_else; |
| 390 | 519 | ||
| 391 | WhileType = (expr("while") | "until") >> not_alpha_num; | 520 | WhileType = (expr("while") | pl::user("until", [](const item_t& item) { |
| 392 | While = WhileType >> space >> disable_do_chain_arg_table_block_rule(Exp >> -(space >> Assignment)) >> space >> opt_body_with("do"); | 521 | State* st = reinterpret_cast<State*>(item.user_data); |
| 393 | Repeat = key("repeat") >> space >> Body >> line_break >> *space_break >> check_indent_match >> space >> key("until") >> space >> Exp; | 522 | return st->noUntilStack.empty() || !st->noUntilStack.back(); |
| 523 | })) >> not_alpha_num; | ||
| 524 | While = key(WhileType) >> space >> (disable_do_chain_arg_table_block_rule(Exp >> -(space >> Assignment)) | expected_expression_error) >> space >> opt_body_with("do"); | ||
| 525 | Repeat = key("repeat") >> space >> ( | ||
| 526 | in_block >> line_break >> *space_break >> check_indent_match | | ||
| 527 | disable_until_rule(Statement) | ||
| 528 | ) >> space >> key("until") >> space >> must_exp; | ||
| 394 | 529 | ||
| 395 | for_key = pl::user(key("for"), [](const item_t& item) { | 530 | for_key = pl::user(key("for"), [](const item_t& item) { |
| 396 | State* st = reinterpret_cast<State*>(item.user_data); | 531 | State* st = reinterpret_cast<State*>(item.user_data); |
| 397 | return st->noForStack.empty() || !st->noForStack.top(); | 532 | return st->noForStack.empty() || !st->noForStack.back(); |
| 398 | }); | 533 | }); |
| 399 | ForStepValue = ',' >> space >> Exp; | 534 | ForStepValue = ',' >> space >> must_exp; |
| 400 | for_args = Variable >> space >> '=' >> space >> Exp >> space >> ',' >> space >> Exp >> space >> -ForStepValue; | 535 | for_args = Variable >> space >> '=' >> space >> must_exp >> space >> ',' >> space >> must_exp >> space >> -ForStepValue; |
| 401 | 536 | ||
| 402 | For = for_key >> space >> disable_do_chain_arg_table_block_rule(for_args) >> space >> opt_body_with("do"); | 537 | ForNum = disable_do_chain_arg_table_block_rule(for_args) >> space >> opt_body_with("do"); |
| 403 | 538 | ||
| 404 | for_in = StarExp | ExpList; | 539 | for_in = StarExp | ExpList | expected_expression_error; |
| 405 | 540 | ||
| 406 | ForEach = for_key >> space >> AssignableNameList >> space >> key("in") >> space >> | 541 | ForEach = AssignableNameList >> space >> key("in") >> space >> |
| 407 | disable_do_chain_arg_table_block_rule(for_in) >> space >> opt_body_with("do"); | 542 | disable_do_chain_arg_table_block_rule(for_in) >> space >> opt_body_with("do"); |
| 408 | 543 | ||
| 544 | For = for_key >> space >> (ForNum | ForEach); | ||
| 545 | |||
| 409 | Do = pl::user(key("do"), [](const item_t& item) { | 546 | Do = pl::user(key("do"), [](const item_t& item) { |
| 410 | State* st = reinterpret_cast<State*>(item.user_data); | 547 | State* st = reinterpret_cast<State*>(item.user_data); |
| 411 | return st->noDoStack.empty() || !st->noDoStack.top(); | 548 | return st->noDoStack.empty() || !st->noDoStack.back(); |
| 412 | }) >> space >> Body; | 549 | }) >> space >> Body; |
| 413 | 550 | ||
| 414 | disable_do = pl::user(true_(), [](const item_t& item) { | 551 | disable_do = pl::user(true_(), [](const item_t& item) { |
| 415 | State* st = reinterpret_cast<State*>(item.user_data); | 552 | State* st = reinterpret_cast<State*>(item.user_data); |
| 416 | st->noDoStack.push(true); | 553 | st->noDoStack.push_back(true); |
| 417 | return true; | 554 | return true; |
| 418 | }); | 555 | }); |
| 419 | 556 | ||
| 420 | enable_do = pl::user(true_(), [](const item_t& item) { | 557 | enable_do = pl::user(true_(), [](const item_t& item) { |
| 421 | State* st = reinterpret_cast<State*>(item.user_data); | 558 | State* st = reinterpret_cast<State*>(item.user_data); |
| 422 | st->noDoStack.pop(); | 559 | st->noDoStack.pop_back(); |
| 423 | return true; | 560 | return true; |
| 424 | }); | 561 | }); |
| 425 | 562 | ||
| @@ -437,46 +574,58 @@ YueParser::YueParser() { | |||
| 437 | 574 | ||
| 438 | disable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) { | 575 | disable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) { |
| 439 | State* st = reinterpret_cast<State*>(item.user_data); | 576 | State* st = reinterpret_cast<State*>(item.user_data); |
| 440 | st->noDoStack.push(true); | 577 | st->noDoStack.push_back(true); |
| 441 | st->noChainBlockStack.push(true); | 578 | st->noChainBlockStack.push_back(true); |
| 442 | st->noTableBlockStack.push(true); | 579 | st->noTableBlockStack.push_back(true); |
| 443 | return true; | 580 | return true; |
| 444 | }); | 581 | }); |
| 445 | 582 | ||
| 446 | enable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) { | 583 | enable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) { |
| 447 | State* st = reinterpret_cast<State*>(item.user_data); | 584 | State* st = reinterpret_cast<State*>(item.user_data); |
| 448 | st->noDoStack.pop(); | 585 | st->noDoStack.pop_back(); |
| 449 | st->noChainBlockStack.pop(); | 586 | st->noChainBlockStack.pop_back(); |
| 450 | st->noTableBlockStack.pop(); | 587 | st->noTableBlockStack.pop_back(); |
| 451 | return true; | 588 | return true; |
| 452 | }); | 589 | }); |
| 453 | 590 | ||
| 454 | disable_arg_table_block = pl::user(true_(), [](const item_t& item) { | 591 | disable_arg_table_block = pl::user(true_(), [](const item_t& item) { |
| 455 | State* st = reinterpret_cast<State*>(item.user_data); | 592 | State* st = reinterpret_cast<State*>(item.user_data); |
| 456 | st->noTableBlockStack.push(true); | 593 | st->noTableBlockStack.push_back(true); |
| 457 | return true; | 594 | return true; |
| 458 | }); | 595 | }); |
| 459 | 596 | ||
| 460 | enable_arg_table_block = pl::user(true_(), [](const item_t& item) { | 597 | enable_arg_table_block = pl::user(true_(), [](const item_t& item) { |
| 461 | State* st = reinterpret_cast<State*>(item.user_data); | 598 | State* st = reinterpret_cast<State*>(item.user_data); |
| 462 | st->noTableBlockStack.pop(); | 599 | st->noTableBlockStack.pop_back(); |
| 463 | return true; | 600 | return true; |
| 464 | }); | 601 | }); |
| 465 | 602 | ||
| 466 | disable_for = pl::user(true_(), [](const item_t& item) { | 603 | disable_for = pl::user(true_(), [](const item_t& item) { |
| 467 | State* st = reinterpret_cast<State*>(item.user_data); | 604 | State* st = reinterpret_cast<State*>(item.user_data); |
| 468 | st->noForStack.push(true); | 605 | st->noForStack.push_back(true); |
| 469 | return true; | 606 | return true; |
| 470 | }); | 607 | }); |
| 471 | 608 | ||
| 472 | enable_for = pl::user(true_(), [](const item_t& item) { | 609 | enable_for = pl::user(true_(), [](const item_t& item) { |
| 473 | State* st = reinterpret_cast<State*>(item.user_data); | 610 | State* st = reinterpret_cast<State*>(item.user_data); |
| 474 | st->noForStack.pop(); | 611 | st->noForStack.pop_back(); |
| 475 | return true; | 612 | return true; |
| 476 | }); | 613 | }); |
| 477 | 614 | ||
| 478 | CatchBlock = line_break >> *space_break >> check_indent_match >> space >> key("catch") >> space >> Variable >> space >> in_block; | 615 | disable_until = pl::user(true_(), [](const item_t& item) { |
| 479 | Try = key("try") >> space >> (in_block | Exp) >> -CatchBlock; | 616 | State* st = reinterpret_cast<State*>(item.user_data); |
| 617 | st->noUntilStack.push_back(true); | ||
| 618 | return true; | ||
| 619 | }); | ||
| 620 | |||
| 621 | enable_until = pl::user(true_(), [](const item_t& item) { | ||
| 622 | State* st = reinterpret_cast<State*>(item.user_data); | ||
| 623 | st->noUntilStack.pop_back(); | ||
| 624 | return true; | ||
| 625 | }); | ||
| 626 | |||
| 627 | CatchBlock = line_break >> *space_break >> check_indent_match >> space >> key("catch") >> space >> must_variable >> space >> (in_block | invalid_try_syntax_error); | ||
| 628 | Try = key("try") >> -ExistentialOp >> space >> (in_block | Exp | invalid_try_syntax_error) >> -CatchBlock; | ||
| 480 | 629 | ||
| 481 | list_value = | 630 | list_value = |
| 482 | and_( | 631 | and_( |
| @@ -498,28 +647,33 @@ YueParser::YueParser() { | |||
| 498 | 647 | ||
| 499 | list_lit_lines = +space_break >> list_lit_line >> *(-(space >> ',') >> space_break >> list_lit_line) >> -(space >> ','); | 648 | list_lit_lines = +space_break >> list_lit_line >> *(-(space >> ',') >> space_break >> list_lit_line) >> -(space >> ','); |
| 500 | 649 | ||
| 650 | end_brackets_expression = ']' | brackets_expression_error; | ||
| 651 | |||
| 501 | Comprehension = '[' >> not_('[') >> | 652 | Comprehension = '[' >> not_('[') >> |
| 502 | Seperator >> space >> ( | 653 | Seperator >> space >> ( |
| 503 | disable_for_rule(list_value) >> space >> ( | 654 | disable_for_rule(list_value) >> space >> ( |
| 504 | CompInner >> space >> ']' | | 655 | CompFor >> space >> end_brackets_expression | |
| 505 | (list_value_list >> -(space >> ',') | space >> ',') >> -list_lit_lines >> white >> ']' | 656 | (list_value_list >> -(space >> ',') | space >> ',') >> -list_lit_lines >> white >> end_brackets_expression |
| 506 | ) | | 657 | ) | |
| 507 | list_lit_lines >> white >> ']' | | 658 | list_lit_lines >> white >> end_brackets_expression | |
| 508 | white >> ']' >> not_(space >> '=') | 659 | white >> ']' >> not_(space >> '=') |
| 509 | ); | 660 | ); |
| 510 | 661 | ||
| 511 | CompValue = ',' >> space >> Exp; | 662 | end_braces_expression = '}' | braces_expression_error; |
| 512 | TblComprehension = and_('{') >> ('{' >> space >> disable_for_rule(Exp >> space >> -(CompValue >> space)) >> CompInner >> space >> '}' | braces_expression_error); | ||
| 513 | 663 | ||
| 514 | CompInner = Seperator >> (CompForEach | CompFor) >> *(space >> comp_clause); | 664 | CompValue = ',' >> space >> must_exp; |
| 515 | StarExp = '*' >> space >> Exp; | 665 | TblComprehension = '{' >> space >> disable_for_rule(Exp >> space >> -(CompValue >> space)) >> (CompFor | braces_expression_error) >> space >> end_braces_expression; |
| 516 | CompForEach = key("for") >> space >> AssignableNameList >> space >> key("in") >> space >> (StarExp | Exp); | 666 | |
| 517 | CompFor = key("for") >> space >> Variable >> space >> '=' >> space >> Exp >> space >> ',' >> space >> Exp >> -ForStepValue; | 667 | CompFor = key("for") >> space >> Seperator >> (CompForNum | CompForEach) >> *(space >> comp_clause); |
| 518 | comp_clause = CompFor | CompForEach | key("when") >> space >> Exp; | 668 | StarExp = '*' >> space >> must_exp; |
| 669 | CompForEach = AssignableNameList >> space >> key("in") >> space >> (StarExp | must_exp); | ||
| 670 | CompForNum = Variable >> space >> '=' >> space >> must_exp >> space >> ',' >> space >> must_exp >> -ForStepValue; | ||
| 671 | comp_clause = key("when") >> space >> must_exp | key("for") >> space >> (CompForNum | CompForEach); | ||
| 519 | 672 | ||
| 520 | Assign = '=' >> space >> Seperator >> ( | 673 | Assign = '=' >> space >> Seperator >> ( |
| 521 | With | If | Switch | TableBlock | | 674 | With | If | Switch | TableBlock | |
| 522 | Exp >> *(space >> set(",;") >> space >> Exp) | 675 | (SpreadListExp | Exp) >> *(space >> set(",;") >> space >> (SpreadListExp | Exp)) | |
| 676 | expected_expression_error | ||
| 523 | ); | 677 | ); |
| 524 | 678 | ||
| 525 | UpdateOp = | 679 | UpdateOp = |
| @@ -527,7 +681,7 @@ YueParser::YueParser() { | |||
| 527 | ">>" | "<<" | "??" | | 681 | ">>" | "<<" | "??" | |
| 528 | set("+-*/%&|^"); | 682 | set("+-*/%&|^"); |
| 529 | 683 | ||
| 530 | Update = UpdateOp >> '=' >> space >> Exp; | 684 | Update = UpdateOp >> '=' >> space >> must_exp; |
| 531 | 685 | ||
| 532 | Assignable = AssignableChain | Variable | SelfItem; | 686 | Assignable = AssignableChain | Variable | SelfItem; |
| 533 | 687 | ||
| @@ -548,35 +702,38 @@ YueParser::YueParser() { | |||
| 548 | UnaryExp = *(UnaryOperator >> space) >> expo_exp >> -(space >> In); | 702 | UnaryExp = *(UnaryOperator >> space) >> expo_exp >> -(space >> In); |
| 549 | 703 | ||
| 550 | pipe_operator = "|>"; | 704 | pipe_operator = "|>"; |
| 551 | pipe_value = pipe_operator >> *space_break >> space >> UnaryExp; | 705 | pipe_value = pipe_operator >> *space_break >> space >> must_unary_exp; |
| 552 | pipe_exp = UnaryExp >> *(space >> pipe_value); | 706 | pipe_exp = UnaryExp >> *(space >> pipe_value); |
| 553 | 707 | ||
| 554 | BinaryOperator = | 708 | BinaryOperator = ( |
| 555 | key("or") | | 709 | key("or") | |
| 556 | key("and") | | 710 | key("and") | |
| 557 | "<=" | ">=" | "~=" | "!=" | "==" | | 711 | "<=" | ">=" | "~=" | "!=" | "==" | |
| 558 | ".." | "<<" | ">>" | "//" | | 712 | ".." | "<<" | ">>" | "//" | |
| 559 | set("+-*/%><|&~"); | 713 | set("+*/%>|&~") | |
| 714 | '-' >> not_('>') | | ||
| 715 | '<' >> not_('-') | ||
| 716 | ) >> not_('='); | ||
| 560 | 717 | ||
| 561 | ExpOpValue = BinaryOperator >> *space_break >> space >> pipe_exp; | 718 | ExpOpValue = BinaryOperator >> *space_break >> space >> (pipe_exp | expected_expression_error); |
| 562 | Exp = Seperator >> pipe_exp >> *(space >> ExpOpValue) >> -(space >> "??" >> space >> Exp); | 719 | Exp = Seperator >> pipe_exp >> *(space >> ExpOpValue) >> -(space >> "??" >> not_('=') >> *space_break >> space >> must_exp); |
| 563 | 720 | ||
| 564 | disable_chain = pl::user(true_(), [](const item_t& item) { | 721 | disable_chain = pl::user(true_(), [](const item_t& item) { |
| 565 | State* st = reinterpret_cast<State*>(item.user_data); | 722 | State* st = reinterpret_cast<State*>(item.user_data); |
| 566 | st->noChainBlockStack.push(true); | 723 | st->noChainBlockStack.push_back(true); |
| 567 | return true; | 724 | return true; |
| 568 | }); | 725 | }); |
| 569 | 726 | ||
| 570 | enable_chain = pl::user(true_(), [](const item_t& item) { | 727 | enable_chain = pl::user(true_(), [](const item_t& item) { |
| 571 | State* st = reinterpret_cast<State*>(item.user_data); | 728 | State* st = reinterpret_cast<State*>(item.user_data); |
| 572 | st->noChainBlockStack.pop(); | 729 | st->noChainBlockStack.pop_back(); |
| 573 | return true; | 730 | return true; |
| 574 | }); | 731 | }); |
| 575 | 732 | ||
| 576 | chain_line = check_indent_match >> space >> (chain_dot_chain | colon_chain) >> -InvokeArgs; | 733 | chain_line = check_indent_match >> space >> (chain_dot_chain | colon_chain) >> -InvokeArgs; |
| 577 | chain_block = pl::user(true_(), [](const item_t& item) { | 734 | chain_block = pl::user(true_(), [](const item_t& item) { |
| 578 | State* st = reinterpret_cast<State*>(item.user_data); | 735 | State* st = reinterpret_cast<State*>(item.user_data); |
| 579 | return st->noChainBlockStack.empty() || !st->noChainBlockStack.top(); | 736 | return st->noChainBlockStack.empty() || !st->noChainBlockStack.back(); |
| 580 | }) >> +space_break >> advance_match >> ensure( | 737 | }) >> +space_break >> advance_match >> ensure( |
| 581 | chain_line >> *(+space_break >> chain_line), pop_indent); | 738 | chain_line >> *(+space_break >> chain_line), pop_indent); |
| 582 | ChainValue = | 739 | ChainValue = |
| @@ -591,7 +748,7 @@ YueParser::YueParser() { | |||
| 591 | st->expLevel++; | 748 | st->expLevel++; |
| 592 | const int max_exp_level = 100; | 749 | const int max_exp_level = 100; |
| 593 | if (st->expLevel > max_exp_level) { | 750 | if (st->expLevel > max_exp_level) { |
| 594 | throw ParserError("nesting expressions exceeds 100 levels"sv, item.begin); | 751 | RaiseError("nesting expressions exceeds 100 levels"sv, item); |
| 595 | } | 752 | } |
| 596 | return true; | 753 | return true; |
| 597 | }); | 754 | }); |
| @@ -606,14 +763,22 @@ YueParser::YueParser() { | |||
| 606 | Value = inc_exp_level >> ensure(SimpleValue | SimpleTable | ChainValue | String, dec_exp_level); | 763 | Value = inc_exp_level >> ensure(SimpleValue | SimpleTable | ChainValue | String, dec_exp_level); |
| 607 | 764 | ||
| 608 | single_string_inner = '\\' >> set("'\\") | not_('\'') >> any_char; | 765 | single_string_inner = '\\' >> set("'\\") | not_('\'') >> any_char; |
| 609 | SingleString = '\'' >> *single_string_inner >> '\''; | 766 | SingleString = '\'' >> *single_string_inner >> ('\'' | unclosed_single_string_error); |
| 610 | 767 | ||
| 611 | interp = "#{" >> space >> (Exp >> space >> '}' | invalid_interpolation_error); | 768 | interp = "#{" >> space >> (Exp >> space >> '}' | invalid_interpolation_error); |
| 612 | double_string_plain = '\\' >> set("\"\\#") | not_('"') >> any_char; | 769 | double_string_plain = '\\' >> set("\"\\#") | not_('"') >> any_char; |
| 613 | DoubleStringInner = +(not_("#{") >> double_string_plain); | 770 | DoubleStringInner = +(not_("#{") >> double_string_plain); |
| 614 | DoubleStringContent = DoubleStringInner | interp; | 771 | DoubleStringContent = DoubleStringInner | interp; |
| 615 | DoubleString = '"' >> Seperator >> *DoubleStringContent >> '"'; | 772 | DoubleString = '"' >> Seperator >> *DoubleStringContent >> ('"' | unclosed_double_string_error); |
| 616 | String = DoubleString | SingleString | LuaString; | 773 | |
| 774 | YAMLIndent = +set(" \t"); | ||
| 775 | YAMLLineInner = +('\\' >> set("\"\\#") | not_("#{" | stop) >> any_char); | ||
| 776 | YAMLLineContent = YAMLLineInner | interp; | ||
| 777 | YAMLLine = check_indent_match >> YAMLIndent >> +(YAMLLineContent) | | ||
| 778 | advance_match >> YAMLIndent >> ensure(+YAMLLineContent, pop_indent); | ||
| 779 | YAMLMultiline = '|' >> space >> Seperator >> +(*set(" \t") >> line_break) >> advance_match >> ensure(YAMLLine >> *(+(*set(" \t") >> line_break) >> YAMLLine), pop_indent); | ||
| 780 | |||
| 781 | String = DoubleString | SingleString | LuaString | YAMLMultiline; | ||
| 617 | 782 | ||
| 618 | lua_string_open = '[' >> *expr('=') >> '['; | 783 | lua_string_open = '[' >> *expr('=') >> '['; |
| 619 | lua_string_close = ']' >> *expr('=') >> ']'; | 784 | lua_string_close = ']' >> *expr('=') >> ']'; |
| @@ -633,15 +798,15 @@ YueParser::YueParser() { | |||
| 633 | 798 | ||
| 634 | LuaStringContent = *(not_(LuaStringClose) >> any_char); | 799 | LuaStringContent = *(not_(LuaStringClose) >> any_char); |
| 635 | 800 | ||
| 636 | LuaString = LuaStringOpen >> -line_break >> LuaStringContent >> LuaStringClose; | 801 | LuaString = LuaStringOpen >> -line_break >> LuaStringContent >> (LuaStringClose | unclosed_lua_string_error); |
| 637 | 802 | ||
| 638 | Parens = '(' >> *space_break >> space >> Exp >> *space_break >> space >> ')'; | 803 | Parens = '(' >> (*space_break >> space >> Exp >> *space_break >> space >> ')' | parenthesis_error); |
| 639 | Callable = Variable | SelfItem | MacroName | Parens; | 804 | Callable = Variable | SelfItem | MacroName | Parens; |
| 640 | 805 | ||
| 641 | fn_args_value_list = Exp >> *(space >> ',' >> space >> Exp); | 806 | fn_args_value_list = Exp >> *(space >> ',' >> space >> Exp); |
| 642 | 807 | ||
| 643 | fn_args_lit_line = ( | 808 | fn_args_lit_line = ( |
| 644 | push_indent_match >> (space >> fn_args_value_list >> pop_indent | pop_indent) | 809 | push_indent_match >> ensure(space >> fn_args_value_list, pop_indent) |
| 645 | ) | ( | 810 | ) | ( |
| 646 | space | 811 | space |
| 647 | ); | 812 | ); |
| @@ -651,14 +816,14 @@ YueParser::YueParser() { | |||
| 651 | fn_args = | 816 | fn_args = |
| 652 | '(' >> -(space >> fn_args_value_list >> -(space >> ',')) >> | 817 | '(' >> -(space >> fn_args_value_list >> -(space >> ',')) >> |
| 653 | -fn_args_lit_lines >> | 818 | -fn_args_lit_lines >> |
| 654 | white >> ')' | space >> '!' >> not_('='); | 819 | white >> -(and_(',') >> unexpected_comma_error) >>')' | space >> '!' >> not_('='); |
| 655 | 820 | ||
| 656 | meta_index = Name | index | String; | 821 | meta_index = Name | index | String; |
| 657 | Metatable = '<' >> space >> '>'; | 822 | Metatable = '<' >> space >> '>'; |
| 658 | Metamethod = '<' >> space >> meta_index >> space >> '>'; | 823 | Metamethod = '<' >> space >> meta_index >> space >> '>'; |
| 659 | 824 | ||
| 660 | ExistentialOp = '?' >> not_('?'); | 825 | ExistentialOp = '?' >> not_('?'); |
| 661 | TableAppendingOp = and_('[') >> ("[]" | brackets_expression_error); | 826 | TableAppendingOp = and_('[') >> "[]"; |
| 662 | PlainItem = +any_char; | 827 | PlainItem = +any_char; |
| 663 | 828 | ||
| 664 | chain_call = ( | 829 | chain_call = ( |
| @@ -683,7 +848,8 @@ YueParser::YueParser() { | |||
| 683 | chain_with_colon = +chain_item >> -colon_chain; | 848 | chain_with_colon = +chain_item >> -colon_chain; |
| 684 | chain_items = chain_with_colon | colon_chain; | 849 | chain_items = chain_with_colon | colon_chain; |
| 685 | 850 | ||
| 686 | index = '[' >> not_('[') >> space >> Exp >> space >> ']'; | 851 | index = '[' >> not_('[') >> space >> (ReversedIndex >> and_(space >> ']') | Exp) >> space >> ']'; |
| 852 | ReversedIndex = '#' >> space >> -('-' >> space >> Exp); | ||
| 687 | chain_item = | 853 | chain_item = |
| 688 | Invoke >> -ExistentialOp | | 854 | Invoke >> -ExistentialOp | |
| 689 | DotChainItem >> -ExistentialOp | | 855 | DotChainItem >> -ExistentialOp | |
| @@ -722,10 +888,8 @@ YueParser::YueParser() { | |||
| 722 | SpreadExp | | 888 | SpreadExp | |
| 723 | NormalDef; | 889 | NormalDef; |
| 724 | 890 | ||
| 725 | table_value_list = table_value >> *(space >> ',' >> space >> table_value); | ||
| 726 | |||
| 727 | table_lit_line = ( | 891 | table_lit_line = ( |
| 728 | push_indent_match >> (space >> table_value_list >> pop_indent | pop_indent) | 892 | push_indent_match >> (space >> not_(line_break | '}') >> (table_value | expected_expression_error) >> *(space >> ',' >> space >> table_value) >> pop_indent | pop_indent) |
| 729 | ) | ( | 893 | ) | ( |
| 730 | space | 894 | space |
| 731 | ); | 895 | ); |
| @@ -734,13 +898,15 @@ YueParser::YueParser() { | |||
| 734 | 898 | ||
| 735 | TableLit = | 899 | TableLit = |
| 736 | '{' >> Seperator >> | 900 | '{' >> Seperator >> |
| 737 | -(space >> table_value_list >> -(space >> ',')) >> | 901 | -(space >> table_value >> *(space >> ',' >> space >> table_value) >> -(space >> ',')) >> |
| 738 | -table_lit_lines >> | 902 | ( |
| 739 | white >> '}'; | 903 | table_lit_lines >> white >> end_braces_expression | |
| 904 | white >> '}' | ||
| 905 | ); | ||
| 740 | 906 | ||
| 741 | table_block_inner = Seperator >> key_value_line >> *(+space_break >> key_value_line); | 907 | table_block_inner = Seperator >> key_value_line >> *(+space_break >> key_value_line); |
| 742 | TableBlock = +space_break >> advance_match >> ensure(table_block_inner, pop_indent); | 908 | TableBlock = +space_break >> advance_match >> ensure(table_block_inner, pop_indent); |
| 743 | TableBlockIndent = '*' >> Seperator >> disable_arg_table_block_rule( | 909 | TableBlockIndent = ('*' | '-' >> space_one) >> Seperator >> disable_arg_table_block_rule( |
| 744 | space >> key_value_list >> -(space >> ',') >> | 910 | space >> key_value_list >> -(space >> ',') >> |
| 745 | -(+space_break >> advance_match >> space >> ensure(key_value_list >> -(space >> ',') >> *(+space_break >> key_value_line), pop_indent))); | 911 | -(+space_break >> advance_match >> space >> ensure(key_value_list >> -(space >> ',') >> *(+space_break >> key_value_line), pop_indent))); |
| 746 | 912 | ||
| @@ -755,13 +921,18 @@ YueParser::YueParser() { | |||
| 755 | ClassDecl = | 921 | ClassDecl = |
| 756 | key("class") >> not_(':') >> disable_arg_table_block_rule( | 922 | key("class") >> not_(':') >> disable_arg_table_block_rule( |
| 757 | -(space >> Assignable) >> | 923 | -(space >> Assignable) >> |
| 758 | -(space >> key("extends") >> prevent_indent >> space >> ensure(Exp, pop_indent)) >> | 924 | -(space >> key("extends") >> prevent_indent >> space >> ensure(must_exp, pop_indent)) >> |
| 759 | -(space >> key("using") >> prevent_indent >> space >> ensure(ExpList, pop_indent)) | 925 | -(space >> key("using") >> prevent_indent >> space >> ensure(ExpList | expected_expression_error, pop_indent)) |
| 760 | ) >> -ClassBlock; | 926 | ) >> -ClassBlock; |
| 761 | 927 | ||
| 762 | GlobalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpListLow)); | 928 | GlobalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpListLow | expected_expression_error)); |
| 763 | GlobalOp = expr('*') | '^'; | 929 | GlobalOp = expr('*') | '^'; |
| 764 | Global = key("global") >> space >> (-(ConstAttrib >> space) >> ClassDecl | GlobalOp | -(ConstAttrib >> space) >> GlobalValues); | 930 | Global = key("global") >> space >> ( |
| 931 | -(ConstAttrib >> space) >> ClassDecl | | ||
| 932 | GlobalOp | | ||
| 933 | -(ConstAttrib >> space) >> GlobalValues | | ||
| 934 | invalid_global_declaration_error | ||
| 935 | ); | ||
| 765 | 936 | ||
| 766 | ExportDefault = key("default"); | 937 | ExportDefault = key("default"); |
| 767 | 938 | ||
| @@ -773,10 +944,10 @@ YueParser::YueParser() { | |||
| 773 | pl::user(space >> ExportDefault >> space >> Exp, [](const item_t& item) { | 944 | pl::user(space >> ExportDefault >> space >> Exp, [](const item_t& item) { |
| 774 | State* st = reinterpret_cast<State*>(item.user_data); | 945 | State* st = reinterpret_cast<State*>(item.user_data); |
| 775 | if (st->exportDefault) { | 946 | if (st->exportDefault) { |
| 776 | throw ParserError("export default has already been declared"sv, item.begin); | 947 | RaiseError("export default has already been declared"sv, item); |
| 777 | } | 948 | } |
| 778 | if (st->exportCount > 1) { | 949 | if (st->exportCount > 1) { |
| 779 | throw ParserError("there are items already being exported"sv, item.begin); | 950 | RaiseError("there are items already being exported"sv, item); |
| 780 | } | 951 | } |
| 781 | st->exportDefault = true; | 952 | st->exportDefault = true; |
| 782 | return true; | 953 | return true; |
| @@ -784,17 +955,17 @@ YueParser::YueParser() { | |||
| 784 | not_(space >> ExportDefault) >> pl::user(true_(), [](const item_t& item) { | 955 | not_(space >> ExportDefault) >> pl::user(true_(), [](const item_t& item) { |
| 785 | State* st = reinterpret_cast<State*>(item.user_data); | 956 | State* st = reinterpret_cast<State*>(item.user_data); |
| 786 | if (st->exportDefault && st->exportCount > 1) { | 957 | if (st->exportDefault && st->exportCount > 1) { |
| 787 | throw ParserError("can not export any more items when 'export default' is declared"sv, item.begin); | 958 | RaiseError("can not export any more items when 'export default' is declared"sv, item); |
| 788 | } | 959 | } |
| 789 | return true; | 960 | return true; |
| 790 | }) >> ( | 961 | }) >> ( |
| 791 | and_(set(".[")) >> ((pl::user(and_('.' >> Metatable), [](const item_t& item) { | 962 | and_(set(".[")) >> ((pl::user(and_('.' >> Metatable), [](const item_t& item) { |
| 792 | State* st = reinterpret_cast<State*>(item.user_data); | 963 | State* st = reinterpret_cast<State*>(item.user_data); |
| 793 | if (st->exportMetatable) { | 964 | if (st->exportMetatable) { |
| 794 | throw ParserError("module metatable duplicated"sv, item.begin); | 965 | RaiseError("module metatable duplicated"sv, item); |
| 795 | } | 966 | } |
| 796 | if (st->exportMetamethod) { | 967 | if (st->exportMetamethod) { |
| 797 | throw ParserError("metatable should be exported before metamethod"sv, item.begin); | 968 | RaiseError("metatable should be exported before metamethod"sv, item); |
| 798 | } | 969 | } |
| 799 | st->exportMetatable = true; | 970 | st->exportMetatable = true; |
| 800 | return true; | 971 | return true; |
| @@ -809,7 +980,8 @@ YueParser::YueParser() { | |||
| 809 | State* st = reinterpret_cast<State*>(item.user_data); | 980 | State* st = reinterpret_cast<State*>(item.user_data); |
| 810 | st->exportMacro = true; | 981 | st->exportMacro = true; |
| 811 | return true; | 982 | return true; |
| 812 | }) | 983 | }) | |
| 984 | invalid_export_syntax_error | ||
| 813 | ) >> not_(space >> StatementAppendix); | 985 | ) >> not_(space >> StatementAppendix); |
| 814 | 986 | ||
| 815 | VariablePair = ':' >> Variable; | 987 | VariablePair = ':' >> Variable; |
| @@ -819,13 +991,13 @@ YueParser::YueParser() { | |||
| 819 | KeyName | | 991 | KeyName | |
| 820 | '[' >> not_('[') >> space >> Exp >> space >> ']' | | 992 | '[' >> not_('[') >> space >> Exp >> space >> ']' | |
| 821 | String | 993 | String |
| 822 | ) >> ':' >> not_(':') >> space >> | 994 | ) >> ':' >> not_(':' | '=' >> not_('>')) >> space >> |
| 823 | (Exp | TableBlock | +space_break >> space >> Exp); | 995 | (Exp | TableBlock | +space_break >> space >> Exp | expected_expression_error); |
| 824 | 996 | ||
| 825 | MetaVariablePair = ":<" >> space >> Variable >> space >> '>'; | 997 | MetaVariablePair = ":<" >> space >> must_variable >> space >> '>'; |
| 826 | 998 | ||
| 827 | MetaNormalPair = '<' >> space >> -meta_index >> space >> ">:" >> space >> | 999 | MetaNormalPair = '<' >> space >> -meta_index >> space >> ">:" >> space >> |
| 828 | (Exp | TableBlock | +space_break >> space >> Exp); | 1000 | (Exp | TableBlock | +space_break >> space >> Exp | expected_expression_error); |
| 829 | 1001 | ||
| 830 | destruct_def = -(space >> '=' >> space >> Exp); | 1002 | destruct_def = -(space >> '=' >> space >> Exp); |
| 831 | VariablePairDef = VariablePair >> destruct_def; | 1003 | VariablePairDef = VariablePair >> destruct_def; |
| @@ -843,29 +1015,39 @@ YueParser::YueParser() { | |||
| 843 | key_value_line = check_indent_match >> space >> ( | 1015 | key_value_line = check_indent_match >> space >> ( |
| 844 | key_value_list >> -(space >> ',') | | 1016 | key_value_list >> -(space >> ',') | |
| 845 | TableBlockIndent | | 1017 | TableBlockIndent | |
| 846 | '*' >> space >> (SpreadExp | Exp | TableBlock) | 1018 | ('*' | '-' >> space_one) >> space >> (SpreadExp | Exp | TableBlock) |
| 847 | ); | 1019 | ); |
| 848 | 1020 | ||
| 849 | fn_arg_def_list = FnArgDef >> *(space >> ',' >> space >> FnArgDef); | 1021 | fn_arg_def_list = FnArgDef >> *(space >> ',' >> space >> FnArgDef); |
| 850 | 1022 | ||
| 851 | fn_arg_def_lit_line = ( | 1023 | fn_arg_def_lit_line = ( |
| 852 | push_indent_match >> (space >> fn_arg_def_list >> pop_indent | pop_indent) | 1024 | push_indent_match >> ensure(space >> fn_arg_def_list, pop_indent) |
| 853 | ) | ( | 1025 | ) | ( |
| 854 | space | 1026 | space |
| 855 | ); | 1027 | ); |
| 856 | 1028 | ||
| 857 | fn_arg_def_lit_lines = fn_arg_def_lit_line >> *(-(space >> ',') >> space_break >> fn_arg_def_lit_line); | 1029 | fn_arg_def_lit_lines = fn_arg_def_lit_line >> *(-(space >> ',') >> space_break >> fn_arg_def_lit_line); |
| 858 | 1030 | ||
| 859 | FnArgDef = (Variable | SelfItem >> -ExistentialOp) >> -(space >> '=' >> space >> Exp); | 1031 | FnArgDef = (Variable | SelfItem >> -ExistentialOp) >> -(space >> '`' >> space >> Name) >> -(space >> '=' >> space >> Exp) | TableLit | SimpleTable; |
| 860 | 1032 | ||
| 861 | FnArgDefList = Seperator >> ( | 1033 | check_vararg_position = and_(white >> (')' | key("using"))) | white >> -(',' >> white) >> vararg_position_error; |
| 862 | fn_arg_def_lit_lines >> -(-(space >> ',') >> white >> VarArg) | | ||
| 863 | white >> VarArg | ||
| 864 | ); | ||
| 865 | 1034 | ||
| 866 | OuterVarShadow = key("using") >> space >> (NameList | key("nil")); | 1035 | var_arg_def = ( |
| 1036 | VarArgDef | | ||
| 1037 | +space_break >> push_indent_match >> ensure(space >> VarArgDef >> -(space >> '`' >> space >> Name), pop_indent) | ||
| 1038 | ) >> check_vararg_position; | ||
| 867 | 1039 | ||
| 868 | FnArgsDef = '(' >> *space_break >> -FnArgDefList >> -(white >> OuterVarShadow) >> white >> ')'; | 1040 | FnArgDefList = Seperator >> |
| 1041 | -fn_arg_def_list >> | ||
| 1042 | -(-(space >> ',') >> +space_break >> fn_arg_def_lit_lines) >> | ||
| 1043 | -(-(space >> ',') >> space >> var_arg_def); | ||
| 1044 | |||
| 1045 | OuterVarShadow = key("using") >> space >> (key("nil") | NameList); | ||
| 1046 | |||
| 1047 | outer_var_shadow_def = OuterVarShadow | | ||
| 1048 | +space_break >> push_indent_match >> ensure(space >> OuterVarShadow, pop_indent); | ||
| 1049 | |||
| 1050 | FnArgsDef = '(' >> space >> -FnArgDefList >> -(space >> outer_var_shadow_def) >> white >> -(and_(',') >> unexpected_comma_error) >> ')'; | ||
| 869 | FnArrow = expr("->") | "=>"; | 1051 | FnArrow = expr("->") | "=>"; |
| 870 | FunLit = pl::user(true_(), [](const item_t& item) { | 1052 | FunLit = pl::user(true_(), [](const item_t& item) { |
| 871 | State* st = reinterpret_cast<State*>(item.user_data); | 1053 | State* st = reinterpret_cast<State*>(item.user_data); |
| @@ -877,23 +1059,30 @@ YueParser::YueParser() { | |||
| 877 | ) >> space >> FnArrow >> -(space >> Body); | 1059 | ) >> space >> FnArrow >> -(space >> Body); |
| 878 | 1060 | ||
| 879 | MacroName = '$' >> UnicodeName; | 1061 | MacroName = '$' >> UnicodeName; |
| 880 | macro_args_def = '(' >> white >> -FnArgDefList >> white >> ')'; | 1062 | macro_args_def = '(' >> space >> -FnArgDefList >> white >> -(and_(',') >> unexpected_comma_error) >> ')'; |
| 881 | MacroLit = -(macro_args_def >> space) >> "->" >> space >> Body; | 1063 | MacroLit = -(macro_args_def >> space) >> "->" >> space >> Body; |
| 882 | MacroFunc = MacroName >> (Invoke | InvokeArgs); | 1064 | MacroFunc = MacroName >> (Invoke | InvokeArgs); |
| 883 | Macro = key("macro") >> space >> UnicodeName >> space >> '=' >> space >> (MacroLit | MacroFunc); | 1065 | Macro = key("macro") >> space >> ( |
| 1066 | UnicodeName >> space >> '=' >> space >> (MacroLit | MacroFunc | invalid_macro_definition_error) | | ||
| 1067 | invalid_macro_definition_error | ||
| 1068 | ); | ||
| 884 | MacroInPlace = '$' >> space >> "->" >> space >> Body; | 1069 | MacroInPlace = '$' >> space >> "->" >> space >> Body; |
| 885 | 1070 | ||
| 886 | NameList = Seperator >> Variable >> *(space >> ',' >> space >> Variable); | 1071 | must_variable = Variable | and_(LuaKeyword >> not_alpha_num) >> keyword_as_identifier_syntax_error | expected_indentifier_error; |
| 887 | NameOrDestructure = Variable | TableLit | Comprehension; | 1072 | |
| 1073 | NameList = Seperator >> must_variable >> *(space >> ',' >> space >> must_variable); | ||
| 1074 | NameOrDestructure = Variable | TableLit | Comprehension | SimpleTable | expected_expression_error; | ||
| 888 | AssignableNameList = Seperator >> NameOrDestructure >> *(space >> ',' >> space >> NameOrDestructure); | 1075 | AssignableNameList = Seperator >> NameOrDestructure >> *(space >> ',' >> space >> NameOrDestructure); |
| 889 | 1076 | ||
| 890 | FnArrowBack = '<' >> set("-="); | 1077 | FnArrowBack = '<' >> set("-="); |
| 891 | Backcall = -(FnArgsDef >> space) >> FnArrowBack >> space >> ChainValue; | 1078 | Backcall = -(FnArgsDef >> space) >> FnArrowBack >> space >> ChainValue; |
| 892 | SubBackcall = FnArrowBack >> space >> ChainValue; | 1079 | SubBackcall = FnArrowBack >> space >> ChainValue; |
| 893 | 1080 | ||
| 1081 | must_unary_exp = UnaryExp | expected_expression_error; | ||
| 1082 | |||
| 894 | PipeBody = Seperator >> | 1083 | PipeBody = Seperator >> |
| 895 | pipe_operator >> space >> UnaryExp >> | 1084 | pipe_operator >> space >> must_unary_exp >> |
| 896 | *(+space_break >> check_indent_match >> space >> pipe_operator >> space >> UnaryExp); | 1085 | *(+space_break >> check_indent_match >> space >> pipe_operator >> space >> must_unary_exp); |
| 897 | 1086 | ||
| 898 | ExpList = Seperator >> Exp >> *(space >> ',' >> space >> Exp); | 1087 | ExpList = Seperator >> Exp >> *(space >> ',' >> space >> Exp); |
| 899 | ExpListLow = Seperator >> Exp >> *(space >> set(",;") >> space >> Exp); | 1088 | ExpListLow = Seperator >> Exp >> *(space >> set(",;") >> space >> Exp); |
| @@ -903,7 +1092,7 @@ YueParser::YueParser() { | |||
| 903 | 1092 | ||
| 904 | arg_table_block = pl::user(true_(), [](const item_t& item) { | 1093 | arg_table_block = pl::user(true_(), [](const item_t& item) { |
| 905 | State* st = reinterpret_cast<State*>(item.user_data); | 1094 | State* st = reinterpret_cast<State*>(item.user_data); |
| 906 | return st->noTableBlockStack.empty() || !st->noTableBlockStack.top(); | 1095 | return st->noTableBlockStack.empty() || !st->noTableBlockStack.back(); |
| 907 | }) >> TableBlock; | 1096 | }) >> TableBlock; |
| 908 | 1097 | ||
| 909 | invoke_args_with_table = | 1098 | invoke_args_with_table = |
| @@ -912,38 +1101,17 @@ YueParser::YueParser() { | |||
| 912 | space_break >> advance_match >> arg_block >> -(-(space >> ',') >> arg_table_block) | 1101 | space_break >> advance_match >> arg_block >> -(-(space >> ',') >> arg_table_block) |
| 913 | ) | arg_table_block; | 1102 | ) | arg_table_block; |
| 914 | 1103 | ||
| 915 | leading_spaces_error = pl::user(+space_one >> '(' >> space >> Exp >> +(space >> ',' >> space >> Exp) >> space >> ')', [](const item_t& item) { | ||
| 916 | throw ParserError("write invoke arguments in parentheses without leading spaces or just leading spaces without parentheses"sv, item.begin); | ||
| 917 | return false; | ||
| 918 | }); | ||
| 919 | |||
| 920 | InvokeArgs = | 1104 | InvokeArgs = |
| 921 | not_(set("-~") | "[]") >> space >> Seperator >> ( | 1105 | not_(set("-~") | "[]") >> space >> Seperator >> ( |
| 922 | Exp >> *(space >> ',' >> space >> Exp) >> -(space >> invoke_args_with_table) | | 1106 | Exp >> *(space >> ',' >> space >> Exp) >> -(space >> invoke_args_with_table) | |
| 923 | arg_table_block | | 1107 | arg_table_block |
| 924 | leading_spaces_error | ||
| 925 | ); | 1108 | ); |
| 926 | 1109 | ||
| 927 | ConstValue = (expr("nil") | "true" | "false") >> not_alpha_num; | 1110 | ConstValue = (expr("nil") | "true" | "false") >> not_alpha_num; |
| 928 | 1111 | ||
| 929 | braces_expression_error = pl::user(true_(), [](const item_t& item) { | ||
| 930 | throw ParserError("syntax error in brace expression"sv, item.begin); | ||
| 931 | return false; | ||
| 932 | }); | ||
| 933 | |||
| 934 | brackets_expression_error = pl::user(true_(), [](const item_t& item) { | ||
| 935 | throw ParserError("syntax error in bracket expression"sv, item.begin); | ||
| 936 | return false; | ||
| 937 | }); | ||
| 938 | |||
| 939 | slice_expression_error = pl::user(true_(), [](const item_t& item) { | ||
| 940 | throw ParserError("syntax error in slice expression"sv, item.begin); | ||
| 941 | return false; | ||
| 942 | }); | ||
| 943 | |||
| 944 | SimpleValue = | 1112 | SimpleValue = |
| 945 | TableLit | ConstValue | If | Switch | Try | With | | 1113 | TableLit | ConstValue | If | Switch | Try | With | |
| 946 | ClassDecl | ForEach | For | While | Do | | 1114 | ClassDecl | For | While | Repeat | Do | |
| 947 | UnaryValue | TblComprehension | Comprehension | | 1115 | UnaryValue | TblComprehension | Comprehension | |
| 948 | FunLit | Num | VarArg; | 1116 | FunLit | Num | VarArg; |
| 949 | 1117 | ||
| @@ -952,63 +1120,59 @@ YueParser::YueParser() { | |||
| 952 | IfLine = IfType >> space >> IfCond; | 1120 | IfLine = IfType >> space >> IfCond; |
| 953 | WhileLine = WhileType >> space >> Exp; | 1121 | WhileLine = WhileType >> space >> Exp; |
| 954 | 1122 | ||
| 955 | YueLineComment = *(not_(set("\r\n")) >> any_char); | ||
| 956 | yue_line_comment = "--" >> YueLineComment >> and_(stop); | ||
| 957 | MultilineCommentInner = multi_line_content; | ||
| 958 | YueMultilineComment = multi_line_open >> MultilineCommentInner >> multi_line_close; | ||
| 959 | yue_comment = check_indent >> ( | ||
| 960 | ( | ||
| 961 | YueMultilineComment >> | ||
| 962 | *(set(" \t") | YueMultilineComment) >> | ||
| 963 | -yue_line_comment | ||
| 964 | ) | yue_line_comment | ||
| 965 | ) >> and_(line_break); | ||
| 966 | |||
| 967 | ChainAssign = Seperator >> Exp >> +(space >> '=' >> space >> Exp >> space >> and_('=')) >> space >> Assign; | 1123 | ChainAssign = Seperator >> Exp >> +(space >> '=' >> space >> Exp >> space >> and_('=')) >> space >> Assign; |
| 968 | 1124 | ||
| 969 | StatementAppendix = (IfLine | WhileLine | CompInner) >> space; | 1125 | StatementAppendix = (IfLine | WhileLine | CompFor) >> space; |
| 970 | Statement = | 1126 | Statement = |
| 971 | Seperator >> | 1127 | ( |
| 972 | -( | 1128 | Import | While | Repeat | For | |
| 973 | yue_comment >> | ||
| 974 | *(line_break >> yue_comment) >> | ||
| 975 | line_break >> | ||
| 976 | check_indent_match | ||
| 977 | ) >> | ||
| 978 | space >> ( | ||
| 979 | Import | While | Repeat | For | ForEach | | ||
| 980 | Return | Local | Global | Export | Macro | | 1129 | Return | Local | Global | Export | Macro | |
| 981 | MacroInPlace | BreakLoop | Label | Goto | ShortTabAppending | | 1130 | MacroInPlace | BreakLoop | Label | Goto | ShortTabAppending | |
| 982 | LocalAttrib | Backcall | PipeBody | ExpListAssign | ChainAssign | | 1131 | LocalAttrib | Backcall | PipeBody | ExpListAssign | ChainAssign | |
| 983 | StatementAppendix >> empty_block_error | 1132 | StatementAppendix >> empty_block_error | |
| 984 | ) >> | 1133 | and_(key("else") | key("elseif") | key("when")) >> dangling_clause_error |
| 985 | space >> | 1134 | ) >> space >> |
| 986 | -StatementAppendix; | 1135 | -StatementAppendix; |
| 987 | 1136 | ||
| 988 | StatementSep = white >> (set("('\"") | "[[" | "[="); | 1137 | StatementSep = white >> (set("('\"") | "[[" | "[="); |
| 989 | 1138 | ||
| 990 | Body = in_block | Statement; | 1139 | Body = in_block | Statement; |
| 991 | 1140 | ||
| 992 | empty_line_break = | 1141 | YueLineComment = *(not_(set("\r\n")) >> any_char); |
| 993 | check_indent >> (multi_line_comment >> space | comment) >> and_(stop) | | 1142 | yue_line_comment = "--" >> YueLineComment >> and_(stop); |
| 994 | advance >> ensure(multi_line_comment >> space | comment, pop_indent) >> and_(stop) | | 1143 | YueMultilineComment = multi_line_content; |
| 995 | plain_space >> and_(line_break); | 1144 | yue_multiline_comment = multi_line_open >> YueMultilineComment >> multi_line_close; |
| 1145 | comment_line = | ||
| 1146 | yue_multiline_comment >> *(set(" \t") | yue_multiline_comment) >> plain_space >> -yue_line_comment | | ||
| 1147 | yue_line_comment; | ||
| 1148 | YueComment = | ||
| 1149 | check_indent >> comment_line >> and_(stop) | | ||
| 1150 | advance >> ensure(comment_line, pop_indent) >> and_(stop); | ||
| 1151 | |||
| 1152 | EmptyLine = plain_space >> and_(stop); | ||
| 996 | 1153 | ||
| 997 | indentation_error = pl::user(not_(pipe_operator | eof()), [](const item_t& item) { | 1154 | indentation_error = pl::user(not_(pipe_operator | eof()), [](const item_t& item) { |
| 998 | throw ParserError("unexpected indent"sv, item.begin); | 1155 | RaiseError("unexpected indent"sv, item); |
| 999 | return false; | 1156 | return false; |
| 1000 | }); | 1157 | }); |
| 1001 | 1158 | ||
| 1002 | line = ( | 1159 | line = *(EmptyLine >> line_break) >> ( |
| 1003 | check_indent_match >> Statement | | 1160 | check_indent_match >> space >> Statement | |
| 1004 | empty_line_break | | 1161 | YueComment | |
| 1005 | advance_match >> ensure(space >> (indentation_error | Statement), pop_indent) | 1162 | advance_match >> ensure(space >> (indentation_error | Statement), pop_indent) |
| 1006 | ); | 1163 | ); |
| 1007 | Block = Seperator >> line >> *(+line_break >> line); | 1164 | Block = Seperator >> (pl::user(true_(), [](const item_t& item) { |
| 1165 | State* st = reinterpret_cast<State*>(item.user_data); | ||
| 1166 | return st->lax; | ||
| 1167 | }) >> lax_line >> *(line_break >> lax_line) | line >> *(line_break >> line)); | ||
| 1008 | 1168 | ||
| 1009 | shebang = "#!" >> *(not_(stop) >> any_char); | 1169 | shebang = "#!" >> *(not_(stop) >> any_char); |
| 1010 | BlockEnd = Block >> white >> stop; | 1170 | BlockEnd = Block >> plain_white >> stop; |
| 1011 | File = -shebang >> -Block >> white >> stop; | 1171 | File = -shebang >> -Block >> plain_white >> stop; |
| 1172 | |||
| 1173 | lax_line = advance_match >> ensure(*(not_(stop) >> any()), pop_indent) | | ||
| 1174 | line >> and_(stop) | | ||
| 1175 | check_indent_match >> *(not_(stop) >> any()); | ||
| 1012 | } | 1176 | } |
| 1013 | // clang-format on | 1177 | // clang-format on |
| 1014 | 1178 | ||
| @@ -1019,7 +1183,7 @@ bool YueParser::startWith(std::string_view codes, rule& r) { | |||
| 1019 | } | 1183 | } |
| 1020 | try { | 1184 | try { |
| 1021 | if (!codes.empty()) { | 1185 | if (!codes.empty()) { |
| 1022 | converted = std::make_unique<input>(_converter.from_bytes(&codes.front(), &codes.back() + 1)); | 1186 | converted = std::make_unique<input>(utf8_decode({&codes.front(), &codes.back() + 1})); |
| 1023 | } else { | 1187 | } else { |
| 1024 | converted = std::make_unique<input>(); | 1188 | converted = std::make_unique<input>(); |
| 1025 | } | 1189 | } |
| @@ -1038,24 +1202,25 @@ bool YueParser::startWith(std::string_view codes, rule& r) { | |||
| 1038 | return true; | 1202 | return true; |
| 1039 | } | 1203 | } |
| 1040 | 1204 | ||
| 1041 | ParseInfo YueParser::parse(std::string_view codes, rule& r) { | 1205 | ParseInfo YueParser::parse(std::string_view codes, rule& r, bool lax) { |
| 1042 | ParseInfo res; | 1206 | ParseInfo res; |
| 1043 | if (codes.substr(0, 3) == "\xEF\xBB\xBF"sv) { | 1207 | if (codes.substr(0, 3) == "\xEF\xBB\xBF"sv) { |
| 1044 | codes = codes.substr(3); | 1208 | codes = codes.substr(3); |
| 1045 | } | 1209 | } |
| 1046 | try { | 1210 | try { |
| 1047 | if (!codes.empty()) { | 1211 | if (!codes.empty()) { |
| 1048 | res.codes = std::make_unique<input>(_converter.from_bytes(&codes.front(), &codes.back() + 1)); | 1212 | res.codes = std::make_unique<input>(utf8_decode({&codes.front(), &codes.back() + 1})); |
| 1049 | } else { | 1213 | } else { |
| 1050 | res.codes = std::make_unique<input>(); | 1214 | res.codes = std::make_unique<input>(); |
| 1051 | } | 1215 | } |
| 1052 | } catch (const std::range_error&) { | 1216 | } catch (const std::exception&) { |
| 1053 | res.error = {"invalid text encoding"s, 1, 1}; | 1217 | res.error = {"invalid text encoding"s, 1, 1}; |
| 1054 | return res; | 1218 | return res; |
| 1055 | } | 1219 | } |
| 1056 | error_list errors; | 1220 | error_list errors; |
| 1057 | try { | 1221 | try { |
| 1058 | State state; | 1222 | State state; |
| 1223 | state.lax = lax; | ||
| 1059 | res.node.set(::yue::parse(*(res.codes), r, errors, &state)); | 1224 | res.node.set(::yue::parse(*(res.codes), r, errors, &state)); |
| 1060 | if (state.exportCount > 0) { | 1225 | if (state.exportCount > 0) { |
| 1061 | int index = 0; | 1226 | int index = 0; |
| @@ -1093,29 +1258,31 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) { | |||
| 1093 | return res; | 1258 | return res; |
| 1094 | } | 1259 | } |
| 1095 | 1260 | ||
| 1096 | ParseInfo YueParser::parse(std::string_view astName, std::string_view codes) { | 1261 | ParseInfo YueParser::parse(std::string_view astName, std::string_view codes, bool lax) { |
| 1097 | auto it = _rules.find(astName); | 1262 | auto it = _rules.find(astName); |
| 1098 | if (it != _rules.end()) { | 1263 | if (it != _rules.end()) { |
| 1099 | return parse(codes, *it->second); | 1264 | return parse(codes, *it->second, lax); |
| 1100 | } | 1265 | } |
| 1101 | return {}; | 1266 | ParseInfo info{}; |
| 1267 | info.error = ParseInfo::Error{"invalid rule: "s + std::string{astName}, 1, 1}; | ||
| 1268 | return info; | ||
| 1102 | } | 1269 | } |
| 1103 | 1270 | ||
| 1104 | bool YueParser::match(std::string_view astName, std::string_view codes) { | 1271 | bool YueParser::match(std::string_view astName, std::string_view codes) { |
| 1105 | auto it = _rules.find(astName); | 1272 | auto it = _rules.find(astName); |
| 1106 | if (it != _rules.end()) { | 1273 | if (it != _rules.end()) { |
| 1107 | auto rEnd = rule(*it->second >> eof()); | 1274 | auto rEnd = rule(*it->second >> eof()); |
| 1108 | return parse(codes, rEnd).node; | 1275 | return parse(codes, rEnd, false).node; |
| 1109 | } | 1276 | } |
| 1110 | return false; | 1277 | return false; |
| 1111 | } | 1278 | } |
| 1112 | 1279 | ||
| 1113 | std::string YueParser::toString(ast_node* node) { | 1280 | std::string YueParser::toString(ast_node* node) { |
| 1114 | return _converter.to_bytes(std::wstring(node->m_begin.m_it, node->m_end.m_it)); | 1281 | return utf8_encode({node->m_begin.m_it, node->m_end.m_it}); |
| 1115 | } | 1282 | } |
| 1116 | 1283 | ||
| 1117 | std::string YueParser::toString(input::iterator begin, input::iterator end) { | 1284 | std::string YueParser::toString(input::iterator begin, input::iterator end) { |
| 1118 | return _converter.to_bytes(std::wstring(begin, end)); | 1285 | return utf8_encode({begin, end}); |
| 1119 | } | 1286 | } |
| 1120 | 1287 | ||
| 1121 | bool YueParser::hasAST(std::string_view name) const { | 1288 | bool YueParser::hasAST(std::string_view name) const { |
| @@ -1141,6 +1308,24 @@ void trim(std::string& str) { | |||
| 1141 | str.erase(0, str.find_first_not_of(" \t\r\n")); | 1308 | str.erase(0, str.find_first_not_of(" \t\r\n")); |
| 1142 | str.erase(str.find_last_not_of(" \t\r\n") + 1); | 1309 | str.erase(str.find_last_not_of(" \t\r\n") + 1); |
| 1143 | } | 1310 | } |
| 1311 | |||
| 1312 | std::string toLuaDoubleString(const std::string& input) { | ||
| 1313 | std::string luaStr = "\""; | ||
| 1314 | for (char c : input) { | ||
| 1315 | switch (c) { | ||
| 1316 | case '\"': luaStr += "\\\""; break; | ||
| 1317 | case '\\': luaStr += "\\\\"; break; | ||
| 1318 | case '\n': luaStr += "\\n"; break; | ||
| 1319 | case '\r': luaStr += "\\r"; break; | ||
| 1320 | case '\t': luaStr += "\\t"; break; | ||
| 1321 | default: | ||
| 1322 | luaStr += c; | ||
| 1323 | break; | ||
| 1324 | } | ||
| 1325 | } | ||
| 1326 | luaStr += "\""; | ||
| 1327 | return luaStr; | ||
| 1328 | } | ||
| 1144 | } // namespace Utils | 1329 | } // namespace Utils |
| 1145 | 1330 | ||
| 1146 | std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCol, int lineOffset) const { | 1331 | std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCol, int lineOffset) const { |
| @@ -1174,7 +1359,7 @@ std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCo | |||
| 1174 | } | 1359 | } |
| 1175 | ++it; | 1360 | ++it; |
| 1176 | } | 1361 | } |
| 1177 | auto line = Converter{}.to_bytes(std::wstring(begin, end)); | 1362 | auto line = utf8_encode({begin, end}); |
| 1178 | while (col < static_cast<int>(line.size()) | 1363 | while (col < static_cast<int>(line.size()) |
| 1179 | && (line[col] == ' ' || line[col] == '\t')) { | 1364 | && (line[col] == ' ' || line[col] == '\t')) { |
| 1180 | col++; | 1365 | col++; |
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index 4488685..acb56d0 100644 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> | 1 | /* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com> |
| 2 | 2 | ||
| 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
| 4 | 4 | ||
| @@ -74,16 +74,16 @@ extern std::unordered_set<std::string> Keywords; | |||
| 74 | class YueParser { | 74 | class YueParser { |
| 75 | public: | 75 | public: |
| 76 | template <class AST> | 76 | template <class AST> |
| 77 | ParseInfo parse(std::string_view codes) { | 77 | ParseInfo parse(std::string_view codes, bool lax) { |
| 78 | return parse(codes, getRule<AST>()); | 78 | return parse(codes, getRule<AST>(), lax); |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | ParseInfo parse(std::string_view astName, std::string_view codes); | 81 | ParseInfo parse(std::string_view astName, std::string_view codes, bool lax); |
| 82 | 82 | ||
| 83 | template <class AST> | 83 | template <class AST> |
| 84 | bool match(std::string_view codes) { | 84 | bool match(std::string_view codes) { |
| 85 | auto rEnd = rule(getRule<AST>() >> eof()); | 85 | auto rEnd = rule(getRule<AST>() >> eof()); |
| 86 | return parse(codes, rEnd).node; | 86 | return parse(codes, rEnd, false).node; |
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | bool match(std::string_view astName, std::string_view codes); | 89 | bool match(std::string_view astName, std::string_view codes); |
| @@ -102,13 +102,14 @@ public: | |||
| 102 | 102 | ||
| 103 | protected: | 103 | protected: |
| 104 | YueParser(); | 104 | YueParser(); |
| 105 | ParseInfo parse(std::string_view codes, rule& r); | 105 | ParseInfo parse(std::string_view codes, rule& r, bool lax); |
| 106 | bool startWith(std::string_view codes, rule& r); | 106 | bool startWith(std::string_view codes, rule& r); |
| 107 | 107 | ||
| 108 | struct State { | 108 | struct State { |
| 109 | State() { | 109 | State() { |
| 110 | indents.push(0); | 110 | indents.push(0); |
| 111 | } | 111 | } |
| 112 | bool lax = false; | ||
| 112 | bool exportDefault = false; | 113 | bool exportDefault = false; |
| 113 | bool exportMacro = false; | 114 | bool exportMacro = false; |
| 114 | bool exportMetatable = false; | 115 | bool exportMetatable = false; |
| @@ -118,11 +119,13 @@ protected: | |||
| 118 | int expLevel = 0; | 119 | int expLevel = 0; |
| 119 | size_t stringOpen = 0; | 120 | size_t stringOpen = 0; |
| 120 | std::string buffer; | 121 | std::string buffer; |
| 122 | std::optional<bool> useTab; | ||
| 121 | std::stack<int> indents; | 123 | std::stack<int> indents; |
| 122 | std::stack<bool> noDoStack; | 124 | std::vector<bool> noDoStack; |
| 123 | std::stack<bool> noChainBlockStack; | 125 | std::vector<bool> noChainBlockStack; |
| 124 | std::stack<bool> noTableBlockStack; | 126 | std::vector<bool> noTableBlockStack; |
| 125 | std::stack<bool> noForStack; | 127 | std::vector<bool> noForStack; |
| 128 | std::vector<bool> noUntilStack; | ||
| 126 | std::unordered_set<std::string> usedNames; | 129 | std::unordered_set<std::string> usedNames; |
| 127 | }; | 130 | }; |
| 128 | 131 | ||
| @@ -132,7 +135,6 @@ protected: | |||
| 132 | } | 135 | } |
| 133 | 136 | ||
| 134 | private: | 137 | private: |
| 135 | Converter _converter; | ||
| 136 | std::unordered_map<std::string_view, rule*> _rules; | 138 | std::unordered_map<std::string_view, rule*> _rules; |
| 137 | 139 | ||
| 138 | template <class T> | 140 | template <class T> |
| @@ -147,7 +149,6 @@ private: | |||
| 147 | } | 149 | } |
| 148 | 150 | ||
| 149 | NONE_AST_RULE(empty_block_error); | 151 | NONE_AST_RULE(empty_block_error); |
| 150 | NONE_AST_RULE(leading_spaces_error); | ||
| 151 | NONE_AST_RULE(indentation_error); | 152 | NONE_AST_RULE(indentation_error); |
| 152 | NONE_AST_RULE(braces_expression_error); | 153 | NONE_AST_RULE(braces_expression_error); |
| 153 | NONE_AST_RULE(brackets_expression_error); | 154 | NONE_AST_RULE(brackets_expression_error); |
| @@ -156,12 +157,42 @@ private: | |||
| 156 | NONE_AST_RULE(invalid_interpolation_error); | 157 | NONE_AST_RULE(invalid_interpolation_error); |
| 157 | NONE_AST_RULE(confusing_unary_not_error); | 158 | NONE_AST_RULE(confusing_unary_not_error); |
| 158 | NONE_AST_RULE(table_key_pair_error); | 159 | NONE_AST_RULE(table_key_pair_error); |
| 159 | NONE_AST_RULE(if_assignment_syntax_error); | 160 | NONE_AST_RULE(assignment_expression_syntax_error); |
| 161 | NONE_AST_RULE(unclosed_single_string_error); | ||
| 162 | NONE_AST_RULE(unclosed_double_string_error); | ||
| 163 | NONE_AST_RULE(unclosed_lua_string_error); | ||
| 164 | NONE_AST_RULE(unexpected_comma_error); | ||
| 165 | NONE_AST_RULE(parenthesis_error); | ||
| 166 | NONE_AST_RULE(dangling_clause_error); | ||
| 167 | NONE_AST_RULE(keyword_as_label_error); | ||
| 168 | NONE_AST_RULE(check_vararg_position); | ||
| 169 | NONE_AST_RULE(vararg_position_error); | ||
| 170 | NONE_AST_RULE(invalid_import_syntax_error); | ||
| 171 | NONE_AST_RULE(invalid_import_as_syntax_error); | ||
| 172 | NONE_AST_RULE(expected_expression_error); | ||
| 173 | NONE_AST_RULE(invalid_from_import_error); | ||
| 174 | NONE_AST_RULE(invalid_export_syntax_error); | ||
| 175 | NONE_AST_RULE(invalid_macro_definition_error); | ||
| 176 | NONE_AST_RULE(invalid_global_declaration_error); | ||
| 177 | NONE_AST_RULE(invalid_local_declaration_error); | ||
| 178 | NONE_AST_RULE(invalid_with_syntax_error); | ||
| 179 | NONE_AST_RULE(invalid_try_syntax_error); | ||
| 180 | NONE_AST_RULE(keyword_as_identifier_syntax_error); | ||
| 181 | NONE_AST_RULE(invalid_number_literal_error); | ||
| 182 | NONE_AST_RULE(invalid_import_literal_error); | ||
| 183 | NONE_AST_RULE(expected_indentifier_error); | ||
| 184 | |||
| 185 | NONE_AST_RULE(must_exp); | ||
| 186 | NONE_AST_RULE(must_unary_exp); | ||
| 187 | NONE_AST_RULE(must_variable); | ||
| 188 | NONE_AST_RULE(end_braces_expression); | ||
| 189 | NONE_AST_RULE(end_brackets_expression); | ||
| 160 | 190 | ||
| 161 | NONE_AST_RULE(inc_exp_level); | 191 | NONE_AST_RULE(inc_exp_level); |
| 162 | NONE_AST_RULE(dec_exp_level); | 192 | NONE_AST_RULE(dec_exp_level); |
| 163 | 193 | ||
| 164 | NONE_AST_RULE(num_char); | 194 | NONE_AST_RULE(num_char); |
| 195 | NONE_AST_RULE(must_num_char); | ||
| 165 | NONE_AST_RULE(num_char_hex); | 196 | NONE_AST_RULE(num_char_hex); |
| 166 | NONE_AST_RULE(num_lit); | 197 | NONE_AST_RULE(num_lit); |
| 167 | NONE_AST_RULE(num_bin_lit); | 198 | NONE_AST_RULE(num_bin_lit); |
| @@ -172,6 +203,7 @@ private: | |||
| 172 | NONE_AST_RULE(line_break); | 203 | NONE_AST_RULE(line_break); |
| 173 | NONE_AST_RULE(any_char); | 204 | NONE_AST_RULE(any_char); |
| 174 | NONE_AST_RULE(white); | 205 | NONE_AST_RULE(white); |
| 206 | NONE_AST_RULE(plain_white); | ||
| 175 | NONE_AST_RULE(stop); | 207 | NONE_AST_RULE(stop); |
| 176 | NONE_AST_RULE(comment); | 208 | NONE_AST_RULE(comment); |
| 177 | NONE_AST_RULE(multi_line_open); | 209 | NONE_AST_RULE(multi_line_open); |
| @@ -217,6 +249,8 @@ private: | |||
| 217 | NONE_AST_RULE(enable_for); | 249 | NONE_AST_RULE(enable_for); |
| 218 | NONE_AST_RULE(enable_fun_lit); | 250 | NONE_AST_RULE(enable_fun_lit); |
| 219 | NONE_AST_RULE(disable_fun_lit); | 251 | NONE_AST_RULE(disable_fun_lit); |
| 252 | NONE_AST_RULE(disable_until); | ||
| 253 | NONE_AST_RULE(enable_until); | ||
| 220 | NONE_AST_RULE(switch_else); | 254 | NONE_AST_RULE(switch_else); |
| 221 | NONE_AST_RULE(switch_block); | 255 | NONE_AST_RULE(switch_block); |
| 222 | NONE_AST_RULE(if_else_if); | 256 | NONE_AST_RULE(if_else_if); |
| @@ -246,6 +280,8 @@ private: | |||
| 246 | NONE_AST_RULE(fn_arg_def_lit_lines); | 280 | NONE_AST_RULE(fn_arg_def_lit_lines); |
| 247 | NONE_AST_RULE(destruct_def); | 281 | NONE_AST_RULE(destruct_def); |
| 248 | NONE_AST_RULE(macro_args_def); | 282 | NONE_AST_RULE(macro_args_def); |
| 283 | NONE_AST_RULE(var_arg_def); | ||
| 284 | NONE_AST_RULE(outer_var_shadow_def); | ||
| 249 | NONE_AST_RULE(chain_call); | 285 | NONE_AST_RULE(chain_call); |
| 250 | NONE_AST_RULE(chain_call_list); | 286 | NONE_AST_RULE(chain_call_list); |
| 251 | NONE_AST_RULE(chain_index_chain); | 287 | NONE_AST_RULE(chain_index_chain); |
| @@ -262,7 +298,6 @@ private: | |||
| 262 | NONE_AST_RULE(table_value); | 298 | NONE_AST_RULE(table_value); |
| 263 | NONE_AST_RULE(table_lit_lines); | 299 | NONE_AST_RULE(table_lit_lines); |
| 264 | NONE_AST_RULE(table_lit_line); | 300 | NONE_AST_RULE(table_lit_line); |
| 265 | NONE_AST_RULE(table_value_list); | ||
| 266 | NONE_AST_RULE(table_block_inner); | 301 | NONE_AST_RULE(table_block_inner); |
| 267 | NONE_AST_RULE(class_line); | 302 | NONE_AST_RULE(class_line); |
| 268 | NONE_AST_RULE(key_value_line); | 303 | NONE_AST_RULE(key_value_line); |
| @@ -279,17 +314,17 @@ private: | |||
| 279 | NONE_AST_RULE(expo_exp); | 314 | NONE_AST_RULE(expo_exp); |
| 280 | NONE_AST_RULE(exp_not_tab); | 315 | NONE_AST_RULE(exp_not_tab); |
| 281 | NONE_AST_RULE(local_const_item); | 316 | NONE_AST_RULE(local_const_item); |
| 282 | NONE_AST_RULE(empty_line_break); | 317 | NONE_AST_RULE(comment_line); |
| 283 | NONE_AST_RULE(yue_comment); | ||
| 284 | NONE_AST_RULE(yue_line_comment); | 318 | NONE_AST_RULE(yue_line_comment); |
| 319 | NONE_AST_RULE(yue_multiline_comment); | ||
| 285 | NONE_AST_RULE(line); | 320 | NONE_AST_RULE(line); |
| 286 | NONE_AST_RULE(shebang); | 321 | NONE_AST_RULE(shebang); |
| 322 | NONE_AST_RULE(lax_line); | ||
| 287 | 323 | ||
| 288 | AST_RULE(Num); | 324 | AST_RULE(Num); |
| 289 | AST_RULE(Name); | 325 | AST_RULE(Name); |
| 290 | AST_RULE(UnicodeName); | 326 | AST_RULE(UnicodeName); |
| 291 | AST_RULE(Variable); | 327 | AST_RULE(Variable); |
| 292 | AST_RULE(LabelName); | ||
| 293 | AST_RULE(LuaKeyword); | 328 | AST_RULE(LuaKeyword); |
| 294 | AST_RULE(Self); | 329 | AST_RULE(Self); |
| 295 | AST_RULE(SelfName); | 330 | AST_RULE(SelfName); |
| @@ -298,6 +333,7 @@ private: | |||
| 298 | AST_RULE(SelfItem); | 333 | AST_RULE(SelfItem); |
| 299 | AST_RULE(KeyName); | 334 | AST_RULE(KeyName); |
| 300 | AST_RULE(VarArg); | 335 | AST_RULE(VarArg); |
| 336 | AST_RULE(VarArgDef); | ||
| 301 | AST_RULE(Seperator); | 337 | AST_RULE(Seperator); |
| 302 | AST_RULE(NameList); | 338 | AST_RULE(NameList); |
| 303 | AST_RULE(LocalFlag); | 339 | AST_RULE(LocalFlag); |
| @@ -315,6 +351,7 @@ private: | |||
| 315 | AST_RULE(ImportAllMacro); | 351 | AST_RULE(ImportAllMacro); |
| 316 | AST_RULE(ImportTabLit); | 352 | AST_RULE(ImportTabLit); |
| 317 | AST_RULE(ImportAs); | 353 | AST_RULE(ImportAs); |
| 354 | AST_RULE(ImportGlobal); | ||
| 318 | AST_RULE(Import); | 355 | AST_RULE(Import); |
| 319 | AST_RULE(Label); | 356 | AST_RULE(Label); |
| 320 | AST_RULE(Goto); | 357 | AST_RULE(Goto); |
| @@ -339,6 +376,7 @@ private: | |||
| 339 | AST_RULE(Repeat); | 376 | AST_RULE(Repeat); |
| 340 | AST_RULE(ForStepValue); | 377 | AST_RULE(ForStepValue); |
| 341 | AST_RULE(For); | 378 | AST_RULE(For); |
| 379 | AST_RULE(ForNum); | ||
| 342 | AST_RULE(ForEach); | 380 | AST_RULE(ForEach); |
| 343 | AST_RULE(Do); | 381 | AST_RULE(Do); |
| 344 | AST_RULE(CatchBlock); | 382 | AST_RULE(CatchBlock); |
| @@ -348,8 +386,8 @@ private: | |||
| 348 | AST_RULE(TblComprehension); | 386 | AST_RULE(TblComprehension); |
| 349 | AST_RULE(StarExp); | 387 | AST_RULE(StarExp); |
| 350 | AST_RULE(CompForEach); | 388 | AST_RULE(CompForEach); |
| 389 | AST_RULE(CompForNum); | ||
| 351 | AST_RULE(CompFor); | 390 | AST_RULE(CompFor); |
| 352 | AST_RULE(CompInner); | ||
| 353 | AST_RULE(Assign); | 391 | AST_RULE(Assign); |
| 354 | AST_RULE(UpdateOp); | 392 | AST_RULE(UpdateOp); |
| 355 | AST_RULE(Update); | 393 | AST_RULE(Update); |
| @@ -360,6 +398,7 @@ private: | |||
| 360 | AST_RULE(ExpOpValue); | 398 | AST_RULE(ExpOpValue); |
| 361 | AST_RULE(Exp); | 399 | AST_RULE(Exp); |
| 362 | AST_RULE(Callable); | 400 | AST_RULE(Callable); |
| 401 | AST_RULE(ReversedIndex); | ||
| 363 | AST_RULE(ChainValue); | 402 | AST_RULE(ChainValue); |
| 364 | AST_RULE(SimpleTable); | 403 | AST_RULE(SimpleTable); |
| 365 | AST_RULE(SimpleValue); | 404 | AST_RULE(SimpleValue); |
| @@ -372,6 +411,11 @@ private: | |||
| 372 | AST_RULE(DoubleStringInner); | 411 | AST_RULE(DoubleStringInner); |
| 373 | AST_RULE(DoubleStringContent); | 412 | AST_RULE(DoubleStringContent); |
| 374 | AST_RULE(DoubleString); | 413 | AST_RULE(DoubleString); |
| 414 | AST_RULE(YAMLIndent); | ||
| 415 | AST_RULE(YAMLLineInner); | ||
| 416 | AST_RULE(YAMLLineContent); | ||
| 417 | AST_RULE(YAMLLine); | ||
| 418 | AST_RULE(YAMLMultiline); | ||
| 375 | AST_RULE(String); | 419 | AST_RULE(String); |
| 376 | AST_RULE(Parens); | 420 | AST_RULE(Parens); |
| 377 | AST_RULE(DotChainItem); | 421 | AST_RULE(DotChainItem); |
| @@ -435,8 +479,9 @@ private: | |||
| 435 | AST_RULE(Statement); | 479 | AST_RULE(Statement); |
| 436 | AST_RULE(StatementSep); | 480 | AST_RULE(StatementSep); |
| 437 | AST_RULE(YueLineComment); | 481 | AST_RULE(YueLineComment); |
| 438 | AST_RULE(MultilineCommentInner); | ||
| 439 | AST_RULE(YueMultilineComment); | 482 | AST_RULE(YueMultilineComment); |
| 483 | AST_RULE(YueComment); | ||
| 484 | AST_RULE(EmptyLine); | ||
| 440 | AST_RULE(ChainAssign); | 485 | AST_RULE(ChainAssign); |
| 441 | AST_RULE(Body); | 486 | AST_RULE(Body); |
| 442 | AST_RULE(Block); | 487 | AST_RULE(Block); |
| @@ -447,6 +492,7 @@ private: | |||
| 447 | namespace Utils { | 492 | namespace Utils { |
| 448 | void replace(std::string& str, std::string_view from, std::string_view to); | 493 | void replace(std::string& str, std::string_view from, std::string_view to); |
| 449 | void trim(std::string& str); | 494 | void trim(std::string& str); |
| 495 | std::string toLuaDoubleString(const std::string& input); | ||
| 450 | } // namespace Utils | 496 | } // namespace Utils |
| 451 | 497 | ||
| 452 | } // namespace yue | 498 | } // namespace yue |
diff --git a/src/yuescript/yuescript.cpp b/src/yuescript/yuescript.cpp index 7e8e8b7..fd2bf62 100644 --- a/src/yuescript/yuescript.cpp +++ b/src/yuescript/yuescript.cpp | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> | 1 | /* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com> |
| 2 | 2 | ||
| 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
| 4 | 4 | ||
| @@ -93,6 +93,12 @@ static void get_config(lua_State* L, yue::YueConfig& config) { | |||
| 93 | config.useSpaceOverTab = lua_toboolean(L, -1) != 0; | 93 | config.useSpaceOverTab = lua_toboolean(L, -1) != 0; |
| 94 | } | 94 | } |
| 95 | lua_pop(L, 1); | 95 | lua_pop(L, 1); |
| 96 | lua_pushliteral(L, "lax"); | ||
| 97 | lua_gettable(L, -2); | ||
| 98 | if (lua_isboolean(L, -1) != 0) { | ||
| 99 | config.lax = lua_toboolean(L, -1) != 0; | ||
| 100 | } | ||
| 101 | lua_pop(L, 1); | ||
| 96 | lua_pushliteral(L, "options"); | 102 | lua_pushliteral(L, "options"); |
| 97 | lua_gettable(L, -2); | 103 | lua_gettable(L, -2); |
| 98 | if (lua_istable(L, -1) != 0) { | 104 | if (lua_istable(L, -1) != 0) { |
| @@ -179,8 +185,13 @@ static int yueformat(lua_State* L) { | |||
| 179 | if (!lua_isnoneornil(L, 2)) { | 185 | if (!lua_isnoneornil(L, 2)) { |
| 180 | tabSize = static_cast<int>(luaL_checkinteger(L, 2)); | 186 | tabSize = static_cast<int>(luaL_checkinteger(L, 2)); |
| 181 | } | 187 | } |
| 188 | bool reserveComment = true; | ||
| 189 | if (!lua_isnoneornil(L, 3)) { | ||
| 190 | luaL_checktype(L, 3, LUA_TBOOLEAN); | ||
| 191 | reserveComment = lua_toboolean(L, 3) != 0; | ||
| 192 | } | ||
| 182 | std::string_view codes(input, len); | 193 | std::string_view codes(input, len); |
| 183 | auto info = yue::YueParser::shared().parse<yue::File_t>(codes); | 194 | auto info = yue::YueParser::shared().parse<yue::File_t>(codes, false); |
| 184 | if (info.error) { | 195 | if (info.error) { |
| 185 | const auto& error = info.error.value(); | 196 | const auto& error = info.error.value(); |
| 186 | if (!info.codes) { | 197 | if (!info.codes) { |
| @@ -200,7 +211,11 @@ static int yueformat(lua_State* L) { | |||
| 200 | } else { | 211 | } else { |
| 201 | formatter.spaceOverTab = false; | 212 | formatter.spaceOverTab = false; |
| 202 | } | 213 | } |
| 214 | formatter.reserveComment = reserveComment; | ||
| 203 | auto result = formatter.toString(info.node.get()); | 215 | auto result = formatter.toString(info.node.get()); |
| 216 | if (!formatter.reserveComment) { | ||
| 217 | yue::Utils::replace(result, "\n\n", "\n"); | ||
| 218 | } | ||
| 204 | lua_pushlstring(L, result.c_str(), result.size()); | 219 | lua_pushlstring(L, result.c_str(), result.size()); |
| 205 | return 1; | 220 | return 1; |
| 206 | } | 221 | } |
| @@ -235,6 +250,7 @@ static int yuecheck(lua_State* L) { | |||
| 235 | } | 250 | } |
| 236 | if (result.globals) { | 251 | if (result.globals) { |
| 237 | for (const auto& global : *result.globals) { | 252 | for (const auto& global : *result.globals) { |
| 253 | if (global.defined) continue; | ||
| 238 | lua_createtable(L, 4, 0); | 254 | lua_createtable(L, 4, 0); |
| 239 | lua_pushliteral(L, "global"); | 255 | lua_pushliteral(L, "global"); |
| 240 | lua_rawseti(L, -2, 1); | 256 | lua_rawseti(L, -2, 1); |
| @@ -247,7 +263,7 @@ static int yuecheck(lua_State* L) { | |||
| 247 | lua_rawseti(L, -2, ++i); | 263 | lua_rawseti(L, -2, ++i); |
| 248 | } | 264 | } |
| 249 | } | 265 | } |
| 250 | if (result.error) { | 266 | if (!config.lax && result.error) { |
| 251 | lua_pushboolean(L, 0); | 267 | lua_pushboolean(L, 0); |
| 252 | lua_insert(L, -2); | 268 | lua_insert(L, -2); |
| 253 | return 2; | 269 | return 2; |
| @@ -282,8 +298,18 @@ static int yuetoast(lua_State* L) { | |||
| 282 | ruleName = {name, nameSize}; | 298 | ruleName = {name, nameSize}; |
| 283 | } | 299 | } |
| 284 | } | 300 | } |
| 301 | bool lax = false; | ||
| 302 | if (!lua_isnoneornil(L, 4)) { | ||
| 303 | luaL_checktype(L, 4, LUA_TBOOLEAN); | ||
| 304 | lax = lua_toboolean(L, 4) != 0; | ||
| 305 | } | ||
| 306 | bool reserveComment = false; | ||
| 307 | if (!lua_isnoneornil(L, 5)) { | ||
| 308 | luaL_checktype(L, 5, LUA_TBOOLEAN); | ||
| 309 | reserveComment = lua_toboolean(L, 5) != 0; | ||
| 310 | } | ||
| 285 | auto& yueParser = yue::YueParser::shared(); | 311 | auto& yueParser = yue::YueParser::shared(); |
| 286 | auto info = ruleName.empty() ? yueParser.parse<yue::File_t>({input, size}) : yueParser.parse(ruleName, {input, size}); | 312 | auto info = ruleName.empty() ? yueParser.parse<yue::File_t>({input, size}, lax) : yueParser.parse(ruleName, {input, size}, lax); |
| 287 | if (!info.error) { | 313 | if (!info.error) { |
| 288 | lua_createtable(L, 0, 0); | 314 | lua_createtable(L, 0, 0); |
| 289 | int tableIndex = lua_gettop(L); | 315 | int tableIndex = lua_gettop(L); |
| @@ -309,13 +335,11 @@ static int yuetoast(lua_State* L) { | |||
| 309 | }; | 335 | }; |
| 310 | do_call(info.node); | 336 | do_call(info.node); |
| 311 | yue::YueFormat formatter{}; | 337 | yue::YueFormat formatter{}; |
| 338 | formatter.reserveComment = reserveComment; | ||
| 312 | while (!stack.empty()) { | 339 | while (!stack.empty()) { |
| 313 | auto& current = stack.top(); | 340 | auto& current = stack.top(); |
| 314 | int continuation = current.continuation; | 341 | int continuation = current.continuation; |
| 315 | auto node = current.node; | 342 | auto node = current.node; |
| 316 | if (auto comment = yue::ast_cast<yue::YueMultilineComment_t>(node)) { | ||
| 317 | node = comment->inner.get(); | ||
| 318 | } | ||
| 319 | switch (continuation) { | 343 | switch (continuation) { |
| 320 | case 0: { | 344 | case 0: { |
| 321 | if (!current.children) { | 345 | if (!current.children) { |
| @@ -324,6 +348,9 @@ static int yuetoast(lua_State* L) { | |||
| 324 | current.hasSep = true; | 348 | current.hasSep = true; |
| 325 | return false; | 349 | return false; |
| 326 | } | 350 | } |
| 351 | if (!reserveComment && yue::ast_is<yue::YueComment_t, yue::EmptyLine_t>(child)) { | ||
| 352 | return false; | ||
| 353 | } | ||
| 327 | if (!current.children) { | 354 | if (!current.children) { |
| 328 | current.children = std::make_unique<std::vector<yue::ast_node*>>(); | 355 | current.children = std::make_unique<std::vector<yue::ast_node*>>(); |
| 329 | } | 356 | } |
