aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/3rdParty/colib/LICENSE21
-rw-r--r--src/3rdParty/colib/ljson.c925
-rw-r--r--src/3rdParty/efsw/FileWatcherGeneric.cpp2
-rwxr-xr-xsrc/3rdParty/utf8cpp.h1277
-rw-r--r--src/yue.cpp47
-rw-r--r--src/yue_wasm.cpp2
-rw-r--r--src/yuescript/parser.cpp29
-rw-r--r--src/yuescript/parser.hpp7
-rw-r--r--src/yuescript/yue_ast.cpp303
-rw-r--r--src/yuescript/yue_ast.h203
-rw-r--r--src/yuescript/yue_compiler.cpp2621
-rw-r--r--src/yuescript/yue_compiler.h4
-rw-r--r--src/yuescript/yue_parser.cpp713
-rw-r--r--src/yuescript/yue_parser.h90
-rw-r--r--src/yuescript/yuescript.cpp41
15 files changed, 5078 insertions, 1207 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 @@
1MIT License
2
3Copyright (c) 2020 colin
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in all
13copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21SOFTWARE.
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
51typedef 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
59static inline void membuffer_init(membuffer_t *buff) {
60 buff->b = buff->s;
61 buff->cap = STACK_BUFF_SIZE;
62 buff->sz = 0;
63}
64
65static inline void membuffer_add_size(membuffer_t *buff, size_t sz) {
66 buff->sz += sz;
67}
68
69static inline void membuffer_reset(membuffer_t *buff) {
70 buff->sz = 0;
71}
72
73static 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
80static 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的可用空间
96static 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// 压入一个字符
103static inline void membuffer_putc(membuffer_t *buff, char c) {
104 membuffer_ensure_space(buff, 1);
105 buff->b[buff->sz++] = c;
106}
107
108// 写入一段内存
109static 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// 压入一个字符:不检查空间(不安全版本)
116static 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// 写入一段内存:不检查空间(不安全版本)
122static 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// 取当前的指针
129static inline char* membuffer_getp(membuffer_t *buff) {
130 return buff->b + buff->sz;
131}
132
133//-----------------------------------------------------------------------------
134// parser
135
136//-------------------------------------
137// 与Lua相关的代码
138
139static inline void l_add_object(lua_State *L) {
140 luaL_checkstack(L, 6, NULL);
141 lua_createtable(L, 0, 4);
142}
143static inline void l_begin_pair(lua_State *L, const char *k, size_t sz) {
144 lua_pushlstring(L, k, sz);
145}
146static inline void l_end_pair(lua_State *L) {
147 lua_rawset(L, -3);
148}
149static inline void l_add_array(lua_State *L) {
150 luaL_checkstack(L, 6, NULL);
151 lua_createtable(L, 4, 0);
152}
153static inline void l_add_index(lua_State *L, int i) {
154 lua_rawseti(L, -2, i+1);
155}
156static inline void l_add_string(lua_State *L, const char *s, size_t sz) {
157 lua_pushlstring(L, s, sz);
158}
159static inline void l_add_float(lua_State *L, double f) {
160 lua_pushnumber(L, (lua_Number)f);
161}
162static inline void l_add_integer(lua_State *L, int64_t i) {
163 lua_pushinteger(L, (lua_Integer)i);
164}
165static inline void l_add_boolean(lua_State *L, int b) {
166 lua_pushboolean(L, b);
167}
168static inline void l_add_null(lua_State *L) {
169 lua_pushlightuserdata(L, NULL);
170}
171static 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解析器
195typedef 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
207static 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
219static inline void parser_free(json_parser_t *parser) {
220 membuffer_free(&parser->buff);
221}
222
223// 抛出错误
224static 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// 取解析到的错误内容
244static 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// 增加深度
254static 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
261static 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
288static 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
295static 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
304static 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
313static 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
322static 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
343static 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
374static 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
390static 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)
419static double powersOf10[] = {10., 100., 1.0e4, 1.0e8, 1.0e16, 1.0e32, 1.0e64, 1.0e128, 1.0e256};
420static 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
512static void parser_process_value(json_parser_t *p);
513
514static 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
548static 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
575static 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文本
605static 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
622typedef 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// 抛出错误
636static 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
646static 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
663static 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// 字符转义表
674static 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};
689static const char hex_digits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
690
691static 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
718static void dumpper_process_value(json_dumpper_t *d, lua_State *L, int depth);
719
720static 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
743static 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
750static 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
770static 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
821static 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
834static 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结尾
878int 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
888int 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
904static const luaL_Reg lib[] = {
905 {"decode", colibc_json_decode},
906 {"encode", colibc_json_encode},
907 {NULL, NULL},
908};
909
910LUALIB_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/efsw/FileWatcherGeneric.cpp b/src/3rdParty/efsw/FileWatcherGeneric.cpp
index 3f3c52e..468d27c 100644
--- a/src/3rdParty/efsw/FileWatcherGeneric.cpp
+++ b/src/3rdParty/efsw/FileWatcherGeneric.cpp
@@ -25,7 +25,7 @@ FileWatcherGeneric::~FileWatcherGeneric() {
25} 25}
26 26
27WatchID FileWatcherGeneric::addWatch( const std::string& directory, FileWatchListener* watcher, 27WatchID FileWatcherGeneric::addWatch( const std::string& directory, FileWatchListener* watcher,
28 bool recursive, const std::vector<WatcherOption>& options ) { 28 bool recursive, const std::vector<WatcherOption>& /*options*/ ) {
29 std::string dir( directory ); 29 std::string dir( directory );
30 30
31 FileSystem::dirAddSlashAtEnd( dir ); 31 FileSystem::dirAddSlashAtEnd( dir );
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/*
4Permission is hereby granted, free of charge, to any person or organization
5obtaining a copy of the software and accompanying documentation covered by
6this license (the "Software") to use, reproduce, display, distribute,
7execute, and transmit the Software, and to prepare derivative works of the
8Software, and to permit third-parties to whom the Software is furnished to
9do so, all subject to the following:
10
11The copyright notices in the Software and this entire statement, including
12the above license grant, this restriction and the following disclaimer,
13must be included in all copies of the Software, in whole or in part, and
14all derivative works of the Software, unless such copies or derivative
15works are solely in the form of machine-executable object code generated by
16a source language processor.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
21SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
22FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
23ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24DEALINGS 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/*
32To control the C++ language version used by the library, you can define UTF_CPP_CPLUSPLUS macro
33and set it to one of the values used by the __cplusplus predefined macro.
34
35For instance,
36 #define UTF_CPP_CPLUSPLUS 199711L
37will cause the UTF-8 CPP library to use only types and language features available in the C++ 98 standard.
38Some library features will be disabled.
39
40If 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
69namespace 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
87namespace 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
515namespace 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
832namespace 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
870namespace 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
934namespace 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
1025namespace 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..2722c55 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
3Permission 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: 3Permission 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>
35template<class R>
36std::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
58template<class R>
59std::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"
42int luaopen_yue(lua_State* L); 74int luaopen_yue(lua_State* L);
75int luaopen_colibc_json(lua_State* L);
43} // extern "C" 76} // extern "C"
44 77
45static void openlibs(void* state) { 78static 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
57void pushYue(lua_State* L, std::string_view name) { 94void pushYue(lua_State* L, std::string_view name) {
@@ -304,7 +341,7 @@ int main(int narg, const char** args) {
304 " -- Read from standard in, print to standard out\n" 341 " -- Read from standard in, print to standard out\n"
305 " (Must be first and only argument)\n\n" 342 " (Must be first and only argument)\n\n"
306 " --target=version Specify the Lua version that codes will be generated to\n" 343 " --target=version Specify the Lua version that codes will be generated to\n"
307 " (version can only be 5.1, 5.2, 5.3 or 5.4)\n" 344 " (version can only be 5.1 to 5.5)\n"
308 " --path=path_str Append an extra Lua search path string to package.path\n\n" 345 " --path=path_str Append an extra Lua search path string to package.path\n\n"
309 " Execute without options to enter REPL, type symbol '$'\n" 346 " Execute without options to enter REPL, type symbol '$'\n"
310 " in a single line to start/stop multi-line mode\n" 347 " in a single line to start/stop multi-line mode\n"
@@ -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
3Permission 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: 3Permission 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
22namespace 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"
28namespace 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
21namespace parserlib { 38namespace parserlib {
22 39
40input utf8_decode(const std::string& str) {
41 return CodeCvt::utf8to32(str);
42}
43
44std::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.
24class _private { 49class _private {
25public: 50public:
@@ -241,7 +266,7 @@ class _string : public _expr {
241public: 266public:
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 {
279public: 304public:
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
27namespace parserlib { 26namespace parserlib {
28 27
29/// type of the parser's input. 28/// type of the parser's input.
30typedef std::basic_string<wchar_t> input; 29typedef std::basic_string<char32_t> input;
31typedef input::iterator input_it; 30typedef input::iterator input_it;
32typedef std::wstring_convert<std::codecvt_utf8_utf16<input::value_type>> Converter; 31
32input utf8_decode(const std::string& str);
33std::string utf8_encode(const input& str);
33 34
34class _private; 35class _private;
35class _expr; 36class _expr;
diff --git a/src/yuescript/yue_ast.cpp b/src/yuescript/yue_ast.cpp
index fe6e726..cfd4cc6 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
3Permission 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: 3Permission 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
32std::string YueFormat::convert(const ast_node* node) { 32std::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
36std::string YueFormat::toString(ast_node* node) { 36std::string YueFormat::toString(ast_node* node) {
@@ -82,6 +82,13 @@ std::string SelfClass_t::to_string(void*) const {
82std::string VarArg_t::to_string(void*) const { 82std::string VarArg_t::to_string(void*) const {
83 return "..."s; 83 return "..."s;
84} 84}
85std::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}
85std::string Seperator_t::to_string(void*) const { 92std::string Seperator_t::to_string(void*) const {
86 return {}; 93 return {};
87} 94}
@@ -167,12 +174,11 @@ std::string ExistentialOp_t::to_string(void*) const {
167std::string TableAppendingOp_t::to_string(void*) const { 174std::string TableAppendingOp_t::to_string(void*) const {
168 return "[]"s; 175 return "[]"s;
169} 176}
170std::string PlainItem_t::to_string(void *) const { 177std::string PlainItem_t::to_string(void*) const {
171 return {}; 178 return {};
172} 179}
173std::string GlobalOp_t::to_string(void* ud) const { 180std::string GlobalOp_t::to_string(void*) const {
174 auto info = reinterpret_cast<YueFormat*>(ud); 181 return "*"s;
175 return info->convert(this);
176} 182}
177std::string ExportDefault_t::to_string(void*) const { 183std::string ExportDefault_t::to_string(void*) const {
178 return "default"s; 184 return "default"s;
@@ -188,22 +194,34 @@ std::string ConstValue_t::to_string(void* ud) const {
188std::string NotIn_t::to_string(void*) const { 194std::string NotIn_t::to_string(void*) const {
189 return {}; 195 return {};
190} 196}
197std::string Break_t::to_string(void*) const {
198 return "break"s;
199}
200std::string Continue_t::to_string(void*) const {
201 return "continue"s;
202}
191std::string BreakLoop_t::to_string(void* ud) const { 203std::string BreakLoop_t::to_string(void* ud) const {
192 auto info = reinterpret_cast<YueFormat*>(ud); 204 if (value) {
193 return info->convert(this); 205 return type->to_string(ud) + ' ' + value->to_string(ud);
206 }
207 return type->to_string(ud);
194} 208}
195std::string YueLineComment_t::to_string(void* ud) const { 209std::string YueLineComment_t::to_string(void* ud) const {
196 auto info = reinterpret_cast<YueFormat*>(ud); 210 auto info = reinterpret_cast<YueFormat*>(ud);
197 return "--"s + info->convert(this); 211 return "--"s + info->convert(this);
198} 212}
199std::string MultilineCommentInner_t::to_string(void* ud) const { 213std::string YueMultilineComment_t::to_string(void* ud) const {
200 auto info = reinterpret_cast<YueFormat*>(ud); 214 auto info = reinterpret_cast<YueFormat*>(ud);
201 return info->convert(this); 215 return "--[["s + info->convert(this) + "]]"s;
202} 216}
203std::string Variable_t::to_string(void* ud) const { 217std::string YueComment_t::to_string(void* ud) const {
204 return name->to_string(ud); 218 if (comment) {
219 return comment->to_string(ud);
220 } else {
221 return {};
222 }
205} 223}
206std::string LabelName_t::to_string(void* ud) const { 224std::string Variable_t::to_string(void* ud) const {
207 return name->to_string(ud); 225 return name->to_string(ud);
208} 226}
209std::string LuaKeyword_t::to_string(void* ud) const { 227std::string LuaKeyword_t::to_string(void* ud) const {
@@ -297,6 +315,20 @@ std::string ImportAs_t::to_string(void* ud) const {
297 } 315 }
298 return join(temp, " "s); 316 return join(temp, " "s);
299} 317}
318std::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}
329std::string ImportAllGlobal_t::to_string(void*) const {
330 return "global"s;
331}
300std::string Import_t::to_string(void* ud) const { 332std::string Import_t::to_string(void* ud) const {
301 if (ast_is<FromImport_t>(content)) { 333 if (ast_is<FromImport_t>(content)) {
302 return content->to_string(ud); 334 return content->to_string(ud);
@@ -324,6 +356,12 @@ std::string Backcall_t::to_string(void* ud) const {
324 temp.emplace_back(value->to_string(ud)); 356 temp.emplace_back(value->to_string(ud));
325 return join(temp, " "sv); 357 return join(temp, " "sv);
326} 358}
359std::string SubBackcall_t::to_string(void* ud) const {
360 str_list temp;
361 temp.emplace_back(arrow->to_string(ud));
362 temp.emplace_back(value->to_string(ud));
363 return join(temp, " "sv);
364}
327std::string PipeBody_t::to_string(void* ud) const { 365std::string PipeBody_t::to_string(void* ud) const {
328 auto info = reinterpret_cast<YueFormat*>(ud); 366 auto info = reinterpret_cast<YueFormat*>(ud);
329 str_list temp; 367 str_list temp;
@@ -332,13 +370,6 @@ std::string PipeBody_t::to_string(void* ud) const {
332 } 370 }
333 return join(temp, "\n"sv); 371 return join(temp, "\n"sv);
334} 372}
335std::string ExpListLow_t::to_string(void* ud) const {
336 str_list temp;
337 for (auto exp : exprs.objects()) {
338 temp.emplace_back(exp->to_string(ud));
339 }
340 return join(temp, "; "sv);
341}
342std::string ExpList_t::to_string(void* ud) const { 373std::string ExpList_t::to_string(void* ud) const {
343 str_list temp; 374 str_list temp;
344 for (auto exp : exprs.objects()) { 375 for (auto exp : exprs.objects()) {
@@ -359,8 +390,8 @@ std::string With_t::to_string(void* ud) const {
359 str_list temp{ 390 str_list temp{
360 eop ? "with?"s : "with"s, 391 eop ? "with?"s : "with"s,
361 valueList->to_string(ud)}; 392 valueList->to_string(ud)};
362 if (assigns) { 393 if (assign) {
363 temp.push_back(assigns->to_string(ud)); 394 temp.push_back(':' + assign->to_string(ud));
364 } 395 }
365 if (body.is<Statement_t>()) { 396 if (body.is<Statement_t>()) {
366 return join(temp, " "sv) + " do "s + body->to_string(ud); 397 return join(temp, " "sv) + " do "s + body->to_string(ud);
@@ -406,6 +437,9 @@ std::string SwitchCase_t::to_string(void* ud) const {
406std::string Switch_t::to_string(void* ud) const { 437std::string Switch_t::to_string(void* ud) const {
407 auto info = reinterpret_cast<YueFormat*>(ud); 438 auto info = reinterpret_cast<YueFormat*>(ud);
408 str_list temp{"switch "s + target->to_string(ud)}; 439 str_list temp{"switch "s + target->to_string(ud)};
440 if (assignment) {
441 temp.back().append(assignment->to_string(ud));
442 }
409 info->pushScope(); 443 info->pushScope();
410 for (auto branch : branches.objects()) { 444 for (auto branch : branches.objects()) {
411 temp.emplace_back(info->ind() + branch->to_string(ud)); 445 temp.emplace_back(info->ind() + branch->to_string(ud));
@@ -449,41 +483,75 @@ std::string If_t::to_string(void* ud) const {
449 temp.back() += " then"s; 483 temp.back() += " then"s;
450 } 484 }
451 ++it; 485 ++it;
452 bool condition = true; 486 enum class NType {
487 Cond,
488 Stat,
489 Block
490 };
491 NType lastType = NType::Cond;
453 for (; it != nodes.objects().end(); ++it) { 492 for (; it != nodes.objects().end(); ++it) {
454 auto node = *it; 493 auto node = *it;
455 switch (node->get_id()) { 494 switch (node->get_id()) {
456 case id<IfCond_t>(): 495 case id<IfCond_t>():
457 temp.emplace_back(info->ind() + "elseif "s + node->to_string(ud)); 496 temp.emplace_back(info->ind() + "elseif "s + node->to_string(ud));
458 condition = true; 497 lastType = NType::Cond;
459 break; 498 break;
460 case id<Statement_t>(): { 499 case id<Statement_t>(): {
461 if (condition) { 500 switch (lastType) {
462 temp.back() += " then "s + node->to_string(ud); 501 case NType::Cond:
463 } else { 502 temp.back() += " then "s + node->to_string(ud);
464 temp.emplace_back(info->ind() + "else "s + node->to_string(ud)); 503 break;
504 case NType::Stat:
505 if (temp.back().back() == '\n') {
506 temp.emplace_back(info->ind() + "else "s + node->to_string(ud));
507 } else {
508 temp.back() += " else "s + node->to_string(ud);
509 }
510 break;
511 case NType::Block:
512 temp.emplace_back(info->ind() + "else "s + node->to_string(ud));
513 break;
465 } 514 }
466 condition = false; 515 lastType = NType::Stat;
467 break; 516 break;
468 } 517 }
469 case id<Block_t>(): { 518 case id<Block_t>(): {
470 if (condition) { 519 switch (lastType) {
471 info->pushScope(); 520 case NType::Cond: {
472 temp.emplace_back(node->to_string(ud)); 521 info->pushScope();
473 if (temp.back().empty()) { 522 temp.emplace_back(node->to_string(ud));
474 temp.back() = info->ind() + "--"s; 523 if (temp.back().empty()) {
524 temp.back() = info->ind() + "--"s;
525 }
526 info->popScope();
527 break;
528 }
529 case NType::Stat: {
530 if (temp.back().back() == '\n') {
531 temp.emplace_back(info->ind() + "else"s);
532 } else {
533 temp.back() += " else"s;
534 }
535 info->pushScope();
536 temp.emplace_back(node->to_string(ud));
537 if (temp.back().empty()) {
538 temp.back() = info->ind() + "--"s;
539 }
540 info->popScope();
541 break;
475 } 542 }
476 info->popScope(); 543 case NType::Block: {
477 } else { 544 temp.emplace_back(info->ind() + "else"s);
478 temp.emplace_back(info->ind() + "else"s); 545 info->pushScope();
479 info->pushScope(); 546 temp.emplace_back(node->to_string(ud));
480 temp.emplace_back(node->to_string(ud)); 547 if (temp.back().empty()) {
481 if (temp.back().empty()) { 548 temp.back() = info->ind() + "--"s;
482 temp.back() = info->ind() + "--"s; 549 }
550 info->popScope();
551 break;
483 } 552 }
484 info->popScope();
485 } 553 }
486 condition = false; 554 lastType = NType::Block;
487 break; 555 break;
488 } 556 }
489 } 557 }
@@ -511,10 +579,10 @@ std::string While_t::to_string(void* ud) const {
511} 579}
512std::string Repeat_t::to_string(void* ud) const { 580std::string Repeat_t::to_string(void* ud) const {
513 auto info = reinterpret_cast<YueFormat*>(ud); 581 auto info = reinterpret_cast<YueFormat*>(ud);
514 str_list temp; 582 if (body.is<Statement_t>()) {
515 if (body->content.is<Statement_t>()) { 583 return "repeat "s + body->to_string(ud) + " until "s + condition->to_string(ud);
516 temp.emplace_back("repeat "s + body->to_string(ud));
517 } else { 584 } else {
585 str_list temp;
518 temp.emplace_back("repeat"s); 586 temp.emplace_back("repeat"s);
519 info->pushScope(); 587 info->pushScope();
520 temp.emplace_back(body->to_string(ud)); 588 temp.emplace_back(body->to_string(ud));
@@ -522,14 +590,14 @@ std::string Repeat_t::to_string(void* ud) const {
522 temp.back() = info->ind() + "--"s; 590 temp.back() = info->ind() + "--"s;
523 } 591 }
524 info->popScope(); 592 info->popScope();
593 temp.emplace_back(info->ind() + "until "s + condition->to_string(ud));
594 return join(temp, "\n"sv);
525 } 595 }
526 temp.emplace_back(info->ind() + "until "s + condition->to_string(ud));
527 return join(temp, "\n"sv);
528} 596}
529std::string ForStepValue_t::to_string(void* ud) const { 597std::string ForStepValue_t::to_string(void* ud) const {
530 return value->to_string(ud); 598 return value->to_string(ud);
531} 599}
532std::string For_t::to_string(void* ud) const { 600std::string ForNum_t::to_string(void* ud) const {
533 auto info = reinterpret_cast<YueFormat*>(ud); 601 auto info = reinterpret_cast<YueFormat*>(ud);
534 auto line = "for "s + varName->to_string(ud) + " = "s + startValue->to_string(ud) + ", "s + stopValue->to_string(ud); 602 auto line = "for "s + varName->to_string(ud) + " = "s + startValue->to_string(ud) + ", "s + stopValue->to_string(ud);
535 if (stepValue) { 603 if (stepValue) {
@@ -568,6 +636,9 @@ std::string ForEach_t::to_string(void* ud) const {
568 return line + '\n' + block; 636 return line + '\n' + block;
569 } 637 }
570} 638}
639std::string For_t::to_string(void* ud) const {
640 return forLoop->to_string(ud);
641}
571std::string Do_t::to_string(void* ud) const { 642std::string Do_t::to_string(void* ud) const {
572 auto info = reinterpret_cast<YueFormat*>(ud); 643 auto info = reinterpret_cast<YueFormat*>(ud);
573 if (body->content.is<Statement_t>()) { 644 if (body->content.is<Statement_t>()) {
@@ -596,10 +667,13 @@ std::string CatchBlock_t::to_string(void* ud) const {
596std::string Try_t::to_string(void* ud) const { 667std::string Try_t::to_string(void* ud) const {
597 auto info = reinterpret_cast<YueFormat*>(ud); 668 auto info = reinterpret_cast<YueFormat*>(ud);
598 str_list temp; 669 str_list temp;
670 temp.emplace_back("try"s);
671 if (eop) {
672 temp.back() += eop->to_string(ud);
673 }
599 if (func.is<Exp_t>()) { 674 if (func.is<Exp_t>()) {
600 temp.emplace_back("try "s + func->to_string(ud)); 675 temp.back() += (" "s + func->to_string(ud));
601 } else { 676 } else {
602 temp.emplace_back("try"s);
603 info->pushScope(); 677 info->pushScope();
604 temp.emplace_back(func->to_string(ud)); 678 temp.emplace_back(func->to_string(ud));
605 if (temp.back().empty()) { 679 if (temp.back().empty()) {
@@ -716,7 +790,7 @@ static bool isInBlockExp(ast_node* node, bool last = false) {
716 return false; 790 return false;
717} 791}
718std::string Comprehension_t::to_string(void* ud) const { 792std::string Comprehension_t::to_string(void* ud) const {
719 if (items.size() != 2 || !ast_is<CompInner_t>(items.back())) { 793 if (items.size() != 2 || !ast_is<CompFor_t>(items.back())) {
720 if (items.size() == 1) { 794 if (items.size() == 1) {
721 str_list temp; 795 str_list temp;
722 for (const auto& item : items.objects()) { 796 for (const auto& item : items.objects()) {
@@ -783,14 +857,14 @@ std::string StarExp_t::to_string(void* ud) const {
783std::string CompForEach_t::to_string(void* ud) const { 857std::string CompForEach_t::to_string(void* ud) const {
784 return "for "s + nameList->to_string(ud) + " in "s + loopValue->to_string(ud); 858 return "for "s + nameList->to_string(ud) + " in "s + loopValue->to_string(ud);
785} 859}
786std::string CompFor_t::to_string(void* ud) const { 860std::string CompForNum_t::to_string(void* ud) const {
787 auto line = "for "s + varName->to_string(ud) + " = "s + startValue->to_string(ud) + ", "s + stopValue->to_string(ud); 861 auto line = "for "s + varName->to_string(ud) + " = "s + startValue->to_string(ud) + ", "s + stopValue->to_string(ud);
788 if (stepValue) { 862 if (stepValue) {
789 line += stepValue->to_string(ud); 863 line += stepValue->to_string(ud);
790 } 864 }
791 return line; 865 return line;
792} 866}
793std::string CompInner_t::to_string(void* ud) const { 867std::string CompFor_t::to_string(void* ud) const {
794 str_list temp; 868 str_list temp;
795 for (auto item : items.objects()) { 869 for (auto item : items.objects()) {
796 if (ast_is<Exp_t>(item)) { 870 if (ast_is<Exp_t>(item)) {
@@ -809,7 +883,7 @@ std::string Assign_t::to_string(void* ud) const {
809 for (auto value : values.objects()) { 883 for (auto value : values.objects()) {
810 temp.emplace_back(value->to_string(ud)); 884 temp.emplace_back(value->to_string(ud));
811 } 885 }
812 return "= "s + join(temp, "; "sv); 886 return "= "s + join(temp, ", "sv);
813} 887}
814std::string Update_t::to_string(void* ud) const { 888std::string Update_t::to_string(void* ud) const {
815 return op->to_string(ud) + "= "s + value->to_string(ud); 889 return op->to_string(ud) + "= "s + value->to_string(ud);
@@ -851,6 +925,12 @@ std::string Exp_t::to_string(void* ud) const {
851 } 925 }
852 return join(temp, " "sv); 926 return join(temp, " "sv);
853} 927}
928std::string ReversedIndex_t::to_string(void* ud) const {
929 if (modifier) {
930 return "[# - "s + modifier->to_string(ud) + ']';
931 }
932 return "[#]"s;
933}
854std::string Callable_t::to_string(void* ud) const { 934std::string Callable_t::to_string(void* ud) const {
855 return item->to_string(ud); 935 return item->to_string(ud);
856} 936}
@@ -937,6 +1017,51 @@ std::string DoubleString_t::to_string(void* ud) const {
937 } 1017 }
938 return '"' + join(temp) + '"'; 1018 return '"' + join(temp) + '"';
939} 1019}
1020std::string YAMLIndent_t::to_string(void* ud) const {
1021 auto info = reinterpret_cast<YueFormat*>(ud);
1022 return info->convert(this);
1023}
1024std::string YAMLLineInner_t::to_string(void* ud) const {
1025 auto info = reinterpret_cast<YueFormat*>(ud);
1026 return info->convert(this);
1027}
1028std::string YAMLLineContent_t::to_string(void* ud) const {
1029 if (content.is<Exp_t>()) {
1030 return "#{"s + content->to_string(ud) + '}';
1031 }
1032 return content->to_string(ud);
1033}
1034std::string YAMLLine_t::to_string(void* ud) const {
1035 str_list temp;
1036 for (auto seg : segments.objects()) {
1037 temp.emplace_back(seg->to_string(ud));
1038 }
1039 return join(temp);
1040}
1041std::string YAMLMultiline_t::to_string(void* ud) const {
1042 auto info = reinterpret_cast<YueFormat*>(ud);
1043 int currentIndent = info->indent;
1044 str_list temp;
1045 int lastIndent = -1;
1046 for (auto line_ : lines.objects()) {
1047 auto line = static_cast<YAMLLine_t*>(line_);
1048 auto indent = line->indent->to_string(ud);
1049 int ind = 0;
1050 for (auto c : indent) {
1051 if (c == ' ') ind++;
1052 if (c == '\t') ind += 4;
1053 }
1054 if (lastIndent < ind) {
1055 info->pushScope();
1056 } else if (lastIndent > ind) {
1057 info->popScope();
1058 }
1059 lastIndent = ind;
1060 temp.emplace_back(indent + line->to_string(ud));
1061 }
1062 info->indent = currentIndent;
1063 return "|\n" + join(temp, "\n"sv) + '\n';
1064}
940std::string String_t::to_string(void* ud) const { 1065std::string String_t::to_string(void* ud) const {
941 return str->to_string(ud); 1066 return str->to_string(ud);
942} 1067}
@@ -1125,7 +1250,7 @@ std::string ClassDecl_t::to_string(void* ud) const {
1125 return line; 1250 return line;
1126} 1251}
1127std::string GlobalValues_t::to_string(void* ud) const { 1252std::string GlobalValues_t::to_string(void* ud) const {
1128 auto line = nameList->to_string(ud); 1253 std::string line = nameList->to_string(ud);
1129 if (valueList) { 1254 if (valueList) {
1130 if (valueList.is<TableBlock_t>()) { 1255 if (valueList.is<TableBlock_t>()) {
1131 line += " =\n"s + valueList->to_string(ud); 1256 line += " =\n"s + valueList->to_string(ud);
@@ -1136,7 +1261,7 @@ std::string GlobalValues_t::to_string(void* ud) const {
1136 return line; 1261 return line;
1137} 1262}
1138std::string Global_t::to_string(void* ud) const { 1263std::string Global_t::to_string(void* ud) const {
1139 return "global "s + item->to_string(ud); 1264 return "global "s + (constAttrib ? "const "s : ""s) + item->to_string(ud);
1140} 1265}
1141std::string Export_t::to_string(void* ud) const { 1266std::string Export_t::to_string(void* ud) const {
1142 auto line = "export"s; 1267 auto line = "export"s;
@@ -1235,6 +1360,9 @@ std::string FnArgDef_t::to_string(void* ud) const {
1235 if (op) { 1360 if (op) {
1236 line += op->to_string(ud); 1361 line += op->to_string(ud);
1237 } 1362 }
1363 if (label) {
1364 line += '`' + label->to_string(ud);
1365 }
1238 if (defaultValue) { 1366 if (defaultValue) {
1239 line += " = "s + defaultValue->to_string(ud); 1367 line += " = "s + defaultValue->to_string(ud);
1240 } 1368 }
@@ -1257,6 +1385,9 @@ std::string FnArgDefList_t::to_string(void* ud) const {
1257 } 1385 }
1258 if (varArg) { 1386 if (varArg) {
1259 temp.emplace_back(info->ind() + varArg->to_string(ud)); 1387 temp.emplace_back(info->ind() + varArg->to_string(ud));
1388 if (label) {
1389 temp.back().append('`' + label->to_string(ud));
1390 }
1260 } 1391 }
1261 return join(temp, "\n"sv); 1392 return join(temp, "\n"sv);
1262 } else { 1393 } else {
@@ -1265,6 +1396,9 @@ std::string FnArgDefList_t::to_string(void* ud) const {
1265 } 1396 }
1266 if (varArg) { 1397 if (varArg) {
1267 temp.emplace_back(varArg->to_string(ud)); 1398 temp.emplace_back(varArg->to_string(ud));
1399 if (label) {
1400 temp.back().append('`' + label->to_string(ud));
1401 }
1268 } 1402 }
1269 return join(temp, ", "sv); 1403 return join(temp, ", "sv);
1270 } 1404 }
@@ -1475,37 +1609,17 @@ std::string StatementAppendix_t::to_string(void* ud) const {
1475 return item->to_string(ud); 1609 return item->to_string(ud);
1476} 1610}
1477std::string Statement_t::to_string(void* ud) const { 1611std::string Statement_t::to_string(void* ud) const {
1478 std::string line; 1612 if (appendix) {
1479 if (!comments.empty()) { 1613 return content->to_string(ud) + ' ' + appendix->to_string(ud);
1480 auto info = reinterpret_cast<YueFormat*>(ud);
1481 str_list temp;
1482 for (ast_node* comment : comments.objects()) {
1483 if (comment == comments.front()) {
1484 temp.push_back(comment->to_string(ud));
1485 } else {
1486 temp.push_back(info->ind() + comment->to_string(ud));
1487 }
1488 }
1489 if (appendix) {
1490 temp.push_back(info->ind() + content->to_string(ud) + ' ' + appendix->to_string(ud));
1491 return join(temp, "\n"sv);
1492 } else {
1493 temp.push_back(info->ind() + content->to_string(ud));
1494 return join(temp, "\n"sv);
1495 }
1496 } else { 1614 } else {
1497 if (appendix) { 1615 return content->to_string(ud);
1498 return content->to_string(ud) + ' ' + appendix->to_string(ud);
1499 } else {
1500 return content->to_string(ud);
1501 }
1502 } 1616 }
1503} 1617}
1504std::string StatementSep_t::to_string(void*) const { 1618std::string StatementSep_t::to_string(void*) const {
1505 return {}; 1619 return {};
1506} 1620}
1507std::string YueMultilineComment_t::to_string(void* ud) const { 1621std::string EmptyLine_t::to_string(void*) const {
1508 return "--[["s + inner->to_string(ud) + "]]"s; 1622 return {};
1509} 1623}
1510std::string ChainAssign_t::to_string(void* ud) const { 1624std::string ChainAssign_t::to_string(void* ud) const {
1511 str_list temp; 1625 str_list temp;
@@ -1520,14 +1634,22 @@ std::string Body_t::to_string(void* ud) const {
1520std::string Block_t::to_string(void* ud) const { 1634std::string Block_t::to_string(void* ud) const {
1521 auto info = reinterpret_cast<YueFormat*>(ud); 1635 auto info = reinterpret_cast<YueFormat*>(ud);
1522 str_list temp; 1636 str_list temp;
1523 for (auto stmt_ : statements.objects()) { 1637 for (auto stmt_ : statementOrComments.objects()) {
1524 auto stmt = static_cast<Statement_t*>(stmt_); 1638 if (auto stmt = ast_cast<Statement_t>(stmt_)) {
1525 if (stmt->content.is<PipeBody_t>()) { 1639 if (stmt->content.is<PipeBody_t>()) {
1526 info->pushScope(); 1640 info->pushScope();
1527 temp.emplace_back(stmt->to_string(ud)); 1641 temp.emplace_back(stmt->to_string(ud));
1528 info->popScope(); 1642 info->popScope();
1529 } else { 1643 } else {
1530 temp.emplace_back(info->ind() + stmt->to_string(ud)); 1644 temp.emplace_back(info->ind() + stmt->to_string(ud));
1645 }
1646 } else if (info->reserveComment) {
1647 if (auto comment = ast_cast<YueComment_t>(stmt_)) {
1648 temp.emplace_back(info->ind() + comment->to_string(ud));
1649 } else {
1650 auto empty = ast_to<EmptyLine_t>(stmt_);
1651 temp.emplace_back(empty->to_string(ud));
1652 }
1531 } 1653 }
1532 } 1654 }
1533 return join(temp, "\n"sv); 1655 return join(temp, "\n"sv);
@@ -1546,3 +1668,4 @@ std::string File_t::to_string(void* ud) const {
1546} // namespace yue 1668} // namespace yue
1547 1669
1548} // namespace parserlib 1670} // namespace parserlib
1671
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h
index 5e70645..5043526 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
3Permission 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: 3Permission 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
@@ -50,7 +50,7 @@ std::string_view ast_name() { return {}; }
50// clang-format off 50// clang-format off
51 51
52namespace yue { 52namespace yue {
53class ExpListLow_t; 53class ExpList_t;
54class TableBlock_t; 54class TableBlock_t;
55class SimpleTable_t; 55class SimpleTable_t;
56class TableLit_t; 56class TableLit_t;
@@ -68,7 +68,7 @@ class Statement_t;
68class Body_t; 68class Body_t;
69class AssignableNameList_t; 69class AssignableNameList_t;
70class StarExp_t; 70class StarExp_t;
71class CompInner_t; 71class CompFor_t;
72class AssignableChain_t; 72class AssignableChain_t;
73class UnaryExp_t; 73class UnaryExp_t;
74class Parens_t; 74class Parens_t;
@@ -103,11 +103,6 @@ AST_NODE(Variable)
103 AST_MEMBER(Variable, &name) 103 AST_MEMBER(Variable, &name)
104AST_END(Variable) 104AST_END(Variable)
105 105
106AST_NODE(LabelName)
107 ast_ptr<true, UnicodeName_t> name;
108 AST_MEMBER(LabelName, &name)
109AST_END(LabelName)
110
111AST_NODE(LuaKeyword) 106AST_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)
140AST_END(KeyName) 135AST_END(KeyName)
141 136
137AST_NODE(VarArgDef)
138 ast_ptr<false, Variable_t> name;
139 AST_MEMBER(VarArgDef, &name)
140AST_END(VarArgDef)
141
142AST_LEAF(VarArg) 142AST_LEAF(VarArg)
143AST_END(VarArg) 143AST_END(VarArg)
144 144
@@ -156,7 +156,7 @@ AST_END(NameList)
156 156
157AST_NODE(LocalValues) 157AST_NODE(LocalValues)
158 ast_ptr<true, NameList_t> nameList; 158 ast_ptr<true, NameList_t> nameList;
159 ast_sel<false, TableBlock_t, ExpListLow_t> valueList; 159 ast_sel<false, TableBlock_t, ExpList_t> valueList;
160 AST_MEMBER(LocalValues, &nameList, &valueList) 160 AST_MEMBER(LocalValues, &nameList, &valueList)
161AST_END(LocalValues) 161AST_END(LocalValues)
162 162
@@ -233,18 +233,28 @@ AST_NODE(ImportAs)
233 AST_MEMBER(ImportAs, &literal, &target) 233 AST_MEMBER(ImportAs, &literal, &target)
234AST_END(ImportAs) 234AST_END(ImportAs)
235 235
236AST_LEAF(ImportAllGlobal)
237AST_END(ImportAllGlobal)
238
239AST_NODE(ImportGlobal)
240 ast_ptr<true, Seperator_t> sep;
241 ast_list<true, UnicodeName_t> segs;
242 ast_ptr<false, Variable_t> target;
243 AST_MEMBER(ImportGlobal, &sep, &segs, &target)
244AST_END(ImportGlobal)
245
236AST_NODE(Import) 246AST_NODE(Import)
237 ast_sel<true, ImportAs_t, ImportFrom_t, FromImport_t> content; 247 ast_sel<true, ImportAs_t, ImportFrom_t, FromImport_t, ImportGlobal_t, ImportAllGlobal_t> content;
238 AST_MEMBER(Import, &content) 248 AST_MEMBER(Import, &content)
239AST_END(Import) 249AST_END(Import)
240 250
241AST_NODE(Label) 251AST_NODE(Label)
242 ast_ptr<true, LabelName_t> label; 252 ast_ptr<true, UnicodeName_t> label;
243 AST_MEMBER(Label, &label) 253 AST_MEMBER(Label, &label)
244AST_END(Label) 254AST_END(Label)
245 255
246AST_NODE(Goto) 256AST_NODE(Goto)
247 ast_ptr<true, LabelName_t> label; 257 ast_ptr<true, UnicodeName_t> label;
248 AST_MEMBER(Goto, &label) 258 AST_MEMBER(Goto, &label)
249AST_END(Goto) 259AST_END(Goto)
250 260
@@ -263,31 +273,27 @@ AST_NODE(Backcall)
263 AST_MEMBER(Backcall, &argsDef, &arrow, &value) 273 AST_MEMBER(Backcall, &argsDef, &arrow, &value)
264AST_END(Backcall) 274AST_END(Backcall)
265 275
266AST_NODE(ExpListLow)
267 ast_ptr<true, Seperator_t> sep;
268 ast_list<true, Exp_t> exprs;
269 AST_MEMBER(ExpListLow, &sep, &exprs)
270AST_END(ExpListLow)
271
272AST_NODE(ExpList) 276AST_NODE(ExpList)
273 ast_ptr<true, Seperator_t> sep; 277 ast_ptr<true, Seperator_t> sep;
274 ast_list<true, Exp_t> exprs; 278 ast_list<true, Exp_t> exprs;
275 AST_MEMBER(ExpList, &sep, &exprs) 279 AST_MEMBER(ExpList, &sep, &exprs)
280 bool followStmtProcessed = false;
281 Statement_t* followStmt = nullptr;
276AST_END(ExpList) 282AST_END(ExpList)
277 283
278AST_NODE(Return) 284AST_NODE(Return)
279 bool allowBlockMacroReturn = false; 285 bool allowBlockMacroReturn = false;
280 bool explicitReturn = true; 286 bool explicitReturn = true;
281 ast_sel<false, TableBlock_t, ExpListLow_t> valueList; 287 ast_sel<false, TableBlock_t, ExpList_t> valueList;
282 AST_MEMBER(Return, &valueList) 288 AST_MEMBER(Return, &valueList)
283AST_END(Return) 289AST_END(Return)
284 290
285AST_NODE(With) 291AST_NODE(With)
286 ast_ptr<false, ExistentialOp_t> eop; 292 ast_ptr<false, ExistentialOp_t> eop;
287 ast_ptr<true, ExpList_t> valueList; 293 ast_ptr<true, ExpList_t> valueList;
288 ast_ptr<false, Assign_t> assigns; 294 ast_ptr<false, Assign_t> assign;
289 ast_sel<true, Block_t, Statement_t> body; 295 ast_sel<true, Block_t, Statement_t> body;
290 AST_MEMBER(With, &eop, &valueList, &assigns, &body) 296 AST_MEMBER(With, &eop, &valueList, &assign, &body)
291AST_END(With) 297AST_END(With)
292 298
293AST_NODE(SwitchList) 299AST_NODE(SwitchList)
@@ -302,20 +308,21 @@ AST_NODE(SwitchCase)
302 AST_MEMBER(SwitchCase, &condition, &body) 308 AST_MEMBER(SwitchCase, &condition, &body)
303AST_END(SwitchCase) 309AST_END(SwitchCase)
304 310
311AST_NODE(Assignment)
312 ast_ptr<false, ExpList_t> expList;
313 ast_ptr<true, Assign_t> assign;
314 AST_MEMBER(Assignment, &expList, &assign)
315AST_END(Assignment)
316
305AST_NODE(Switch) 317AST_NODE(Switch)
306 ast_ptr<true, Exp_t> target; 318 ast_ptr<true, Exp_t> target;
319 ast_ptr<false, Assignment_t> assignment;
307 ast_ptr<true, Seperator_t> sep; 320 ast_ptr<true, Seperator_t> sep;
308 ast_list<true, SwitchCase_t> branches; 321 ast_list<true, SwitchCase_t> branches;
309 ast_sel<false, Block_t, Statement_t> lastBranch; 322 ast_sel<false, Block_t, Statement_t> lastBranch;
310 AST_MEMBER(Switch, &target, &sep, &branches, &lastBranch) 323 AST_MEMBER(Switch, &target, &assignment, &sep, &branches, &lastBranch)
311AST_END(Switch) 324AST_END(Switch)
312 325
313AST_NODE(Assignment)
314 ast_ptr<false, ExpList_t> expList;
315 ast_ptr<true, Assign_t> assign;
316 AST_MEMBER(Assignment, &expList, &assign)
317AST_END(Assignment)
318
319AST_NODE(IfCond) 326AST_NODE(IfCond)
320 ast_ptr<true, Exp_t> condition; 327 ast_ptr<true, Exp_t> condition;
321 ast_ptr<false, Assignment_t> assignment; 328 ast_ptr<false, Assignment_t> assignment;
@@ -343,7 +350,7 @@ AST_NODE(While)
343AST_END(While) 350AST_END(While)
344 351
345AST_NODE(Repeat) 352AST_NODE(Repeat)
346 ast_ptr<true, Body_t> body; 353 ast_sel<true, Block_t, Statement_t> body;
347 ast_ptr<true, Exp_t> condition; 354 ast_ptr<true, Exp_t> condition;
348 AST_MEMBER(Repeat, &body, &condition) 355 AST_MEMBER(Repeat, &body, &condition)
349AST_END(Repeat) 356AST_END(Repeat)
@@ -353,14 +360,14 @@ AST_NODE(ForStepValue)
353 AST_MEMBER(ForStepValue, &value) 360 AST_MEMBER(ForStepValue, &value)
354AST_END(ForStepValue) 361AST_END(ForStepValue)
355 362
356AST_NODE(For) 363AST_NODE(ForNum)
357 ast_ptr<true, Variable_t> varName; 364 ast_ptr<true, Variable_t> varName;
358 ast_ptr<true, Exp_t> startValue; 365 ast_ptr<true, Exp_t> startValue;
359 ast_ptr<true, Exp_t> stopValue; 366 ast_ptr<true, Exp_t> stopValue;
360 ast_ptr<false, ForStepValue_t> stepValue; 367 ast_ptr<false, ForStepValue_t> stepValue;
361 ast_sel<true, Block_t, Statement_t> body; 368 ast_sel<true, Block_t, Statement_t> body;
362 AST_MEMBER(For, &varName, &startValue, &stopValue, &stepValue, &body) 369 AST_MEMBER(ForNum, &varName, &startValue, &stopValue, &stepValue, &body)
363AST_END(For) 370AST_END(ForNum)
364 371
365AST_NODE(ForEach) 372AST_NODE(ForEach)
366 ast_ptr<true, AssignableNameList_t> nameList; 373 ast_ptr<true, AssignableNameList_t> nameList;
@@ -369,6 +376,11 @@ AST_NODE(ForEach)
369 AST_MEMBER(ForEach, &nameList, &loopValue, &body) 376 AST_MEMBER(ForEach, &nameList, &loopValue, &body)
370AST_END(ForEach) 377AST_END(ForEach)
371 378
379AST_NODE(For)
380 ast_sel<true, ForEach_t, ForNum_t> forLoop;
381 AST_MEMBER(For, &forLoop)
382AST_END(For)
383
372AST_NODE(Do) 384AST_NODE(Do)
373 ast_ptr<true, Body_t> body; 385 ast_ptr<true, Body_t> body;
374 AST_MEMBER(Do, &body) 386 AST_MEMBER(Do, &body)
@@ -381,14 +393,15 @@ AST_NODE(CatchBlock)
381AST_END(CatchBlock) 393AST_END(CatchBlock)
382 394
383AST_NODE(Try) 395AST_NODE(Try)
396 ast_ptr<false, ExistentialOp_t> eop;
384 ast_sel<true, Block_t, Exp_t> func; 397 ast_sel<true, Block_t, Exp_t> func;
385 ast_ptr<false, CatchBlock_t> catchBlock; 398 ast_ptr<false, CatchBlock_t> catchBlock;
386 AST_MEMBER(Try, &func, &catchBlock) 399 AST_MEMBER(Try, &eop, &func, &catchBlock)
387AST_END(Try) 400AST_END(Try)
388 401
389AST_NODE(Comprehension) 402AST_NODE(Comprehension)
390 ast_ptr<true, Seperator_t> sep; 403 ast_ptr<true, Seperator_t> sep;
391 ast_sel_list<false, NormalDef_t, SpreadListExp_t, CompInner_t, 404 ast_sel_list<false, NormalDef_t, SpreadListExp_t, CompFor_t,
392 /*non-syntax-rule*/ Statement_t> items; 405 /*non-syntax-rule*/ Statement_t> items;
393 AST_MEMBER(Comprehension, &sep, &items) 406 AST_MEMBER(Comprehension, &sep, &items)
394AST_END(Comprehension) 407AST_END(Comprehension)
@@ -401,7 +414,7 @@ AST_END(CompValue)
401AST_NODE(TblComprehension) 414AST_NODE(TblComprehension)
402 ast_ptr<true, Exp_t> key; 415 ast_ptr<true, Exp_t> key;
403 ast_ptr<false, CompValue_t> value; 416 ast_ptr<false, CompValue_t> value;
404 ast_ptr<true, CompInner_t> forLoop; 417 ast_ptr<true, CompFor_t> forLoop;
405 AST_MEMBER(TblComprehension, &key, &value, &forLoop) 418 AST_MEMBER(TblComprehension, &key, &value, &forLoop)
406AST_END(TblComprehension) 419AST_END(TblComprehension)
407 420
@@ -416,23 +429,23 @@ AST_NODE(CompForEach)
416 AST_MEMBER(CompForEach, &nameList, &loopValue) 429 AST_MEMBER(CompForEach, &nameList, &loopValue)
417AST_END(CompForEach) 430AST_END(CompForEach)
418 431
419AST_NODE(CompFor) 432AST_NODE(CompForNum)
420 ast_ptr<true, Variable_t> varName; 433 ast_ptr<true, Variable_t> varName;
421 ast_ptr<true, Exp_t> startValue; 434 ast_ptr<true, Exp_t> startValue;
422 ast_ptr<true, Exp_t> stopValue; 435 ast_ptr<true, Exp_t> stopValue;
423 ast_ptr<false, ForStepValue_t> stepValue; 436 ast_ptr<false, ForStepValue_t> stepValue;
424 AST_MEMBER(CompFor, &varName, &startValue, &stopValue, &stepValue) 437 AST_MEMBER(CompForNum, &varName, &startValue, &stopValue, &stepValue)
425AST_END(CompFor) 438AST_END(CompForNum)
426 439
427AST_NODE(CompInner) 440AST_NODE(CompFor)
428 ast_ptr<true, Seperator_t> sep; 441 ast_ptr<true, Seperator_t> sep;
429 ast_sel_list<true, CompFor_t, CompForEach_t, Exp_t> items; 442 ast_sel_list<true, CompForNum_t, CompForEach_t, Exp_t> items;
430 AST_MEMBER(CompInner, &sep, &items) 443 AST_MEMBER(CompFor, &sep, &items)
431AST_END(CompInner) 444AST_END(CompFor)
432 445
433AST_NODE(Assign) 446AST_NODE(Assign)
434 ast_ptr<true, Seperator_t> sep; 447 ast_ptr<true, Seperator_t> sep;
435 ast_sel_list<true, With_t, If_t, Switch_t, TableBlock_t, Exp_t> values; 448 ast_sel_list<true, With_t, If_t, Switch_t, TableBlock_t, Exp_t, SpreadListExp_t> values;
436 AST_MEMBER(Assign, &sep, &values) 449 AST_MEMBER(Assign, &sep, &values)
437AST_END(Assign) 450AST_END(Assign)
438 451
@@ -547,8 +560,8 @@ AST_NODE(SimpleValue)
547 ast_sel<true, 560 ast_sel<true,
548 TableLit_t, ConstValue_t, 561 TableLit_t, ConstValue_t,
549 If_t, Switch_t, With_t, ClassDecl_t, 562 If_t, Switch_t, With_t, ClassDecl_t,
550 ForEach_t, For_t, While_t, Do_t, Try_t, 563 For_t, While_t, Repeat_t,
551 UnaryValue_t, 564 Do_t, Try_t, UnaryValue_t,
552 TblComprehension_t, Comprehension_t, 565 TblComprehension_t, Comprehension_t,
553 FunLit_t, Num_t, VarArg_t> value; 566 FunLit_t, Num_t, VarArg_t> value;
554 AST_MEMBER(SimpleValue, &value) 567 AST_MEMBER(SimpleValue, &value)
@@ -587,8 +600,31 @@ AST_NODE(DoubleString)
587 AST_MEMBER(DoubleString, &sep, &segments) 600 AST_MEMBER(DoubleString, &sep, &segments)
588AST_END(DoubleString) 601AST_END(DoubleString)
589 602
603AST_LEAF(YAMLIndent)
604AST_END(YAMLIndent)
605
606AST_LEAF(YAMLLineInner)
607AST_END(YAMLLineInner)
608
609AST_NODE(YAMLLineContent)
610 ast_sel<true, YAMLLineInner_t, Exp_t> content;
611 AST_MEMBER(YAMLLineContent, &content)
612AST_END(YAMLLineContent)
613
614AST_NODE(YAMLLine)
615 ast_ptr<true, YAMLIndent_t> indent;
616 ast_list<true, YAMLLineContent_t> segments;
617 AST_MEMBER(YAMLLine, &indent, &segments)
618AST_END(YAMLLine)
619
620AST_NODE(YAMLMultiline)
621 ast_ptr<true, Seperator_t> sep;
622 ast_list<true, YAMLLine_t> lines;
623 AST_MEMBER(YAMLMultiline, &sep, &lines)
624AST_END(YAMLMultiline)
625
590AST_NODE(String) 626AST_NODE(String)
591 ast_sel<true, DoubleString_t, SingleString_t, LuaString_t> str; 627 ast_sel<true, DoubleString_t, SingleString_t, LuaString_t, YAMLMultiline_t> str;
592 AST_MEMBER(String, &str) 628 AST_MEMBER(String, &str)
593AST_END(String) 629AST_END(String)
594 630
@@ -639,9 +675,14 @@ AST_END(TableAppendingOp)
639AST_LEAF(PlainItem) 675AST_LEAF(PlainItem)
640AST_END(PlainItem) 676AST_END(PlainItem)
641 677
678AST_NODE(ReversedIndex)
679 ast_ptr<false, Exp_t> modifier;
680 AST_MEMBER(ReversedIndex, &modifier)
681AST_END(ReversedIndex)
682
642AST_NODE(ChainValue) 683AST_NODE(ChainValue)
643 ast_ptr<true, Seperator_t> sep; 684 ast_ptr<true, Seperator_t> sep;
644 ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Slice_t, Exp_t, String_t, InvokeArgs_t, ExistentialOp_t, TableAppendingOp_t, 685 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,
645 /*non-syntax-rule*/ PlainItem_t> items; 686 /*non-syntax-rule*/ PlainItem_t> items;
646 AST_MEMBER(ChainValue, &sep, &items) 687 AST_MEMBER(ChainValue, &sep, &items)
647AST_END(ChainValue) 688AST_END(ChainValue)
@@ -717,7 +758,7 @@ AST_END(ClassDecl)
717 758
718AST_NODE(GlobalValues) 759AST_NODE(GlobalValues)
719 ast_ptr<true, NameList_t> nameList; 760 ast_ptr<true, NameList_t> nameList;
720 ast_sel<false, TableBlock_t, ExpListLow_t> valueList; 761 ast_sel<false, TableBlock_t, ExpList_t> valueList;
721 AST_MEMBER(GlobalValues, &nameList, &valueList) 762 AST_MEMBER(GlobalValues, &nameList, &valueList)
722AST_END(GlobalValues) 763AST_END(GlobalValues)
723 764
@@ -725,8 +766,9 @@ AST_LEAF(GlobalOp)
725AST_END(GlobalOp) 766AST_END(GlobalOp)
726 767
727AST_NODE(Global) 768AST_NODE(Global)
769 ast_ptr<false, ConstAttrib_t> constAttrib;
728 ast_sel<true, ClassDecl_t, GlobalOp_t, GlobalValues_t> item; 770 ast_sel<true, ClassDecl_t, GlobalOp_t, GlobalValues_t> item;
729 AST_MEMBER(Global, &item) 771 AST_MEMBER(Global, &constAttrib, &item)
730AST_END(Global) 772AST_END(Global)
731 773
732AST_LEAF(ExportDefault) 774AST_LEAF(ExportDefault)
@@ -740,17 +782,19 @@ AST_NODE(Export)
740AST_END(Export) 782AST_END(Export)
741 783
742AST_NODE(FnArgDef) 784AST_NODE(FnArgDef)
743 ast_sel<true, Variable_t, SelfItem_t> name; 785 ast_sel<true, Variable_t, SelfItem_t, SimpleTable_t, TableLit_t> name;
744 ast_ptr<false, ExistentialOp_t> op; 786 ast_ptr<false, ExistentialOp_t> op;
787 ast_ptr<false, Name_t> label;
745 ast_ptr<false, Exp_t> defaultValue; 788 ast_ptr<false, Exp_t> defaultValue;
746 AST_MEMBER(FnArgDef, &name, &op, &defaultValue) 789 AST_MEMBER(FnArgDef, &name, &op, &label, &defaultValue)
747AST_END(FnArgDef) 790AST_END(FnArgDef)
748 791
749AST_NODE(FnArgDefList) 792AST_NODE(FnArgDefList)
750 ast_ptr<true, Seperator_t> sep; 793 ast_ptr<true, Seperator_t> sep;
751 ast_list<false, FnArgDef_t> definitions; 794 ast_list<false, FnArgDef_t> definitions;
752 ast_ptr<false, VarArg_t> varArg; 795 ast_ptr<false, VarArgDef_t> varArg;
753 AST_MEMBER(FnArgDefList, &sep, &definitions, &varArg) 796 ast_ptr<false, Name_t> label;
797 AST_MEMBER(FnArgDefList, &sep, &definitions, &varArg, &label)
754AST_END(FnArgDefList) 798AST_END(FnArgDefList)
755 799
756AST_NODE(OuterVarShadow) 800AST_NODE(OuterVarShadow)
@@ -769,7 +813,7 @@ AST_END(FnArrow)
769 813
770AST_NODE(FunLit) 814AST_NODE(FunLit)
771 ast_ptr<false, FnArgsDef_t> argsDef; 815 ast_ptr<false, FnArgsDef_t> argsDef;
772 ast_sel<false, ExpListLow_t, DefaultValue_t> defaultReturn; 816 ast_sel<false, ExpList_t, DefaultValue_t> defaultReturn;
773 ast_ptr<true, FnArrow_t> arrow; 817 ast_ptr<true, FnArrow_t> arrow;
774 ast_ptr<false, Body_t> body; 818 ast_ptr<false, Body_t> body;
775 bool noRecursion = false; 819 bool noRecursion = false;
@@ -806,7 +850,7 @@ AST_NODE(Macro)
806AST_END(Macro) 850AST_END(Macro)
807 851
808AST_NODE(NameOrDestructure) 852AST_NODE(NameOrDestructure)
809 ast_sel<true, Variable_t, TableLit_t, Comprehension_t> item; 853 ast_sel<true, Variable_t, SimpleTable_t, TableLit_t, Comprehension_t> item;
810 AST_MEMBER(NameOrDestructure, &item) 854 AST_MEMBER(NameOrDestructure, &item)
811AST_END(NameOrDestructure) 855AST_END(NameOrDestructure)
812 856
@@ -838,9 +882,15 @@ AST_NODE(UnaryExp)
838 AST_MEMBER(UnaryExp, &ops, &expos, &inExp) 882 AST_MEMBER(UnaryExp, &ops, &expos, &inExp)
839AST_END(UnaryExp) 883AST_END(UnaryExp)
840 884
885AST_NODE(SubBackcall)
886 ast_ptr<true, FnArrowBack_t> arrow;
887 ast_ptr<true, ChainValue_t> value;
888 AST_MEMBER(SubBackcall, &arrow, &value)
889AST_END(SubBackcall)
890
841AST_NODE(ExpListAssign) 891AST_NODE(ExpListAssign)
842 ast_ptr<true, ExpList_t> expList; 892 ast_ptr<true, ExpList_t> expList;
843 ast_sel<false, Update_t, Assign_t> action; 893 ast_sel<false, Update_t, Assign_t, SubBackcall_t> action;
844 AST_MEMBER(ExpListAssign, &expList, &action) 894 AST_MEMBER(ExpListAssign, &expList, &action)
845AST_END(ExpListAssign) 895AST_END(ExpListAssign)
846 896
@@ -856,7 +906,17 @@ AST_NODE(WhileLine)
856 AST_MEMBER(WhileLine, &type, &condition) 906 AST_MEMBER(WhileLine, &type, &condition)
857AST_END(WhileLine) 907AST_END(WhileLine)
858 908
859AST_LEAF(BreakLoop) 909AST_LEAF(Break)
910AST_END(Break)
911
912AST_LEAF(Continue)
913AST_END(Continue)
914
915AST_NODE(BreakLoop)
916 ast_sel<true, Break_t, Continue_t> type;
917 ast_ptr<false, Exp_t> value;
918 AST_MEMBER(BreakLoop, &type, &value)
919 std::string varBWV;
860AST_END(BreakLoop) 920AST_END(BreakLoop)
861 921
862AST_NODE(PipeBody) 922AST_NODE(PipeBody)
@@ -866,7 +926,7 @@ AST_NODE(PipeBody)
866AST_END(PipeBody) 926AST_END(PipeBody)
867 927
868AST_NODE(StatementAppendix) 928AST_NODE(StatementAppendix)
869 ast_sel<true, IfLine_t, WhileLine_t, CompInner_t> item; 929 ast_sel<true, IfLine_t, WhileLine_t, CompFor_t> item;
870 AST_MEMBER(StatementAppendix, &item) 930 AST_MEMBER(StatementAppendix, &item)
871AST_END(StatementAppendix) 931AST_END(StatementAppendix)
872 932
@@ -876,14 +936,17 @@ AST_END(StatementSep)
876AST_LEAF(YueLineComment) 936AST_LEAF(YueLineComment)
877AST_END(YueLineComment) 937AST_END(YueLineComment)
878 938
879AST_LEAF(MultilineCommentInner) 939AST_LEAF(YueMultilineComment)
880AST_END(MultilineCommentInner)
881
882AST_NODE(YueMultilineComment)
883 ast_ptr<true, MultilineCommentInner_t> inner;
884 AST_MEMBER(YueMultilineComment, &inner)
885AST_END(YueMultilineComment) 940AST_END(YueMultilineComment)
886 941
942AST_NODE(YueComment)
943 ast_sel<true, YueLineComment_t, YueMultilineComment_t> comment;
944 AST_MEMBER(YueComment, &comment)
945AST_END(YueComment)
946
947AST_LEAF(EmptyLine)
948AST_END(EmptyLine)
949
887AST_NODE(ChainAssign) 950AST_NODE(ChainAssign)
888 ast_ptr<true, Seperator_t> sep; 951 ast_ptr<true, Seperator_t> sep;
889 ast_list<true, Exp_t> exprs; 952 ast_list<true, Exp_t> exprs;
@@ -892,16 +955,14 @@ AST_NODE(ChainAssign)
892AST_END(ChainAssign) 955AST_END(ChainAssign)
893 956
894AST_NODE(Statement) 957AST_NODE(Statement)
895 ast_ptr<true, Seperator_t> sep;
896 ast_sel_list<false, YueLineComment_t, YueMultilineComment_t> comments;
897 ast_sel<true, 958 ast_sel<true,
898 Import_t, While_t, Repeat_t, For_t, ForEach_t, 959 Import_t, While_t, Repeat_t, For_t,
899 Return_t, Local_t, Global_t, Export_t, Macro_t, MacroInPlace_t, 960 Return_t, Local_t, Global_t, Export_t, Macro_t, MacroInPlace_t,
900 BreakLoop_t, Label_t, Goto_t, ShortTabAppending_t, 961 BreakLoop_t, Label_t, Goto_t, ShortTabAppending_t,
901 Backcall_t, LocalAttrib_t, PipeBody_t, ExpListAssign_t, ChainAssign_t 962 Backcall_t, LocalAttrib_t, PipeBody_t, ExpListAssign_t, ChainAssign_t
902 > content; 963 > content;
903 ast_ptr<false, StatementAppendix_t> appendix; 964 ast_ptr<false, StatementAppendix_t> appendix;
904 AST_MEMBER(Statement, &sep, &comments, &content, &appendix) 965 AST_MEMBER(Statement, &content, &appendix)
905AST_END(Statement) 966AST_END(Statement)
906 967
907AST_NODE(Body) 968AST_NODE(Body)
@@ -911,8 +972,8 @@ AST_END(Body)
911 972
912AST_NODE(Block) 973AST_NODE(Block)
913 ast_ptr<true, Seperator_t> sep; 974 ast_ptr<true, Seperator_t> sep;
914 ast_list<false, Statement_t> statements; 975 ast_sel_list<false, Statement_t, YueComment_t, EmptyLine_t> statementOrComments;
915 AST_MEMBER(Block, &sep, &statements) 976 AST_MEMBER(Block, &sep, &statementOrComments)
916AST_END(Block) 977AST_END(Block)
917 978
918AST_NODE(BlockEnd) 979AST_NODE(BlockEnd)
@@ -931,9 +992,9 @@ struct YueFormat {
931 int indent = 0; 992 int indent = 0;
932 bool spaceOverTab = false; 993 bool spaceOverTab = false;
933 int tabSpaces = 4; 994 int tabSpaces = 4;
995 bool reserveComment = true;
934 std::string toString(ast_node* node); 996 std::string toString(ast_node* node);
935 997
936 Converter converter{};
937 void pushScope(); 998 void pushScope();
938 void popScope(); 999 void popScope();
939 std::string convert(const ast_node* node); 1000 std::string convert(const ast_node* node);
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index 590c502..f9b4f18 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
3Permission 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: 3Permission 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
81const std::string_view version = "0.27.5"sv; 81const std::string_view version = "0.32.1"sv;
82const std::string_view extension = "yue"sv; 82const std::string_view extension = "yue"sv;
83 83
84class CompileError : public std::logic_error { 84class CompileError : public std::logic_error {
@@ -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";
@@ -429,8 +430,18 @@ private:
429 }; 430 };
430 enum class VarType { 431 enum class VarType {
431 Local = 0, 432 Local = 0,
432 Const = 1, 433 LocalConst = 1,
433 Global = 2 434 Global = 2,
435 GlobalConst = 3
436 };
437 struct Scope;
438 struct ImportedGlobal {
439 std::string* globalCodeLine = nullptr;
440 std::unordered_map<std::string, VarType>* vars = nullptr;
441 std::string indent;
442 std::string nl;
443 std::unordered_set<std::string_view> globals;
444 str_list globalList;
434 }; 445 };
435 struct Scope { 446 struct Scope {
436 GlobalMode mode = GlobalMode::None; 447 GlobalMode mode = GlobalMode::None;
@@ -440,8 +451,10 @@ private:
440#endif 451#endif
441 std::unique_ptr<std::unordered_map<std::string, VarType>> vars; 452 std::unique_ptr<std::unordered_map<std::string, VarType>> vars;
442 std::unique_ptr<std::unordered_set<std::string>> allows; 453 std::unique_ptr<std::unordered_set<std::string>> allows;
454 std::unique_ptr<ImportedGlobal> importedGlobal;
443 }; 455 };
444 std::list<Scope> _scopes; 456 std::list<Scope> _scopes;
457 ImportedGlobal* _importedGlobal = nullptr;
445 static const std::string Empty; 458 static const std::string Empty;
446 459
447 enum class MemType { 460 enum class MemType {
@@ -558,7 +571,7 @@ private:
558 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) { 571 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) {
559 auto vars = it->vars.get(); 572 auto vars = it->vars.get();
560 auto vit = vars->find(name); 573 auto vit = vars->find(name);
561 if (vit != vars->end() && vit->second != VarType::Global) { 574 if (vit != vars->end() && (vit->second == VarType::Local || vit->second == VarType::LocalConst)) {
562 local = true; 575 local = true;
563 break; 576 break;
564 } 577 }
@@ -571,7 +584,7 @@ private:
571 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) { 584 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) {
572 auto vars = it->vars.get(); 585 auto vars = it->vars.get();
573 auto vit = vars->find(name); 586 auto vit = vars->find(name);
574 if (vit != vars->end() && vit->second == VarType::Global) { 587 if (vit != vars->end() && (vit->second == VarType::Global || vit->second == VarType::GlobalConst)) {
575 global = true; 588 global = true;
576 break; 589 break;
577 } 590 }
@@ -593,7 +606,7 @@ private:
593 auto vars = it->vars.get(); 606 auto vars = it->vars.get();
594 auto vit = vars->find(name); 607 auto vit = vars->find(name);
595 if (vit != vars->end()) { 608 if (vit != vars->end()) {
596 isConst = (vit->second == VarType::Const); 609 isConst = (vit->second == VarType::LocalConst || vit->second == VarType::GlobalConst);
597 break; 610 break;
598 } 611 }
599 if (checkShadowScopeOnly && it->allows) break; 612 if (checkShadowScopeOnly && it->allows) break;
@@ -874,9 +887,13 @@ private:
874 return false; 887 return false;
875 } 888 }
876 889
877 void markVarConst(const std::string& name) { 890 bool isListComp(Comprehension_t* comp) const {
891 return comp->items.size() == 2 && ast_is<CompFor_t>(comp->items.back());
892 }
893
894 void markVarLocalConst(const std::string& name) {
878 auto& scope = _scopes.back(); 895 auto& scope = _scopes.back();
879 scope.vars->insert_or_assign(name, VarType::Const); 896 scope.vars->insert_or_assign(name, VarType::LocalConst);
880 } 897 }
881 898
882 void markVarShadowed() { 899 void markVarShadowed() {
@@ -895,6 +912,11 @@ private:
895 scope.vars->insert_or_assign(name, VarType::Global); 912 scope.vars->insert_or_assign(name, VarType::Global);
896 } 913 }
897 914
915 void markVarGlobalConst(const std::string& name) {
916 auto& scope = _scopes.back();
917 scope.vars->insert_or_assign(name, VarType::GlobalConst);
918 }
919
898 void addToAllowList(const std::string& name) { 920 void addToAllowList(const std::string& name) {
899 auto& scope = _scopes.back(); 921 auto& scope = _scopes.back();
900 scope.allows->insert(name); 922 scope.allows->insert(name);
@@ -961,7 +983,7 @@ private:
961 } 983 }
962 } 984 }
963 985
964 const std::string nll(ast_node* node) const { 986 const std::string nl(ast_node* node) const {
965 if (_config.reserveLineNumber) { 987 if (_config.reserveLineNumber) {
966 return " -- "s + std::to_string(node->m_begin.m_line + _config.lineOffset) + _newLine; 988 return " -- "s + std::to_string(node->m_begin.m_line + _config.lineOffset) + _newLine;
967 } else { 989 } else {
@@ -969,14 +991,6 @@ private:
969 } 991 }
970 } 992 }
971 993
972 const std::string nlr(ast_node* node) const {
973 if (_config.reserveLineNumber) {
974 return " -- "s + std::to_string(node->m_end.m_line + _config.lineOffset) + _newLine;
975 } else {
976 return _newLine;
977 }
978 }
979
980 void incIndentOffset() { 994 void incIndentOffset() {
981 _indentOffset++; 995 _indentOffset++;
982 } 996 }
@@ -1043,13 +1057,6 @@ private:
1043 } 1057 }
1044 break; 1058 break;
1045 } 1059 }
1046 case id<ExpListLow_t>(): {
1047 auto expList = static_cast<ExpListLow_t*>(item);
1048 if (expList->exprs.size() == 1) {
1049 exp = static_cast<Exp_t*>(expList->exprs.front());
1050 }
1051 break;
1052 }
1053 case id<SwitchList_t>(): { 1060 case id<SwitchList_t>(): {
1054 auto expList = static_cast<SwitchList_t*>(item); 1061 auto expList = static_cast<SwitchList_t*>(item);
1055 if (expList->exprs.size() == 1) { 1062 if (expList->exprs.size() == 1) {
@@ -1078,12 +1085,12 @@ private:
1078 return nullptr; 1085 return nullptr;
1079 } 1086 }
1080 1087
1081 Value_t* singleValueFrom(ast_node* item) const { 1088 Value_t* singleValueFrom(ast_node* item, bool forceUnparened = false) const {
1082 if (auto unary = singleUnaryExpFrom(item)) { 1089 if (auto unary = singleUnaryExpFrom(item)) {
1083 if (unary->ops.empty()) { 1090 if (unary->ops.empty()) {
1084 Value_t* value = static_cast<Value_t*>(unary->expos.back()); 1091 Value_t* value = static_cast<Value_t*>(unary->expos.back());
1085 if (auto chain = ast_cast<ChainValue_t>(value->item); chain && chain->items.size() == 1) { 1092 if (auto chain = ast_cast<ChainValue_t>(value->item); chain && chain->items.size() == 1) {
1086 if (auto parens = chain->get_by_path<Callable_t, Parens_t>(); parens && parens->extra) { 1093 if (auto parens = chain->get_by_path<Callable_t, Parens_t>(); parens && (forceUnparened || parens->extra)) {
1087 if (auto insideValue = singleValueFrom(parens->expr)) { 1094 if (auto insideValue = singleValueFrom(parens->expr)) {
1088 return insideValue; 1095 return insideValue;
1089 } 1096 }
@@ -1143,6 +1150,22 @@ private:
1143 return exp; 1150 return exp;
1144 } 1151 }
1145 1152
1153 ast_ptr<false, Return_t> newReturn(Exp_t* value) {
1154 auto returnNode = value->new_ptr<Return_t>();
1155 returnNode->explicitReturn = false;
1156 auto expList = value->new_ptr<ExpList_t>();
1157 expList->exprs.push_back(value);
1158 returnNode->valueList.set(expList);
1159 return returnNode;
1160 }
1161
1162 ast_ptr<false, Return_t> newReturn(ExpList_t* valueList) {
1163 auto returnNode = valueList->new_ptr<Return_t>();
1164 returnNode->explicitReturn = false;
1165 returnNode->valueList.set(valueList);
1166 return returnNode;
1167 }
1168
1146 SimpleValue_t* simpleSingleValueFrom(ast_node* node) const { 1169 SimpleValue_t* simpleSingleValueFrom(ast_node* node) const {
1147 auto value = singleValueFrom(node); 1170 auto value = singleValueFrom(node);
1148 if (value && value->item.is<SimpleValue_t>()) { 1171 if (value && value->item.is<SimpleValue_t>()) {
@@ -1163,14 +1186,22 @@ private:
1163 return nullptr; 1186 return nullptr;
1164 } 1187 }
1165 1188
1166 Statement_t* lastStatementFrom(const node_container& stmts) const { 1189 Statement_t* lastStatementFrom(const node_container& statementOrComments) const {
1167 if (!stmts.empty()) { 1190 if (!statementOrComments.empty()) {
1168 auto it = stmts.end(); 1191 for (auto it = statementOrComments.rbegin(); it != statementOrComments.rend(); ++it) {
1169 --it; 1192 if (auto stmt = ast_cast<Statement_t>(*it)) {
1170 while (!static_cast<Statement_t*>(*it)->content && it != stmts.begin()) { 1193 return stmt;
1171 --it; 1194 }
1195 }
1196 }
1197 return nullptr;
1198 }
1199
1200 Statement_t* firstStatementFrom(Block_t* block) const {
1201 for (auto stmt_ : block->statementOrComments.objects()) {
1202 if (auto stmt = ast_cast<Statement_t>(stmt_)) {
1203 return stmt;
1172 } 1204 }
1173 return static_cast<Statement_t*>(*it);
1174 } 1205 }
1175 return nullptr; 1206 return nullptr;
1176 } 1207 }
@@ -1179,16 +1210,26 @@ private:
1179 if (auto stmt = body->content.as<Statement_t>()) { 1210 if (auto stmt = body->content.as<Statement_t>()) {
1180 return stmt; 1211 return stmt;
1181 } else { 1212 } else {
1182 const auto& stmts = body->content.to<Block_t>()->statements.objects(); 1213 const auto& stmts = body->content.to<Block_t>()->statementOrComments.objects();
1183 return lastStatementFrom(stmts); 1214 return lastStatementFrom(stmts);
1184 } 1215 }
1185 } 1216 }
1186 1217
1187 Statement_t* lastStatementFrom(Block_t* block) const { 1218 Statement_t* lastStatementFrom(Block_t* block) const {
1188 const auto& stmts = block->statements.objects(); 1219 const auto& stmts = block->statementOrComments.objects();
1189 return lastStatementFrom(stmts); 1220 return lastStatementFrom(stmts);
1190 } 1221 }
1191 1222
1223 int countStatementFrom(Block_t* block) const {
1224 int count = 0;
1225 for (auto stmt_ : block->statementOrComments.objects()) {
1226 if (ast_is<Statement_t>(stmt_)) {
1227 count++;
1228 }
1229 }
1230 return count;
1231 }
1232
1192 Exp_t* lastExpFromAssign(ast_node* action) { 1233 Exp_t* lastExpFromAssign(ast_node* action) {
1193 switch (action->get_id()) { 1234 switch (action->get_id()) {
1194 case id<Update_t>(): { 1235 case id<Update_t>(): {
@@ -1232,7 +1273,7 @@ private:
1232 } 1273 }
1233 case id<Local_t>(): { 1274 case id<Local_t>(): {
1234 if (auto localValues = static_cast<Local_t*>(stmt->content.get())->item.as<LocalValues_t>()) { 1275 if (auto localValues = static_cast<Local_t*>(stmt->content.get())->item.as<LocalValues_t>()) {
1235 if (auto expList = localValues->valueList.as<ExpListLow_t>()) { 1276 if (auto expList = localValues->valueList.as<ExpList_t>()) {
1236 return static_cast<Exp_t*>(expList->exprs.back()); 1277 return static_cast<Exp_t*>(expList->exprs.back());
1237 } 1278 }
1238 } 1279 }
@@ -1240,7 +1281,7 @@ private:
1240 } 1281 }
1241 case id<Global_t>(): { 1282 case id<Global_t>(): {
1242 if (auto globalValues = static_cast<Global_t*>(stmt->content.get())->item.as<GlobalValues_t>()) { 1283 if (auto globalValues = static_cast<Global_t*>(stmt->content.get())->item.as<GlobalValues_t>()) {
1243 if (auto expList = globalValues->valueList.as<ExpListLow_t>()) { 1284 if (auto expList = globalValues->valueList.as<ExpList_t>()) {
1244 return static_cast<Exp_t*>(expList->exprs.back()); 1285 return static_cast<Exp_t*>(expList->exprs.back());
1245 } 1286 }
1246 } 1287 }
@@ -1252,7 +1293,7 @@ private:
1252 1293
1253 template <class T> 1294 template <class T>
1254 ast_ptr<false, T> toAst(std::string_view codes, ast_node* parent) { 1295 ast_ptr<false, T> toAst(std::string_view codes, ast_node* parent) {
1255 auto res = _parser.parse<T>(std::string(codes)); 1296 auto res = _parser.parse<T>(std::string(codes), false);
1256 if (res.error) { 1297 if (res.error) {
1257 throw CompileError(res.error.value().msg, parent); 1298 throw CompileError(res.error.value().msg, parent);
1258 } 1299 }
@@ -1275,6 +1316,8 @@ private:
1275 Common, 1316 Common,
1276 EndWithColon, 1317 EndWithColon,
1277 EndWithEOP, 1318 EndWithEOP,
1319 EndWithSlice,
1320 HasRIndex,
1278 HasEOP, 1321 HasEOP,
1279 HasKeyword, 1322 HasKeyword,
1280 HasUnicode, 1323 HasUnicode,
@@ -1293,6 +1336,9 @@ private:
1293 if (ast_is<ExistentialOp_t>(chainValue->items.back())) { 1336 if (ast_is<ExistentialOp_t>(chainValue->items.back())) {
1294 return ChainType::EndWithEOP; 1337 return ChainType::EndWithEOP;
1295 } 1338 }
1339 if (ast_is<Slice_t>(chainValue->items.back())) {
1340 return ChainType::EndWithSlice;
1341 }
1296 if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) { 1342 if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) {
1297 if (dot->name.is<Metatable_t>()) { 1343 if (dot->name.is<Metatable_t>()) {
1298 return ChainType::Metatable; 1344 return ChainType::Metatable;
@@ -1318,6 +1364,8 @@ private:
1318 } 1364 }
1319 } else if (ast_is<ExistentialOp_t>(item)) { 1365 } else if (ast_is<ExistentialOp_t>(item)) {
1320 return ChainType::HasEOP; 1366 return ChainType::HasEOP;
1367 } else if (ast_is<ReversedIndex_t>(item)) {
1368 return ChainType::HasRIndex;
1321 } 1369 }
1322 } 1370 }
1323 return type; 1371 return type;
@@ -1347,10 +1395,10 @@ private:
1347 std::ostringstream buf; 1395 std::ostringstream buf;
1348 for (auto it = uname->m_begin.m_it; it != uname->m_end.m_it; ++it) { 1396 for (auto it = uname->m_begin.m_it; it != uname->m_end.m_it; ++it) {
1349 auto ch = *it; 1397 auto ch = *it;
1350 if (ch > 255) { 1398 if (ch <= 0x7F && ((ch == '_') || ((ch | 0x20) >= 'a' && (ch | 0x20) <= 'z') || (ch >= '0' && ch <= '9'))) {
1351 buf << "_u"sv << std::hex << static_cast<int>(ch);
1352 } else {
1353 buf << static_cast<char>(ch); 1399 buf << static_cast<char>(ch);
1400 } else {
1401 buf << "_u"sv << std::hex << static_cast<uint32_t>(ch);
1354 } 1402 }
1355 } 1403 }
1356 return buf.str(); 1404 return buf.str();
@@ -1432,6 +1480,7 @@ private:
1432 case id<DotChainItem_t>(): 1480 case id<DotChainItem_t>():
1433 case id<Exp_t>(): 1481 case id<Exp_t>():
1434 case id<TableAppendingOp_t>(): 1482 case id<TableAppendingOp_t>():
1483 case id<ReversedIndex_t>():
1435 return true; 1484 return true;
1436 } 1485 }
1437 } 1486 }
@@ -1449,7 +1498,7 @@ private:
1449 if (simpleValue->value.is<TableLit_t>()) { 1498 if (simpleValue->value.is<TableLit_t>()) {
1450 return true; 1499 return true;
1451 } else if (auto comp = simpleValue->value.as<Comprehension_t>()) { 1500 } else if (auto comp = simpleValue->value.as<Comprehension_t>()) {
1452 if (comp->items.size() != 2 || !ast_is<CompInner_t>(comp->items.back())) { 1501 if (!isListComp(comp)) {
1453 return true; 1502 return true;
1454 } 1503 }
1455 } 1504 }
@@ -1581,16 +1630,26 @@ private:
1581 return !_varArgs.empty() && _varArgs.top().usedVar ? "end)(...)"s : "end)()"s; 1630 return !_varArgs.empty() && _varArgs.top().usedVar ? "end)(...)"s : "end)()"s;
1582 } 1631 }
1583 1632
1633 void markGlobalImported(const std::string& name) {
1634 if (_importedGlobal->globals.find(name) == _importedGlobal->globals.end() && !isSolidDefined(name)) {
1635 const auto& global = _importedGlobal->globalList.emplace_back(name);
1636 _importedGlobal->globals.insert(global);
1637 _importedGlobal->vars->insert_or_assign(name, VarType::LocalConst);
1638 }
1639 }
1640
1584 std::string globalVar(std::string_view var, ast_node* x, AccessType accessType) { 1641 std::string globalVar(std::string_view var, ast_node* x, AccessType accessType) {
1585 std::string str(var); 1642 std::string str(var);
1586 if (_config.lintGlobalVariable) { 1643 if (_importedGlobal) {
1644 markGlobalImported(str);
1645 } else if (_config.lintGlobalVariable) {
1587 if (!isLocal(str)) { 1646 if (!isLocal(str)) {
1588 auto key = str + ':' + std::to_string(x->m_begin.m_line) + ':' + std::to_string(x->m_begin.m_col); 1647 auto key = str + ':' + std::to_string(x->m_begin.m_line) + ':' + std::to_string(x->m_begin.m_col);
1589 if (_globals.find(key) == _globals.end()) { 1648 if (_globals.find(key) == _globals.end()) {
1590 if (accessType == AccessType::Read && _funcLevel > 1) { 1649 if (accessType == AccessType::Read && _funcLevel > 1) {
1591 accessType = AccessType::Capture; 1650 accessType = AccessType::Capture;
1592 } 1651 }
1593 _globals[key] = {str, x->m_begin.m_line, x->m_begin.m_col, accessType}; 1652 _globals[key] = {str, x->m_begin.m_line, x->m_begin.m_col, accessType, isSolidDefined(str)};
1594 } 1653 }
1595 } 1654 }
1596 } 1655 }
@@ -1632,24 +1691,31 @@ private:
1632 return; 1691 return;
1633 } 1692 }
1634 1693
1635 void transformStatement(Statement_t* statement, str_list& out) { 1694 void transformComment(YueComment_t* comment, str_list& out) {
1636 auto x = statement; 1695 if (!_config.reserveComment) {
1637 if (_config.reserveComment && !x->comments.empty()) { 1696 return;
1638 for (ast_node* node : x->comments.objects()) { 1697 }
1639 switch (node->get_id()) { 1698 auto node = comment->comment.get();
1640 case id<YueLineComment_t>(): { 1699 if (!node) {
1641 auto comment = ast_cast<YueLineComment_t>(node); 1700 out.push_back("\n"s);
1642 out.push_back(indent() + "--"s + _parser.toString(comment) + '\n'); 1701 return;
1643 break; 1702 }
1644 } 1703 switch (node->get_id()) {
1645 case id<YueMultilineComment_t>(): { 1704 case id<YueLineComment_t>(): {
1646 auto comment = ast_cast<YueMultilineComment_t>(node); 1705 auto content = static_cast<YueLineComment_t*>(node);
1647 out.push_back(indent() + _parser.toString(comment) + '\n'); 1706 out.push_back(indent() + "--"s + _parser.toString(content) + '\n');
1648 break; 1707 break;
1649 } 1708 }
1650 } 1709 case id<YueMultilineComment_t>(): {
1710 auto content = static_cast<YueMultilineComment_t*>(node);
1711 out.push_back(indent() + "--[["s + _parser.toString(content) + "]]\n"s);
1712 break;
1651 } 1713 }
1652 } 1714 }
1715 }
1716
1717 void transformStatement(Statement_t* statement, str_list& out) {
1718 auto x = statement;
1653 if (statement->appendix) { 1719 if (statement->appendix) {
1654 if (auto assignment = assignmentFrom(statement)) { 1720 if (auto assignment = assignmentFrom(statement)) {
1655 auto preDefine = getPreDefineLine(assignment); 1721 auto preDefine = getPreDefineLine(assignment);
@@ -1713,7 +1779,7 @@ private:
1713 throw CompileError("while-loop line decorator is not supported here"sv, appendix->item.get()); 1779 throw CompileError("while-loop line decorator is not supported here"sv, appendix->item.get());
1714 break; 1780 break;
1715 } 1781 }
1716 case id<CompInner_t>(): { 1782 case id<CompFor_t>(): {
1717 throw CompileError("for-loop line decorator is not supported here"sv, appendix->item.get()); 1783 throw CompileError("for-loop line decorator is not supported here"sv, appendix->item.get());
1718 break; 1784 break;
1719 } 1785 }
@@ -1774,8 +1840,8 @@ private:
1774 statement->content.set(expListAssign); 1840 statement->content.set(expListAssign);
1775 break; 1841 break;
1776 } 1842 }
1777 case id<CompInner_t>(): { 1843 case id<CompFor_t>(): {
1778 auto compInner = appendix->item.to<CompInner_t>(); 1844 auto compInner = appendix->item.to<CompFor_t>();
1779 auto comp = x->new_ptr<Comprehension_t>(); 1845 auto comp = x->new_ptr<Comprehension_t>();
1780 auto stmt = x->new_ptr<Statement_t>(); 1846 auto stmt = x->new_ptr<Statement_t>();
1781 stmt->content.set(statement->content); 1847 stmt->content.set(statement->content);
@@ -1840,11 +1906,12 @@ private:
1840 case id<ForEach_t>(): transformForEach(static_cast<ForEach_t*>(value), out); break; 1906 case id<ForEach_t>(): transformForEach(static_cast<ForEach_t*>(value), out); break;
1841 case id<For_t>(): transformFor(static_cast<For_t*>(value), out); break; 1907 case id<For_t>(): transformFor(static_cast<For_t*>(value), out); break;
1842 case id<While_t>(): transformWhile(static_cast<While_t*>(value), out); break; 1908 case id<While_t>(): transformWhile(static_cast<While_t*>(value), out); break;
1909 case id<Repeat_t>(): transformRepeat(static_cast<Repeat_t*>(value), out); break;
1843 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Common); break; 1910 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Common); break;
1844 case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Common); break; 1911 case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Common); break;
1845 case id<Comprehension_t>(): { 1912 case id<Comprehension_t>(): {
1846 auto comp = static_cast<Comprehension_t*>(value); 1913 auto comp = static_cast<Comprehension_t*>(value);
1847 if (comp->items.size() == 2 && ast_is<CompInner_t>(comp->items.back())) { 1914 if (isListComp(comp)) {
1848 transformCompCommon(comp, out); 1915 transformCompCommon(comp, out);
1849 } else { 1916 } else {
1850 specialSingleValue = false; 1917 specialSingleValue = false;
@@ -1968,7 +2035,7 @@ private:
1968 return indent() + "local "s + join(defs, ", "sv); 2035 return indent() + "local "s + join(defs, ", "sv);
1969 } 2036 }
1970 2037
1971 std::string getDestrucureDefine(ExpListAssign_t* assignment) { 2038 std::string getDestructureDefine(ExpListAssign_t* assignment) {
1972 auto info = extractDestructureInfo(assignment, true, false); 2039 auto info = extractDestructureInfo(assignment, true, false);
1973 if (!info.destructures.empty()) { 2040 if (!info.destructures.empty()) {
1974 str_list defs; 2041 str_list defs;
@@ -1999,8 +2066,31 @@ private:
1999 return clearBuf(); 2066 return clearBuf();
2000 } 2067 }
2001 2068
2069 str_list getArgDestructureList(ExpListAssign_t* assignment) {
2070 str_list defs;
2071 auto info = extractDestructureInfo(assignment, true, false);
2072 if (!info.destructures.empty()) {
2073 for (const auto& des : info.destructures) {
2074 if (std::holds_alternative<Destructure>(des)) {
2075 const auto& destruct = std::get<Destructure>(des);
2076 for (const auto& item : destruct.items) {
2077 if (item.targetVar.empty()) {
2078 throw CompileError("can only destruct argument to variable"sv, item.target);
2079 } else {
2080 defs.push_back(item.targetVar);
2081 }
2082 }
2083 } else {
2084 const auto& assignment = std::get<AssignmentPtr>(des);
2085 YUEE("AST node mismatch", assignment.ptr);
2086 }
2087 }
2088 }
2089 return defs;
2090 }
2091
2002 std::string getPreDefine(ExpListAssign_t* assignment) { 2092 std::string getPreDefine(ExpListAssign_t* assignment) {
2003 auto preDefine = getDestrucureDefine(assignment); 2093 auto preDefine = getDestructureDefine(assignment);
2004 if (preDefine.empty()) { 2094 if (preDefine.empty()) {
2005 preDefine = toLocalDecl(transformAssignDefs(assignment->expList, DefOp::Mark)); 2095 preDefine = toLocalDecl(transformAssignDefs(assignment->expList, DefOp::Mark));
2006 } 2096 }
@@ -2009,7 +2099,7 @@ private:
2009 2099
2010 std::string getPreDefineLine(ExpListAssign_t* assignment) { 2100 std::string getPreDefineLine(ExpListAssign_t* assignment) {
2011 auto preDefine = getPreDefine(assignment); 2101 auto preDefine = getPreDefine(assignment);
2012 if (!preDefine.empty()) preDefine += nll(assignment); 2102 if (!preDefine.empty()) preDefine += nl(assignment);
2013 return preDefine; 2103 return preDefine;
2014 } 2104 }
2015 2105
@@ -2051,13 +2141,16 @@ private:
2051 if (item.targetVar.empty()) { 2141 if (item.targetVar.empty()) {
2052 throw CompileError("can only declare variable as const"sv, item.target); 2142 throw CompileError("can only declare variable as const"sv, item.target);
2053 } 2143 }
2054 markVarConst(item.targetVar); 2144 markVarLocalConst(item.targetVar);
2055 } 2145 }
2056 } 2146 }
2057 } 2147 }
2058 } 2148 }
2059 2149
2060 bool transformAssignment(ExpListAssign_t* assignment, str_list& out, bool optionalDestruct = false) { 2150 bool transformAssignment(ExpListAssign_t* assignment, str_list& out, bool optionalDestruct = false) {
2151 if (assignment->action.is<SubBackcall_t>()) {
2152 YUEE("AST node mismatch", assignment->action);
2153 }
2061 checkAssignable(assignment->expList); 2154 checkAssignable(assignment->expList);
2062 BLOCK_START 2155 BLOCK_START
2063 auto assign = ast_cast<Assign_t>(assignment->action); 2156 auto assign = ast_cast<Assign_t>(assignment->action);
@@ -2162,14 +2255,14 @@ private:
2162 temp.push_back(getPreDefineLine(assignment)); 2255 temp.push_back(getPreDefineLine(assignment));
2163 bool needScope = !currentScope().lastStatement; 2256 bool needScope = !currentScope().lastStatement;
2164 if (needScope) { 2257 if (needScope) {
2165 temp.push_back(indent() + "do"s + nll(assignment)); 2258 temp.push_back(indent() + "do"s + nl(assignment));
2166 pushScope(); 2259 pushScope();
2167 } 2260 }
2168 transformAssignment(preAssignment, temp); 2261 transformAssignment(preAssignment, temp);
2169 transformAssignment(assignment, temp); 2262 transformAssignment(assignment, temp);
2170 if (needScope) { 2263 if (needScope) {
2171 popScope(); 2264 popScope();
2172 temp.push_back(indent() + "end"s + nll(assignment)); 2265 temp.push_back(indent() + "end"s + nl(assignment));
2173 } 2266 }
2174 out.push_back(join(temp)); 2267 out.push_back(join(temp));
2175 return false; 2268 return false;
@@ -2214,7 +2307,8 @@ private:
2214 BREAK_IF(!value); 2307 BREAK_IF(!value);
2215 auto chainValue = value->item.as<ChainValue_t>(); 2308 auto chainValue = value->item.as<ChainValue_t>();
2216 BREAK_IF(!chainValue); 2309 BREAK_IF(!chainValue);
2217 if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) { 2310 auto last = chainValue->items.back();
2311 if (auto dot = ast_cast<DotChainItem_t>(last)) {
2218 BREAK_IF(!dot->name.is<Metatable_t>()); 2312 BREAK_IF(!dot->name.is<Metatable_t>());
2219 str_list temp; 2313 str_list temp;
2220 auto [beforeAssignment, afterAssignment] = splitAssignment(); 2314 auto [beforeAssignment, afterAssignment] = splitAssignment();
@@ -2238,14 +2332,14 @@ private:
2238 throw CompileError("right value missing"sv, values.front()); 2332 throw CompileError("right value missing"sv, values.front());
2239 } 2333 }
2240 transformAssignItem(*vit, args); 2334 transformAssignItem(*vit, args);
2241 _buf << indent() << globalVar("setmetatable"sv, x, AccessType::Read) << '(' << join(args, ", "sv) << ')' << nll(x); 2335 _buf << indent() << globalVar("setmetatable"sv, x, AccessType::Read) << '(' << join(args, ", "sv) << ')' << nl(x);
2242 temp.push_back(clearBuf()); 2336 temp.push_back(clearBuf());
2243 if (!afterAssignment->expList->exprs.empty()) { 2337 if (!afterAssignment->expList->exprs.empty()) {
2244 transformAssignment(afterAssignment, temp); 2338 transformAssignment(afterAssignment, temp);
2245 } 2339 }
2246 out.push_back(join(temp)); 2340 out.push_back(join(temp));
2247 return false; 2341 return false;
2248 } else if (ast_is<TableAppendingOp_t>(chainValue->items.back())) { 2342 } else if (ast_is<TableAppendingOp_t>(last)) {
2249 str_list temp; 2343 str_list temp;
2250 auto [beforeAssignment, afterAssignment] = splitAssignment(); 2344 auto [beforeAssignment, afterAssignment] = splitAssignment();
2251 if (!beforeAssignment->expList->exprs.empty()) { 2345 if (!beforeAssignment->expList->exprs.empty()) {
@@ -2267,7 +2361,7 @@ private:
2267 if (varName.empty() || !isLocal(varName)) { 2361 if (varName.empty() || !isLocal(varName)) {
2268 if (needScope) { 2362 if (needScope) {
2269 extraScoped = true; 2363 extraScoped = true;
2270 temp.push_back(indent() + "do"s + nll(x)); 2364 temp.push_back(indent() + "do"s + nl(x));
2271 pushScope(); 2365 pushScope();
2272 } 2366 }
2273 auto objVar = getUnusedName("_obj_"sv); 2367 auto objVar = getUnusedName("_obj_"sv);
@@ -2279,24 +2373,74 @@ private:
2279 transformAssignment(newAssignment, temp); 2373 transformAssignment(newAssignment, temp);
2280 varName = objVar; 2374 varName = objVar;
2281 } 2375 }
2282 auto newAssignment = x->new_ptr<ExpListAssign_t>(); 2376 if (auto spread = ast_cast<SpreadListExp_t>(*vit)) {
2283 newAssignment->expList.set(toAst<ExpList_t>(varName + "[#"s + varName + "+1]"s, x)); 2377 auto lenVar = getUnusedName("_len_"sv);
2284 auto assign = x->new_ptr<Assign_t>(); 2378 forceAddToScope(lenVar);
2285 if (vit == values.end()) { 2379 temp.push_back(indent() + "local "s + lenVar + " = #"s + varName + " + 1"s + nl(spread));
2286 throw CompileError("right value missing"sv, values.front()); 2380 auto elmVar = getUnusedName("_elm_"sv);
2381 _buf << varName << '[' << lenVar << "],"s << lenVar << "="s << elmVar << ',' << lenVar << "+1 for "s << elmVar << " in *nil"s;
2382 auto stmt = toAst<Statement_t>(clearBuf(), spread);
2383 auto comp = stmt->appendix->item.to<CompFor_t>();
2384 ast_to<CompForEach_t>(comp->items.front())->loopValue.to<StarExp_t>()->value.set(spread->exp);
2385 transformStatement(stmt, temp);
2386 } else {
2387 auto newAssignment = x->new_ptr<ExpListAssign_t>();
2388 newAssignment->expList.set(toAst<ExpList_t>(varName + "[#"s + varName + "+1]"s, x));
2389 auto assign = x->new_ptr<Assign_t>();
2390 if (vit == values.end()) {
2391 throw CompileError("right value missing"sv, values.front());
2392 }
2393 assign->values.push_back(*vit);
2394 newAssignment->action.set(assign);
2395 transformAssignment(newAssignment, temp);
2287 } 2396 }
2288 assign->values.push_back(*vit);
2289 newAssignment->action.set(assign);
2290 transformAssignment(newAssignment, temp);
2291 if (extraScoped) { 2397 if (extraScoped) {
2292 popScope(); 2398 popScope();
2293 temp.push_back(indent() + "end"s + nlr(x)); 2399 temp.push_back(indent() + "end"s + nl(x));
2294 } 2400 }
2295 if (!afterAssignment->expList->exprs.empty()) { 2401 if (!afterAssignment->expList->exprs.empty()) {
2296 transformAssignment(afterAssignment, temp); 2402 transformAssignment(afterAssignment, temp);
2297 } 2403 }
2298 out.push_back(join(temp)); 2404 out.push_back(join(temp));
2299 return false; 2405 return false;
2406 } else if (ast_is<ReversedIndex_t>(last)) {
2407 if (chainValue->items.size() == 1) {
2408 if (_withVars.empty()) {
2409 throw CompileError("short dot/colon syntax must be called within a with block"sv, x);
2410 } else {
2411 break;
2412 }
2413 }
2414 auto tmpChain = chainValue->new_ptr<ChainValue_t>();
2415 tmpChain->items.dup(chainValue->items);
2416 tmpChain->items.pop_back();
2417 auto tmpLeft = newExp(tmpChain, tmpChain);
2418 auto leftVar = singleVariableFrom(tmpLeft, AccessType::Read);
2419 if (!leftVar.empty() && isLocal(leftVar)) {
2420 break;
2421 }
2422 leftVar = getUnusedName("_obj_"sv);
2423 auto tmpAsmt = assignmentFrom(toAst<Exp_t>(leftVar, tmpLeft), tmpLeft, tmpLeft);
2424 str_list temp;
2425 transformAssignment(tmpAsmt, temp);
2426 auto [beforeAssignment, afterAssignment] = splitAssignment();
2427 if (!beforeAssignment->expList->exprs.empty()) {
2428 transformAssignment(beforeAssignment, temp);
2429 }
2430 if (vit == values.end()) {
2431 throw CompileError("right value missing"sv, values.front());
2432 }
2433 auto newChain = chainValue->new_ptr<ChainValue_t>();
2434 newChain->items.push_back(toAst<Callable_t>(leftVar, newChain));
2435 newChain->items.push_back(chainValue->items.back());
2436 auto newLeft = newExp(newChain, newChain);
2437 auto newAsmt = assignmentFrom(newLeft, *vit, newLeft);
2438 transformAssignment(newAsmt, temp);
2439 if (!afterAssignment->expList->exprs.empty()) {
2440 transformAssignment(afterAssignment, temp);
2441 }
2442 out.push_back(join(temp));
2443 return false;
2300 } else { 2444 } else {
2301 break; 2445 break;
2302 } 2446 }
@@ -2320,6 +2464,17 @@ private:
2320 out.back().insert(0, preDefine); 2464 out.back().insert(0, preDefine);
2321 return false; 2465 return false;
2322 } 2466 }
2467 case id<Try_t>(): {
2468 auto tryNode = static_cast<Try_t*>(value);
2469 if (tryNode->eop) {
2470 auto assignList = assignment->expList.get();
2471 std::string preDefine = getPreDefineLine(assignment);
2472 transformTry(tryNode, out, ExpUsage::Assignment, assignList);
2473 out.back().insert(0, preDefine);
2474 return false;
2475 }
2476 break;
2477 }
2323 case id<Switch_t>(): { 2478 case id<Switch_t>(): {
2324 auto switchNode = static_cast<Switch_t*>(value); 2479 auto switchNode = static_cast<Switch_t*>(value);
2325 auto assignList = assignment->expList.get(); 2480 auto assignList = assignment->expList.get();
@@ -2347,7 +2502,7 @@ private:
2347 case id<Comprehension_t>(): { 2502 case id<Comprehension_t>(): {
2348 auto comp = static_cast<Comprehension_t*>(value); 2503 auto comp = static_cast<Comprehension_t*>(value);
2349 auto expList = assignment->expList.get(); 2504 auto expList = assignment->expList.get();
2350 if (comp->items.size() == 2 && ast_is<CompInner_t>(comp->items.back())) { 2505 if (isListComp(comp)) {
2351 std::string preDefine = getPreDefineLine(assignment); 2506 std::string preDefine = getPreDefineLine(assignment);
2352 transformComprehension(comp, out, ExpUsage::Assignment, expList); 2507 transformComprehension(comp, out, ExpUsage::Assignment, expList);
2353 out.back().insert(0, preDefine); 2508 out.back().insert(0, preDefine);
@@ -2391,6 +2546,13 @@ private:
2391 out.back().insert(0, preDefine); 2546 out.back().insert(0, preDefine);
2392 return false; 2547 return false;
2393 } 2548 }
2549 case id<Repeat_t>(): {
2550 auto expList = assignment->expList.get();
2551 std::string preDefine = getPreDefineLine(assignment);
2552 transformRepeatInPlace(static_cast<Repeat_t*>(value), out, expList);
2553 out.back().insert(0, preDefine);
2554 return false;
2555 }
2394 case id<TableLit_t>(): { 2556 case id<TableLit_t>(): {
2395 auto tableLit = static_cast<TableLit_t*>(value); 2557 auto tableLit = static_cast<TableLit_t*>(value);
2396 if (hasSpreadExp(tableLit->values.objects())) { 2558 if (hasSpreadExp(tableLit->values.objects())) {
@@ -2443,12 +2605,14 @@ private:
2443 switch (type) { 2605 switch (type) {
2444 case ChainType::HasEOP: 2606 case ChainType::HasEOP:
2445 case ChainType::EndWithColon: 2607 case ChainType::EndWithColon:
2608 case ChainType::EndWithSlice:
2446 case ChainType::MetaFieldInvocation: { 2609 case ChainType::MetaFieldInvocation: {
2447 std::string preDefine = getPreDefineLine(assignment); 2610 std::string preDefine = getPreDefineLine(assignment);
2448 transformChainValue(chainValue, out, ExpUsage::Assignment, expList, false, optionalDestruct); 2611 transformChainValue(chainValue, out, ExpUsage::Assignment, expList, false, optionalDestruct);
2449 out.back().insert(0, preDefine); 2612 out.back().insert(0, preDefine);
2450 return false; 2613 return false;
2451 } 2614 }
2615 case ChainType::HasRIndex:
2452 case ChainType::HasKeyword: 2616 case ChainType::HasKeyword:
2453 case ChainType::HasUnicode: 2617 case ChainType::HasUnicode:
2454 case ChainType::Macro: 2618 case ChainType::Macro:
@@ -2464,6 +2628,10 @@ private:
2464 auto info = extractDestructureInfo(assignment, false, optionalDestruct); 2628 auto info = extractDestructureInfo(assignment, false, optionalDestruct);
2465 if (info.destructures.empty()) { 2629 if (info.destructures.empty()) {
2466 transformAssignmentCommon(assignment, out); 2630 transformAssignmentCommon(assignment, out);
2631 if (assignment->expList->followStmt) {
2632 transformStatement(assignment->expList->followStmt, out);
2633 assignment->expList->followStmtProcessed = true;
2634 }
2467 return true; 2635 return true;
2468 } else { 2636 } else {
2469 auto x = assignment; 2637 auto x = assignment;
@@ -2499,11 +2667,11 @@ private:
2499 checkConst(def, x); 2667 checkConst(def, x);
2500 addToScope(def); 2668 addToScope(def);
2501 } 2669 }
2502 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nll(x)); 2670 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nl(x));
2503 } 2671 }
2504 if (needScope) { 2672 if (needScope) {
2505 extraScope = true; 2673 extraScope = true;
2506 temp.push_back(indent() + "do"s + nll(x)); 2674 temp.push_back(indent() + "do"s + nl(x));
2507 pushScope(); 2675 pushScope();
2508 } 2676 }
2509 } 2677 }
@@ -2555,13 +2723,13 @@ private:
2555 continue; 2723 continue;
2556 } 2724 }
2557 if (extraScope) { 2725 if (extraScope) {
2558 temp.push_back(indent() + "do"s + nll(x)); 2726 temp.push_back(indent() + "do"s + nl(x));
2559 pushScope(); 2727 pushScope();
2560 } 2728 }
2561 if (!pair.targetVar.empty()) { 2729 if (!pair.targetVar.empty()) {
2562 checkConst(pair.targetVar, x); 2730 checkConst(pair.targetVar, x);
2563 if (addToScope(pair.targetVar)) { 2731 if (addToScope(pair.targetVar)) {
2564 _buf << indent() << "local "sv << pair.targetVar << nll(x); 2732 _buf << indent() << "local "sv << pair.targetVar << nl(x);
2565 temp.push_back(clearBuf()); 2733 temp.push_back(clearBuf());
2566 } 2734 }
2567 } 2735 }
@@ -2571,7 +2739,7 @@ private:
2571 objVar = destruct.valueVar; 2739 objVar = destruct.valueVar;
2572 } else { 2740 } else {
2573 if (needScope) { 2741 if (needScope) {
2574 temp.push_back(indent() + "do"s + nll(x)); 2742 temp.push_back(indent() + "do"s + nl(x));
2575 pushScope(); 2743 pushScope();
2576 } 2744 }
2577 objVar = getUnusedName("_obj_"sv); 2745 objVar = getUnusedName("_obj_"sv);
@@ -2587,7 +2755,7 @@ private:
2587 if (!isLocalValue) { 2755 if (!isLocalValue) {
2588 if (needScope) { 2756 if (needScope) {
2589 popScope(); 2757 popScope();
2590 _buf << indent() << "end"sv << nlr(x); 2758 _buf << indent() << "end"sv << nl(x);
2591 temp.push_back(clearBuf()); 2759 temp.push_back(clearBuf());
2592 } 2760 }
2593 } 2761 }
@@ -2625,9 +2793,9 @@ private:
2625 checkConst(def, x); 2793 checkConst(def, x);
2626 addToScope(def); 2794 addToScope(def);
2627 } 2795 }
2628 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nll(x)); 2796 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nl(x));
2629 } 2797 }
2630 temp.push_back(indent() + "do"s + nll(x)); 2798 temp.push_back(indent() + "do"s + nl(x));
2631 pushScope(); 2799 pushScope();
2632 } 2800 }
2633 } else { 2801 } else {
@@ -2636,11 +2804,11 @@ private:
2636 checkConst(def, x); 2804 checkConst(def, x);
2637 addToScope(def); 2805 addToScope(def);
2638 } 2806 }
2639 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nll(x)); 2807 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nl(x));
2640 } 2808 }
2641 if (needScope) { 2809 if (needScope) {
2642 extraScope = true; 2810 extraScope = true;
2643 temp.push_back(indent() + "do"s + nll(x)); 2811 temp.push_back(indent() + "do"s + nl(x));
2644 pushScope(); 2812 pushScope();
2645 } 2813 }
2646 auto valVar = getUnusedName("_obj_"sv); 2814 auto valVar = getUnusedName("_obj_"sv);
@@ -2655,7 +2823,7 @@ private:
2655 if (destruct.inlineAssignment) { 2823 if (destruct.inlineAssignment) {
2656 if (needScope && !extraScope) { 2824 if (needScope && !extraScope) {
2657 extraScope = true; 2825 extraScope = true;
2658 temp.push_back(indent() + "do"s + nll(x)); 2826 temp.push_back(indent() + "do"s + nl(x));
2659 pushScope(); 2827 pushScope();
2660 } 2828 }
2661 transformAssignment(destruct.inlineAssignment, temp); 2829 transformAssignment(destruct.inlineAssignment, temp);
@@ -2720,17 +2888,21 @@ private:
2720 } 2888 }
2721 if (extraScope) { 2889 if (extraScope) {
2722 popScope(); 2890 popScope();
2723 _buf << indent() << "end"sv << nlr(x); 2891 _buf << indent() << "end"sv << nl(x);
2724 temp.push_back(clearBuf()); 2892 temp.push_back(clearBuf());
2725 } 2893 }
2726 } 2894 }
2727 if (extraScope) { 2895 if (extraScope) {
2728 popScope(); 2896 popScope();
2729 temp.push_back(indent() + "end"s + nlr(x)); 2897 temp.push_back(indent() + "end"s + nl(x));
2730 } 2898 }
2731 out.push_back(join(temp)); 2899 out.push_back(join(temp));
2900 if (assignment->expList->followStmt) {
2901 transformStatement(assignment->expList->followStmt, out);
2902 assignment->expList->followStmtProcessed = true;
2903 }
2904 return false;
2732 } 2905 }
2733 return false;
2734 } 2906 }
2735 2907
2736 void transformAssignItem(ast_node* value, str_list& out) { 2908 void transformAssignItem(ast_node* value, str_list& out) {
@@ -2740,6 +2912,7 @@ private:
2740 case id<Switch_t>(): transformSwitch(static_cast<Switch_t*>(value), out, ExpUsage::Closure); break; 2912 case id<Switch_t>(): transformSwitch(static_cast<Switch_t*>(value), out, ExpUsage::Closure); break;
2741 case id<TableBlock_t>(): transformTableBlock(static_cast<TableBlock_t*>(value), out); break; 2913 case id<TableBlock_t>(): transformTableBlock(static_cast<TableBlock_t*>(value), out); break;
2742 case id<Exp_t>(): transformExp(static_cast<Exp_t*>(value), out, ExpUsage::Closure); break; 2914 case id<Exp_t>(): transformExp(static_cast<Exp_t*>(value), out, ExpUsage::Closure); break;
2915 case id<SpreadListExp_t>(): throw CompileError("can only be used for ranged table append assignments"sv, value); break;
2743 default: YUEE("AST node mismatch", value); break; 2916 default: YUEE("AST node mismatch", value); break;
2744 } 2917 }
2745 } 2918 }
@@ -2754,7 +2927,7 @@ private:
2754 if (auto tbA = item->get_by_path<TableLit_t>()) { 2927 if (auto tbA = item->get_by_path<TableLit_t>()) {
2755 tableItems = &tbA->values.objects(); 2928 tableItems = &tbA->values.objects();
2756 } else if (auto tbB = item->get_by_path<Comprehension_t>()) { 2929 } else if (auto tbB = item->get_by_path<Comprehension_t>()) {
2757 if (tbB->items.size() == 2 && ast_is<CompInner_t>(tbB->items.back())) { 2930 if (isListComp(tbB)) {
2758 throw CompileError("invalid destructure value"sv, tbB); 2931 throw CompileError("invalid destructure value"sv, tbB);
2759 } 2932 }
2760 tableItems = &tbB->items.objects(); 2933 tableItems = &tbB->items.objects();
@@ -2785,7 +2958,7 @@ private:
2785 } 2958 }
2786 case id<Comprehension_t>(): { 2959 case id<Comprehension_t>(): {
2787 auto table = static_cast<Comprehension_t*>(node); 2960 auto table = static_cast<Comprehension_t*>(node);
2788 if (table->items.size() == 2 && ast_is<CompInner_t>(table->items.back())) { 2961 if (isListComp(table)) {
2789 throw CompileError("invalid destructure value"sv, table); 2962 throw CompileError("invalid destructure value"sv, table);
2790 } 2963 }
2791 tableItems = &table->items.objects(); 2964 tableItems = &table->items.objects();
@@ -2796,20 +2969,46 @@ private:
2796 if (!tableItems) throw CompileError("invalid destructure value"sv, node); 2969 if (!tableItems) throw CompileError("invalid destructure value"sv, node);
2797 std::list<DestructItem> pairs; 2970 std::list<DestructItem> pairs;
2798 int index = 0; 2971 int index = 0;
2972 int count = 0;
2973 bool hasSpread = false;
2799 auto subMetaDestruct = node->new_ptr<TableLit_t>(); 2974 auto subMetaDestruct = node->new_ptr<TableLit_t>();
2800 for (auto pair : *tableItems) { 2975 for (auto pair : *tableItems) {
2801 switch (pair->get_id()) { 2976 switch (pair->get_id()) {
2802 case id<Exp_t>(): 2977 case id<Exp_t>():
2803 case id<NormalDef_t>(): { 2978 case id<NormalDef_t>(): {
2979 ++index;
2804 Exp_t* defVal = nullptr; 2980 Exp_t* defVal = nullptr;
2805 if (auto nd = ast_cast<NormalDef_t>(pair)) { 2981 if (auto nd = ast_cast<NormalDef_t>(pair)) {
2806 pair = nd->item.get(); 2982 pair = nd->item.get();
2807 defVal = nd->defVal.get(); 2983 defVal = nd->defVal.get();
2808 } 2984 }
2809 ++index; 2985 bool assignable = false;
2810 if (!varDefOnly && !isAssignable(static_cast<Exp_t*>(pair))) { 2986 try {
2987 assignable = isAssignable(static_cast<Exp_t*>(pair));
2988 } catch (const CompileError& e) {
2989 if (!varDefOnly) throw e;
2990 }
2991 if (!assignable && !varDefOnly) {
2992 if (optional) break;
2811 throw CompileError("can't destructure value"sv, pair); 2993 throw CompileError("can't destructure value"sv, pair);
2812 } 2994 }
2995 ast_ptr<true, ast_node> indexItem;
2996 if (hasSpread) {
2997 int rIndex = count - index;
2998 indexItem.set(toAst<ReversedIndex_t>('#' + (rIndex == 0 ? Empty : "-"s + std::to_string(rIndex)), pair));
2999 } else {
3000 indexItem.set(toAst<Exp_t>(std::to_string(index), pair));
3001 }
3002 if (optional && varDefOnly && !assignable) {
3003 if (defVal) {
3004 throw CompileError("default value is not supported here"sv, defVal);
3005 }
3006 auto exp = static_cast<Exp_t*>(pair);
3007 auto chain = exp->new_ptr<ChainValue_t>();
3008 chain->items.push_back(indexItem);
3009 pairs.push_back({exp, Empty, chain, nullptr});
3010 break;
3011 }
2813 auto value = singleValueFrom(pair); 3012 auto value = singleValueFrom(pair);
2814 auto item = value->item.get(); 3013 auto item = value->item.get();
2815 ast_node* subExp = ast_cast<SimpleTable_t>(item); 3014 ast_node* subExp = ast_cast<SimpleTable_t>(item);
@@ -2820,7 +3019,6 @@ private:
2820 throw CompileError("default value is not supported here"sv, defVal); 3019 throw CompileError("default value is not supported here"sv, defVal);
2821 } 3020 }
2822 } 3021 }
2823 auto indexItem = toAst<Exp_t>(std::to_string(index), value);
2824 for (auto& p : subPairs) { 3022 for (auto& p : subPairs) {
2825 if (sep) p.structure->items.push_front(sep); 3023 if (sep) p.structure->items.push_front(sep);
2826 p.structure->items.push_front(indexItem); 3024 p.structure->items.push_front(indexItem);
@@ -2831,7 +3029,6 @@ private:
2831 auto varName = singleVariableFrom(exp, AccessType::None); 3029 auto varName = singleVariableFrom(exp, AccessType::None);
2832 if (varName == "_"sv) break; 3030 if (varName == "_"sv) break;
2833 auto chain = exp->new_ptr<ChainValue_t>(); 3031 auto chain = exp->new_ptr<ChainValue_t>();
2834 auto indexItem = toAst<Exp_t>(std::to_string(index), exp);
2835 chain->items.push_back(indexItem); 3032 chain->items.push_back(indexItem);
2836 pairs.push_back({exp, 3033 pairs.push_back({exp,
2837 varName, 3034 varName,
@@ -2889,7 +3086,25 @@ private:
2889 } 3086 }
2890 } 3087 }
2891 if (auto exp = np->value.as<Exp_t>()) { 3088 if (auto exp = np->value.as<Exp_t>()) {
2892 if (!varDefOnly && !isAssignable(exp)) throw CompileError("can't do destructure value"sv, exp); 3089 bool assignable = false;
3090 try {
3091 assignable = isAssignable(exp);
3092 } catch (const CompileError& e) {
3093 if (!varDefOnly) throw e;
3094 }
3095 if (!assignable && !varDefOnly) {
3096 if (optional) break;
3097 throw CompileError("can't destructure value"sv, pair);
3098 }
3099 if (optional && varDefOnly && !assignable) {
3100 if (defVal) {
3101 throw CompileError("default value is not supported here"sv, defVal);
3102 }
3103 auto chain = exp->new_ptr<ChainValue_t>();
3104 if (keyIndex) chain->items.push_back(keyIndex);
3105 pairs.push_back({exp, Empty, chain, nullptr});
3106 break;
3107 }
2893 auto item = singleValueFrom(exp)->item.get(); 3108 auto item = singleValueFrom(exp)->item.get();
2894 ast_node* subExp = ast_cast<SimpleTable_t>(item); 3109 ast_node* subExp = ast_cast<SimpleTable_t>(item);
2895 if (subExp || (subExp = item->get_by_path<TableLit_t>()) || (subExp = item->get_by_path<Comprehension_t>())) { 3110 if (subExp || (subExp = item->get_by_path<TableLit_t>()) || (subExp = item->get_by_path<Comprehension_t>())) {
@@ -2938,7 +3153,13 @@ private:
2938 auto tb = static_cast<TableBlockIndent_t*>(pair); 3153 auto tb = static_cast<TableBlockIndent_t*>(pair);
2939 ++index; 3154 ++index;
2940 auto subPairs = destructFromExp(tb, varDefOnly, optional); 3155 auto subPairs = destructFromExp(tb, varDefOnly, optional);
2941 auto indexItem = toAst<Exp_t>(std::to_string(index), tb); 3156 ast_ptr<true, ast_node> indexItem;
3157 if (hasSpread) {
3158 int rIndex = count - index;
3159 indexItem.set(toAst<ReversedIndex_t>('#' + (rIndex == 0 ? Empty : "-"s + std::to_string(rIndex)), tb));
3160 } else {
3161 indexItem.set(toAst<Exp_t>(std::to_string(index), tb));
3162 }
2942 for (auto& p : subPairs) { 3163 for (auto& p : subPairs) {
2943 if (sep) p.structure->items.push_front(sep); 3164 if (sep) p.structure->items.push_front(sep);
2944 p.structure->items.push_front(indexItem); 3165 p.structure->items.push_front(indexItem);
@@ -2995,6 +3216,42 @@ private:
2995 subMetaDestruct->values.push_back(newPairDef); 3216 subMetaDestruct->values.push_back(newPairDef);
2996 break; 3217 break;
2997 } 3218 }
3219 case id<SpreadListExp_t>():
3220 case id<SpreadExp_t>(): {
3221 ++index;
3222 if (hasSpread) {
3223 throw CompileError("duplicated spread expression"sv, pair);
3224 }
3225 hasSpread = true;
3226 for (auto item : *tableItems) {
3227 if (ast_is<
3228 SpreadListExp_t, SpreadExp_t,
3229 TableBlockIndent_t,
3230 Exp_t, NormalDef_t>(item)) {
3231 count++;
3232 }
3233 }
3234 Exp_t* exp = nullptr;
3235 if (auto se = ast_cast<SpreadExp_t>(pair)) {
3236 exp = se->exp.get();
3237 } else {
3238 exp = ast_to<SpreadListExp_t>(pair)->exp.get();
3239 }
3240 auto varName = singleVariableFrom(exp, AccessType::None);
3241 if (varName == "_"sv) break;
3242 int start = index;
3243 int stop = index - count - 1;
3244 auto chain = exp->new_ptr<ChainValue_t>();
3245 auto slice = toAst<Slice_t>(
3246 '[' + (start == 1 ? Empty : std::to_string(start)) + ',' + (stop == -1 ? Empty : std::to_string(stop)) + ']', exp);
3247 chain->items.push_back(slice);
3248 auto nil = toAst<Exp_t>("nil"sv, slice);
3249 pairs.push_back({exp,
3250 varName,
3251 chain,
3252 nil.get()});
3253 break;
3254 }
2998 default: YUEE("AST node mismatch", pair); break; 3255 default: YUEE("AST node mismatch", pair); break;
2999 } 3256 }
3000 } 3257 }
@@ -3072,7 +3329,7 @@ private:
3072 if (auto tab = sVal->value.as<TableLit_t>()) { 3329 if (auto tab = sVal->value.as<TableLit_t>()) {
3073 destructNode = tab; 3330 destructNode = tab;
3074 } else if (auto comp = sVal->value.as<Comprehension_t>()) { 3331 } else if (auto comp = sVal->value.as<Comprehension_t>()) {
3075 if (comp->items.size() != 2 || !ast_is<CompInner_t>(comp->items.back())) { 3332 if (!isListComp(comp)) {
3076 destructNode = comp; 3333 destructNode = comp;
3077 } 3334 }
3078 } 3335 }
@@ -3111,7 +3368,11 @@ private:
3111 break; 3368 break;
3112 default: YUEE("AST node mismatch", destructNode); break; 3369 default: YUEE("AST node mismatch", destructNode); break;
3113 } 3370 }
3114 if (dlist->empty()) throw CompileError("expect items to be destructured"sv, destructNode); 3371 if (dlist->empty()) {
3372 if (!optional) {
3373 throw CompileError("expect items to be destructured"sv, destructNode);
3374 }
3375 }
3115 for (auto item : *dlist) { 3376 for (auto item : *dlist) {
3116 switch (item->get_id()) { 3377 switch (item->get_id()) {
3117 case id<MetaVariablePairDef_t>(): { 3378 case id<MetaVariablePairDef_t>(): {
@@ -3247,7 +3508,9 @@ private:
3247 simpleValue->value.set(tab); 3508 simpleValue->value.set(tab);
3248 auto pairs = destructFromExp(newExp(simpleValue, expr), varDefOnly, optional); 3509 auto pairs = destructFromExp(newExp(simpleValue, expr), varDefOnly, optional);
3249 if (pairs.empty()) { 3510 if (pairs.empty()) {
3250 throw CompileError("expect items to be destructured"sv, tab); 3511 if (!optional) {
3512 throw CompileError("expect items to be destructured"sv, tab);
3513 }
3251 } 3514 }
3252 destruct.items = std::move(pairs); 3515 destruct.items = std::move(pairs);
3253 if (!varDefOnly) { 3516 if (!varDefOnly) {
@@ -3286,7 +3549,7 @@ private:
3286 destruct.valueVar.clear(); 3549 destruct.valueVar.clear();
3287 } 3550 }
3288 } 3551 }
3289 destructs.push_back(destruct); 3552 destructs.push_back(std::move(destruct));
3290 } 3553 }
3291 } 3554 }
3292 } else { 3555 } else {
@@ -3453,7 +3716,7 @@ private:
3453 _buf << defs; 3716 _buf << defs;
3454 else 3717 else
3455 _buf << indent() << left; 3718 _buf << indent() << left;
3456 _buf << " = "sv << left << ' ' << op << ' ' << right << nll(assignment); 3719 _buf << " = "sv << left << ' ' << op << ' ' << right << nl(assignment);
3457 out.push_back(clearBuf()); 3720 out.push_back(clearBuf());
3458 break; 3721 break;
3459 } 3722 }
@@ -3463,7 +3726,7 @@ private:
3463 bool oneLined = defs.size() == expList->exprs.objects().size(); 3726 bool oneLined = defs.size() == expList->exprs.objects().size();
3464 bool nonRecursionFunLit = false; 3727 bool nonRecursionFunLit = false;
3465 for (auto val : assign->values.objects()) { 3728 for (auto val : assign->values.objects()) {
3466 if (auto value = singleValueFrom(val)) { 3729 if (auto value = singleValueFrom(val, true)) {
3467 if (auto spValue = value->item.as<SimpleValue_t>()) { 3730 if (auto spValue = value->item.as<SimpleValue_t>()) {
3468 if (auto funLit = spValue->value.as<FunLit_t>()) { 3731 if (auto funLit = spValue->value.as<FunLit_t>()) {
3469 if (funLit->noRecursion) { 3732 if (funLit->noRecursion) {
@@ -3500,9 +3763,9 @@ private:
3500 transformExpList(expList, temp); 3763 transformExpList(expList, temp);
3501 std::string left = std::move(temp.back()); 3764 std::string left = std::move(temp.back());
3502 temp.pop_back(); 3765 temp.pop_back();
3503 out.push_back(indent() + left + " = "s + join(temp, ", "sv) + nll(assignment)); 3766 out.push_back(indent() + left + " = "s + join(temp, ", "sv) + nl(assignment));
3504 } else { 3767 } else {
3505 out.push_back(preDefine + " = "s + join(temp, ", "sv) + nll(assignment)); 3768 out.push_back(preDefine + " = "s + join(temp, ", "sv) + nl(assignment));
3506 } 3769 }
3507 } else { 3770 } else {
3508 std::string preDefine = toLocalDecl(defs); 3771 std::string preDefine = toLocalDecl(defs);
@@ -3518,7 +3781,7 @@ private:
3518 for (auto value : assign->values.objects()) { 3781 for (auto value : assign->values.objects()) {
3519 transformAssignItem(value, temp); 3782 transformAssignItem(value, temp);
3520 } 3783 }
3521 out.push_back((preDefine.empty() ? Empty : preDefine + nll(assignment)) + indent() + left + " = "s + join(temp, ", "sv) + nll(assignment)); 3784 out.push_back((preDefine.empty() ? Empty : preDefine + nl(assignment)) + indent() + left + " = "s + join(temp, ", "sv) + nl(assignment));
3522 } 3785 }
3523 break; 3786 break;
3524 } 3787 }
@@ -3619,7 +3882,7 @@ private:
3619 if (usage != ExpUsage::Closure) { 3882 if (usage != ExpUsage::Closure) {
3620 if (!currentScope().lastStatement) { 3883 if (!currentScope().lastStatement) {
3621 extraScope = true; 3884 extraScope = true;
3622 temp.push_back(indent() + "do"s + nll(asmt)); 3885 temp.push_back(indent() + "do"s + nl(asmt));
3623 pushScope(); 3886 pushScope();
3624 } 3887 }
3625 } 3888 }
@@ -3652,7 +3915,7 @@ private:
3652 if (usage != ExpUsage::Closure) { 3915 if (usage != ExpUsage::Closure) {
3653 if (!currentScope().lastStatement) { 3916 if (!currentScope().lastStatement) {
3654 extraScope = true; 3917 extraScope = true;
3655 temp.push_back(indent() + "do"s + nll(asmt)); 3918 temp.push_back(indent() + "do"s + nl(asmt));
3656 pushScope(); 3919 pushScope();
3657 } 3920 }
3658 } 3921 }
@@ -3681,12 +3944,12 @@ private:
3681 if (pair != ifCondPairs.front()) { 3944 if (pair != ifCondPairs.front()) {
3682 _buf << "else"sv; 3945 _buf << "else"sv;
3683 } 3946 }
3684 _buf << "if "sv << condStr << " then"sv << nll(condition); 3947 _buf << "if "sv << condStr << " then"sv << nl(condition);
3685 temp.push_back(clearBuf()); 3948 temp.push_back(clearBuf());
3686 } 3949 }
3687 if (pair.second) { 3950 if (pair.second) {
3688 if (!pair.first) { 3951 if (!pair.first) {
3689 temp.push_back(indent() + "else"s + nll(pair.second)); 3952 temp.push_back(indent() + "else"s + nl(pair.second));
3690 } 3953 }
3691 pushScope(); 3954 pushScope();
3692 if (pair == ifCondPairs.front() && extraAssignment) { 3955 if (pair == ifCondPairs.front() && extraAssignment) {
@@ -3696,17 +3959,17 @@ private:
3696 popScope(); 3959 popScope();
3697 } 3960 }
3698 if (!pair.first) { 3961 if (!pair.first) {
3699 temp.push_back(indent() + "end"s + nll(nodes.front())); 3962 temp.push_back(indent() + "end"s + nl(nodes.front()));
3700 break; 3963 break;
3701 } 3964 }
3702 } 3965 }
3703 if (extraScope) { 3966 if (extraScope) {
3704 popScope(); 3967 popScope();
3705 temp.push_back(indent() + "end"s + nlr(nodes.front())); 3968 temp.push_back(indent() + "end"s + nl(nodes.front()));
3706 } 3969 }
3707 if (usage == ExpUsage::Closure) { 3970 if (usage == ExpUsage::Closure) {
3708 popScope(); 3971 popScope();
3709 *funcStart = anonFuncStart() + nll(nodes.front()); 3972 *funcStart = anonFuncStart() + nl(nodes.front());
3710 temp.push_back(indent() + anonFuncEnd()); 3973 temp.push_back(indent() + anonFuncEnd());
3711 popAnonVarArg(); 3974 popAnonVarArg();
3712 popFunctionScope(); 3975 popFunctionScope();
@@ -3727,14 +3990,6 @@ private:
3727 out.push_back(join(temp, ", "sv)); 3990 out.push_back(join(temp, ", "sv));
3728 } 3991 }
3729 3992
3730 void transformExpListLow(ExpListLow_t* expListLow, str_list& out) {
3731 str_list temp;
3732 for (auto exp : expListLow->exprs.objects()) {
3733 transformExp(static_cast<Exp_t*>(exp), temp, ExpUsage::Closure);
3734 }
3735 out.push_back(join(temp, ", "sv));
3736 }
3737
3738 void transform_pipe_exp(const node_container& values, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { 3993 void transform_pipe_exp(const node_container& values, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
3739 if (values.size() == 1 && usage == ExpUsage::Closure) { 3994 if (values.size() == 1 && usage == ExpUsage::Closure) {
3740 transformUnaryExp(static_cast<UnaryExp_t*>(values.front()), out, ExpUsage::Closure); 3995 transformUnaryExp(static_cast<UnaryExp_t*>(values.front()), out, ExpUsage::Closure);
@@ -3801,16 +4056,12 @@ private:
3801 } else { 4056 } else {
3802 transformExp(arg, out, ExpUsage::Closure); 4057 transformExp(arg, out, ExpUsage::Closure);
3803 out.back().insert(0, indent()); 4058 out.back().insert(0, indent());
3804 out.back().append(nlr(x)); 4059 out.back().append(nl(x));
3805 } 4060 }
3806 return; 4061 return;
3807 } 4062 }
3808 case ExpUsage::Return: { 4063 case ExpUsage::Return: {
3809 auto ret = x->new_ptr<Return_t>(); 4064 auto ret = newReturn(arg);
3810 ret->explicitReturn = false;
3811 auto expListLow = x->new_ptr<ExpListLow_t>();
3812 expListLow->exprs.push_back(arg);
3813 ret->valueList.set(expListLow);
3814 transformReturn(ret, out); 4065 transformReturn(ret, out);
3815 return; 4066 return;
3816 } 4067 }
@@ -3925,7 +4176,7 @@ private:
3925 auto stmt = exp->new_ptr<Statement_t>(); 4176 auto stmt = exp->new_ptr<Statement_t>();
3926 stmt->content.set(preDefine); 4177 stmt->content.set(preDefine);
3927 preDefine.set(nullptr); 4178 preDefine.set(nullptr);
3928 block->statements.push_back(stmt); 4179 block->statementOrComments.push_back(stmt);
3929 auto simpleValue = exp->new_ptr<SimpleValue_t>(); 4180 auto simpleValue = exp->new_ptr<SimpleValue_t>();
3930 simpleValue->value.set(ifNode); 4181 simpleValue->value.set(ifNode);
3931 auto explist = exp->new_ptr<ExpList_t>(); 4182 auto explist = exp->new_ptr<ExpList_t>();
@@ -3934,7 +4185,7 @@ private:
3934 expListAssign->expList.set(explist); 4185 expListAssign->expList.set(explist);
3935 stmt = exp->new_ptr<Statement_t>(); 4186 stmt = exp->new_ptr<Statement_t>();
3936 stmt->content.set(expListAssign); 4187 stmt->content.set(expListAssign);
3937 block->statements.push_back(stmt); 4188 block->statementOrComments.push_back(stmt);
3938 nodes->push_back(block); 4189 nodes->push_back(block);
3939 nodes = &ifNode->nodes; 4190 nodes = &ifNode->nodes;
3940 } else { 4191 } else {
@@ -3942,7 +4193,7 @@ private:
3942 auto stmt = exp->new_ptr<Statement_t>(); 4193 auto stmt = exp->new_ptr<Statement_t>();
3943 stmt->content.set(preDefine); 4194 stmt->content.set(preDefine);
3944 preDefine.set(nullptr); 4195 preDefine.set(nullptr);
3945 block->statements.push_back(stmt); 4196 block->statementOrComments.push_back(stmt);
3946 auto simpleValue = exp->new_ptr<SimpleValue_t>(); 4197 auto simpleValue = exp->new_ptr<SimpleValue_t>();
3947 simpleValue->value.set(ifNode); 4198 simpleValue->value.set(ifNode);
3948 auto explist = exp->new_ptr<ExpList_t>(); 4199 auto explist = exp->new_ptr<ExpList_t>();
@@ -3951,7 +4202,7 @@ private:
3951 expListAssign->expList.set(explist); 4202 expListAssign->expList.set(explist);
3952 stmt = exp->new_ptr<Statement_t>(); 4203 stmt = exp->new_ptr<Statement_t>();
3953 stmt->content.set(expListAssign); 4204 stmt->content.set(expListAssign);
3954 block->statements.push_back(stmt); 4205 block->statementOrComments.push_back(stmt);
3955 auto body = exp->new_ptr<Body_t>(); 4206 auto body = exp->new_ptr<Body_t>();
3956 body->content.set(block); 4207 body->content.set(block);
3957 auto doNode = exp->new_ptr<Do_t>(); 4208 auto doNode = exp->new_ptr<Do_t>();
@@ -4035,11 +4286,7 @@ private:
4035 break; 4286 break;
4036 } 4287 }
4037 case ExpUsage::Return: { 4288 case ExpUsage::Return: {
4038 auto expListLow = exp->new_ptr<ExpListLow_t>(); 4289 auto returnNode = newReturn(e);
4039 expListLow->exprs.push_back(e);
4040 auto returnNode = exp->new_ptr<Return_t>();
4041 returnNode->explicitReturn = false;
4042 returnNode->valueList.set(expListLow);
4043 transformReturn(returnNode, out); 4290 transformReturn(returnNode, out);
4044 break; 4291 break;
4045 } 4292 }
@@ -4113,7 +4360,7 @@ private:
4113 auto stmt = x->new_ptr<Statement_t>(); 4360 auto stmt = x->new_ptr<Statement_t>();
4114 stmt->content.set(expListAssign); 4361 stmt->content.set(expListAssign);
4115 auto blk = x->new_ptr<Block_t>(); 4362 auto blk = x->new_ptr<Block_t>();
4116 blk->statements.push_back(stmt); 4363 blk->statementOrComments.push_back(stmt);
4117 newBlock.set(blk); 4364 newBlock.set(blk);
4118 } 4365 }
4119 if (!globals.empty()) { 4366 if (!globals.empty()) {
@@ -4205,15 +4452,21 @@ private:
4205 4452
4206 std::optional<std::pair<std::string, str_list>> upValueFuncFromExp(Exp_t* exp, str_list* ensureArgListInTheEnd, bool blockRewrite) { 4453 std::optional<std::pair<std::string, str_list>> upValueFuncFromExp(Exp_t* exp, str_list* ensureArgListInTheEnd, bool blockRewrite) {
4207 if (checkUpValueFuncAvailable(exp)) { 4454 if (checkUpValueFuncAvailable(exp)) {
4208 auto returnNode = exp->new_ptr<Return_t>();
4209 returnNode->explicitReturn = false;
4210 auto returnList = exp->new_ptr<ExpListLow_t>();
4211 returnList->exprs.push_back(exp);
4212 returnNode->valueList.set(returnList);
4213 auto block = exp->new_ptr<Block_t>(); 4455 auto block = exp->new_ptr<Block_t>();
4456 if (auto sVal = simpleSingleValueFrom(exp)) {
4457 if (auto doNode = sVal->value.as<Do_t>()) {
4458 if (auto blk = doNode->body->content.as<Block_t>()) {
4459 block->statementOrComments.dup(blk->statementOrComments);
4460 } else {
4461 block->statementOrComments.push_back(doNode->body->content.to<Statement_t>());
4462 }
4463 return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false, blockRewrite);
4464 }
4465 }
4466 auto returnNode = newReturn(exp);
4214 auto stmt = exp->new_ptr<Statement_t>(); 4467 auto stmt = exp->new_ptr<Statement_t>();
4215 stmt->content.set(returnNode); 4468 stmt->content.set(returnNode);
4216 block->statements.push_back(stmt); 4469 block->statementOrComments.push_back(stmt);
4217 return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false, blockRewrite); 4470 return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false, blockRewrite);
4218 } 4471 }
4219 return std::nullopt; 4472 return std::nullopt;
@@ -4270,7 +4523,7 @@ private:
4270 bool extraScope = !currentScope().lastStatement; 4523 bool extraScope = !currentScope().lastStatement;
4271 if (forAssignment) { 4524 if (forAssignment) {
4272 if (extraScope) { 4525 if (extraScope) {
4273 temp.push_back(indent() + "do"s + nll(x)); 4526 temp.push_back(indent() + "do"s + nl(x));
4274 pushScope(); 4527 pushScope();
4275 } 4528 }
4276 } 4529 }
@@ -4287,26 +4540,24 @@ private:
4287 return false; 4540 return false;
4288 }; 4541 };
4289 switch (usage) { 4542 switch (usage) {
4290 case ExpUsage::Common: YUEE("AST node mismatch", x); return; 4543 case ExpUsage::Common:
4544 YUEE("AST node mismatch", x);
4545 return;
4291 case ExpUsage::Return: 4546 case ExpUsage::Return:
4292 case ExpUsage::Closure: { 4547 case ExpUsage::Closure: {
4293 prepareValue(); 4548 prepareValue();
4294 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); 4549 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nl(x);
4295 _buf << indent(1) << "return "s << objVar << nll(x); 4550 _buf << indent(1) << "return "s << objVar << nl(x);
4296 _buf << indent() << "else"s << nll(x); 4551 _buf << indent() << "else"s << nl(x);
4297 temp.push_back(clearBuf()); 4552 temp.push_back(clearBuf());
4298 auto ret = x->new_ptr<Return_t>();
4299 ret->explicitReturn = false;
4300 auto retList = x->new_ptr<ExpListLow_t>();
4301 retList->exprs.push_back(exp->nilCoalesed);
4302 ret->valueList.set(retList);
4303 incIndentOffset(); 4553 incIndentOffset();
4554 auto ret = newReturn(exp->nilCoalesed);
4304 transformReturn(ret, temp); 4555 transformReturn(ret, temp);
4305 decIndentOffset(); 4556 decIndentOffset();
4306 temp.push_back(indent() + "end"s + nll(x)); 4557 temp.push_back(indent() + "end"s + nl(x));
4307 if (usage == ExpUsage::Closure) { 4558 if (usage == ExpUsage::Closure) {
4308 popScope(); 4559 popScope();
4309 *funcStart = anonFuncStart() + nll(x); 4560 *funcStart = anonFuncStart() + nl(x);
4310 temp.push_back(indent() + anonFuncEnd()); 4561 temp.push_back(indent() + anonFuncEnd());
4311 popAnonVarArg(); 4562 popAnonVarArg();
4312 popFunctionScope(); 4563 popFunctionScope();
@@ -4323,14 +4574,14 @@ private:
4323 assign->values.push_back(exp); 4574 assign->values.push_back(exp);
4324 temp.push_back(getPreDefineLine(assignment)); 4575 temp.push_back(getPreDefineLine(assignment));
4325 extraScope = prepareValue(true); 4576 extraScope = prepareValue(true);
4326 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); 4577 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nl(x);
4327 temp.push_back(clearBuf()); 4578 temp.push_back(clearBuf());
4328 pushScope(); 4579 pushScope();
4329 assign->values.clear(); 4580 assign->values.clear();
4330 assign->values.push_back(toAst<Exp_t>(objVar, x)); 4581 assign->values.push_back(toAst<Exp_t>(objVar, x));
4331 transformAssignment(assignment, temp); 4582 transformAssignment(assignment, temp);
4332 popScope(); 4583 popScope();
4333 temp.push_back(indent() + "else"s + nll(x)); 4584 temp.push_back(indent() + "else"s + nl(x));
4334 assign->values.clear(); 4585 assign->values.clear();
4335 assign->values.push_back(exp->nilCoalesed); 4586 assign->values.push_back(exp->nilCoalesed);
4336 } else { 4587 } else {
@@ -4338,17 +4589,17 @@ private:
4338 assign->values.push_back(exp->nilCoalesed); 4589 assign->values.push_back(exp->nilCoalesed);
4339 temp.push_back(getPreDefineLine(assignment)); 4590 temp.push_back(getPreDefineLine(assignment));
4340 transformExp(left, temp, ExpUsage::Closure); 4591 transformExp(left, temp, ExpUsage::Closure);
4341 _buf << indent() << "if "sv << temp.back() << " == nil then"sv << nll(x); 4592 _buf << indent() << "if "sv << temp.back() << " == nil then"sv << nl(x);
4342 temp.pop_back(); 4593 temp.pop_back();
4343 temp.push_back(clearBuf()); 4594 temp.push_back(clearBuf());
4344 } 4595 }
4345 pushScope(); 4596 pushScope();
4346 transformAssignment(assignment, temp); 4597 transformAssignment(assignment, temp);
4347 popScope(); 4598 popScope();
4348 temp.push_back(indent() + "end"s + nlr(x)); 4599 temp.push_back(indent() + "end"s + nl(x));
4349 if (extraScope) { 4600 if (extraScope) {
4350 popScope(); 4601 popScope();
4351 temp.push_back(indent() + "end"s + nlr(x)); 4602 temp.push_back(indent() + "end"s + nl(x));
4352 } 4603 }
4353 break; 4604 break;
4354 } 4605 }
@@ -4372,13 +4623,17 @@ private:
4372 switch (item->get_id()) { 4623 switch (item->get_id()) {
4373 case id<Variable_t>(): { 4624 case id<Variable_t>(): {
4374 transformVariable(static_cast<Variable_t*>(item), out); 4625 transformVariable(static_cast<Variable_t*>(item), out);
4375 if (_config.lintGlobalVariable && accessType != AccessType::None && !isLocal(out.back())) { 4626 if (accessType != AccessType::None) {
4376 auto key = out.back() + ':' + std::to_string(item->m_begin.m_line) + ':' + std::to_string(item->m_begin.m_col); 4627 if (_importedGlobal) {
4377 if (_globals.find(key) == _globals.end()) { 4628 markGlobalImported(out.back());
4378 if (accessType == AccessType::Read && _funcLevel > 1) { 4629 } else if (_config.lintGlobalVariable && !isLocal(out.back())) {
4379 accessType = AccessType::Capture; 4630 auto key = out.back() + ':' + std::to_string(item->m_begin.m_line) + ':' + std::to_string(item->m_begin.m_col);
4631 if (_globals.find(key) == _globals.end()) {
4632 if (accessType == AccessType::Read && _funcLevel > 1) {
4633 accessType = AccessType::Capture;
4634 }
4635 _globals[key] = {out.back(), item->m_begin.m_line, item->m_begin.m_col, accessType, isSolidDefined(out.back())};
4380 } 4636 }
4381 _globals[key] = {out.back(), item->m_begin.m_line, item->m_begin.m_col, accessType};
4382 } 4637 }
4383 } 4638 }
4384 break; 4639 break;
@@ -4410,6 +4665,7 @@ private:
4410 case id<ForEach_t>(): transformForEachClosure(static_cast<ForEach_t*>(value), out); break; 4665 case id<ForEach_t>(): transformForEachClosure(static_cast<ForEach_t*>(value), out); break;
4411 case id<For_t>(): transformForClosure(static_cast<For_t*>(value), out); break; 4666 case id<For_t>(): transformForClosure(static_cast<For_t*>(value), out); break;
4412 case id<While_t>(): transformWhileClosure(static_cast<While_t*>(value), out); break; 4667 case id<While_t>(): transformWhileClosure(static_cast<While_t*>(value), out); break;
4668 case id<Repeat_t>(): transformRepeatClosure(static_cast<Repeat_t*>(value), out); break;
4413 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Closure); break; 4669 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Closure); break;
4414 case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Closure); break; 4670 case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Closure); break;
4415 case id<UnaryValue_t>(): transformUnaryValue(static_cast<UnaryValue_t*>(value), out); break; 4671 case id<UnaryValue_t>(): transformUnaryValue(static_cast<UnaryValue_t*>(value), out); break;
@@ -4446,23 +4702,21 @@ private:
4446 switch (content->get_id()) { 4702 switch (content->get_id()) {
4447 case id<Block_t>(): { 4703 case id<Block_t>(): {
4448 auto block = static_cast<Block_t*>(content); 4704 auto block = static_cast<Block_t*>(content);
4449 newBlock->statements.dup(block->statements); 4705 newBlock->statementOrComments.dup(block->statementOrComments);
4450 break; 4706 break;
4451 } 4707 }
4452 case id<Statement_t>(): { 4708 case id<Statement_t>(): {
4453 newBlock->statements.push_back(content); 4709 newBlock->statementOrComments.push_back(content);
4454 break; 4710 break;
4455 } 4711 }
4456 default: YUEE("AST node mismatch", content); break; 4712 default: YUEE("AST node mismatch", content); break;
4457 } 4713 }
4458 } 4714 }
4459 if (funLit->defaultReturn.is<ExpListLow_t>()) { 4715 if (auto defaultReturn = funLit->defaultReturn.as<ExpList_t>()) {
4460 auto returnNode = newBlock->new_ptr<Return_t>(); 4716 auto returnNode = newReturn(defaultReturn);
4461 returnNode->explicitReturn = false;
4462 returnNode->valueList.set(funLit->defaultReturn);
4463 auto stmt = newBlock->new_ptr<Statement_t>(); 4717 auto stmt = newBlock->new_ptr<Statement_t>();
4464 stmt->content.set(returnNode); 4718 stmt->content.set(returnNode);
4465 newBlock->statements.push_back(stmt); 4719 newBlock->statementOrComments.push_back(stmt);
4466 } 4720 }
4467 transformBlock(newBlock, temp, ExpUsage::Common); 4721 transformBlock(newBlock, temp, ExpUsage::Common);
4468 } else { 4722 } else {
@@ -4484,7 +4738,7 @@ private:
4484 } 4738 }
4485 _buf << args << ')'; 4739 _buf << args << ')';
4486 if (!initArgs.empty() || !bodyCodes.empty()) { 4740 if (!initArgs.empty() || !bodyCodes.empty()) {
4487 _buf << nlr(argsDef) << initArgs << bodyCodes; 4741 _buf << nl(argsDef) << initArgs << bodyCodes;
4488 popScope(); 4742 popScope();
4489 _buf << indent() << "end"sv; 4743 _buf << indent() << "end"sv;
4490 } else { 4744 } else {
@@ -4495,7 +4749,7 @@ private:
4495 auto& bodyCodes = temp.back(); 4749 auto& bodyCodes = temp.back();
4496 _buf << "function("sv << (isFatArrow ? "self"s : Empty) << ')'; 4750 _buf << "function("sv << (isFatArrow ? "self"s : Empty) << ')';
4497 if (!bodyCodes.empty()) { 4751 if (!bodyCodes.empty()) {
4498 _buf << nll(funLit) << bodyCodes; 4752 _buf << nl(funLit) << bodyCodes;
4499 popScope(); 4753 popScope();
4500 _buf << indent() << "end"sv; 4754 _buf << indent() << "end"sv;
4501 } else { 4755 } else {
@@ -4512,7 +4766,7 @@ private:
4512 auto x = body; 4766 auto x = body;
4513 if (auto stmt = body->content.as<Statement_t>()) { 4767 if (auto stmt = body->content.as<Statement_t>()) {
4514 auto block = x->new_ptr<Block_t>(); 4768 auto block = x->new_ptr<Block_t>();
4515 block->statements.push_back(stmt); 4769 block->statementOrComments.push_back(stmt);
4516 transformBlock(block, out, usage, assignList); 4770 transformBlock(block, out, usage, assignList);
4517 } else { 4771 } else {
4518 transformBlock(body->content.to<Block_t>(), out, usage, assignList); 4772 transformBlock(body->content.to<Block_t>(), out, usage, assignList);
@@ -4524,13 +4778,15 @@ private:
4524 out.push_back(Empty); 4778 out.push_back(Empty);
4525 return; 4779 return;
4526 } 4780 }
4527 const auto& nodes = block->statements.objects(); 4781 const auto& nodes = block->statementOrComments.objects();
4782 auto lastStmt = lastStatementFrom(nodes);
4528 LocalMode mode = LocalMode::None; 4783 LocalMode mode = LocalMode::None;
4529 Local_t *any = nullptr, *capital = nullptr; 4784 Local_t *any = nullptr, *capital = nullptr;
4530 for (auto it = nodes.begin(); it != nodes.end(); ++it) { 4785 for (auto it = nodes.begin(); it != nodes.end(); ++it) {
4531 auto node = *it; 4786 auto node = *it;
4532 auto stmt = static_cast<Statement_t*>(node); 4787 auto stmt = ast_cast<Statement_t>(node);
4533 if (!stmt->appendix && stmt->content.is<Return_t>() && stmt != nodes.back()) { 4788 if (!stmt) continue;
4789 if (!stmt->appendix && stmt->content.is<Return_t>() && stmt != lastStmt) {
4534 throw CompileError("'return' statement must be the last line in the block"sv, stmt->content); 4790 throw CompileError("'return' statement must be the last line in the block"sv, stmt->content);
4535 } else if (auto pipeBody = stmt->content.as<PipeBody_t>()) { 4791 } else if (auto pipeBody = stmt->content.as<PipeBody_t>()) {
4536 auto x = stmt; 4792 auto x = stmt;
@@ -4539,6 +4795,16 @@ private:
4539 BREAK_IF(it == nodes.begin()); 4795 BREAK_IF(it == nodes.begin());
4540 auto last = it; 4796 auto last = it;
4541 --last; 4797 --last;
4798 bool found = true;
4799 while (!ast_is<Statement_t>(*last)) {
4800 if (last == nodes.begin()) {
4801 found = false;
4802 break;
4803 } else {
4804 --last;
4805 }
4806 }
4807 BREAK_IF(!found);
4542 auto lst = static_cast<Statement_t*>(*last); 4808 auto lst = static_cast<Statement_t*>(*last);
4543 if (lst->appendix) { 4809 if (lst->appendix) {
4544 throw CompileError("statement decorator must be placed at the end of pipe chain"sv, lst->appendix.get()); 4810 throw CompileError("statement decorator must be placed at the end of pipe chain"sv, lst->appendix.get());
@@ -4556,9 +4822,17 @@ private:
4556 stmt->content.set(nullptr); 4822 stmt->content.set(nullptr);
4557 auto next = it; 4823 auto next = it;
4558 ++next; 4824 ++next;
4825 Statement_t* nextStmt = nullptr;
4826 while (next != nodes.end()) {
4827 nextStmt = ast_cast<Statement_t>(*next);
4828 if (nextStmt) {
4829 break;
4830 }
4831 ++next;
4832 }
4559 BLOCK_START 4833 BLOCK_START
4560 BREAK_IF(next == nodes.end()); 4834 BREAK_IF(!nextStmt);
4561 BREAK_IF(!static_cast<Statement_t*>(*next)->content.as<PipeBody_t>()); 4835 BREAK_IF(!nextStmt->content.as<PipeBody_t>());
4562 throw CompileError("indent mismatch in pipe chain"sv, *next); 4836 throw CompileError("indent mismatch in pipe chain"sv, *next);
4563 BLOCK_END 4837 BLOCK_END
4564 } else if (auto backcall = stmt->content.as<Backcall_t>()) { 4838 } else if (auto backcall = stmt->content.as<Backcall_t>()) {
@@ -4566,7 +4840,7 @@ private:
4566 auto newBlock = x->new_ptr<Block_t>(); 4840 auto newBlock = x->new_ptr<Block_t>();
4567 if (it != nodes.begin()) { 4841 if (it != nodes.begin()) {
4568 for (auto i = nodes.begin(); i != it; ++i) { 4842 for (auto i = nodes.begin(); i != it; ++i) {
4569 newBlock->statements.push_back(*i); 4843 newBlock->statementOrComments.push_back(*i);
4570 } 4844 }
4571 } 4845 }
4572 x = backcall; 4846 x = backcall;
@@ -4577,7 +4851,7 @@ private:
4577 ++next; 4851 ++next;
4578 if (next != nodes.end()) { 4852 if (next != nodes.end()) {
4579 for (auto i = next; i != nodes.end(); ++i) { 4853 for (auto i = next; i != nodes.end(); ++i) {
4580 block->statements.push_back(*i); 4854 block->statementOrComments.push_back(*i);
4581 } 4855 }
4582 } 4856 }
4583 auto body = x->new_ptr<Body_t>(); 4857 auto body = x->new_ptr<Body_t>();
@@ -4629,7 +4903,7 @@ private:
4629 expListAssign->expList.set(expList); 4903 expListAssign->expList.set(expList);
4630 newStmt->content.set(expListAssign); 4904 newStmt->content.set(expListAssign);
4631 newStmt->appendix.set(stmt->appendix); 4905 newStmt->appendix.set(stmt->appendix);
4632 newBlock->statements.push_back(newStmt); 4906 newBlock->statementOrComments.push_back(newStmt);
4633 } 4907 }
4634 transformBlock(newBlock, out, usage, assignList, isRoot); 4908 transformBlock(newBlock, out, usage, assignList, isRoot);
4635 return; 4909 return;
@@ -4656,7 +4930,7 @@ private:
4656 throw CompileError("while-loop line decorator is not supported here"sv, appendix->item.get()); 4930 throw CompileError("while-loop line decorator is not supported here"sv, appendix->item.get());
4657 break; 4931 break;
4658 } 4932 }
4659 case id<CompInner_t>(): { 4933 case id<CompFor_t>(): {
4660 throw CompileError("for-loop line decorator is not supported here"sv, appendix->item.get()); 4934 throw CompileError("for-loop line decorator is not supported here"sv, appendix->item.get());
4661 break; 4935 break;
4662 } 4936 }
@@ -4685,7 +4959,7 @@ private:
4685 auto newBlock = x->new_ptr<Block_t>(); 4959 auto newBlock = x->new_ptr<Block_t>();
4686 if (it != nodes.begin()) { 4960 if (it != nodes.begin()) {
4687 for (auto i = nodes.begin(); i != it; ++i) { 4961 for (auto i = nodes.begin(); i != it; ++i) {
4688 newBlock->statements.push_back(*i); 4962 newBlock->statementOrComments.push_back(*i);
4689 } 4963 }
4690 } 4964 }
4691 x = expListAssign; 4965 x = expListAssign;
@@ -4695,7 +4969,7 @@ private:
4695 ++next; 4969 ++next;
4696 if (next != nodes.end()) { 4970 if (next != nodes.end()) {
4697 for (auto i = next; i != nodes.end(); ++i) { 4971 for (auto i = next; i != nodes.end(); ++i) {
4698 followingBlock->statements.push_back(*i); 4972 followingBlock->statementOrComments.push_back(*i);
4699 } 4973 }
4700 } 4974 }
4701 } 4975 }
@@ -4723,17 +4997,13 @@ private:
4723 newAssignment->action.set(newAssign); 4997 newAssignment->action.set(newAssign);
4724 auto newStatement = x->new_ptr<Statement_t>(); 4998 auto newStatement = x->new_ptr<Statement_t>();
4725 newStatement->content.set(newAssignment); 4999 newStatement->content.set(newAssignment);
4726 followingBlock->statements.push_front(newStatement); 5000 followingBlock->statementOrComments.push_front(newStatement);
4727 } 5001 }
4728 argNames.push_back("..."s); 5002 argNames.push_back("..."s);
4729 auto newBody = x->new_ptr<Body_t>(); 5003 auto newBody = x->new_ptr<Body_t>();
4730 newBody->content.set(followingBlock); 5004 newBody->content.set(followingBlock);
4731 { 5005 {
4732 auto doNode = x->new_ptr<Do_t>(); 5006 if (auto result = upValueFuncFromBlock(followingBlock.get(), &argNames, false, true)) {
4733 doNode->body.set(newBody);
4734 auto simpleValue = x->new_ptr<SimpleValue_t>();
4735 simpleValue->value.set(doNode);
4736 if (auto result = upValueFuncFromExp(newExp(simpleValue, x), &argNames, true)) {
4737 auto [funcName, args] = std::move(*result); 5007 auto [funcName, args] = std::move(*result);
4738 str_list finalArgs; 5008 str_list finalArgs;
4739 for (const auto& arg : args) { 5009 for (const auto& arg : args) {
@@ -4741,9 +5011,14 @@ private:
4741 finalArgs.push_back(arg); 5011 finalArgs.push_back(arg);
4742 } 5012 }
4743 } 5013 }
4744 newBlock->statements.push_back(toAst<Statement_t>(funcName + ' ' + join(finalArgs, ","sv), x)); 5014 auto lastNewStmt = toAst<Statement_t>(funcName + ' ' + (finalArgs.empty() ? "nil"s : join(finalArgs, ","sv)), x);
4745 auto sVal = singleValueFrom(static_cast<Statement_t*>(newBlock->statements.back())->content.to<ExpListAssign_t>()->expList); 5015 newBlock->statementOrComments.push_back(lastNewStmt);
4746 ast_to<InvokeArgs_t>(sVal->item.to<ChainValue_t>()->items.back())->args.dup(newInvoke->args); 5016 auto sVal = singleValueFrom(lastNewStmt->content.to<ExpListAssign_t>()->expList);
5017 auto invokArgs = ast_to<InvokeArgs_t>(sVal->item.to<ChainValue_t>()->items.back());
5018 if (finalArgs.empty()) {
5019 invokArgs->args.clear();
5020 }
5021 invokArgs->args.dup(newInvoke->args);
4747 transformBlock(newBlock, out, usage, assignList, isRoot); 5022 transformBlock(newBlock, out, usage, assignList, isRoot);
4748 return; 5023 return;
4749 } 5024 }
@@ -4768,7 +5043,7 @@ private:
4768 newItemListAssign->expList.set(newItemList); 5043 newItemListAssign->expList.set(newItemList);
4769 auto newItemStatement = x->new_ptr<Statement_t>(); 5044 auto newItemStatement = x->new_ptr<Statement_t>();
4770 newItemStatement->content.set(newItemListAssign); 5045 newItemStatement->content.set(newItemListAssign);
4771 newBlock->statements.push_back(newItemStatement); 5046 newBlock->statementOrComments.push_back(newItemStatement);
4772 transformBlock(newBlock, out, usage, assignList, isRoot); 5047 transformBlock(newBlock, out, usage, assignList, isRoot);
4773 return; 5048 return;
4774 BLOCK_END 5049 BLOCK_END
@@ -4777,11 +5052,11 @@ private:
4777 auto newBlock = x->new_ptr<Block_t>(); 5052 auto newBlock = x->new_ptr<Block_t>();
4778 if (it != nodes.begin()) { 5053 if (it != nodes.begin()) {
4779 for (auto i = nodes.begin(); i != it; ++i) { 5054 for (auto i = nodes.begin(); i != it; ++i) {
4780 newBlock->statements.push_back(*i); 5055 newBlock->statementOrComments.push_back(*i);
4781 } 5056 }
4782 } 5057 }
4783 localAttrib->attrib.set(localAttrib->new_ptr<ConstAttrib_t>()); 5058 localAttrib->attrib.set(localAttrib->new_ptr<ConstAttrib_t>());
4784 newBlock->statements.push_back(*it); 5059 newBlock->statementOrComments.push_back(*it);
4785 x = localAttrib; 5060 x = localAttrib;
4786 auto followingBlock = x->new_ptr<Block_t>(); 5061 auto followingBlock = x->new_ptr<Block_t>();
4787 { 5062 {
@@ -4789,7 +5064,7 @@ private:
4789 ++next; 5064 ++next;
4790 if (next != nodes.end()) { 5065 if (next != nodes.end()) {
4791 for (auto i = next; i != nodes.end(); ++i) { 5066 for (auto i = next; i != nodes.end(); ++i) {
4792 followingBlock->statements.push_back(*i); 5067 followingBlock->statementOrComments.push_back(*i);
4793 } 5068 }
4794 } 5069 }
4795 } 5070 }
@@ -4811,13 +5086,44 @@ private:
4811 auto value = singleValueFrom(pCallExp); 5086 auto value = singleValueFrom(pCallExp);
4812 value->item.to<SimpleValue_t>()->value.to<Try_t>()->func.set(followingBlock); 5087 value->item.to<SimpleValue_t>()->value.to<Try_t>()->func.set(followingBlock);
4813 for (const auto& stmt : getCloses) { 5088 for (const auto& stmt : getCloses) {
4814 newBlock->statements.push_back(toAst<Statement_t>(stmt, x)); 5089 newBlock->statementOrComments.push_back(toAst<Statement_t>(stmt, x));
4815 } 5090 }
4816 newBlock->statements.push_back(pCallStmt); 5091 newBlock->statementOrComments.push_back(pCallStmt);
4817 for (const auto& stmt : doCloses) { 5092 for (const auto& stmt : doCloses) {
4818 newBlock->statements.push_back(toAst<Statement_t>(stmt, x)); 5093 newBlock->statementOrComments.push_back(toAst<Statement_t>(stmt, x));
5094 }
5095 newBlock->statementOrComments.push_back(toAst<Statement_t>("if "s + okVar + " then return ... else error ..."s, x));
5096 transformBlock(newBlock, out, usage, assignList, isRoot);
5097 return;
5098 } else if (auto expListAssign = stmt->content.as<ExpListAssign_t>();
5099 expListAssign && expListAssign->action && expListAssign->action.is<SubBackcall_t>()) {
5100 auto x = *nodes.begin();
5101 auto newBlock = x->new_ptr<Block_t>();
5102 if (it != nodes.begin()) {
5103 for (auto i = nodes.begin(); i != it; ++i) {
5104 newBlock->statementOrComments.push_back(*i);
5105 }
5106 }
5107 auto doBackcall = static_cast<SubBackcall_t*>(expListAssign->action.get());
5108 auto backcall = expListAssign->new_ptr<Backcall_t>();
5109 auto argsDef = backcall->new_ptr<FnArgsDef_t>();
5110 try {
5111 auto defList = toAst<FnArgDefList_t>(YueFormat{}.toString(expListAssign->expList), expListAssign->expList);
5112 argsDef->defList.set(defList);
5113 } catch (const std::exception&) {
5114 throw CompileError("backcall syntax error", backcall);
5115 }
5116 backcall->argsDef.set(argsDef);
5117 backcall->arrow.set(doBackcall->arrow);
5118 backcall->value.set(doBackcall->value);
5119 auto newStmt = backcall->new_ptr<Statement_t>();
5120 newStmt->content.set(backcall);
5121 newStmt->appendix.set(stmt->appendix);
5122 newBlock->statementOrComments.push_back(newStmt);
5123 auto ait = it;
5124 for (auto i = ++ait; i != nodes.end(); ++i) {
5125 newBlock->statementOrComments.push_back(*i);
4819 } 5126 }
4820 newBlock->statements.push_back(toAst<Statement_t>("if "s + okVar + " then return ... else error ..."s, x));
4821 transformBlock(newBlock, out, usage, assignList, isRoot); 5127 transformBlock(newBlock, out, usage, assignList, isRoot);
4822 return; 5128 return;
4823 } 5129 }
@@ -4928,7 +5234,7 @@ private:
4928 } 5234 }
4929 } 5235 }
4930 if (isRoot && !_info.moduleName.empty() && !_info.exportMacro) { 5236 if (isRoot && !_info.moduleName.empty() && !_info.exportMacro) {
4931 block->statements.push_front(toAst<Statement_t>(_info.moduleName + (_info.exportDefault ? "=nil"s : (_info.exportMetatable ? "=<>:{}"s : "={}"s)), block)); 5237 block->statementOrComments.push_front(toAst<Statement_t>(_info.moduleName + (_info.exportDefault ? "=nil"s : (_info.exportMetatable ? "=<>:{}"s : "={}"s)), block));
4932 } 5238 }
4933 switch (usage) { 5239 switch (usage) {
4934 case ExpUsage::Closure: 5240 case ExpUsage::Closure:
@@ -4941,11 +5247,9 @@ private:
4941 auto expList = expListFrom(last); 5247 auto expList = expListFrom(last);
4942 BREAK_IF(!expList); 5248 BREAK_IF(!expList);
4943 BREAK_IF(last->appendix && !last->appendix->item.is<IfLine_t>()); 5249 BREAK_IF(last->appendix && !last->appendix->item.is<IfLine_t>());
4944 auto expListLow = x->new_ptr<ExpListLow_t>();
4945 expListLow->exprs.dup(expList->exprs);
4946 auto returnNode = x->new_ptr<Return_t>(); 5250 auto returnNode = x->new_ptr<Return_t>();
4947 returnNode->explicitReturn = false; 5251 returnNode->explicitReturn = false;
4948 returnNode->valueList.set(expListLow); 5252 returnNode->valueList.set(expList);
4949 returnNode->allowBlockMacroReturn = true; 5253 returnNode->allowBlockMacroReturn = true;
4950 last->content.set(returnNode); 5254 last->content.set(returnNode);
4951 BLOCK_END 5255 BLOCK_END
@@ -4965,7 +5269,7 @@ private:
4965 break; 5269 break;
4966 } 5270 }
4967 } 5271 }
4968 bool lastAssignable = (expListFrom(last) || ast_is<For_t, ForEach_t, While_t>(last->content)); 5272 bool lastAssignable = (expListFrom(last) || ast_is<For_t, While_t>(last->content));
4969 if (lastAssignable) { 5273 if (lastAssignable) {
4970 auto x = last; 5274 auto x = last;
4971 auto newAssignment = x->new_ptr<ExpListAssign_t>(); 5275 auto newAssignment = x->new_ptr<ExpListAssign_t>();
@@ -4990,45 +5294,88 @@ private:
4990 } 5294 }
4991 if (!nodes.empty()) { 5295 if (!nodes.empty()) {
4992 str_list temp; 5296 str_list temp;
5297 auto lastStmt = lastStatementFrom(nodes);
4993 for (auto node : nodes) { 5298 for (auto node : nodes) {
4994 currentScope().lastStatement = (node == nodes.back()) && currentScope().mode == GlobalMode::None; 5299 if (auto comment = ast_cast<YueComment_t>(node)) {
4995 transformStatement(static_cast<Statement_t*>(node), temp); 5300 transformComment(comment, temp);
4996 if (isRoot && !_rootDefs.empty()) { 5301 continue;
4997 auto last = std::move(temp.back()); 5302 }
4998 temp.pop_back(); 5303 if (!ast_is<Statement_t>(node)) {
4999 temp.insert(temp.end(), _rootDefs.begin(), _rootDefs.end()); 5304 continue;
5000 _rootDefs.clear(); 5305 }
5001 temp.push_back(std::move(last)); 5306 auto transformNode = [&]() {
5002 } 5307 currentScope().lastStatement = (node == lastStmt) && currentScope().mode == GlobalMode::None;
5003 if (!temp.empty() && _parser.startWith<StatementSep_t>(temp.back())) { 5308 auto stmt = static_cast<Statement_t*>(node);
5004 auto rit = ++temp.rbegin(); 5309 if (auto importNode = stmt->content.as<Import_t>();
5005 if (rit != temp.rend() && !rit->empty()) { 5310 importNode && importNode->content.is<ImportAllGlobal_t>()) {
5006 auto index = std::string::npos; 5311 if (_importedGlobal) {
5007 if (_config.reserveLineNumber) { 5312 throw CompileError("import global redeclared in same scope"sv, importNode);
5008 index = rit->rfind(" -- "sv);
5009 } else { 5313 } else {
5010 index = rit->find_last_not_of('\n'); 5314 auto& scope = currentScope();
5011 if (index != std::string::npos) index++; 5315 scope.importedGlobal = std::make_unique<ImportedGlobal>();
5012 } 5316 _importedGlobal = scope.importedGlobal.get();
5013 if (index != std::string::npos) { 5317 _importedGlobal->vars = scope.vars.get();
5014 auto ending = rit->substr(0, index); 5318 _importedGlobal->indent = indent();
5015 auto ind = ending.find_last_of(" \t\n"sv); 5319 _importedGlobal->nl = nl(stmt);
5016 if (ind != std::string::npos) { 5320 _importedGlobal->globalCodeLine = &temp.emplace_back();
5017 ending = ending.substr(ind + 1); 5321 }
5322 } else {
5323 transformStatement(stmt, temp);
5324 }
5325 if (isRoot && !_rootDefs.empty()) {
5326 auto last = std::move(temp.back());
5327 temp.pop_back();
5328 temp.insert(temp.end(), _rootDefs.begin(), _rootDefs.end());
5329 _rootDefs.clear();
5330 temp.push_back(std::move(last));
5331 }
5332 if (!temp.empty() && _parser.startWith<StatementSep_t>(temp.back())) {
5333 auto rit = ++temp.rbegin();
5334 if (rit != temp.rend() && !rit->empty()) {
5335 auto index = std::string::npos;
5336 if (_config.reserveLineNumber) {
5337 index = rit->rfind(" -- "sv);
5338 } else {
5339 index = rit->find_last_not_of('\n');
5340 if (index != std::string::npos) index++;
5018 } 5341 }
5019 if (LuaKeywords.find(ending) == LuaKeywords.end()) { 5342 if (index != std::string::npos) {
5020 rit->insert(index, ";"sv); 5343 auto ending = rit->substr(0, index);
5344 auto ind = ending.find_last_of(" \t\n"sv);
5345 if (ind != std::string::npos) {
5346 ending = ending.substr(ind + 1);
5347 }
5348 if (LuaKeywords.find(ending) == LuaKeywords.end()) {
5349 rit->insert(index, ";"sv);
5350 }
5021 } 5351 }
5022 } 5352 }
5023 } 5353 }
5354 };
5355 if (_config.lax) {
5356 try {
5357 transformNode();
5358 } catch (const CompileError&) { }
5359 } else {
5360 transformNode();
5024 } 5361 }
5025 } 5362 }
5363 if (auto importedGlobal = currentScope().importedGlobal.get()) {
5364 int target = getLuaTarget(block);
5365 auto attrib = target >= 504 ? " <const>"s : Empty;
5366 str_list globalCodes;
5367 for (const auto& global : importedGlobal->globalList) {
5368 globalCodes.emplace_back(importedGlobal->indent + "local "s + global + attrib + " = "s + global + importedGlobal->nl);
5369 }
5370 *importedGlobal->globalCodeLine = join(globalCodes);
5371 _importedGlobal = nullptr;
5372 }
5026 out.push_back(join(temp)); 5373 out.push_back(join(temp));
5027 } else { 5374 } else {
5028 out.push_back(Empty); 5375 out.push_back(Empty);
5029 } 5376 }
5030 if (isRoot && !_info.moduleName.empty() && !_info.exportMacro) { 5377 if (isRoot && !_info.moduleName.empty() && !_info.exportMacro) {
5031 out.back().append(indent() + "return "s + _info.moduleName + nlr(block)); 5378 out.back().append(indent() + "return "s + _info.moduleName + nl(block));
5032 } 5379 }
5033 } 5380 }
5034 5381
@@ -5229,18 +5576,29 @@ private:
5229 auto macroLit = macro->decl.to<MacroLit_t>(); 5576 auto macroLit = macro->decl.to<MacroLit_t>();
5230 auto argsDef = macroLit->argsDef.get(); 5577 auto argsDef = macroLit->argsDef.get();
5231 str_list newArgs; 5578 str_list newArgs;
5579 str_list argChecks;
5580 bool hasCheck = false;
5232 if (argsDef) { 5581 if (argsDef) {
5233 for (auto def_ : argsDef->definitions.objects()) { 5582 for (auto def_ : argsDef->definitions.objects()) {
5234 auto def = static_cast<FnArgDef_t*>(def_); 5583 auto def = static_cast<FnArgDef_t*>(def_);
5235 if (def->name.is<SelfItem_t>()) { 5584 if (def->name.is<SelfItem_t>()) {
5236 throw CompileError("self name is not supported for macro function argument"sv, def->name); 5585 throw CompileError("self name is not supported for macro function argument"sv, def->name);
5237 } else { 5586 } else {
5587 if (def->op) throw CompileError("invalid existence checking"sv, def->op);
5588 if (def->label) {
5589 hasCheck = true;
5590 const auto& astName = argChecks.emplace_back(_parser.toString(def->label));
5591 if (!_parser.hasAST(astName)) {
5592 throw CompileError("invalid AST name"sv, def->label);
5593 }
5594 } else {
5595 argChecks.emplace_back();
5596 }
5238 std::string defVal; 5597 std::string defVal;
5239 if (def->defaultValue) { 5598 if (def->defaultValue) {
5240 defVal = _parser.toString(def->defaultValue); 5599 defVal = _parser.toString(def->defaultValue);
5241 Utils::trim(defVal); 5600 Utils::trim(defVal);
5242 defVal.insert(0, "=[==========["sv); 5601 defVal = '=' + Utils::toLuaDoubleString(defVal);
5243 defVal.append("]==========]"sv);
5244 } 5602 }
5245 newArgs.emplace_back(_parser.toString(def->name) + defVal); 5603 newArgs.emplace_back(_parser.toString(def->name) + defVal);
5246 } 5604 }
@@ -5248,6 +5606,14 @@ private:
5248 if (argsDef->varArg) { 5606 if (argsDef->varArg) {
5249 newArgs.emplace_back(_parser.toString(argsDef->varArg)); 5607 newArgs.emplace_back(_parser.toString(argsDef->varArg));
5250 } 5608 }
5609 if (argsDef->label) {
5610 hasCheck = true;
5611 const auto& astName = _parser.toString(argsDef->label);
5612 if (!_parser.hasAST(astName)) {
5613 throw CompileError("invalid AST name"sv, argsDef->label);
5614 }
5615 argChecks.emplace_back("..."s + astName);
5616 }
5251 } 5617 }
5252 std::string macroCodes = "_ENV=require('yue').macro_env\n("s + join(newArgs, ","sv) + ")->"s + _parser.toString(macroLit->body); 5618 std::string macroCodes = "_ENV=require('yue').macro_env\n("s + join(newArgs, ","sv) + ")->"s + _parser.toString(macroLit->body);
5253 auto chunkName = "=(macro "s + macroName + ')'; 5619 auto chunkName = "=(macro "s + macroName + ')';
@@ -5278,6 +5644,24 @@ private:
5278 throw CompileError("failed to generate macro function\n"s + err, macroLit); 5644 throw CompileError("failed to generate macro function\n"s + err, macroLit);
5279 } // cur true macro 5645 } // cur true macro
5280 lua_remove(L, -2); // cur macro 5646 lua_remove(L, -2); // cur macro
5647 if (hasCheck) {
5648 lua_createtable(L, 0, 0); // cur macro checks
5649 int i = 1;
5650 for (const auto& check : argChecks) {
5651 if (check.empty()) {
5652 lua_pushboolean(L, 0);
5653 lua_rawseti(L, -2, i);
5654 } else {
5655 lua_pushlstring(L, check.c_str(), check.size());
5656 lua_rawseti(L, -2, i);
5657 }
5658 i++;
5659 }
5660 lua_createtable(L, 2, 0); // cur macro checks macrotab
5661 lua_insert(L, -3); // cur macrotab macro checks
5662 lua_rawseti(L, -3, 1); // macrotab[1] = checks, cur macrotab macro
5663 lua_rawseti(L, -2, 2); // macrotab[2] = macro, cur macrotab
5664 } // cur macro
5281 if (exporting && _config.exporting && !_config.module.empty()) { 5665 if (exporting && _config.exporting && !_config.module.empty()) {
5282 pushModuleTable(_config.module); // cur macro module 5666 pushModuleTable(_config.module); // cur macro module
5283 lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro module name 5667 lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro module name
@@ -5310,7 +5694,7 @@ private:
5310 if (!target) target = returnNode; 5694 if (!target) target = returnNode;
5311 throw CompileError("explicit return statement is not allowed in this context"sv, target); 5695 throw CompileError("explicit return statement is not allowed in this context"sv, target);
5312 } 5696 }
5313 if (auto valueList = returnNode->valueList.as<ExpListLow_t>()) { 5697 if (auto valueList = returnNode->valueList.as<ExpList_t>()) {
5314 if (valueList->exprs.size() == 1) { 5698 if (valueList->exprs.size() == 1) {
5315 auto exp = static_cast<Exp_t*>(valueList->exprs.back()); 5699 auto exp = static_cast<Exp_t*>(valueList->exprs.back());
5316 if (isPurePipeChain(exp)) { 5700 if (isPurePipeChain(exp)) {
@@ -5352,11 +5736,11 @@ private:
5352 case id<While_t>(): 5736 case id<While_t>():
5353 transformWhileInPlace(static_cast<While_t*>(value), out); 5737 transformWhileInPlace(static_cast<While_t*>(value), out);
5354 return; 5738 return;
5355 case id<For_t>(): 5739 case id<Repeat_t>():
5356 transformForInPlace(static_cast<For_t*>(value), out); 5740 transformRepeatInPlace(static_cast<Repeat_t*>(value), out);
5357 return; 5741 return;
5358 case id<ForEach_t>(): 5742 case id<For_t>():
5359 transformForEachInPlace(static_cast<ForEach_t*>(value), out); 5743 transformForInPlace(static_cast<For_t*>(value), out, nullptr);
5360 return; 5744 return;
5361 case id<If_t>(): 5745 case id<If_t>():
5362 transformIf(static_cast<If_t*>(value), out, ExpUsage::Return); 5746 transformIf(static_cast<If_t*>(value), out, ExpUsage::Return);
@@ -5376,12 +5760,12 @@ private:
5376 } 5760 }
5377 } 5761 }
5378 transformValue(singleValue, out); 5762 transformValue(singleValue, out);
5379 out.back() = indent() + "return "s + out.back() + nlr(returnNode); 5763 out.back() = indent() + "return "s + out.back() + nl(returnNode);
5380 return; 5764 return;
5381 } else { 5765 } else {
5382 str_list temp; 5766 str_list temp;
5383 transformExpListLow(valueList, temp); 5767 transformExpList(valueList, temp);
5384 out.push_back(indent() + "return "s + temp.back() + nlr(returnNode)); 5768 out.push_back(indent() + "return "s + temp.back() + nl(returnNode));
5385 } 5769 }
5386 } else if (auto tableBlock = returnNode->valueList.as<TableBlock_t>()) { 5770 } else if (auto tableBlock = returnNode->valueList.as<TableBlock_t>()) {
5387 const auto& values = tableBlock->values.objects(); 5771 const auto& values = tableBlock->values.objects();
@@ -5389,10 +5773,10 @@ private:
5389 transformSpreadTable(values, out, ExpUsage::Return, nullptr, false); 5773 transformSpreadTable(values, out, ExpUsage::Return, nullptr, false);
5390 } else { 5774 } else {
5391 transformTable(values, out); 5775 transformTable(values, out);
5392 out.back() = indent() + "return "s + out.back() + nlr(returnNode); 5776 out.back() = indent() + "return "s + out.back() + nl(returnNode);
5393 } 5777 }
5394 } else { 5778 } else {
5395 out.push_back(indent() + "return"s + nll(returnNode)); 5779 out.push_back(indent() + "return"s + nl(returnNode));
5396 } 5780 }
5397 } 5781 }
5398 5782
@@ -5423,6 +5807,7 @@ private:
5423 bool checkExistence = false; 5807 bool checkExistence = false;
5424 std::string name; 5808 std::string name;
5425 std::string assignSelf; 5809 std::string assignSelf;
5810 ast_ptr<false, ExpListAssign_t> assignment;
5426 }; 5811 };
5427 std::list<ArgItem> argItems; 5812 std::list<ArgItem> argItems;
5428 str_list temp; 5813 str_list temp;
@@ -5432,7 +5817,11 @@ private:
5432 auto def = static_cast<FnArgDef_t*>(_def); 5817 auto def = static_cast<FnArgDef_t*>(_def);
5433 auto& arg = argItems.emplace_back(); 5818 auto& arg = argItems.emplace_back();
5434 switch (def->name->get_id()) { 5819 switch (def->name->get_id()) {
5435 case id<Variable_t>(): arg.name = variableToString(static_cast<Variable_t*>(def->name.get())); break; 5820 case id<Variable_t>(): {
5821 if (def->op) throw CompileError("invalid existence checking"sv, def->op);
5822 arg.name = variableToString(static_cast<Variable_t*>(def->name.get()));
5823 break;
5824 }
5436 case id<SelfItem_t>(): { 5825 case id<SelfItem_t>(): {
5437 assignSelf = true; 5826 assignSelf = true;
5438 if (def->op) { 5827 if (def->op) {
@@ -5473,6 +5862,22 @@ private:
5473 } 5862 }
5474 break; 5863 break;
5475 } 5864 }
5865 case id<TableLit_t>(): {
5866 arg.name = getUnusedName("_arg_"sv);
5867 auto simpleValue = def->new_ptr<SimpleValue_t>();
5868 simpleValue->value.set(def->name);
5869 auto asmt = assignmentFrom(newExp(simpleValue, def), toAst<Exp_t>(arg.name, def), def);
5870 arg.assignment = asmt;
5871 break;
5872 }
5873 case id<SimpleTable_t>(): {
5874 arg.name = getUnusedName("_arg_"sv);
5875 auto value = def->new_ptr<Value_t>();
5876 value->item.set(def->name);
5877 auto asmt = assignmentFrom(newExp(value, def), toAst<Exp_t>(arg.name, def), def);
5878 arg.assignment = asmt;
5879 break;
5880 }
5476 default: YUEE("AST node mismatch", def->name.get()); break; 5881 default: YUEE("AST node mismatch", def->name.get()); break;
5477 } 5882 }
5478 forceAddToScope(arg.name); 5883 forceAddToScope(arg.name);
@@ -5486,23 +5891,46 @@ private:
5486 assignment->action.set(assign); 5891 assignment->action.set(assign);
5487 transformAssignment(assignment, temp); 5892 transformAssignment(assignment, temp);
5488 popScope(); 5893 popScope();
5489 _buf << indent() << "if "sv << arg.name << " == nil then"sv << nll(def); 5894 _buf << indent() << "if "sv << arg.name << " == nil then"sv << nl(def);
5490 _buf << temp.back(); 5895 _buf << temp.back();
5491 _buf << indent() << "end"sv << nll(def); 5896 _buf << indent() << "end"sv << nl(def);
5492 temp.back() = clearBuf(); 5897 temp.back() = clearBuf();
5493 } 5898 }
5494 if (varNames.empty()) 5899 if (arg.assignment) {
5900 auto names = getArgDestructureList(arg.assignment);
5901 for (const auto& name : names) {
5902 forceAddToScope(name);
5903 }
5904 temp.emplace_back(indent() + "local "s + join(names, ", "sv) + nl(def));
5905 transformAssignment(arg.assignment, temp);
5906 }
5907 if (varNames.empty()) {
5495 varNames = arg.name; 5908 varNames = arg.name;
5496 else 5909 } else {
5497 varNames.append(", "s + arg.name); 5910 varNames.append(", "s + arg.name);
5911 }
5498 } 5912 }
5499 if (argDefList->varArg) { 5913 if (argDefList->varArg) {
5914 std::string varStr;
5915 if (auto varName = argDefList->varArg->name.get()) {
5916 varStr = variableToString(varName);
5917 int target = getLuaTarget(varName);
5918 forceAddToScope(varStr);
5919 if (target < 505) {
5920 temp.push_back(indent() + "local "s + varStr + " = {"s + nl(varName));
5921 temp.push_back(indent(1) + "n = "s + globalVar("select", varName, AccessType::Read) + "(\"#\", ...),"s + nl(varName));
5922 temp.push_back(indent(1) + "..."s + nl(varName));
5923 temp.push_back(indent() + '}' + nl(varName));
5924 varStr.clear();
5925 }
5926 }
5500 auto& arg = argItems.emplace_back(); 5927 auto& arg = argItems.emplace_back();
5501 arg.name = "..."sv; 5928 arg.name = "..."sv;
5502 if (varNames.empty()) 5929 if (varNames.empty()) {
5503 varNames = arg.name; 5930 varNames = arg.name + varStr;
5504 else 5931 } else {
5505 varNames.append(", "s + arg.name); 5932 varNames.append(", "s + arg.name + varStr);
5933 }
5506 _varArgs.top().hasVar = true; 5934 _varArgs.top().hasVar = true;
5507 } 5935 }
5508 if (assignSelf) { 5936 if (assignSelf) {
@@ -5571,6 +5999,45 @@ private:
5571 } 5999 }
5572 } 6000 }
5573 6001
6002 bool transformChainEndWithSlice(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) {
6003 auto x = chainList.front();
6004 if (ast_is<Slice_t>(chainList.back())) {
6005 auto comp = x->new_ptr<Comprehension_t>();
6006 {
6007 auto chainValue = x->new_ptr<ChainValue_t>();
6008 for (auto item : chainList) {
6009 chainValue->items.push_back(item);
6010 }
6011 auto itemVar = getUnusedName("_item_"sv);
6012 auto expCode = YueFormat{}.toString(chainValue);
6013 auto compCode = '[' + itemVar + " for "s + itemVar + " in *"s + expCode + ']';
6014 comp.set(toAst<Comprehension_t>(compCode, x));
6015 }
6016 switch (usage) {
6017 case ExpUsage::Assignment: {
6018 auto simpleValue = x->new_ptr<SimpleValue_t>();
6019 simpleValue->value.set(comp);
6020 auto exp = newExp(simpleValue, x);
6021 auto assignment = x->new_ptr<ExpListAssign_t>();
6022 assignment->expList.set(assignList);
6023 auto assign = x->new_ptr<Assign_t>();
6024 assign->values.push_back(exp);
6025 assignment->action.set(assign);
6026 transformAssignment(assignment, out);
6027 break;
6028 }
6029 case ExpUsage::Return:
6030 transformComprehension(comp, out, ExpUsage::Return);
6031 break;
6032 default:
6033 transformComprehension(comp, out, ExpUsage::Closure);
6034 break;
6035 }
6036 return true;
6037 }
6038 return false;
6039 }
6040
5574 bool transformChainEndWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) { 6041 bool transformChainEndWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) {
5575 auto x = chainList.front(); 6042 auto x = chainList.front();
5576 if (ast_is<ExistentialOp_t>(chainList.back())) { 6043 if (ast_is<ExistentialOp_t>(chainList.back())) {
@@ -5605,7 +6072,7 @@ private:
5605 case ExpUsage::Return: 6072 case ExpUsage::Return:
5606 transformParens(parens, out); 6073 transformParens(parens, out);
5607 out.back().insert(0, indent() + "return "s); 6074 out.back().insert(0, indent() + "return "s);
5608 out.back().append(nlr(x)); 6075 out.back().append(nl(x));
5609 break; 6076 break;
5610 default: 6077 default:
5611 transformParens(parens, out); 6078 transformParens(parens, out);
@@ -5676,7 +6143,7 @@ private:
5676 } 6143 }
5677 } 6144 }
5678 if (isScoped) { 6145 if (isScoped) {
5679 temp.push_back(indent() + "do"s + nll(x)); 6146 temp.push_back(indent() + "do"s + nl(x));
5680 pushScope(); 6147 pushScope();
5681 } 6148 }
5682 objVar = getUnusedName("_obj_"sv); 6149 objVar = getUnusedName("_obj_"sv);
@@ -5736,9 +6203,9 @@ private:
5736 _buf << typeVar << "=type "sv << objVar; 6203 _buf << typeVar << "=type "sv << objVar;
5737 auto typeAssign = toAst<ExpListAssign_t>(clearBuf(), partOne); 6204 auto typeAssign = toAst<ExpListAssign_t>(clearBuf(), partOne);
5738 transformAssignment(typeAssign, temp); 6205 transformAssignment(typeAssign, temp);
5739 _buf << indent() << "if \"table\" == " << typeVar << " or \"userdata\" == "sv << typeVar << " then"sv << nll(x); 6206 _buf << indent() << "if \"table\" == " << typeVar << " or \"userdata\" == "sv << typeVar << " then"sv << nl(x);
5740 } else { 6207 } else {
5741 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); 6208 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nl(x);
5742 } 6209 }
5743 temp.push_back(clearBuf()); 6210 temp.push_back(clearBuf());
5744 pushScope(); 6211 pushScope();
@@ -5764,25 +6231,21 @@ private:
5764 case ExpUsage::Return: 6231 case ExpUsage::Return:
5765 case ExpUsage::Closure: { 6232 case ExpUsage::Closure: {
5766 auto exp = newExp(partTwo, x); 6233 auto exp = newExp(partTwo, x);
5767 auto ret = x->new_ptr<Return_t>(); 6234 auto ret = newReturn(exp);
5768 ret->explicitReturn = false;
5769 auto expListLow = x->new_ptr<ExpListLow_t>();
5770 expListLow->exprs.push_back(exp);
5771 ret->valueList.set(expListLow);
5772 transformReturn(ret, temp); 6235 transformReturn(ret, temp);
5773 break; 6236 break;
5774 } 6237 }
5775 } 6238 }
5776 popScope(); 6239 popScope();
5777 temp.push_back(indent() + "end"s + nlr(x)); 6240 temp.push_back(indent() + "end"s + nl(x));
5778 switch (usage) { 6241 switch (usage) {
5779 case ExpUsage::Return: 6242 case ExpUsage::Return:
5780 temp.push_back(indent() + "return nil"s + nlr(x)); 6243 temp.push_back(indent() + "return nil"s + nl(x));
5781 break; 6244 break;
5782 case ExpUsage::Closure: 6245 case ExpUsage::Closure:
5783 temp.push_back(indent() + "return nil"s + nlr(x)); 6246 temp.push_back(indent() + "return nil"s + nl(x));
5784 popScope(); 6247 popScope();
5785 *funcStart = anonFuncStart() + nll(x); 6248 *funcStart = anonFuncStart() + nl(x);
5786 temp.push_back(indent() + anonFuncEnd()); 6249 temp.push_back(indent() + anonFuncEnd());
5787 popAnonVarArg(); 6250 popAnonVarArg();
5788 popFunctionScope(); 6251 popFunctionScope();
@@ -5792,7 +6255,7 @@ private:
5792 } 6255 }
5793 if (isScoped) { 6256 if (isScoped) {
5794 popScope(); 6257 popScope();
5795 temp.push_back(indent() + "end"s + nlr(x)); 6258 temp.push_back(indent() + "end"s + nl(x));
5796 } 6259 }
5797 out.push_back(join(temp)); 6260 out.push_back(join(temp));
5798 return true; 6261 return true;
@@ -5809,7 +6272,7 @@ private:
5809 switch (usage) { 6272 switch (usage) {
5810 case ExpUsage::Assignment: 6273 case ExpUsage::Assignment:
5811 if (isScoped) { 6274 if (isScoped) {
5812 temp.push_back(indent() + "do"s + nll(x)); 6275 temp.push_back(indent() + "do"s + nl(x));
5813 pushScope(); 6276 pushScope();
5814 } 6277 }
5815 break; 6278 break;
@@ -5863,11 +6326,7 @@ private:
5863 switch (usage) { 6326 switch (usage) {
5864 case ExpUsage::Closure: 6327 case ExpUsage::Closure:
5865 case ExpUsage::Return: { 6328 case ExpUsage::Return: {
5866 auto returnNode = x->new_ptr<Return_t>(); 6329 auto returnNode = newReturn(funLit);
5867 returnNode->explicitReturn = false;
5868 auto expListLow = x->new_ptr<ExpListLow_t>();
5869 expListLow->exprs.push_back(funLit);
5870 returnNode->valueList.set(expListLow);
5871 transformReturn(returnNode, temp); 6330 transformReturn(returnNode, temp);
5872 break; 6331 break;
5873 } 6332 }
@@ -5887,12 +6346,12 @@ private:
5887 case ExpUsage::Assignment: 6346 case ExpUsage::Assignment:
5888 if (isScoped) { 6347 if (isScoped) {
5889 popScope(); 6348 popScope();
5890 temp.push_back(indent() + "end"s + nlr(x)); 6349 temp.push_back(indent() + "end"s + nl(x));
5891 } 6350 }
5892 break; 6351 break;
5893 case ExpUsage::Closure: 6352 case ExpUsage::Closure:
5894 popScope(); 6353 popScope();
5895 *funcStart = anonFuncStart() + nll(x); 6354 *funcStart = anonFuncStart() + nl(x);
5896 temp.push_back(indent() + anonFuncEnd()); 6355 temp.push_back(indent() + anonFuncEnd());
5897 popAnonVarArg(); 6356 popAnonVarArg();
5898 popFunctionScope(); 6357 popFunctionScope();
@@ -5968,7 +6427,7 @@ private:
5968 pushScope(); 6427 pushScope();
5969 } else if (usage != ExpUsage::Return) { 6428 } else if (usage != ExpUsage::Return) {
5970 if (isScoped) { 6429 if (isScoped) {
5971 temp.push_back(indent() + "do"s + nll(x)); 6430 temp.push_back(indent() + "do"s + nl(x));
5972 pushScope(); 6431 pushScope();
5973 } 6432 }
5974 } 6433 }
@@ -5998,25 +6457,17 @@ private:
5998 } 6457 }
5999 switch (usage) { 6458 switch (usage) {
6000 case ExpUsage::Closure: { 6459 case ExpUsage::Closure: {
6001 auto returnNode = x->new_ptr<Return_t>(); 6460 auto returnNode = newReturn(newChainExp);
6002 returnNode->explicitReturn = false;
6003 auto values = x->new_ptr<ExpListLow_t>();
6004 values->exprs.push_back(newChainExp);
6005 returnNode->valueList.set(values);
6006 transformReturn(returnNode, temp); 6461 transformReturn(returnNode, temp);
6007 popScope(); 6462 popScope();
6008 *funcStart = anonFuncStart() + nll(x); 6463 *funcStart = anonFuncStart() + nl(x);
6009 temp.push_back(indent() + anonFuncEnd()); 6464 temp.push_back(indent() + anonFuncEnd());
6010 popAnonVarArg(); 6465 popAnonVarArg();
6011 popFunctionScope(); 6466 popFunctionScope();
6012 break; 6467 break;
6013 } 6468 }
6014 case ExpUsage::Return: { 6469 case ExpUsage::Return: {
6015 auto returnNode = x->new_ptr<Return_t>(); 6470 auto returnNode = newReturn(newChainExp);
6016 returnNode->explicitReturn = false;
6017 auto values = x->new_ptr<ExpListLow_t>();
6018 values->exprs.push_back(newChainExp);
6019 returnNode->valueList.set(values);
6020 transformReturn(returnNode, temp); 6471 transformReturn(returnNode, temp);
6021 break; 6472 break;
6022 } 6473 }
@@ -6029,7 +6480,7 @@ private:
6029 transformAssignment(assignment, temp); 6480 transformAssignment(assignment, temp);
6030 if (isScoped) { 6481 if (isScoped) {
6031 popScope(); 6482 popScope();
6032 temp.push_back(indent() + "end"s + nlr(x)); 6483 temp.push_back(indent() + "end"s + nl(x));
6033 } 6484 }
6034 break; 6485 break;
6035 } 6486 }
@@ -6037,7 +6488,7 @@ private:
6037 transformExp(newChainExp, temp, usage); 6488 transformExp(newChainExp, temp, usage);
6038 if (isScoped) { 6489 if (isScoped) {
6039 popScope(); 6490 popScope();
6040 temp.push_back(indent() + "end"s + nlr(x)); 6491 temp.push_back(indent() + "end"s + nl(x));
6041 } 6492 }
6042 break; 6493 break;
6043 } 6494 }
@@ -6088,7 +6539,7 @@ private:
6088 case id<ColonChainItem_t>(): 6539 case id<ColonChainItem_t>():
6089 case id<Exp_t>(): 6540 case id<Exp_t>():
6090 if (_withVars.empty()) { 6541 if (_withVars.empty()) {
6091 throw CompileError("short dot/colon and indexing syntax must be called within a with block"sv, x); 6542 throw CompileError("short dot/colon/indexing syntax must be called within a with block"sv, x);
6092 } else { 6543 } else {
6093 temp.push_back(_withVars.top()); 6544 temp.push_back(_withVars.top());
6094 } 6545 }
@@ -6142,7 +6593,7 @@ private:
6142 assignment->action.set(assign); 6593 assignment->action.set(assign);
6143 auto stmt = x->new_ptr<Statement_t>(); 6594 auto stmt = x->new_ptr<Statement_t>();
6144 stmt->content.set(assignment); 6595 stmt->content.set(assignment);
6145 block->statements.push_back(stmt); 6596 block->statementOrComments.push_back(stmt);
6146 } 6597 }
6147 } 6598 }
6148 ast_ptr<false, Exp_t> nexp; 6599 ast_ptr<false, Exp_t> nexp;
@@ -6188,7 +6639,7 @@ private:
6188 expListAssign->expList.set(expList); 6639 expListAssign->expList.set(expList);
6189 auto stmt = x->new_ptr<Statement_t>(); 6640 auto stmt = x->new_ptr<Statement_t>();
6190 stmt->content.set(expListAssign); 6641 stmt->content.set(expListAssign);
6191 block->statements.push_back(stmt); 6642 block->statementOrComments.push_back(stmt);
6192 } 6643 }
6193 switch (usage) { 6644 switch (usage) {
6194 case ExpUsage::Common: 6645 case ExpUsage::Common:
@@ -6202,7 +6653,7 @@ private:
6202 default: 6653 default:
6203 break; 6654 break;
6204 } 6655 }
6205 if (block->statements.size() == 1) { 6656 if (block->statementOrComments.size() == 1) {
6206 transformExp(nexp, out, usage, assignList); 6657 transformExp(nexp, out, usage, assignList);
6207 } else { 6658 } else {
6208 auto body = x->new_ptr<Body_t>(); 6659 auto body = x->new_ptr<Body_t>();
@@ -6234,6 +6685,120 @@ private:
6234 } 6685 }
6235 return; 6686 return;
6236 } 6687 }
6688 break;
6689 }
6690 case id<ReversedIndex_t>(): {
6691 auto rIndex = static_cast<ReversedIndex_t*>(*it);
6692 auto current = it;
6693 auto prevChain = x->new_ptr<ChainValue_t>();
6694 for (auto i = chainList.begin(); i != current; ++i) {
6695 prevChain->items.push_back(*i);
6696 }
6697 auto var = singleVariableFrom(prevChain, AccessType::None);
6698 if (!var.empty() && isLocal(var)) {
6699 auto indexNode = toAst<Exp_t>('#' + var, rIndex);
6700 if (rIndex->modifier) {
6701 auto opValue = rIndex->new_ptr<ExpOpValue_t>();
6702 opValue->op.set(toAst<BinaryOperator_t>("-"sv, rIndex));
6703 opValue->pipeExprs.dup(rIndex->modifier->pipeExprs);
6704 indexNode->opValues.push_back(opValue);
6705 indexNode->opValues.dup(rIndex->modifier->opValues);
6706 indexNode->nilCoalesed.set(rIndex->modifier->nilCoalesed);
6707 }
6708 prevChain->items.push_back(indexNode);
6709 auto next = current;
6710 ++next;
6711 for (auto i = next; i != chainList.end(); ++i) {
6712 prevChain->items.push_back(*i);
6713 }
6714 if (usage == ExpUsage::Assignment) {
6715 auto assignment = x->new_ptr<ExpListAssign_t>();
6716 assignment->expList.set(assignList);
6717 auto assign = x->new_ptr<Assign_t>();
6718 assign->values.push_back(newExp(prevChain, x));
6719 assignment->action.set(assign);
6720 transformAssignment(assignment, out);
6721 return;
6722 }
6723 transformChainValue(prevChain, out, usage, assignList);
6724 return;
6725 } else {
6726 auto itemVar = getUnusedName("_item_"sv);
6727 auto asmt = assignmentFrom(toAst<Exp_t>(itemVar, x), newExp(prevChain, x), x);
6728 auto stmt1 = x->new_ptr<Statement_t>();
6729 stmt1->content.set(asmt);
6730 auto newChain = x->new_ptr<ChainValue_t>();
6731 newChain->items.push_back(toAst<Callable_t>(itemVar, x));
6732 auto indexNode = toAst<Exp_t>('#' + itemVar, rIndex);
6733 if (rIndex->modifier) {
6734 auto opValue = rIndex->new_ptr<ExpOpValue_t>();
6735 opValue->op.set(toAst<BinaryOperator_t>("-"sv, rIndex));
6736 opValue->pipeExprs.dup(rIndex->modifier->pipeExprs);
6737 indexNode->opValues.push_back(opValue);
6738 indexNode->opValues.dup(rIndex->modifier->opValues);
6739 indexNode->nilCoalesed.set(rIndex->modifier->nilCoalesed);
6740 }
6741 newChain->items.push_back(indexNode);
6742 auto expList = x->new_ptr<ExpList_t>();
6743 expList->exprs.push_back(newExp(newChain, x));
6744 auto expListAssign = x->new_ptr<ExpListAssign_t>();
6745 expListAssign->expList.set(expList);
6746 auto stmt2 = x->new_ptr<Statement_t>();
6747 stmt2->content.set(expListAssign);
6748 auto block = x->new_ptr<Block_t>();
6749 block->statementOrComments.push_back(stmt1);
6750 block->statementOrComments.push_back(stmt2);
6751 auto body = x->new_ptr<Body_t>();
6752 body->content.set(block);
6753 auto doNode = x->new_ptr<Do_t>();
6754 doNode->body.set(body);
6755 if (usage == ExpUsage::Assignment) {
6756 auto next = current;
6757 ++next;
6758 for (auto i = next; i != chainList.end(); ++i) {
6759 newChain->items.push_back(*i);
6760 }
6761 auto assignment = x->new_ptr<ExpListAssign_t>();
6762 assignment->expList.set(assignList);
6763 auto assign = x->new_ptr<Assign_t>();
6764 auto sVal = x->new_ptr<SimpleValue_t>();
6765 sVal->value.set(doNode);
6766 assign->values.push_back(newExp(sVal, x));
6767 assignment->action.set(assign);
6768 transformAssignment(assignment, out);
6769 return;
6770 }
6771 if (usage == ExpUsage::Closure) {
6772 auto next = current;
6773 ++next;
6774 if (next != chainList.end()) {
6775 doNode->new_ptr<ChainValue_t>();
6776 auto dVal = doNode->new_ptr<SimpleValue_t>();
6777 dVal->value.set(doNode);
6778 auto dExp = newExp(dVal, dVal);
6779 auto dParen = dExp->new_ptr<Parens_t>();
6780 dParen->extra = true;
6781 dParen->expr.set(dExp);
6782 auto dCallable = dExp->new_ptr<Callable_t>();
6783 dCallable->item.set(dParen);
6784 auto dChain = doNode->new_ptr<ChainValue_t>();
6785 dChain->items.push_back(dCallable);
6786 for (auto i = next; i != chainList.end(); ++i) {
6787 dChain->items.push_back(*i);
6788 }
6789 transformExp(newExp(dChain, dExp), out, usage);
6790 return;
6791 }
6792 }
6793 auto next = current;
6794 ++next;
6795 for (auto i = next; i != chainList.end(); ++i) {
6796 newChain->items.push_back(*i);
6797 }
6798 transformDo(doNode, out, usage);
6799 return;
6800 }
6801 break;
6237 } 6802 }
6238 } 6803 }
6239 } 6804 }
@@ -6283,10 +6848,10 @@ private:
6283 } 6848 }
6284 switch (usage) { 6849 switch (usage) {
6285 case ExpUsage::Common: 6850 case ExpUsage::Common:
6286 out.push_back(indent() + join(temp) + nll(x)); 6851 out.push_back(indent() + join(temp) + nl(x));
6287 break; 6852 break;
6288 case ExpUsage::Return: 6853 case ExpUsage::Return:
6289 out.push_back(indent() + "return "s + join(temp) + nll(x)); 6854 out.push_back(indent() + "return "s + join(temp) + nl(x));
6290 break; 6855 break;
6291 case ExpUsage::Assignment: YUEE("invalid expression usage", x); break; 6856 case ExpUsage::Assignment: YUEE("invalid expression usage", x); break;
6292 default: 6857 default:
@@ -6418,7 +6983,7 @@ private:
6418 } 6983 }
6419 } 6984 }
6420 } 6985 }
6421 int len = lua_objlen(L, -1); 6986 int len = static_cast<int>(lua_objlen(L, -1));
6422 lua_pushnil(L); // cur nil 6987 lua_pushnil(L); // cur nil
6423 for (int i = len; i >= 1; i--) { 6988 for (int i = len; i >= 1; i--) {
6424 lua_pop(L, 1); // cur 6989 lua_pop(L, 1); // cur
@@ -6430,7 +6995,25 @@ private:
6430 break; 6995 break;
6431 } 6996 }
6432 } 6997 }
6433 if (!lua_isfunction(L, -1)) { 6998 str_list checks;
6999 if (lua_istable(L, -1)) {
7000 lua_rawgeti(L, -1, 1); // cur macrotab checks
7001 int len = static_cast<int>(lua_objlen(L, -1));
7002 for (int i = 1; i <= len; i++) {
7003 lua_rawgeti(L, -1, i);
7004 if (lua_toboolean(L, -1) == 0) {
7005 checks.emplace_back();
7006 } else {
7007 size_t str_len = 0;
7008 auto str = lua_tolstring(L, -1, &str_len);
7009 checks.emplace_back(std::string{str, str_len});
7010 }
7011 lua_pop(L, 1);
7012 }
7013 lua_pop(L, 1);
7014 lua_rawgeti(L, -1, 2); // cur macrotab macroFunc
7015 lua_remove(L, -2); // cur macroFunc
7016 } else if (!lua_isfunction(L, -1)) {
6434 auto code = expandBuiltinMacro(macroName, x); 7017 auto code = expandBuiltinMacro(macroName, x);
6435 if (!code.empty()) return code; 7018 if (!code.empty()) return code;
6436 if (macroName == "is_ast"sv) { 7019 if (macroName == "is_ast"sv) {
@@ -6475,11 +7058,34 @@ private:
6475 } // cur macroFunc 7058 } // cur macroFunc
6476 pushYue("pcall"sv); // cur macroFunc pcall 7059 pushYue("pcall"sv); // cur macroFunc pcall
6477 lua_insert(L, -2); // cur pcall macroFunc 7060 lua_insert(L, -2); // cur pcall macroFunc
6478 if (!lua_checkstack(L, argStrs.size())) { 7061 if (!lua_checkstack(L, static_cast<int>(argStrs.size()))) {
6479 throw CompileError("too much macro params"s, x); 7062 throw CompileError("too much macro params"s, x);
6480 } 7063 }
7064 auto checkIt = checks.begin();
7065 node_container::const_iterator argIt;
7066 if (args) {
7067 argIt = args->begin();
7068 }
6481 for (const auto& arg : argStrs) { 7069 for (const auto& arg : argStrs) {
7070 if (checkIt != checks.end()) {
7071 if (checkIt->empty()) {
7072 ++checkIt;
7073 } else {
7074 if ((*checkIt)[0] == '.') {
7075 auto astName = checkIt->substr(3);
7076 if (!_parser.match(astName, arg)) {
7077 throw CompileError("expecting \""s + astName + "\", AST mismatch"s, *argIt);
7078 }
7079 } else {
7080 if (!_parser.match(*checkIt, arg)) {
7081 throw CompileError("expecting \""s + *checkIt + "\", AST mismatch"s, *argIt);
7082 }
7083 ++checkIt;
7084 }
7085 }
7086 }
6482 lua_pushlstring(L, arg.c_str(), arg.size()); 7087 lua_pushlstring(L, arg.c_str(), arg.size());
7088 ++argIt;
6483 } // cur pcall macroFunc args... 7089 } // cur pcall macroFunc args...
6484 bool success = lua_pcall(L, static_cast<int>(argStrs.size()), 1, 0) == 0; 7090 bool success = lua_pcall(L, static_cast<int>(argStrs.size()), 1, 0) == 0;
6485 if (!success) { // cur err 7091 if (!success) { // cur err
@@ -6571,8 +7177,8 @@ private:
6571 throw CompileError("lua macro is not expanding to valid block\n"s + err, x); 7177 throw CompileError("lua macro is not expanding to valid block\n"s + err, x);
6572 } 7178 }
6573 if (!codes.empty()) { 7179 if (!codes.empty()) {
6574 codes.insert(0, indent() + "do"s + nll(chainValue)); 7180 codes.insert(0, indent() + "do"s + nl(chainValue));
6575 codes.append(_newLine + indent() + "end"s + nlr(chainValue)); 7181 codes.append(_newLine + indent() + "end"s + nl(chainValue));
6576 } 7182 }
6577 return {nullptr, nullptr, std::move(codes), std::move(localVars)}; 7183 return {nullptr, nullptr, std::move(codes), std::move(localVars)};
6578 } else { 7184 } else {
@@ -6609,14 +7215,14 @@ private:
6609 } else { 7215 } else {
6610 if (!codes.empty()) { 7216 if (!codes.empty()) {
6611 if (isBlock) { 7217 if (isBlock) {
6612 info = _parser.parse<BlockEnd_t>(codes); 7218 info = _parser.parse<BlockEnd_t>(codes, false);
6613 if (info.error) { 7219 if (info.error) {
6614 throw CompileError("failed to expand macro as block: "s + info.error.value().msg, x); 7220 throw CompileError("failed to expand macro as block: "s + info.error.value().msg, x);
6615 } 7221 }
6616 } else { 7222 } else {
6617 info = _parser.parse<Exp_t>(codes); 7223 info = _parser.parse<Exp_t>(codes, false);
6618 if (!info.node && allowBlockMacroReturn) { 7224 if (!info.node && allowBlockMacroReturn) {
6619 info = _parser.parse<BlockEnd_t>(codes); 7225 info = _parser.parse<BlockEnd_t>(codes, false);
6620 if (info.error) { 7226 if (info.error) {
6621 throw CompileError("failed to expand macro as expr or block: "s + info.error.value().msg, x); 7227 throw CompileError("failed to expand macro as expr or block: "s + info.error.value().msg, x);
6622 } 7228 }
@@ -6661,7 +7267,7 @@ private:
6661 auto stmt = x->new_ptr<Statement_t>(); 7267 auto stmt = x->new_ptr<Statement_t>();
6662 stmt->content.set(exps); 7268 stmt->content.set(exps);
6663 auto block = x->new_ptr<Block_t>(); 7269 auto block = x->new_ptr<Block_t>();
6664 block->statements.push_back(stmt); 7270 block->statementOrComments.push_back(stmt);
6665 info.node.set(block); 7271 info.node.set(block);
6666 } else { 7272 } else {
6667 info.node.set(exp); 7273 info.node.set(exp);
@@ -6698,7 +7304,7 @@ private:
6698 return; 7304 return;
6699 } 7305 }
6700 if (usage == ExpUsage::Common || (usage == ExpUsage::Return && node.is<Block_t>())) { 7306 if (usage == ExpUsage::Common || (usage == ExpUsage::Return && node.is<Block_t>())) {
6701 if (node.to<Block_t>()->statements.empty()) { 7307 if (node.to<Block_t>()->statementOrComments.empty()) {
6702 out.push_back(Empty); 7308 out.push_back(Empty);
6703 } else { 7309 } else {
6704 auto doBody = node->new_ptr<Body_t>(); 7310 auto doBody = node->new_ptr<Body_t>();
@@ -6720,11 +7326,7 @@ private:
6720 break; 7326 break;
6721 } 7327 }
6722 case ExpUsage::Return: { 7328 case ExpUsage::Return: {
6723 auto expListLow = x->new_ptr<ExpListLow_t>(); 7329 auto returnNode = newReturn(node.to<Exp_t>());
6724 expListLow->exprs.push_back(node);
6725 auto returnNode = x->new_ptr<Return_t>();
6726 returnNode->explicitReturn = false;
6727 returnNode->valueList.set(expListLow);
6728 transformReturn(returnNode, out); 7330 transformReturn(returnNode, out);
6729 break; 7331 break;
6730 } 7332 }
@@ -6752,6 +7354,9 @@ private:
6752 if (transformChainEndWithColonItem(chainList, out, usage, assignList)) { 7354 if (transformChainEndWithColonItem(chainList, out, usage, assignList)) {
6753 return; 7355 return;
6754 } 7356 }
7357 if (transformChainEndWithSlice(chainList, out, usage, assignList)) {
7358 return;
7359 }
6755 transformChainList(chainList, out, usage, assignList); 7360 transformChainList(chainList, out, usage, assignList);
6756 } 7361 }
6757 7362
@@ -6848,7 +7453,7 @@ private:
6848 } 7453 }
6849 } 7454 }
6850 } else if (auto comp = sval->value.as<Comprehension_t>()) { 7455 } else if (auto comp = sval->value.as<Comprehension_t>()) {
6851 if (comp->items.size() != 2 || !ast_is<CompInner_t>(comp->items.back())) { 7456 if (!isListComp(comp)) {
6852 discrete = inExp->new_ptr<ExpList_t>(); 7457 discrete = inExp->new_ptr<ExpList_t>();
6853 for (ast_node* val : comp->items.objects()) { 7458 for (ast_node* val : comp->items.objects()) {
6854 if (auto def = ast_cast<NormalDef_t>(val)) { 7459 if (auto def = ast_cast<NormalDef_t>(val)) {
@@ -6877,7 +7482,7 @@ private:
6877 auto assignment = assignmentFrom(toAst<Exp_t>(checkVar, inExp), newExp(inExp, inExp), inExp); 7482 auto assignment = assignmentFrom(toAst<Exp_t>(checkVar, inExp), newExp(inExp, inExp), inExp);
6878 auto stmt = x->new_ptr<Statement_t>(); 7483 auto stmt = x->new_ptr<Statement_t>();
6879 stmt->content.set(assignment); 7484 stmt->content.set(assignment);
6880 block->statements.push_back(stmt); 7485 block->statementOrComments.push_back(stmt);
6881 } 7486 }
6882 if (varName.empty()) { 7487 if (varName.empty()) {
6883 auto newUnaryExp = x->new_ptr<UnaryExp_t>(); 7488 auto newUnaryExp = x->new_ptr<UnaryExp_t>();
@@ -6889,7 +7494,7 @@ private:
6889 auto assignment = assignmentFrom(assignExp, exp, x); 7494 auto assignment = assignmentFrom(assignExp, exp, x);
6890 auto stmt = x->new_ptr<Statement_t>(); 7495 auto stmt = x->new_ptr<Statement_t>();
6891 stmt->content.set(assignment); 7496 stmt->content.set(assignment);
6892 block->statements.push_back(stmt); 7497 block->statementOrComments.push_back(stmt);
6893 } 7498 }
6894 auto findVar = getUnusedName("_find_"); 7499 auto findVar = getUnusedName("_find_");
6895 auto itemVar = getUnusedName("_item_"); 7500 auto itemVar = getUnusedName("_item_");
@@ -6905,7 +7510,7 @@ private:
6905 } 7510 }
6906 auto blockStr = clearBuf(); 7511 auto blockStr = clearBuf();
6907 auto checkBlock = toAst<Block_t>(blockStr, inExp); 7512 auto checkBlock = toAst<Block_t>(blockStr, inExp);
6908 block->statements.dup(checkBlock->statements); 7513 block->statementOrComments.dup(checkBlock->statementOrComments);
6909 auto body = x->new_ptr<Body_t>(); 7514 auto body = x->new_ptr<Body_t>();
6910 body->content.set(block); 7515 body->content.set(block);
6911 auto doNode = x->new_ptr<Do_t>(); 7516 auto doNode = x->new_ptr<Do_t>();
@@ -6925,16 +7530,16 @@ private:
6925 } else { 7530 } else {
6926 auto arrayCheck = [&](bool exist) { 7531 auto arrayCheck = [&](bool exist) {
6927 auto indexVar = getUnusedName("_index_"); 7532 auto indexVar = getUnusedName("_index_");
6928 _buf << indent() << "for "sv << indexVar << " = 1, #"sv << checkVar << " do"sv << nll(x); 7533 _buf << indent() << "for "sv << indexVar << " = 1, #"sv << checkVar << " do"sv << nl(x);
6929 incIndentOffset(); 7534 incIndentOffset();
6930 _buf << indent() << "if "sv << checkVar << '[' << indexVar << "] == "sv << varName << " then"sv << nll(x); 7535 _buf << indent() << "if "sv << checkVar << '[' << indexVar << "] == "sv << varName << " then"sv << nl(x);
6931 incIndentOffset(); 7536 incIndentOffset();
6932 _buf << indent() << "return "sv << (exist ? "true"sv : "false"sv) << nll(x); 7537 _buf << indent() << "return "sv << (exist ? "true"sv : "false"sv) << nl(x);
6933 decIndentOffset(); 7538 decIndentOffset();
6934 _buf << indent() << "end"sv << nll(x); 7539 _buf << indent() << "end"sv << nl(x);
6935 decIndentOffset(); 7540 decIndentOffset();
6936 _buf << indent() << "end"sv << nll(x); 7541 _buf << indent() << "end"sv << nl(x);
6937 _buf << indent() << "return "sv << (exist ? "false"sv : "true"sv) << nll(x); 7542 _buf << indent() << "return "sv << (exist ? "false"sv : "true"sv) << nl(x);
6938 temp.push_back(clearBuf()); 7543 temp.push_back(clearBuf());
6939 }; 7544 };
6940 bool useShortCheck = (usage == ExpUsage::Closure) && !varName.empty() && !checkVar.empty() && isLocal(checkVar); 7545 bool useShortCheck = (usage == ExpUsage::Closure) && !varName.empty() && !checkVar.empty() && isLocal(checkVar);
@@ -6950,7 +7555,7 @@ private:
6950 pushAnonVarArg(); 7555 pushAnonVarArg();
6951 pushScope(); 7556 pushScope();
6952 arrayCheck(true); 7557 arrayCheck(true);
6953 temp.push_front("(#"s + checkVar + " > 0 and "s + anonFuncStart() + nll(x)); 7558 temp.push_front("(#"s + checkVar + " > 0 and "s + anonFuncStart() + nl(x));
6954 popScope(); 7559 popScope();
6955 temp.push_back(indent() + anonFuncEnd() + ')'); 7560 temp.push_back(indent() + anonFuncEnd() + ')');
6956 if (unary_exp->inExp->not_) { 7561 if (unary_exp->inExp->not_) {
@@ -6987,7 +7592,7 @@ private:
6987 arrayCheck(!unary_exp->inExp->not_); 7592 arrayCheck(!unary_exp->inExp->not_);
6988 } else { 7593 } else {
6989 arrayCheck(!unary_exp->inExp->not_); 7594 arrayCheck(!unary_exp->inExp->not_);
6990 temp.push_front(anonFuncStart() + nll(x)); 7595 temp.push_front(anonFuncStart() + nl(x));
6991 popScope(); 7596 popScope();
6992 temp.push_back(indent() + anonFuncEnd()); 7597 temp.push_back(indent() + anonFuncEnd());
6993 popAnonVarArg(); 7598 popAnonVarArg();
@@ -7027,7 +7632,7 @@ private:
7027 pushScope(); 7632 pushScope();
7028 } else if (usage == ExpUsage::Assignment) { 7633 } else if (usage == ExpUsage::Assignment) {
7029 if (isScoped) { 7634 if (isScoped) {
7030 temp.push_back(indent() + "do"s + nll(x)); 7635 temp.push_back(indent() + "do"s + nl(x));
7031 pushScope(); 7636 pushScope();
7032 } 7637 }
7033 } 7638 }
@@ -7067,10 +7672,10 @@ private:
7067 if (unary_exp->inExp->not_) { 7672 if (unary_exp->inExp->not_) {
7068 _buf << ")"sv; 7673 _buf << ")"sv;
7069 } 7674 }
7070 _buf << nll(x); 7675 _buf << nl(x);
7071 temp.push_back(clearBuf()); 7676 temp.push_back(clearBuf());
7072 if (usage == ExpUsage::Closure) { 7677 if (usage == ExpUsage::Closure) {
7073 temp.push_front(anonFuncStart() + nll(x)); 7678 temp.push_front(anonFuncStart() + nl(x));
7074 popScope(); 7679 popScope();
7075 temp.push_back(indent() + anonFuncEnd()); 7680 temp.push_back(indent() + anonFuncEnd());
7076 out.push_back(join(temp)); 7681 out.push_back(join(temp));
@@ -7079,7 +7684,7 @@ private:
7079 } else if (usage == ExpUsage::Assignment) { 7684 } else if (usage == ExpUsage::Assignment) {
7080 if (isScoped) { 7685 if (isScoped) {
7081 popScope(); 7686 popScope();
7082 temp.push_back(indent() + "end"s + nll(x)); 7687 temp.push_back(indent() + "end"s + nl(x));
7083 } 7688 }
7084 out.push_back(join(temp)); 7689 out.push_back(join(temp));
7085 } else { 7690 } else {
@@ -7113,7 +7718,7 @@ private:
7113 } 7718 }
7114 _buf << ')'; 7719 _buf << ')';
7115 if (usage == ExpUsage::Assignment || usage == ExpUsage::Return) { 7720 if (usage == ExpUsage::Assignment || usage == ExpUsage::Return) {
7116 _buf << nll(discrete); 7721 _buf << nl(discrete);
7117 } 7722 }
7118 out.push_back(clearBuf()); 7723 out.push_back(clearBuf());
7119 } 7724 }
@@ -7153,7 +7758,7 @@ private:
7153 try { 7758 try {
7154 unsigned long long value = std::stoull(binaryPart, nullptr, 2); 7759 unsigned long long value = std::stoull(binaryPart, nullptr, 2);
7155 numStr = std::to_string(value); 7760 numStr = std::to_string(value);
7156 } catch (const std::exception& e) { 7761 } catch (const std::exception&) {
7157 throw CompileError("invalid binary literal"sv, num); 7762 throw CompileError("invalid binary literal"sv, num);
7158 } 7763 }
7159 } else if (getLuaTarget(num) < 502) { 7764 } else if (getLuaTarget(num) < 502) {
@@ -7233,7 +7838,7 @@ private:
7233 forceAddToScope(tableVar); 7838 forceAddToScope(tableVar);
7234 auto it = values.begin(); 7839 auto it = values.begin();
7235 if (ast_is<SpreadExp_t, SpreadListExp_t>(*it)) { 7840 if (ast_is<SpreadExp_t, SpreadListExp_t>(*it)) {
7236 temp.push_back(indent() + "local "s + tableVar + " = { }"s + nll(x)); 7841 temp.push_back(indent() + "local "s + tableVar + " = { }"s + nl(x));
7237 } else { 7842 } else {
7238 auto initialTab = x->new_ptr<TableLit_t>(); 7843 auto initialTab = x->new_ptr<TableLit_t>();
7239 while (it != values.end() && !ast_is<SpreadExp_t, SpreadListExp_t>(*it)) { 7844 while (it != values.end() && !ast_is<SpreadExp_t, SpreadListExp_t>(*it)) {
@@ -7241,7 +7846,7 @@ private:
7241 ++it; 7846 ++it;
7242 } 7847 }
7243 transformTable(initialTab->values.objects(), temp); 7848 transformTable(initialTab->values.objects(), temp);
7244 temp.back() = indent() + "local "s + tableVar + " = "s + temp.back() + nll(*it); 7849 temp.back() = indent() + "local "s + tableVar + " = "s + temp.back() + nl(*it);
7245 } 7850 }
7246 for (; it != values.end(); ++it) { 7851 for (; it != values.end(); ++it) {
7247 auto item = *it; 7852 auto item = *it;
@@ -7261,14 +7866,14 @@ private:
7261 transformAssignment(assignment, temp); 7866 transformAssignment(assignment, temp);
7262 } 7867 }
7263 forceAddToScope(indexVar); 7868 forceAddToScope(indexVar);
7264 temp.push_back(indent() + "local "s + indexVar + " = 1"s + nll(item)); 7869 temp.push_back(indent() + "local "s + indexVar + " = 1"s + nl(item));
7265 _buf << "for "sv << keyVar << ',' << valueVar << " in pairs "sv << objVar 7870 _buf << "for "sv << keyVar << ',' << valueVar << " in pairs "sv << objVar
7266 << "\n\tif "sv << indexVar << "=="sv << keyVar 7871 << "\n\tif "sv << indexVar << "=="sv << keyVar
7267 << "\n\t\t"sv << tableVar << "[]="sv << valueVar 7872 << "\n\t\t"sv << tableVar << "[]="sv << valueVar
7268 << "\n\t\t"sv << indexVar << "+=1"sv 7873 << "\n\t\t"sv << indexVar << "+=1"sv
7269 << "\n\telse "sv << tableVar << '[' << keyVar << "]="sv << valueVar; 7874 << "\n\telse "sv << tableVar << '[' << keyVar << "]="sv << valueVar;
7270 auto forEach = toAst<ForEach_t>(clearBuf(), item); 7875 auto forNode = toAst<For_t>(clearBuf(), item);
7271 transformForEach(forEach, temp); 7876 transformFor(forNode, temp);
7272 break; 7877 break;
7273 } 7878 }
7274 case id<SpreadListExp_t>(): { 7879 case id<SpreadListExp_t>(): {
@@ -7285,12 +7890,12 @@ private:
7285 transformAssignment(assignment, temp); 7890 transformAssignment(assignment, temp);
7286 } 7891 }
7287 forceAddToScope(indexVar); 7892 forceAddToScope(indexVar);
7288 temp.push_back(indent() + "local "s + indexVar + " = #"s + tableVar + " + 1"s + nll(item)); 7893 temp.push_back(indent() + "local "s + indexVar + " = #"s + tableVar + " + 1"s + nl(item));
7289 _buf << "for "sv << valueVar << " in *"sv << objVar 7894 _buf << "for "sv << valueVar << " in *"sv << objVar
7290 << "\n\t"sv << tableVar << '[' << indexVar << "]="sv << valueVar 7895 << "\n\t"sv << tableVar << '[' << indexVar << "]="sv << valueVar
7291 << "\n\t"sv << indexVar << "+=1"sv; 7896 << "\n\t"sv << indexVar << "+=1"sv;
7292 auto forEach = toAst<ForEach_t>(clearBuf(), item); 7897 auto forNode = toAst<For_t>(clearBuf(), item);
7293 transformForEach(forEach, temp); 7898 transformFor(forNode, temp);
7294 break; 7899 break;
7295 } 7900 }
7296 case id<VariablePair_t>(): 7901 case id<VariablePair_t>():
@@ -7468,9 +8073,9 @@ private:
7468 break; 8073 break;
7469 case ExpUsage::Closure: { 8074 case ExpUsage::Closure: {
7470 out.push_back(join(temp)); 8075 out.push_back(join(temp));
7471 out.back().append(indent() + "return "s + tableVar + nlr(x)); 8076 out.back().append(indent() + "return "s + tableVar + nl(x));
7472 popScope(); 8077 popScope();
7473 out.back().insert(0, anonFuncStart() + nll(x)); 8078 out.back().insert(0, anonFuncStart() + nl(x));
7474 out.back().append(indent() + anonFuncEnd()); 8079 out.back().append(indent() + anonFuncEnd());
7475 popAnonVarArg(); 8080 popAnonVarArg();
7476 popFunctionScope(); 8081 popFunctionScope();
@@ -7486,13 +8091,13 @@ private:
7486 if (extraScope) popScope(); 8091 if (extraScope) popScope();
7487 out.push_back(join(temp)); 8092 out.push_back(join(temp));
7488 if (extraScope) { 8093 if (extraScope) {
7489 out.back() = indent() + "do"s + nll(x) + out.back() + indent() + "end"s + nlr(x); 8094 out.back() = indent() + "do"s + nl(x) + out.back() + indent() + "end"s + nl(x);
7490 } 8095 }
7491 break; 8096 break;
7492 } 8097 }
7493 case ExpUsage::Return: 8098 case ExpUsage::Return:
7494 out.push_back(join(temp)); 8099 out.push_back(join(temp));
7495 out.back().append(indent() + "return "s + tableVar + nlr(x)); 8100 out.back().append(indent() + "return "s + tableVar + nl(x));
7496 break; 8101 break;
7497 default: 8102 default:
7498 break; 8103 break;
@@ -7613,11 +8218,11 @@ private:
7613 default: YUEE("AST node mismatch", item); break; 8218 default: YUEE("AST node mismatch", item); break;
7614 } 8219 }
7615 if (!isMetamethod) { 8220 if (!isMetamethod) {
7616 temp.back() = indent() + (value == values.back() ? temp.back() : temp.back() + ',') + nll(value); 8221 temp.back() = indent() + (value == values.back() ? temp.back() : temp.back() + ',') + nl(value);
7617 } 8222 }
7618 } 8223 }
7619 if (metatable->pairs.empty() && !metatableItem) { 8224 if (metatable->pairs.empty() && !metatableItem) {
7620 out.push_back('{' + nll(x) + join(temp)); 8225 out.push_back('{' + nl(x) + join(temp));
7621 decIndentOffset(); 8226 decIndentOffset();
7622 out.back() += (indent() + '}'); 8227 out.back() += (indent() + '}');
7623 } else { 8228 } else {
@@ -7627,7 +8232,7 @@ private:
7627 decIndentOffset(); 8232 decIndentOffset();
7628 tabStr += "{ }"sv; 8233 tabStr += "{ }"sv;
7629 } else { 8234 } else {
7630 tabStr += ('{' + nll(x) + join(temp)); 8235 tabStr += ('{' + nl(x) + join(temp));
7631 decIndentOffset(); 8236 decIndentOffset();
7632 tabStr += (indent() + '}'); 8237 tabStr += (indent() + '}');
7633 } 8238 }
@@ -7671,18 +8276,18 @@ private:
7671 void transformCompCommon(Comprehension_t* comp, str_list& out) { 8276 void transformCompCommon(Comprehension_t* comp, str_list& out) {
7672 str_list temp; 8277 str_list temp;
7673 auto x = comp; 8278 auto x = comp;
7674 auto compInner = static_cast<CompInner_t*>(comp->items.back()); 8279 auto compFor = static_cast<CompFor_t*>(comp->items.back());
7675 for (auto item : compInner->items.objects()) { 8280 for (auto item : compFor->items.objects()) {
7676 switch (item->get_id()) { 8281 switch (item->get_id()) {
7677 case id<CompForEach_t>(): 8282 case id<CompForEach_t>():
7678 transformCompForEach(static_cast<CompForEach_t*>(item), temp); 8283 transformCompForEach(static_cast<CompForEach_t*>(item), temp);
7679 break; 8284 break;
7680 case id<CompFor_t>(): 8285 case id<CompForNum_t>():
7681 transformCompFor(static_cast<CompFor_t*>(item), temp); 8286 transformCompForNum(static_cast<CompForNum_t*>(item), temp);
7682 break; 8287 break;
7683 case id<Exp_t>(): 8288 case id<Exp_t>():
7684 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure); 8289 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure);
7685 temp.back() = indent() + "if "s + temp.back() + " then"s + nll(item); 8290 temp.back() = indent() + "if "s + temp.back() + " then"s + nl(item);
7686 pushScope(); 8291 pushScope();
7687 break; 8292 break;
7688 default: YUEE("AST node mismatch", item); break; 8293 default: YUEE("AST node mismatch", item); break;
@@ -7702,16 +8307,16 @@ private:
7702 auto value = std::move(temp.back()); 8307 auto value = std::move(temp.back());
7703 temp.pop_back(); 8308 temp.pop_back();
7704 _buf << join(temp) << value; 8309 _buf << join(temp) << value;
7705 for (size_t i = 0; i < compInner->items.objects().size(); ++i) { 8310 for (size_t i = 0; i < compFor->items.objects().size(); ++i) {
7706 popScope(); 8311 popScope();
7707 _buf << indent() << "end"sv << nll(comp); 8312 _buf << indent() << "end"sv << nl(comp);
7708 } 8313 }
7709 out.push_back(clearBuf()); 8314 out.push_back(clearBuf());
7710 } 8315 }
7711 8316
7712 void transformComprehension(Comprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { 8317 void transformComprehension(Comprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
7713 auto x = comp; 8318 auto x = comp;
7714 if (comp->items.size() != 2 || !ast_is<CompInner_t>(comp->items.back())) { 8319 if (!isListComp(comp)) {
7715 switch (usage) { 8320 switch (usage) {
7716 case ExpUsage::Assignment: { 8321 case ExpUsage::Assignment: {
7717 auto tableLit = x->new_ptr<TableLit_t>(); 8322 auto tableLit = x->new_ptr<TableLit_t>();
@@ -7733,11 +8338,7 @@ private:
7733 auto simpleValue = x->new_ptr<SimpleValue_t>(); 8338 auto simpleValue = x->new_ptr<SimpleValue_t>();
7734 simpleValue->value.set(tableLit); 8339 simpleValue->value.set(tableLit);
7735 auto exp = newExp(simpleValue, x); 8340 auto exp = newExp(simpleValue, x);
7736 auto returnNode = x->new_ptr<Return_t>(); 8341 auto returnNode = newReturn(exp);
7737 returnNode->explicitReturn = false;
7738 auto expList = x->new_ptr<ExpListLow_t>();
7739 expList->exprs.push_back(exp);
7740 returnNode->valueList.set(expList);
7741 transformReturn(returnNode, out); 8342 transformReturn(returnNode, out);
7742 break; 8343 break;
7743 } 8344 }
@@ -7750,9 +8351,16 @@ private:
7750 } 8351 }
7751 return; 8352 return;
7752 } 8353 }
7753 auto def = ast_cast<NormalDef_t>(comp->items.front()); 8354 ast_node* value = nullptr;
7754 if (!def || def->defVal) { 8355 bool isSpread = ast_is<SpreadListExp_t>(comp->items.front());
7755 throw CompileError("invalid comprehension expression", comp->items.front()); 8356 if (isSpread) {
8357 value = comp->items.front();
8358 } else {
8359 auto def = ast_cast<NormalDef_t>(comp->items.front());
8360 if (!def || def->defVal) {
8361 throw CompileError("invalid comprehension expression", comp->items.front());
8362 }
8363 value = def->item.get();
7756 } 8364 }
7757 bool extraScope = false; 8365 bool extraScope = false;
7758 switch (usage) { 8366 switch (usage) {
@@ -7776,31 +8384,33 @@ private:
7776 default: 8384 default:
7777 break; 8385 break;
7778 } 8386 }
7779 auto value = def->item.get(); 8387 auto compFor = static_cast<CompFor_t*>(comp->items.back());
7780 auto compInner = static_cast<CompInner_t*>(comp->items.back());
7781 str_list temp; 8388 str_list temp;
7782 std::string accumVar = getUnusedName("_accum_"sv); 8389 std::string accumVar = getUnusedName("_accum_"sv);
7783 std::string lenVar = getUnusedName("_len_"sv);
7784 addToScope(accumVar); 8390 addToScope(accumVar);
7785 addToScope(lenVar); 8391 std::string lenVar;
7786 for (auto item : compInner->items.objects()) { 8392 if (!isSpread) {
8393 lenVar = getUnusedName("_len_"sv);
8394 addToScope(lenVar);
8395 }
8396 for (auto item : compFor->items.objects()) {
7787 switch (item->get_id()) { 8397 switch (item->get_id()) {
7788 case id<CompForEach_t>(): 8398 case id<CompForEach_t>():
7789 transformCompForEach(static_cast<CompForEach_t*>(item), temp); 8399 transformCompForEach(static_cast<CompForEach_t*>(item), temp);
7790 break; 8400 break;
7791 case id<CompFor_t>(): 8401 case id<CompForNum_t>():
7792 transformCompFor(static_cast<CompFor_t*>(item), temp); 8402 transformCompForNum(static_cast<CompForNum_t*>(item), temp);
7793 break; 8403 break;
7794 case id<Exp_t>(): 8404 case id<Exp_t>():
7795 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure); 8405 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure);
7796 temp.back() = indent() + "if "s + temp.back() + " then"s + nll(item); 8406 temp.back() = indent() + "if "s + temp.back() + " then"s + nl(item);
7797 pushScope(); 8407 pushScope();
7798 break; 8408 break;
7799 default: YUEE("AST node mismatch", item); break; 8409 default: YUEE("AST node mismatch", item); break;
7800 } 8410 }
7801 } 8411 }
7802 { 8412 {
7803 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); 8413 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + (isSpread ? "]"s : lenVar + ']'), x);
7804 auto assign = x->new_ptr<Assign_t>(); 8414 auto assign = x->new_ptr<Assign_t>();
7805 assign->values.push_back(value); 8415 assign->values.push_back(value);
7806 auto assignment = x->new_ptr<ExpListAssign_t>(); 8416 auto assignment = x->new_ptr<ExpListAssign_t>();
@@ -7810,25 +8420,30 @@ private:
7810 } 8420 }
7811 auto assignStr = std::move(temp.back()); 8421 auto assignStr = std::move(temp.back());
7812 temp.pop_back(); 8422 temp.pop_back();
7813 for (size_t i = 0; i < compInner->items.objects().size(); ++i) { 8423 for (size_t i = 0; i < compFor->items.objects().size(); ++i) {
7814 popScope(); 8424 popScope();
7815 } 8425 }
7816 _buf << indent() << "local "sv << accumVar << " = { }"sv << nll(comp); 8426 _buf << indent() << "local "sv << accumVar << " = { }"sv << nl(comp);
7817 _buf << indent() << "local "sv << lenVar << " = 1"sv << nll(comp); 8427 if (isSpread) {
7818 _buf << join(temp); 8428 _buf << join(temp);
7819 _buf << assignStr; 8429 _buf << assignStr;
7820 _buf << indent(int(temp.size())) << lenVar << " = "sv << lenVar << " + 1"sv << nll(comp); 8430 } else {
8431 _buf << indent() << "local "sv << lenVar << " = 1"sv << nl(comp);
8432 _buf << join(temp);
8433 _buf << assignStr;
8434 _buf << indent(int(temp.size())) << lenVar << " = "sv << lenVar << " + 1"sv << nl(comp);
8435 }
7821 for (int ind = int(temp.size()) - 1; ind > -1; --ind) { 8436 for (int ind = int(temp.size()) - 1; ind > -1; --ind) {
7822 _buf << indent(ind) << "end"sv << nll(comp); 8437 _buf << indent(ind) << "end"sv << nl(comp);
7823 } 8438 }
7824 switch (usage) { 8439 switch (usage) {
7825 case ExpUsage::Common: 8440 case ExpUsage::Common:
7826 break; 8441 break;
7827 case ExpUsage::Closure: { 8442 case ExpUsage::Closure: {
7828 out.push_back(clearBuf()); 8443 out.push_back(clearBuf());
7829 out.back().append(indent() + "return "s + accumVar + nlr(comp)); 8444 out.back().append(indent() + "return "s + accumVar + nl(comp));
7830 popScope(); 8445 popScope();
7831 out.back().insert(0, anonFuncStart() + nll(comp)); 8446 out.back().insert(0, anonFuncStart() + nl(comp));
7832 out.back().append(indent() + anonFuncEnd()); 8447 out.back().append(indent() + anonFuncEnd());
7833 popAnonVarArg(); 8448 popAnonVarArg();
7834 popFunctionScope(); 8449 popFunctionScope();
@@ -7845,13 +8460,13 @@ private:
7845 out.back().append(temp.back()); 8460 out.back().append(temp.back());
7846 if (extraScope) { 8461 if (extraScope) {
7847 popScope(); 8462 popScope();
7848 out.back() = indent() + "do"s + nll(comp) + out.back() + indent() + "end"s + nlr(comp); 8463 out.back() = indent() + "do"s + nl(comp) + out.back() + indent() + "end"s + nl(comp);
7849 } 8464 }
7850 break; 8465 break;
7851 } 8466 }
7852 case ExpUsage::Return: 8467 case ExpUsage::Return:
7853 out.push_back(clearBuf()); 8468 out.push_back(clearBuf());
7854 out.back().append(indent() + "return "s + accumVar + nlr(comp)); 8469 out.back().append(indent() + "return "s + accumVar + nl(comp));
7855 break; 8470 break;
7856 default: 8471 default:
7857 break; 8472 break;
@@ -7859,6 +8474,11 @@ private:
7859 } 8474 }
7860 8475
7861 bool transformForEachHead(AssignableNameList_t* nameList, ast_node* loopTarget, str_list& out, bool inClosure) { 8476 bool transformForEachHead(AssignableNameList_t* nameList, ast_node* loopTarget, str_list& out, bool inClosure) {
8477 enum class NumState {
8478 Unknown,
8479 Positive,
8480 Negtive
8481 };
7862 auto x = nameList; 8482 auto x = nameList;
7863 str_list temp; 8483 str_list temp;
7864 str_list vars; 8484 str_list vars;
@@ -7877,13 +8497,8 @@ private:
7877 varConstAfter = vars.back(); 8497 varConstAfter = vars.back();
7878 } 8498 }
7879 break; 8499 break;
7880 case id<TableLit_t>(): { 8500 case id<SimpleTable_t>():
7881 auto desVar = getUnusedName("_des_"sv); 8501 case id<TableLit_t>():
7882 destructPairs.emplace_back(item, toAst<Exp_t>(desVar, x));
7883 vars.push_back(desVar);
7884 varAfter.push_back(desVar);
7885 break;
7886 }
7887 case id<Comprehension_t>(): { 8502 case id<Comprehension_t>(): {
7888 auto desVar = getUnusedName("_des_"sv); 8503 auto desVar = getUnusedName("_des_"sv);
7889 destructPairs.emplace_back(item, toAst<Exp_t>(desVar, x)); 8504 destructPairs.emplace_back(item, toAst<Exp_t>(desVar, x));
@@ -7925,15 +8540,35 @@ private:
7925 for (auto item : chainList) { 8540 for (auto item : chainList) {
7926 chain->items.push_back(item); 8541 chain->items.push_back(item);
7927 } 8542 }
7928 std::string startValue("1"sv); 8543 std::string startValue;
8544 NumState startStatus = NumState::Unknown;
7929 if (auto exp = slice->startValue.as<Exp_t>()) { 8545 if (auto exp = slice->startValue.as<Exp_t>()) {
7930 transformExp(exp, temp, ExpUsage::Closure); 8546 transformExp(exp, temp, ExpUsage::Closure);
8547 if (temp.back().at(0) == '-') {
8548 if (_parser.match<Num_t>(temp.back().substr(1))) {
8549 startStatus = NumState::Negtive;
8550 }
8551 } else {
8552 if (_parser.match<Num_t>(temp.back())) {
8553 startStatus = NumState::Positive;
8554 }
8555 }
7931 startValue = std::move(temp.back()); 8556 startValue = std::move(temp.back());
7932 temp.pop_back(); 8557 temp.pop_back();
7933 } 8558 }
7934 std::string stopValue; 8559 std::string stopValue;
8560 NumState stopStatus = NumState::Unknown;
7935 if (auto exp = slice->stopValue.as<Exp_t>()) { 8561 if (auto exp = slice->stopValue.as<Exp_t>()) {
7936 transformExp(exp, temp, ExpUsage::Closure); 8562 transformExp(exp, temp, ExpUsage::Closure);
8563 if (temp.back().at(0) == '-') {
8564 if (_parser.match<Num_t>(temp.back().substr(1))) {
8565 stopStatus = NumState::Negtive;
8566 }
8567 } else {
8568 if (_parser.match<Num_t>(temp.back())) {
8569 stopStatus = NumState::Positive;
8570 }
8571 }
7937 stopValue = std::move(temp.back()); 8572 stopValue = std::move(temp.back());
7938 temp.pop_back(); 8573 temp.pop_back();
7939 } 8574 }
@@ -7947,38 +8582,94 @@ private:
7947 std::string prefix; 8582 std::string prefix;
7948 if (!inClosure && needScope) { 8583 if (!inClosure && needScope) {
7949 extraScope = true; 8584 extraScope = true;
7950 prefix = indent() + "do"s + nll(x); 8585 prefix = indent() + "do"s + nl(x);
7951 pushScope(); 8586 pushScope();
7952 } 8587 }
7953 listVar = getUnusedName("_list_"sv); 8588 listVar = getUnusedName("_list_"sv);
7954 varBefore.push_back(listVar); 8589 varBefore.push_back(listVar);
7955 transformChainValue(chain, temp, ExpUsage::Closure); 8590 transformChainValue(chain, temp, ExpUsage::Closure);
7956 _buf << prefix << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList); 8591 _buf << prefix << indent() << "local "sv << listVar << " = "sv << temp.back() << nl(nameList);
8592 }
8593 if (startValue.empty()) {
8594 startValue = "1"s;
8595 startStatus = NumState::Positive;
8596 }
8597 std::string minVar;
8598 if (startStatus != NumState::Positive) {
8599 std::string prefix;
8600 if (!extraScope && !inClosure && needScope) {
8601 extraScope = true;
8602 prefix = indent() + "do"s + nl(x);
8603 pushScope();
8604 }
8605 minVar = getUnusedName("_min_"sv);
8606 varBefore.push_back(minVar);
8607 if (startStatus == NumState::Negtive) {
8608 _buf << prefix << indent() << "local "sv << minVar << " = "sv << "#"sv << listVar << " + "sv << startValue << " + 1"sv << nl(nameList);
8609 } else {
8610 _buf << prefix << indent() << "local "sv << minVar << " = "sv << startValue << nl(nameList);
8611 }
8612 }
8613 bool defaultStop = false;
8614 if (stopValue.empty()) {
8615 stopValue = "#"s + listVar;
8616 defaultStop = true;
7957 } 8617 }
7958 std::string maxVar; 8618 std::string maxVar;
7959 if (!stopValue.empty()) { 8619 if (stopStatus != NumState::Positive) {
7960 std::string prefix; 8620 std::string prefix;
7961 if (!extraScope && !inClosure && needScope) { 8621 if (!extraScope && !inClosure && needScope) {
7962 extraScope = true; 8622 extraScope = true;
7963 prefix = indent() + "do"s + nll(x); 8623 prefix = indent() + "do"s + nl(x);
7964 pushScope(); 8624 pushScope();
7965 } 8625 }
7966 maxVar = getUnusedName("_max_"sv); 8626 maxVar = getUnusedName("_max_"sv);
7967 varBefore.push_back(maxVar); 8627 varBefore.push_back(maxVar);
7968 _buf << prefix << indent() << "local "sv << maxVar << " = "sv << stopValue << nll(nameList); 8628 if (stopStatus == NumState::Negtive) {
8629 _buf << indent() << "local "sv << maxVar << " = "sv << "#"sv << listVar << " + "sv << stopValue << " + 1"sv << nl(nameList);
8630 } else {
8631 _buf << prefix << indent() << "local "sv << maxVar << " = "sv << stopValue << nl(nameList);
8632 }
8633 }
8634 if (startStatus == NumState::Unknown) {
8635 _buf << indent() << minVar << " = "sv << minVar << " < 0 and #"sv << listVar << " + "sv << minVar << " + 1 or "sv << minVar << nl(nameList);
8636 }
8637 if (!defaultStop && stopStatus == NumState::Unknown) {
8638 _buf << indent() << maxVar << " = "sv << maxVar << " < 0 and #"sv << listVar << " + "sv << maxVar << " + 1 or "sv << maxVar << nl(nameList);
7969 } 8639 }
7970 _buf << indent() << "for "sv << indexVar << " = "sv; 8640 _buf << indent() << "for "sv << indexVar << " = "sv;
7971 _buf << startValue << ", "sv; 8641 if (startValue.empty()) {
8642 _buf << "1"sv;
8643 } else {
8644 switch (startStatus) {
8645 case NumState::Unknown:
8646 case NumState::Negtive:
8647 _buf << minVar;
8648 break;
8649 case NumState::Positive:
8650 _buf << startValue;
8651 break;
8652 }
8653 }
8654 _buf << ", "sv;
7972 if (stopValue.empty()) { 8655 if (stopValue.empty()) {
7973 _buf << "#"sv << listVar; 8656 _buf << "#"sv << listVar;
7974 } else { 8657 } else {
7975 _buf << maxVar << " < 0 and #"sv << listVar << " + "sv << maxVar << " or "sv << maxVar; 8658 switch (stopStatus) {
8659 case NumState::Unknown:
8660 case NumState::Negtive:
8661 _buf << maxVar;
8662 break;
8663 case NumState::Positive:
8664 _buf << stopValue;
8665 break;
8666 }
7976 } 8667 }
7977 if (!stepValue.empty()) { 8668 if (!stepValue.empty()) {
7978 _buf << ", "sv << stepValue; 8669 _buf << ", "sv << stepValue;
7979 } 8670 }
7980 _buf << " do"sv << nlr(loopTarget); 8671 _buf << " do"sv << nl(loopTarget);
7981 _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nll(nameList); 8672 _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nl(nameList);
7982 out.push_back(clearBuf()); 8673 out.push_back(clearBuf());
7983 BLOCK_END 8674 BLOCK_END
7984 bool newListVal = false; 8675 bool newListVal = false;
@@ -7989,21 +8680,21 @@ private:
7989 } 8680 }
7990 if (!endWithSlice) { 8681 if (!endWithSlice) {
7991 transformExp(star_exp->value, temp, ExpUsage::Closure); 8682 transformExp(star_exp->value, temp, ExpUsage::Closure);
7992 if (newListVal) _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList); 8683 if (newListVal) _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nl(nameList);
7993 _buf << indent() << "for "sv << indexVar << " = 1, #"sv << listVar << " do"sv << nlr(loopTarget); 8684 _buf << indent() << "for "sv << indexVar << " = 1, #"sv << listVar << " do"sv << nl(loopTarget);
7994 _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nll(nameList); 8685 _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nl(nameList);
7995 out.push_back(clearBuf()); 8686 out.push_back(clearBuf());
7996 } 8687 }
7997 break; 8688 break;
7998 } 8689 }
7999 case id<Exp_t>(): 8690 case id<Exp_t>():
8000 transformExp(static_cast<Exp_t*>(loopTarget), temp, ExpUsage::Closure); 8691 transformExp(static_cast<Exp_t*>(loopTarget), temp, ExpUsage::Closure);
8001 _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nlr(loopTarget); 8692 _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nl(loopTarget);
8002 out.push_back(clearBuf()); 8693 out.push_back(clearBuf());
8003 break; 8694 break;
8004 case id<ExpList_t>(): 8695 case id<ExpList_t>():
8005 transformExpList(static_cast<ExpList_t*>(loopTarget), temp); 8696 transformExpList(static_cast<ExpList_t*>(loopTarget), temp);
8006 _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nlr(loopTarget); 8697 _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nl(loopTarget);
8007 out.push_back(clearBuf()); 8698 out.push_back(clearBuf());
8008 break; 8699 break;
8009 default: YUEE("AST node mismatch", loopTarget); break; 8700 default: YUEE("AST node mismatch", loopTarget); break;
@@ -8012,15 +8703,22 @@ private:
8012 pushScope(); 8703 pushScope();
8013 for (const auto& var : vars) forceAddToScope(var); 8704 for (const auto& var : vars) forceAddToScope(var);
8014 for (const auto& var : varAfter) addToScope(var); 8705 for (const auto& var : varAfter) addToScope(var);
8015 if (!varConstAfter.empty()) markVarConst(varConstAfter); 8706 if (!varConstAfter.empty()) markVarLocalConst(varConstAfter);
8016 if (!destructPairs.empty()) { 8707 if (!destructPairs.empty()) {
8017 temp.clear(); 8708 temp.clear();
8018 for (auto& pair : destructPairs) { 8709 for (auto& pair : destructPairs) {
8019 auto sValue = x->new_ptr<SimpleValue_t>();
8020 sValue->value.set(pair.first);
8021 auto exp = newExp(sValue, x);
8022 auto expList = x->new_ptr<ExpList_t>(); 8710 auto expList = x->new_ptr<ExpList_t>();
8023 expList->exprs.push_back(exp); 8711 if (ast_is<SimpleTable_t>(pair.first)) {
8712 auto value = x->new_ptr<Value_t>();
8713 value->item.set(pair.first);
8714 auto exp = newExp(value, x);
8715 expList->exprs.push_back(exp);
8716 } else {
8717 auto sValue = x->new_ptr<SimpleValue_t>();
8718 sValue->value.set(pair.first);
8719 auto exp = newExp(sValue, x);
8720 expList->exprs.push_back(exp);
8721 }
8024 auto assign = x->new_ptr<Assign_t>(); 8722 auto assign = x->new_ptr<Assign_t>();
8025 assign->values.push_back(pair.second); 8723 assign->values.push_back(pair.second);
8026 auto assignment = x->new_ptr<ExpListAssign_t>(); 8724 auto assignment = x->new_ptr<ExpListAssign_t>();
@@ -8080,7 +8778,7 @@ private:
8080 out.push_back('(' + join(temp, ", "sv) + ')'); 8778 out.push_back('(' + join(temp, ", "sv) + ')');
8081 } 8779 }
8082 8780
8083 void transformForHead(Variable_t* var, Exp_t* startVal, Exp_t* stopVal, ForStepValue_t* stepVal, str_list& out) { 8781 void transformForNumHead(Variable_t* var, Exp_t* startVal, Exp_t* stopVal, ForStepValue_t* stepVal, str_list& out) {
8084 str_list temp; 8782 str_list temp;
8085 std::string varName = variableToString(var); 8783 std::string varName = variableToString(var);
8086 transformExp(startVal, temp, ExpUsage::Closure); 8784 transformExp(startVal, temp, ExpUsage::Closure);
@@ -8094,37 +8792,70 @@ private:
8094 const auto& start = *it; 8792 const auto& start = *it;
8095 const auto& stop = *(++it); 8793 const auto& stop = *(++it);
8096 const auto& step = *(++it); 8794 const auto& step = *(++it);
8097 _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : ", "s + step) << " do"sv << nll(var); 8795 _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : ", "s + step) << " do"sv << nl(var);
8098 pushScope(); 8796 pushScope();
8099 forceAddToScope(varName); 8797 forceAddToScope(varName);
8100 markVarConst(varName); 8798 markVarLocalConst(varName);
8101 out.push_back(clearBuf()); 8799 out.push_back(clearBuf());
8102 } 8800 }
8103 8801
8104 void transformForHead(For_t* forNode, str_list& out) { 8802 void transformForNumHead(ForNum_t* forNum, str_list& out) {
8105 transformForHead(forNode->varName, forNode->startValue, forNode->stopValue, forNode->stepValue, out); 8803 transformForNumHead(forNum->varName, forNum->startValue, forNum->stopValue, forNum->stepValue, out);
8106 } 8804 }
8107 8805
8108 void transform_plain_body(ast_node* body, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { 8806 void transform_plain_body(ast_node* bodyOrStmt, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
8109 switch (body->get_id()) { 8807 switch (bodyOrStmt->get_id()) {
8110 case id<Block_t>(): 8808 case id<Block_t>():
8111 transformBlock(static_cast<Block_t*>(body), out, usage, assignList); 8809 transformBlock(static_cast<Block_t*>(bodyOrStmt), out, usage, assignList);
8112 break; 8810 break;
8113 case id<Statement_t>(): { 8811 case id<Statement_t>(): {
8114 auto newBlock = body->new_ptr<Block_t>(); 8812 auto newBlock = bodyOrStmt->new_ptr<Block_t>();
8115 newBlock->statements.push_back(body); 8813 newBlock->statementOrComments.push_back(bodyOrStmt);
8116 transformBlock(newBlock, out, usage, assignList); 8814 transformBlock(newBlock, out, usage, assignList);
8117 break; 8815 break;
8118 } 8816 }
8119 default: YUEE("AST node mismatch", body); break; 8817 default: YUEE("AST node mismatch", bodyOrStmt); break;
8120 } 8818 }
8121 } 8819 }
8122 8820
8123 bool hasContinueStatement(ast_node* body) { 8821 enum class BreakLoopType {
8124 return traversal::Stop == body->traverse([&](ast_node* node) { 8822 None = 0,
8823 Break = 1,
8824 BreakWithValue = 1 << 1,
8825 Continue = 1 << 2
8826 };
8827
8828 bool hasBreak(uint32_t breakLoopType) const {
8829 return (breakLoopType & int(BreakLoopType::Break)) != 0;
8830 }
8831
8832 bool hasBreakWithValue(uint32_t breakLoopType) const {
8833 return (breakLoopType & int(BreakLoopType::BreakWithValue)) != 0;
8834 }
8835
8836 bool hasContinue(uint32_t breakLoopType) const {
8837 return (breakLoopType & int(BreakLoopType::Continue)) != 0;
8838 }
8839
8840 uint32_t getBreakLoopType(ast_node* body, const std::string& varBWV) {
8841 uint32_t type = 0;
8842 body->traverse([&](ast_node* node) {
8125 if (auto stmt = ast_cast<Statement_t>(node)) { 8843 if (auto stmt = ast_cast<Statement_t>(node)) {
8126 if (stmt->content.is<BreakLoop_t>()) { 8844 if (auto breakLoop = stmt->content.as<BreakLoop_t>()) {
8127 return _parser.toString(stmt->content) == "continue"sv ? traversal::Stop : traversal::Return; 8845 if (breakLoop->type.is<Continue_t>()) {
8846 type |= int(BreakLoopType::Continue);
8847 return traversal::Return;
8848 } else {
8849 if (breakLoop->value) {
8850 if (varBWV.empty()) {
8851 throw CompileError("break with a value is not allowed here"sv, breakLoop->value);
8852 }
8853 type |= int(BreakLoopType::BreakWithValue);
8854 breakLoop->varBWV = varBWV;
8855 } else {
8856 type |= int(BreakLoopType::Break);
8857 }
8858 }
8128 } else if (auto expList = expListFrom(stmt)) { 8859 } else if (auto expList = expListFrom(stmt)) {
8129 BLOCK_START 8860 BLOCK_START
8130 auto value = singleValueFrom(expList); 8861 auto value = singleValueFrom(expList);
@@ -8135,40 +8866,30 @@ private:
8135 switch (sVal->get_id()) { 8866 switch (sVal->get_id()) {
8136 case id<With_t>(): { 8867 case id<With_t>(): {
8137 auto withNode = static_cast<With_t*>(sVal); 8868 auto withNode = static_cast<With_t*>(sVal);
8138 if (hasContinueStatement(withNode->body)) { 8869 type |= getBreakLoopType(withNode->body, varBWV);
8139 return traversal::Stop; 8870 return traversal::Return;
8140 }
8141 break;
8142 } 8871 }
8143 case id<Do_t>(): { 8872 case id<Do_t>(): {
8144 auto doNode = static_cast<Do_t*>(sVal); 8873 auto doNode = static_cast<Do_t*>(sVal);
8145 if (hasContinueStatement(doNode->body)) { 8874 type |= getBreakLoopType(doNode->body, varBWV);
8146 return traversal::Stop; 8875 return traversal::Return;
8147 }
8148 break;
8149 } 8876 }
8150 case id<If_t>(): { 8877 case id<If_t>(): {
8151 auto ifNode = static_cast<If_t*>(sVal); 8878 auto ifNode = static_cast<If_t*>(sVal);
8152 for (auto n : ifNode->nodes.objects()) { 8879 for (auto n : ifNode->nodes.objects()) {
8153 if (hasContinueStatement(n)) { 8880 type |= getBreakLoopType(n, varBWV);
8154 return traversal::Stop;
8155 }
8156 } 8881 }
8157 break; 8882 return traversal::Return;
8158 } 8883 }
8159 case id<Switch_t>(): { 8884 case id<Switch_t>(): {
8160 auto switchNode = static_cast<Switch_t*>(sVal); 8885 auto switchNode = static_cast<Switch_t*>(sVal);
8161 for (auto branch : switchNode->branches.objects()) { 8886 for (auto branch : switchNode->branches.objects()) {
8162 if (hasContinueStatement(static_cast<SwitchCase_t*>(branch)->body)) { 8887 type |= getBreakLoopType(static_cast<SwitchCase_t*>(branch)->body, varBWV);
8163 return traversal::Stop;
8164 }
8165 } 8888 }
8166 if (switchNode->lastBranch) { 8889 if (switchNode->lastBranch) {
8167 if (hasContinueStatement(switchNode->lastBranch)) { 8890 type |= getBreakLoopType(switchNode->lastBranch, varBWV);
8168 return traversal::Stop;
8169 }
8170 } 8891 }
8171 break; 8892 return traversal::Return;
8172 } 8893 }
8173 } 8894 }
8174 BLOCK_END 8895 BLOCK_END
@@ -8182,12 +8903,13 @@ private:
8182 } 8903 }
8183 return traversal::Return; 8904 return traversal::Return;
8184 }); 8905 });
8906 return type;
8185 } 8907 }
8186 8908
8187 void addDoToLastLineReturn(ast_node* body) { 8909 void addDoToLastLineReturn(ast_node* body) {
8188 if (auto block = ast_cast<Block_t>(body); block && !block->statements.empty()) { 8910 if (auto block = ast_cast<Block_t>(body); block && !block->statementOrComments.empty()) {
8189 auto last = static_cast<Statement_t*>(block->statements.back()); 8911 auto last = lastStatementFrom(block);
8190 if (last->content.is<Return_t>()) { 8912 if (last && last->content.is<Return_t>()) {
8191 auto doNode = last->new_ptr<Do_t>(); 8913 auto doNode = last->new_ptr<Do_t>();
8192 auto newBody = last->new_ptr<Body_t>(); 8914 auto newBody = last->new_ptr<Body_t>();
8193 auto newStmt = last->new_ptr<Statement_t>(); 8915 auto newStmt = last->new_ptr<Statement_t>();
@@ -8205,30 +8927,30 @@ private:
8205 } 8927 }
8206 } 8928 }
8207 8929
8208 void transformLoopBody(ast_node* body, str_list& out, const std::string& appendContent, ExpUsage usage, ExpList_t* assignList = nullptr) { 8930 void transformLoopBody(ast_node* body, str_list& out, uint32_t breakLoopType, ExpUsage usage, ExpList_t* assignList = nullptr) {
8209 str_list temp; 8931 str_list temp;
8210 bool extraDo = false; 8932 bool extraDo = false;
8211 bool withContinue = hasContinueStatement(body); 8933 bool withContinue = hasContinue(breakLoopType);
8212 int target = getLuaTarget(body); 8934 int target = getLuaTarget(body);
8213 std::string extraLabel; 8935 std::string extraLabel;
8214 if (withContinue) { 8936 if (withContinue) {
8215 if (target < 502) { 8937 if (target < 502) {
8216 if (auto block = ast_cast<Block_t>(body)) { 8938 if (auto block = ast_cast<Block_t>(body)) {
8217 if (!block->statements.empty()) { 8939 if (!block->statementOrComments.empty()) {
8218 auto stmt = static_cast<Statement_t*>(block->statements.back()); 8940 auto stmt = lastStatementFrom(block);
8219 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { 8941 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) {
8220 extraDo = _parser.toString(breakLoop) == "break"sv; 8942 extraDo = breakLoop->type.is<Break_t>();
8221 } 8943 }
8222 } 8944 }
8223 } 8945 }
8224 auto continueVar = getUnusedName("_continue_"sv); 8946 auto continueVar = getUnusedName("_continue_"sv);
8225 addToScope(continueVar); 8947 addToScope(continueVar);
8226 _continueVars.push({continueVar, nullptr}); 8948 _continueVars.push({continueVar, nullptr});
8227 _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body); 8949 _buf << indent() << "local "sv << continueVar << " = false"sv << nl(body);
8228 _buf << indent() << "repeat"sv << nll(body); 8950 _buf << indent() << "repeat"sv << nl(body);
8229 pushScope(); 8951 pushScope();
8230 if (extraDo) { 8952 if (extraDo) {
8231 _buf << indent() << "do"sv << nll(body); 8953 _buf << indent() << "do"sv << nl(body);
8232 pushScope(); 8954 pushScope();
8233 } 8955 }
8234 temp.push_back(clearBuf()); 8956 temp.push_back(clearBuf());
@@ -8248,28 +8970,20 @@ private:
8248 if (target < 502) { 8970 if (target < 502) {
8249 if (extraDo) { 8971 if (extraDo) {
8250 popScope(); 8972 popScope();
8251 _buf << indent() << "end"sv << nll(body); 8973 _buf << indent() << "end"sv << nl(body);
8252 }
8253 if (!appendContent.empty()) {
8254 _buf << indent() << appendContent;
8255 } 8974 }
8256 _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); 8975 _buf << indent() << _continueVars.top().var << " = true"sv << nl(body);
8257 popScope(); 8976 popScope();
8258 _buf << indent() << "until true"sv << nlr(body); 8977 _buf << indent() << "until true"sv << nl(body);
8259 _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nlr(body); 8978 _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nl(body);
8260 _buf << indent(1) << "break"sv << nlr(body); 8979 _buf << indent(1) << "break"sv << nl(body);
8261 _buf << indent() << "end"sv << nlr(body); 8980 _buf << indent() << "end"sv << nl(body);
8262 temp.push_back(clearBuf()); 8981 temp.push_back(clearBuf());
8263 _continueVars.pop(); 8982 _continueVars.pop();
8264 } else { 8983 } else {
8265 if (!appendContent.empty()) {
8266 temp.push_back(indent() + appendContent);
8267 }
8268 temp.push_back(extraLabel); 8984 temp.push_back(extraLabel);
8269 _continueVars.pop(); 8985 _continueVars.pop();
8270 } 8986 }
8271 } else if (!appendContent.empty()) {
8272 temp.back().append(indent() + appendContent);
8273 } 8987 }
8274 out.push_back(join(temp)); 8988 out.push_back(join(temp));
8275 } 8989 }
@@ -8277,8 +8991,9 @@ private:
8277 std::string transformRepeatBody(Repeat_t* repeatNode, str_list& out) { 8991 std::string transformRepeatBody(Repeat_t* repeatNode, str_list& out) {
8278 str_list temp; 8992 str_list temp;
8279 bool extraDo = false; 8993 bool extraDo = false;
8280 auto body = repeatNode->body->content.get(); 8994 auto body = repeatNode->body.get();
8281 bool withContinue = hasContinueStatement(body); 8995 auto breakLoopType = getBreakLoopType(body, Empty);
8996 bool withContinue = hasContinue(breakLoopType);
8282 std::string conditionVar; 8997 std::string conditionVar;
8283 std::string extraLabel; 8998 std::string extraLabel;
8284 ast_ptr<false, ExpListAssign_t> condAssign; 8999 ast_ptr<false, ExpListAssign_t> condAssign;
@@ -8286,10 +9001,10 @@ private:
8286 if (withContinue) { 9001 if (withContinue) {
8287 if (target < 502) { 9002 if (target < 502) {
8288 if (auto block = ast_cast<Block_t>(body)) { 9003 if (auto block = ast_cast<Block_t>(body)) {
8289 if (!block->statements.empty()) { 9004 if (!block->statementOrComments.empty()) {
8290 auto stmt = static_cast<Statement_t*>(block->statements.back()); 9005 auto stmt = lastStatementFrom(block);
8291 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { 9006 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) {
8292 extraDo = _parser.toString(breakLoop) == "break"sv; 9007 extraDo = breakLoop->type.is<Break_t>();
8293 } 9008 }
8294 } 9009 }
8295 } 9010 }
@@ -8304,12 +9019,12 @@ private:
8304 assign->values.push_back(repeatNode->condition); 9019 assign->values.push_back(repeatNode->condition);
8305 _continueVars.push({continueVar, assignment.get()}); 9020 _continueVars.push({continueVar, assignment.get()});
8306 } 9021 }
8307 _buf << indent() << "local "sv << conditionVar << " = false"sv << nll(body); 9022 _buf << indent() << "local "sv << conditionVar << " = false"sv << nl(body);
8308 _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body); 9023 _buf << indent() << "local "sv << continueVar << " = false"sv << nl(body);
8309 _buf << indent() << "repeat"sv << nll(body); 9024 _buf << indent() << "repeat"sv << nl(body);
8310 pushScope(); 9025 pushScope();
8311 if (extraDo) { 9026 if (extraDo) {
8312 _buf << indent() << "do"sv << nll(body); 9027 _buf << indent() << "do"sv << nl(body);
8313 pushScope(); 9028 pushScope();
8314 } 9029 }
8315 temp.push_back(clearBuf()); 9030 temp.push_back(clearBuf());
@@ -8330,14 +9045,14 @@ private:
8330 transformAssignment(_continueVars.top().condAssign, temp); 9045 transformAssignment(_continueVars.top().condAssign, temp);
8331 if (extraDo) { 9046 if (extraDo) {
8332 popScope(); 9047 popScope();
8333 _buf << indent() << "end"sv << nll(body); 9048 _buf << indent() << "end"sv << nl(body);
8334 } 9049 }
8335 _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); 9050 _buf << indent() << _continueVars.top().var << " = true"sv << nl(body);
8336 popScope(); 9051 popScope();
8337 _buf << indent() << "until true"sv << nlr(body); 9052 _buf << indent() << "until true"sv << nl(body);
8338 _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nlr(body); 9053 _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nl(body);
8339 _buf << indent(1) << "break"sv << nlr(body); 9054 _buf << indent(1) << "break"sv << nl(body);
8340 _buf << indent() << "end"sv << nlr(body); 9055 _buf << indent() << "end"sv << nl(body);
8341 temp.push_back(clearBuf()); 9056 temp.push_back(clearBuf());
8342 _continueVars.pop(); 9057 _continueVars.pop();
8343 } else { 9058 } else {
@@ -8349,34 +9064,48 @@ private:
8349 return conditionVar; 9064 return conditionVar;
8350 } 9065 }
8351 9066
8352 void transformFor(For_t* forNode, str_list& out) { 9067 void transformForNum(ForNum_t* forNum, str_list& out) {
8353 str_list temp; 9068 str_list temp;
8354 transformForHead(forNode, temp); 9069 transformForNumHead(forNum, temp);
8355 transformLoopBody(forNode->body, temp, Empty, ExpUsage::Common); 9070 auto breakLoopType = getBreakLoopType(forNum->body, Empty);
9071 transformLoopBody(forNum->body, temp, breakLoopType, ExpUsage::Common);
8356 popScope(); 9072 popScope();
8357 out.push_back(join(temp) + indent() + "end"s + nlr(forNode)); 9073 out.push_back(join(temp) + indent() + "end"s + nl(forNum));
8358 } 9074 }
8359 9075
8360 std::string transformForInner(For_t* forNode, str_list& out) { 9076 std::string transformForNumInner(ForNum_t* forNum, str_list& out) {
8361 auto x = forNode; 9077 auto x = forNum;
8362 std::string accum = getUnusedName("_accum_"sv); 9078 std::string accum = getUnusedName("_accum_"sv);
8363 addToScope(accum); 9079 addToScope(accum);
8364 std::string len = getUnusedName("_len_"sv); 9080 std::string len = getUnusedName("_len_"sv);
8365 addToScope(len); 9081 addToScope(len);
8366 _buf << indent() << "local "sv << accum << " = { }"sv << nll(forNode); 9082 auto breakLoopType = getBreakLoopType(forNum->body, accum);
8367 _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode); 9083 _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(forNum);
8368 out.push_back(clearBuf()); 9084 out.emplace_back(clearBuf());
8369 transformForHead(forNode, out); 9085 _buf << indent() << "local "sv << len << " = 1"sv << nl(forNum);
8370 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); 9086 auto& lenAssign = out.emplace_back(clearBuf());
8371 auto lenLine = len + " = "s + len + " + 1"s + nlr(forNode->body); 9087 transformForNumHead(forNum, out);
8372 transformLoopBody(forNode->body, out, lenLine, ExpUsage::Assignment, expList); 9088 if (hasBreakWithValue(breakLoopType)) {
9089 lenAssign.clear();
9090 transformLoopBody(forNum->body, out, breakLoopType, ExpUsage::Common);
9091 } else {
9092 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x);
9093 auto followStmt = toAst<Statement_t>(len + "+=1"s, forNum->body);
9094 expList->followStmt = followStmt.get();
9095 transformLoopBody(forNum->body, out, breakLoopType, ExpUsage::Assignment, expList);
9096 if (!expList->followStmtProcessed) {
9097 lenAssign.clear();
9098 }
9099 }
8373 popScope(); 9100 popScope();
8374 out.push_back(indent() + "end"s + nlr(forNode)); 9101 out.push_back(indent() + "end"s + nl(forNum));
8375 return accum; 9102 return accum;
8376 } 9103 }
8377 9104
8378 void transformForClosure(For_t* forNode, str_list& out) { 9105 void transformForNumClosure(ForNum_t* forNum, str_list& out) {
8379 auto simpleValue = forNode->new_ptr<SimpleValue_t>(); 9106 auto forNode = forNum->new_ptr<For_t>();
9107 forNode->forLoop.set(forNum);
9108 auto simpleValue = forNum->new_ptr<SimpleValue_t>();
8380 simpleValue->value.set(forNode); 9109 simpleValue->value.set(forNode);
8381 if (transformAsUpValueFunc(newExp(simpleValue, forNode), out)) { 9110 if (transformAsUpValueFunc(newExp(simpleValue, forNode), out)) {
8382 return; 9111 return;
@@ -8386,26 +9115,26 @@ private:
8386 pushAnonVarArg(); 9115 pushAnonVarArg();
8387 std::string& funcStart = temp.emplace_back(); 9116 std::string& funcStart = temp.emplace_back();
8388 pushScope(); 9117 pushScope();
8389 auto accum = transformForInner(forNode, temp); 9118 auto accum = transformForNumInner(forNum, temp);
8390 temp.push_back(indent() + "return "s + accum + nlr(forNode)); 9119 temp.push_back(indent() + "return "s + accum + nl(forNum));
8391 popScope(); 9120 popScope();
8392 funcStart = anonFuncStart() + nll(forNode); 9121 funcStart = anonFuncStart() + nl(forNum);
8393 temp.push_back(indent() + anonFuncEnd()); 9122 temp.push_back(indent() + anonFuncEnd());
8394 popAnonVarArg(); 9123 popAnonVarArg();
8395 popFunctionScope(); 9124 popFunctionScope();
8396 out.push_back(join(temp)); 9125 out.push_back(join(temp));
8397 } 9126 }
8398 9127
8399 void transformForInPlace(For_t* forNode, str_list& out, ExpList_t* assignExpList = nullptr) { 9128 void transformForNumInPlace(ForNum_t* forNum, str_list& out, ExpList_t* assignExpList) {
8400 auto x = forNode; 9129 auto x = forNum;
8401 str_list temp; 9130 str_list temp;
8402 bool isScoped = !currentScope().lastStatement; 9131 bool isScoped = !currentScope().lastStatement;
8403 if (assignExpList) { 9132 if (assignExpList) {
8404 if (isScoped) { 9133 if (isScoped) {
8405 _buf << indent() << "do"sv << nll(forNode); 9134 _buf << indent() << "do"sv << nl(forNum);
8406 pushScope(); 9135 pushScope();
8407 } 9136 }
8408 auto accum = transformForInner(forNode, temp); 9137 auto accum = transformForNumInner(forNum, temp);
8409 auto assign = x->new_ptr<Assign_t>(); 9138 auto assign = x->new_ptr<Assign_t>();
8410 assign->values.push_back(toAst<Exp_t>(accum, x)); 9139 assign->values.push_back(toAst<Exp_t>(accum, x));
8411 auto assignment = x->new_ptr<ExpListAssign_t>(); 9140 auto assignment = x->new_ptr<ExpListAssign_t>();
@@ -8414,14 +9143,11 @@ private:
8414 transformAssignment(assignment, temp); 9143 transformAssignment(assignment, temp);
8415 if (isScoped) { 9144 if (isScoped) {
8416 popScope(); 9145 popScope();
8417 temp.push_back(indent() + "end"s + nlr(forNode)); 9146 temp.push_back(indent() + "end"s + nl(forNum));
8418 } 9147 }
8419 } else { 9148 } else {
8420 auto accum = transformForInner(forNode, temp); 9149 auto accum = transformForNumInner(forNum, temp);
8421 auto returnNode = x->new_ptr<Return_t>(); 9150 auto returnNode = newReturn(toAst<Exp_t>(accum, forNum));
8422 returnNode->explicitReturn = false;
8423 auto expListLow = toAst<ExpListLow_t>(accum, x);
8424 returnNode->valueList.set(expListLow);
8425 transformReturn(returnNode, temp); 9151 transformReturn(returnNode, temp);
8426 } 9152 }
8427 out.push_back(join(temp)); 9153 out.push_back(join(temp));
@@ -8448,12 +9174,13 @@ private:
8448 void transformForEach(ForEach_t* forEach, str_list& out) { 9174 void transformForEach(ForEach_t* forEach, str_list& out) {
8449 str_list temp; 9175 str_list temp;
8450 bool extraScoped = transformForEachHead(forEach->nameList, forEach->loopValue, temp, false); 9176 bool extraScoped = transformForEachHead(forEach->nameList, forEach->loopValue, temp, false);
8451 transformLoopBody(forEach->body, temp, Empty, ExpUsage::Common); 9177 auto breakLoopType = getBreakLoopType(forEach->body, Empty);
9178 transformLoopBody(forEach->body, temp, breakLoopType, ExpUsage::Common);
8452 popScope(); 9179 popScope();
8453 out.push_back(temp.front() + temp.back() + indent() + "end"s + nlr(forEach)); 9180 out.push_back(temp.front() + temp.back() + indent() + "end"s + nl(forEach));
8454 if (extraScoped) { 9181 if (extraScoped) {
8455 popScope(); 9182 popScope();
8456 out.back().append(indent() + "end"s + nlr(forEach)); 9183 out.back().append(indent() + "end"s + nl(forEach));
8457 } 9184 }
8458 } 9185 }
8459 9186
@@ -8463,22 +9190,35 @@ private:
8463 addToScope(accum); 9190 addToScope(accum);
8464 std::string len = getUnusedName("_len_"sv); 9191 std::string len = getUnusedName("_len_"sv);
8465 addToScope(len); 9192 addToScope(len);
8466 _buf << indent() << "local "sv << accum << " = { }"sv << nll(forEach); 9193 auto breakLoopType = getBreakLoopType(forEach->body, accum);
8467 _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach); 9194 _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(forEach);
8468 out.push_back(clearBuf()); 9195 out.emplace_back(clearBuf());
9196 _buf << indent() << "local "sv << len << " = 1"sv << nl(forEach);
9197 auto& lenAssign = out.emplace_back(clearBuf());
8469 transformForEachHead(forEach->nameList, forEach->loopValue, out, true); 9198 transformForEachHead(forEach->nameList, forEach->loopValue, out, true);
8470 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); 9199 if (hasBreakWithValue(breakLoopType)) {
8471 auto lenLine = len + " = "s + len + " + 1"s + nlr(forEach->body); 9200 lenAssign.clear();
8472 transformLoopBody(forEach->body, out, lenLine, ExpUsage::Assignment, expList); 9201 transformLoopBody(forEach->body, out, breakLoopType, ExpUsage::Common);
9202 } else {
9203 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x);
9204 auto followStmt = toAst<Statement_t>(len + "+=1"s, forEach->body);
9205 expList->followStmt = followStmt.get();
9206 transformLoopBody(forEach->body, out, breakLoopType, ExpUsage::Assignment, expList);
9207 if (!expList->followStmtProcessed) {
9208 lenAssign.clear();
9209 }
9210 }
8473 popScope(); 9211 popScope();
8474 out.push_back(indent() + "end"s + nlr(forEach)); 9212 out.push_back(indent() + "end"s + nl(forEach));
8475 return accum; 9213 return accum;
8476 } 9214 }
8477 9215
8478 void transformForEachClosure(ForEach_t* forEach, str_list& out) { 9216 void transformForEachClosure(ForEach_t* forEach, str_list& out) {
9217 auto forNode = forEach->new_ptr<For_t>();
9218 forNode->forLoop.set(forEach);
8479 auto simpleValue = forEach->new_ptr<SimpleValue_t>(); 9219 auto simpleValue = forEach->new_ptr<SimpleValue_t>();
8480 simpleValue->value.set(forEach); 9220 simpleValue->value.set(forNode);
8481 if (transformAsUpValueFunc(newExp(simpleValue, forEach), out)) { 9221 if (transformAsUpValueFunc(newExp(simpleValue, forNode), out)) {
8482 return; 9222 return;
8483 } 9223 }
8484 str_list temp; 9224 str_list temp;
@@ -8487,22 +9227,22 @@ private:
8487 std::string& funcStart = temp.emplace_back(); 9227 std::string& funcStart = temp.emplace_back();
8488 pushScope(); 9228 pushScope();
8489 auto accum = transformForEachInner(forEach, temp); 9229 auto accum = transformForEachInner(forEach, temp);
8490 temp.push_back(indent() + "return "s + accum + nlr(forEach)); 9230 temp.push_back(indent() + "return "s + accum + nl(forEach));
8491 popScope(); 9231 popScope();
8492 funcStart = anonFuncStart() + nll(forEach); 9232 funcStart = anonFuncStart() + nl(forEach);
8493 temp.push_back(indent() + anonFuncEnd()); 9233 temp.push_back(indent() + anonFuncEnd());
8494 popAnonVarArg(); 9234 popAnonVarArg();
8495 popFunctionScope(); 9235 popFunctionScope();
8496 out.push_back(join(temp)); 9236 out.push_back(join(temp));
8497 } 9237 }
8498 9238
8499 void transformForEachInPlace(ForEach_t* forEach, str_list& out, ExpList_t* assignExpList = nullptr) { 9239 void transformForEachInPlace(ForEach_t* forEach, str_list& out, ExpList_t* assignExpList) {
8500 auto x = forEach; 9240 auto x = forEach;
8501 str_list temp; 9241 str_list temp;
8502 bool isScoped = !currentScope().lastStatement; 9242 bool isScoped = !currentScope().lastStatement;
8503 if (assignExpList) { 9243 if (assignExpList) {
8504 if (isScoped) { 9244 if (isScoped) {
8505 _buf << indent() << "do"sv << nll(forEach); 9245 _buf << indent() << "do"sv << nl(forEach);
8506 pushScope(); 9246 pushScope();
8507 } 9247 }
8508 auto accum = transformForEachInner(forEach, temp); 9248 auto accum = transformForEachInner(forEach, temp);
@@ -8514,19 +9254,58 @@ private:
8514 transformAssignment(assignment, temp); 9254 transformAssignment(assignment, temp);
8515 if (isScoped) { 9255 if (isScoped) {
8516 popScope(); 9256 popScope();
8517 temp.push_back(indent() + "end"s + nlr(forEach)); 9257 temp.push_back(indent() + "end"s + nl(forEach));
8518 } 9258 }
8519 } else { 9259 } else {
8520 auto accum = transformForEachInner(forEach, temp); 9260 auto accum = transformForEachInner(forEach, temp);
8521 auto returnNode = x->new_ptr<Return_t>(); 9261 auto returnNode = newReturn(toAst<Exp_t>(accum, forEach));
8522 returnNode->explicitReturn = false;
8523 auto expListLow = toAst<ExpListLow_t>(accum, x);
8524 returnNode->valueList.set(expListLow);
8525 transformReturn(returnNode, temp); 9262 transformReturn(returnNode, temp);
8526 } 9263 }
8527 out.push_back(join(temp)); 9264 out.push_back(join(temp));
8528 } 9265 }
8529 9266
9267 void transformFor(For_t* forNode, str_list& out) {
9268 switch (forNode->forLoop->get_id()) {
9269 case id<ForNum_t>():
9270 transformForNum(static_cast<ForNum_t*>(forNode->forLoop.get()), out);
9271 break;
9272 case id<ForEach_t>():
9273 transformForEach(static_cast<ForEach_t*>(forNode->forLoop.get()), out);
9274 break;
9275 default:
9276 YUEE("AST node mismatch", forNode->forLoop.get());
9277 break;
9278 }
9279 }
9280
9281 void transformForClosure(For_t* forNode, str_list& out) {
9282 switch (forNode->forLoop->get_id()) {
9283 case id<ForNum_t>():
9284 transformForNumClosure(static_cast<ForNum_t*>(forNode->forLoop.get()), out);
9285 break;
9286 case id<ForEach_t>():
9287 transformForEachClosure(static_cast<ForEach_t*>(forNode->forLoop.get()), out);
9288 break;
9289 default:
9290 YUEE("AST node mismatch", forNode->forLoop.get());
9291 break;
9292 }
9293 }
9294
9295 void transformForInPlace(For_t* forNode, str_list& out, ExpList_t* assignExpList) {
9296 switch (forNode->forLoop->get_id()) {
9297 case id<ForNum_t>():
9298 transformForNumInPlace(static_cast<ForNum_t*>(forNode->forLoop.get()), out, assignExpList);
9299 break;
9300 case id<ForEach_t>():
9301 transformForEachInPlace(static_cast<ForEach_t*>(forNode->forLoop.get()), out, assignExpList);
9302 break;
9303 default:
9304 YUEE("AST node mismatch", forNode->forLoop.get());
9305 break;
9306 }
9307 }
9308
8530 void transform_variable_pair(VariablePair_t* pair, str_list& out) { 9309 void transform_variable_pair(VariablePair_t* pair, str_list& out) {
8531 auto name = _parser.toString(pair->name); 9310 auto name = _parser.toString(pair->name);
8532 if (pair->name->name.is<UnicodeName_t>()) { 9311 if (pair->name->name.is<UnicodeName_t>()) {
@@ -8536,10 +9315,12 @@ private:
8536 } else { 9315 } else {
8537 out.push_back(name + " = "s + name); 9316 out.push_back(name + " = "s + name);
8538 } 9317 }
8539 if (_config.lintGlobalVariable && !isLocal(name)) { 9318 if (_importedGlobal) {
9319 markGlobalImported(name);
9320 } else if (_config.lintGlobalVariable && !isLocal(name)) {
8540 auto key = name + ':' + std::to_string(pair->name->m_begin.m_line) + ':' + std::to_string(pair->name->m_begin.m_col); 9321 auto key = name + ':' + std::to_string(pair->name->m_begin.m_line) + ':' + std::to_string(pair->name->m_begin.m_col);
8541 if (_globals.find(key) != _globals.end()) { 9322 if (_globals.find(key) == _globals.end()) {
8542 _globals[key] = {name, pair->name->m_begin.m_line, pair->name->m_begin.m_col, _funcLevel > 1 ? AccessType::Capture : AccessType::Read}; 9323 _globals[key] = {name, pair->name->m_begin.m_line, pair->name->m_begin.m_col, _funcLevel > 1 ? AccessType::Capture : AccessType::Read, isSolidDefined(name)};
8543 } 9324 }
8544 } 9325 }
8545 } 9326 }
@@ -8653,12 +9434,64 @@ private:
8653 out.push_back(temp.empty() ? "\"\""s : join(temp, " .. "sv)); 9434 out.push_back(temp.empty() ? "\"\""s : join(temp, " .. "sv));
8654 } 9435 }
8655 9436
9437 void transformYAMLMultiline(YAMLMultiline_t* multiline, str_list& out) {
9438 std::optional<std::string> indent;
9439 str_list temp;
9440 for (auto line_ : multiline->lines.objects()) {
9441 auto line = static_cast<YAMLLine_t*>(line_);
9442 auto indentStr = _parser.toString(line->indent);
9443 if (!indent) {
9444 indent = indentStr;
9445 }
9446 if (std::string_view{indentStr.c_str(), indent.value().size()} != indent.value()) {
9447 throw CompileError("inconsistent indent"sv, line);
9448 }
9449 indentStr = indentStr.substr(indent.value().size());
9450 str_list segs;
9451 bool firstSeg = true;
9452 for (auto seg_ : line->segments.objects()) {
9453 auto content = static_cast<YAMLLineContent_t*>(seg_)->content.get();
9454 switch (content->get_id()) {
9455 case id<YAMLLineInner_t>(): {
9456 auto seqStr = _parser.toString(content);
9457 Utils::replace(seqStr, "\\#"sv, "#"sv);
9458 if (firstSeg) {
9459 firstSeg = false;
9460 seqStr.insert(0, indentStr);
9461 }
9462 segs.push_back(Utils::toLuaDoubleString(seqStr));
9463 break;
9464 }
9465 case id<Exp_t>(): {
9466 if (firstSeg) {
9467 firstSeg = false;
9468 if (!indentStr.empty()) {
9469 segs.push_back(Utils::toLuaDoubleString(indentStr));
9470 }
9471 }
9472 transformExp(static_cast<Exp_t*>(content), segs, ExpUsage::Closure);
9473 segs.back() = globalVar("tostring"sv, content, AccessType::Read) + '(' + segs.back() + ')';
9474 break;
9475 }
9476 default: YUEE("AST node mismatch", content); break;
9477 }
9478 }
9479 temp.push_back(join(segs, " .. "sv));
9480 }
9481 auto str = join(temp, " .. '\\n' .. "sv);
9482 Utils::replace(str, "\" .. '\\n' .. \""sv, "\\n"sv);
9483 Utils::replace(str, "\" .. '\\n'"sv, "\\n\""sv);
9484 Utils::replace(str, "'\\n' .. \""sv, "\"\\n"sv);
9485 out.push_back(str);
9486 }
9487
8656 void transformString(String_t* string, str_list& out) { 9488 void transformString(String_t* string, str_list& out) {
8657 auto str = string->str.get(); 9489 auto str = string->str.get();
8658 switch (str->get_id()) { 9490 switch (str->get_id()) {
8659 case id<SingleString_t>(): transformSingleString(static_cast<SingleString_t*>(str), out); break; 9491 case id<SingleString_t>(): transformSingleString(static_cast<SingleString_t*>(str), out); break;
8660 case id<DoubleString_t>(): transformDoubleString(static_cast<DoubleString_t*>(str), out); break; 9492 case id<DoubleString_t>(): transformDoubleString(static_cast<DoubleString_t*>(str), out); break;
8661 case id<LuaString_t>(): transformLuaString(static_cast<LuaString_t*>(str), out); break; 9493 case id<LuaString_t>(): transformLuaString(static_cast<LuaString_t*>(str), out); break;
9494 case id<YAMLMultiline_t>(): transformYAMLMultiline(static_cast<YAMLMultiline_t*>(str), out); break;
8662 default: YUEE("AST node mismatch", str); break; 9495 default: YUEE("AST node mismatch", str); break;
8663 } 9496 }
8664 } 9497 }
@@ -8689,7 +9522,7 @@ private:
8689 pushScope(); 9522 pushScope();
8690 transformClassDecl(classDecl, temp, ExpUsage::Return); 9523 transformClassDecl(classDecl, temp, ExpUsage::Return);
8691 popScope(); 9524 popScope();
8692 funcStart = anonFuncStart() + nll(classDecl); 9525 funcStart = anonFuncStart() + nl(classDecl);
8693 temp.push_back(indent() + anonFuncEnd()); 9526 temp.push_back(indent() + anonFuncEnd());
8694 popAnonVarArg(); 9527 popAnonVarArg();
8695 popFunctionScope(); 9528 popFunctionScope();
@@ -8713,7 +9546,7 @@ private:
8713 bool newDefined = false; 9546 bool newDefined = false;
8714 std::tie(className, newDefined, classTextName) = defineClassVariable(assignable); 9547 std::tie(className, newDefined, classTextName) = defineClassVariable(assignable);
8715 if (newDefined) { 9548 if (newDefined) {
8716 temp.push_back(indent() + "local "s + className + nll(classDecl)); 9549 temp.push_back(indent() + "local "s + className + nl(classDecl));
8717 } 9550 }
8718 if (classTextName.empty()) { 9551 if (classTextName.empty()) {
8719 if (auto chain = ast_cast<AssignableChain_t>(assignable->item)) { 9552 if (auto chain = ast_cast<AssignableChain_t>(assignable->item)) {
@@ -8750,12 +9583,12 @@ private:
8750 } 9583 }
8751 } 9584 }
8752 if (isScoped) { 9585 if (isScoped) {
8753 temp.push_back(indent() + "do"s + nll(classDecl)); 9586 temp.push_back(indent() + "do"s + nl(classDecl));
8754 pushScope(); 9587 pushScope();
8755 } 9588 }
8756 auto classVar = getUnusedName("_class_"sv); 9589 auto classVar = getUnusedName("_class_"sv);
8757 addToScope(classVar); 9590 addToScope(classVar);
8758 temp.push_back(indent() + "local "s + classVar + nll(classDecl)); 9591 temp.push_back(indent() + "local "s + classVar + nl(classDecl));
8759 auto block = classDecl->new_ptr<Block_t>(); 9592 auto block = classDecl->new_ptr<Block_t>();
8760 str_list classConstVars; 9593 str_list classConstVars;
8761 if (body) { 9594 if (body) {
@@ -8764,7 +9597,7 @@ private:
8764 if (auto statement = ast_cast<Statement_t>(item)) { 9597 if (auto statement = ast_cast<Statement_t>(item)) {
8765 ClassDecl_t* clsDecl = nullptr; 9598 ClassDecl_t* clsDecl = nullptr;
8766 if (auto assignment = assignmentFrom(statement)) { 9599 if (auto assignment = assignmentFrom(statement)) {
8767 block->statements.push_back(statement); 9600 block->statementOrComments.push_back(statement);
8768 auto names = transformAssignDefs(assignment->expList.get(), DefOp::Mark); 9601 auto names = transformAssignDefs(assignment->expList.get(), DefOp::Mark);
8769 for (const auto& name : names) { 9602 for (const auto& name : names) {
8770 varDefs.push_back(name.first); 9603 varDefs.push_back(name.first);
@@ -8794,12 +9627,12 @@ private:
8794 clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>(); 9627 clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>();
8795 BLOCK_END 9628 BLOCK_END
8796 } else if (auto expList = expListFrom(statement)) { 9629 } else if (auto expList = expListFrom(statement)) {
8797 block->statements.push_back(statement); 9630 block->statementOrComments.push_back(statement);
8798 if (auto value = singleValueFrom(expList)) { 9631 if (auto value = singleValueFrom(expList)) {
8799 clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>(); 9632 clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>();
8800 } 9633 }
8801 } else if (auto local = statement->content.as<Local_t>()) { 9634 } else if (auto local = statement->content.as<Local_t>()) {
8802 block->statements.push_back(statement); 9635 block->statementOrComments.push_back(statement);
8803 if (auto values = local->item.as<LocalValues_t>()) { 9636 if (auto values = local->item.as<LocalValues_t>()) {
8804 for (auto name : values->nameList->names.objects()) { 9637 for (auto name : values->nameList->names.objects()) {
8805 auto varName = variableToString(static_cast<Variable_t*>(name)); 9638 auto varName = variableToString(static_cast<Variable_t*>(name));
@@ -8840,7 +9673,7 @@ private:
8840 auto names = transformAssignDefs(assignment->expList.get(), DefOp::Get); 9673 auto names = transformAssignDefs(assignment->expList.get(), DefOp::Get);
8841 for (const auto& name : names) { 9674 for (const auto& name : names) {
8842 forceAddToScope(name.first); 9675 forceAddToScope(name.first);
8843 markVarConst(name.first); 9676 markVarLocalConst(name.first);
8844 varDefs.push_back(name.first); 9677 varDefs.push_back(name.first);
8845 classConstVars.push_back(name.first); 9678 classConstVars.push_back(name.first);
8846 } 9679 }
@@ -8854,7 +9687,7 @@ private:
8854 for (const auto& item : destruct.items) { 9687 for (const auto& item : destruct.items) {
8855 if (!item.targetVar.empty()) { 9688 if (!item.targetVar.empty()) {
8856 forceAddToScope(item.targetVar); 9689 forceAddToScope(item.targetVar);
8857 markVarConst(item.targetVar); 9690 markVarLocalConst(item.targetVar);
8858 varDefs.push_back(item.targetVar); 9691 varDefs.push_back(item.targetVar);
8859 classConstVars.push_back(item.targetVar); 9692 classConstVars.push_back(item.targetVar);
8860 } 9693 }
@@ -8862,7 +9695,6 @@ private:
8862 } 9695 }
8863 } 9696 }
8864 auto stmt = statement->new_ptr<Statement_t>(); 9697 auto stmt = statement->new_ptr<Statement_t>();
8865 stmt->comments.dup(statement->comments);
8866 auto newAttrib = localAttrib->new_ptr<LocalAttrib_t>(); 9698 auto newAttrib = localAttrib->new_ptr<LocalAttrib_t>();
8867 newAttrib->attrib.set(localAttrib->attrib); 9699 newAttrib->attrib.set(localAttrib->attrib);
8868 newAttrib->leftList.dup(localAttrib->leftList); 9700 newAttrib->leftList.dup(localAttrib->leftList);
@@ -8870,7 +9702,7 @@ private:
8870 newAttrib->forceLocal = false; 9702 newAttrib->forceLocal = false;
8871 stmt->content.set(newAttrib); 9703 stmt->content.set(newAttrib);
8872 stmt->appendix.set(statement->appendix); 9704 stmt->appendix.set(statement->appendix);
8873 block->statements.push_back(stmt); 9705 block->statementOrComments.push_back(stmt);
8874 } else if (statement->content.is<Global_t>()) { 9706 } else if (statement->content.is<Global_t>()) {
8875 throw CompileError("global statement is not allowed here"sv, statement->content); 9707 throw CompileError("global statement is not allowed here"sv, statement->content);
8876 } 9708 }
@@ -8884,7 +9716,7 @@ private:
8884 } 9716 }
8885 } 9717 }
8886 if (!varDefs.empty()) { 9718 if (!varDefs.empty()) {
8887 temp.push_back(indent() + "local "s + join(varDefs, ", "sv) + nll(body)); 9719 temp.push_back(indent() + "local "s + join(varDefs, ", "sv) + nl(body));
8888 } 9720 }
8889 } 9721 }
8890 std::string parent, parentVar; 9722 std::string parent, parentVar;
@@ -8894,7 +9726,7 @@ private:
8894 transformExp(extend, temp, ExpUsage::Closure); 9726 transformExp(extend, temp, ExpUsage::Closure);
8895 parent = std::move(temp.back()); 9727 parent = std::move(temp.back());
8896 temp.pop_back(); 9728 temp.pop_back();
8897 temp.push_back(indent() + "local "s + parentVar + " = "s + parent + nll(classDecl)); 9729 temp.push_back(indent() + "local "s + parentVar + " = "s + parent + nl(classDecl));
8898 } 9730 }
8899 auto baseVar = getUnusedName("_base_"sv); 9731 auto baseVar = getUnusedName("_base_"sv);
8900 addToScope(baseVar); 9732 addToScope(baseVar);
@@ -8913,7 +9745,7 @@ private:
8913 for (; it != members.end(); ++it) { 9745 for (; it != members.end(); ++it) {
8914 auto& member = *it; 9746 auto& member = *it;
8915 if (member.type == MemType::Property) { 9747 if (member.type == MemType::Property) {
8916 statements.push_back(indent() + member.item + nll(content)); 9748 statements.push_back(indent() + member.item + nl(content));
8917 } else { 9749 } else {
8918 member.item = indent(1) + member.item; 9750 member.item = indent(1) + member.item;
8919 } 9751 }
@@ -8925,32 +9757,34 @@ private:
8925 } 9757 }
8926 } 9758 }
8927 for (const auto& classVar : classConstVars) { 9759 for (const auto& classVar : classConstVars) {
8928 auto& scope = _scopes.back(); 9760 forceAddToScope(classVar);
8929 scope.vars->insert_or_assign(classVar, VarType::Local);
8930 } 9761 }
8931 for (auto stmt_ : block->statements.objects()) { 9762 forceAddToScope("self"s);
8932 transformStatement(static_cast<Statement_t*>(stmt_), statements); 9763 for (auto stmt_ : block->statementOrComments.objects()) {
9764 if (auto stmt = ast_cast<Statement_t>(stmt_)) {
9765 transformStatement(stmt, statements);
9766 }
8933 } 9767 }
8934 for (auto& member : members) { 9768 for (auto& member : members) {
8935 switch (member.type) { 9769 switch (member.type) {
8936 case MemType::Common: 9770 case MemType::Common:
8937 commons.push_back((commons.empty() ? Empty : ',' + nll(member.node)) + member.item); 9771 commons.push_back((commons.empty() ? Empty : ',' + nl(member.node)) + member.item);
8938 break; 9772 break;
8939 case MemType::Builtin: 9773 case MemType::Builtin:
8940 builtins.push_back((builtins.empty() ? Empty : ',' + nll(member.node)) + member.item); 9774 builtins.push_back((builtins.empty() ? Empty : ',' + nl(member.node)) + member.item);
8941 break; 9775 break;
8942 default: break; 9776 default: break;
8943 } 9777 }
8944 } 9778 }
8945 if (!commons.empty()) { 9779 if (!commons.empty()) {
8946 temp.back() += '{' + nll(body); 9780 temp.back() += '{' + nl(body);
8947 temp.push_back(join(commons) + nll(body)); 9781 temp.push_back(join(commons) + nl(body));
8948 temp.push_back(indent() + '}' + nll(body)); 9782 temp.push_back(indent() + '}' + nl(body));
8949 } else { 9783 } else {
8950 temp.back() += "{ }"s + nll(body); 9784 temp.back() += "{ }"s + nl(body);
8951 } 9785 }
8952 } else { 9786 } else {
8953 temp.back() += "{ }"s + nll(classDecl); 9787 temp.back() += "{ }"s + nl(classDecl);
8954 } 9788 }
8955 if (classDecl->mixes) { 9789 if (classDecl->mixes) {
8956 auto item = getUnusedName("_item_"sv); 9790 auto item = getUnusedName("_item_"sv);
@@ -8983,72 +9817,72 @@ private:
8983 transformAssignment(assignment, tmp); 9817 transformAssignment(assignment, tmp);
8984 } 9818 }
8985 if (extend) { 9819 if (extend) {
8986 _buf << indent() << "setmetatable("sv << baseVar << ", "sv << parentVar << ".__base)"sv << nll(classDecl); 9820 _buf << indent() << "setmetatable("sv << baseVar << ", "sv << parentVar << ".__base)"sv << nl(classDecl);
8987 } 9821 }
8988 _buf << indent() << classVar << " = "sv << globalVar("setmetatable"sv, classDecl, AccessType::Read) << "({"sv << nll(classDecl); 9822 _buf << indent() << classVar << " = "sv << globalVar("setmetatable"sv, classDecl, AccessType::Read) << "({"sv << nl(classDecl);
8989 if (!builtins.empty()) { 9823 if (!builtins.empty()) {
8990 _buf << join(builtins) << ',' << nll(classDecl); 9824 _buf << join(builtins) << ',' << nl(classDecl);
8991 } else { 9825 } else {
8992 if (extend) { 9826 if (extend) {
8993 _buf << indent(1) << "__init = function(self, ...)"sv << nll(classDecl); 9827 _buf << indent(1) << "__init = function(self, ...)"sv << nl(classDecl);
8994 _buf << indent(2) << "return "sv << classVar << ".__parent.__init(self, ...)"sv << nll(classDecl); 9828 _buf << indent(2) << "return "sv << classVar << ".__parent.__init(self, ...)"sv << nl(classDecl);
8995 _buf << indent(1) << "end,"sv << nll(classDecl); 9829 _buf << indent(1) << "end,"sv << nl(classDecl);
8996 } else { 9830 } else {
8997 _buf << indent(1) << "__init = function() end,"sv << nll(classDecl); 9831 _buf << indent(1) << "__init = function() end,"sv << nl(classDecl);
8998 } 9832 }
8999 } 9833 }
9000 _buf << indent(1) << "__base = "sv << baseVar; 9834 _buf << indent(1) << "__base = "sv << baseVar;
9001 if (!classTextName.empty()) { 9835 if (!classTextName.empty()) {
9002 _buf << ","sv << nll(classDecl); 9836 _buf << ","sv << nl(classDecl);
9003 _buf << indent(1) << "__name = "sv << classTextName; 9837 _buf << indent(1) << "__name = "sv << classTextName;
9004 } 9838 }
9005 if (extend) { 9839 if (extend) {
9006 _buf << ","sv << nll(classDecl); 9840 _buf << ","sv << nl(classDecl);
9007 _buf << indent(1) << "__parent = "sv << parentVar; 9841 _buf << indent(1) << "__parent = "sv << parentVar;
9008 } 9842 }
9009 _buf << nll(classDecl); 9843 _buf << nl(classDecl);
9010 _buf << indent() << "}, {"sv << nll(classDecl); 9844 _buf << indent() << "}, {"sv << nl(classDecl);
9011 if (extend) { 9845 if (extend) {
9012 _buf << indent(1) << "__index = function(cls, name)"sv << nll(classDecl); 9846 _buf << indent(1) << "__index = function(cls, name)"sv << nl(classDecl);
9013 _buf << indent(2) << "local val = rawget("sv << baseVar << ", name)"sv << nll(classDecl); 9847 _buf << indent(2) << "local val = rawget("sv << baseVar << ", name)"sv << nl(classDecl);
9014 _buf << indent(2) << "if val == nil then"sv << nll(classDecl); 9848 _buf << indent(2) << "if val == nil then"sv << nl(classDecl);
9015 _buf << indent(3) << "local parent = rawget(cls, \"__parent\")"sv << nll(classDecl); 9849 _buf << indent(3) << "local parent = rawget(cls, \"__parent\")"sv << nl(classDecl);
9016 _buf << indent(3) << "if parent then"sv << nll(classDecl); 9850 _buf << indent(3) << "if parent then"sv << nl(classDecl);
9017 _buf << indent(4) << "return parent[name]"sv << nll(classDecl); 9851 _buf << indent(4) << "return parent[name]"sv << nl(classDecl);
9018 _buf << indent(3) << "end"sv << nll(classDecl); 9852 _buf << indent(3) << "end"sv << nl(classDecl);
9019 _buf << indent(2) << "else"sv << nll(classDecl); 9853 _buf << indent(2) << "else"sv << nl(classDecl);
9020 _buf << indent(3) << "return val"sv << nll(classDecl); 9854 _buf << indent(3) << "return val"sv << nl(classDecl);
9021 _buf << indent(2) << "end"sv << nll(classDecl); 9855 _buf << indent(2) << "end"sv << nl(classDecl);
9022 _buf << indent(1) << "end,"sv << nll(classDecl); 9856 _buf << indent(1) << "end,"sv << nl(classDecl);
9023 } else { 9857 } else {
9024 _buf << indent(1) << "__index = "sv << baseVar << ","sv << nll(classDecl); 9858 _buf << indent(1) << "__index = "sv << baseVar << ","sv << nl(classDecl);
9025 } 9859 }
9026 _buf << indent(1) << "__call = function(cls, ...)"sv << nll(classDecl); 9860 _buf << indent(1) << "__call = function(cls, ...)"sv << nl(classDecl);
9027 pushScope(); 9861 pushScope();
9028 auto selfVar = getUnusedName("_self_"sv); 9862 auto selfVar = getUnusedName("_self_"sv);
9029 addToScope(selfVar); 9863 addToScope(selfVar);
9030 _buf << indent(1) << "local "sv << selfVar << " = setmetatable({ }, "sv << baseVar << ")"sv << nll(classDecl); 9864 _buf << indent(1) << "local "sv << selfVar << " = setmetatable({ }, "sv << baseVar << ")"sv << nl(classDecl);
9031 _buf << indent(1) << "cls.__init("sv << selfVar << ", ...)"sv << nll(classDecl); 9865 _buf << indent(1) << "cls.__init("sv << selfVar << ", ...)"sv << nl(classDecl);
9032 _buf << indent(1) << "return "sv << selfVar << nll(classDecl); 9866 _buf << indent(1) << "return "sv << selfVar << nl(classDecl);
9033 popScope(); 9867 popScope();
9034 _buf << indent(1) << "end"sv << nll(classDecl); 9868 _buf << indent(1) << "end"sv << nl(classDecl);
9035 _buf << indent() << "})"sv << nll(classDecl); 9869 _buf << indent() << "})"sv << nl(classDecl);
9036 _buf << indent() << baseVar << ".__class = "sv << classVar << nll(classDecl); 9870 _buf << indent() << baseVar << ".__class = "sv << classVar << nl(classDecl);
9037 if (!statements.empty()) { 9871 if (!statements.empty()) {
9038 _buf << indent() << "local self = "sv << classVar << ';' << nll(classDecl); 9872 _buf << indent() << "local self = "sv << classVar << ';' << nl(classDecl);
9039 } 9873 }
9040 _buf << join(statements); 9874 _buf << join(statements);
9041 if (extend) { 9875 if (extend) {
9042 _buf << indent() << "if "sv << parentVar << ".__inherited then"sv << nll(classDecl); 9876 _buf << indent() << "if "sv << parentVar << ".__inherited then"sv << nl(classDecl);
9043 _buf << indent(1) << parentVar << ".__inherited("sv << parentVar << ", "sv << classVar << ")"sv << nll(classDecl); 9877 _buf << indent(1) << parentVar << ".__inherited("sv << parentVar << ", "sv << classVar << ")"sv << nl(classDecl);
9044 _buf << indent() << "end"sv << nll(classDecl); 9878 _buf << indent() << "end"sv << nl(classDecl);
9045 } 9879 }
9046 if (!assignItem.empty()) { 9880 if (!assignItem.empty()) {
9047 _buf << indent() << assignItem << " = "sv << classVar << nll(classDecl); 9881 _buf << indent() << assignItem << " = "sv << classVar << nl(classDecl);
9048 } 9882 }
9049 switch (usage) { 9883 switch (usage) {
9050 case ExpUsage::Return: { 9884 case ExpUsage::Return: {
9051 _buf << indent() << "return "sv << classVar << nlr(classDecl); 9885 _buf << indent() << "return "sv << classVar << nl(classDecl);
9052 break; 9886 break;
9053 } 9887 }
9054 case ExpUsage::Assignment: { 9888 case ExpUsage::Assignment: {
@@ -9060,7 +9894,7 @@ private:
9060 temp.push_back(clearBuf()); 9894 temp.push_back(clearBuf());
9061 if (isScoped) { 9895 if (isScoped) {
9062 popScope(); 9896 popScope();
9063 temp.push_back(indent() + "end"s + nlr(classDecl)); 9897 temp.push_back(indent() + "end"s + nl(classDecl));
9064 } 9898 }
9065 out.push_back(join(temp)); 9899 out.push_back(join(temp));
9066 } 9900 }
@@ -9223,7 +10057,7 @@ private:
9223 pushScope(); 10057 pushScope();
9224 transformWith(with, temp, nullptr, true); 10058 transformWith(with, temp, nullptr, true);
9225 popScope(); 10059 popScope();
9226 funcStart = anonFuncStart() + nll(with); 10060 funcStart = anonFuncStart() + nl(with);
9227 temp.push_back(indent() + anonFuncEnd()); 10061 temp.push_back(indent() + anonFuncEnd());
9228 popAnonVarArg(); 10062 popAnonVarArg();
9229 popFunctionScope(); 10063 popFunctionScope();
@@ -9236,11 +10070,11 @@ private:
9236 std::string withVar; 10070 std::string withVar;
9237 bool needScope = !currentScope().lastStatement && !returnValue; 10071 bool needScope = !currentScope().lastStatement && !returnValue;
9238 bool extraScope = false; 10072 bool extraScope = false;
9239 if (with->assigns) { 10073 if (with->assign) {
9240 auto vars = getAssignVars(with); 10074 auto vars = getAssignVars(with);
9241 if (vars.front().empty() || isDeclaredAsGlobal(vars.front())) { 10075 if (vars.front().empty() || isDeclaredAsGlobal(vars.front())) {
9242 if (with->assigns->values.objects().size() == 1) { 10076 if (with->assign->values.objects().size() == 1) {
9243 auto var = singleVariableFrom(with->assigns->values.objects().front(), AccessType::Read); 10077 auto var = singleVariableFrom(with->assign->values.objects().front(), AccessType::Read);
9244 if (!var.empty() && isLocal(var)) { 10078 if (!var.empty() && isLocal(var)) {
9245 withVar = var; 10079 withVar = var;
9246 } 10080 }
@@ -9250,11 +10084,11 @@ private:
9250 auto assignment = x->new_ptr<ExpListAssign_t>(); 10084 auto assignment = x->new_ptr<ExpListAssign_t>();
9251 assignment->expList.set(toAst<ExpList_t>(withVar, x)); 10085 assignment->expList.set(toAst<ExpList_t>(withVar, x));
9252 auto assign = x->new_ptr<Assign_t>(); 10086 auto assign = x->new_ptr<Assign_t>();
9253 assign->values.push_back(with->assigns->values.objects().front()); 10087 assign->values.push_back(with->assign->values.objects().front());
9254 assignment->action.set(assign); 10088 assignment->action.set(assign);
9255 if (needScope) { 10089 if (needScope) {
9256 extraScope = true; 10090 extraScope = true;
9257 temp.push_back(indent() + "do"s + nll(with)); 10091 temp.push_back(indent() + "do"s + nl(with));
9258 pushScope(); 10092 pushScope();
9259 } 10093 }
9260 transformAssignment(assignment, temp); 10094 transformAssignment(assignment, temp);
@@ -9264,7 +10098,7 @@ private:
9264 auto assign = x->new_ptr<Assign_t>(); 10098 auto assign = x->new_ptr<Assign_t>();
9265 assign->values.push_back(toAst<Exp_t>(withVar, x)); 10099 assign->values.push_back(toAst<Exp_t>(withVar, x));
9266 bool skipFirst = true; 10100 bool skipFirst = true;
9267 for (auto value : with->assigns->values.objects()) { 10101 for (auto value : with->assign->values.objects()) {
9268 if (skipFirst) { 10102 if (skipFirst) {
9269 skipFirst = false; 10103 skipFirst = false;
9270 continue; 10104 continue;
@@ -9277,10 +10111,10 @@ private:
9277 withVar = vars.front(); 10111 withVar = vars.front();
9278 auto assignment = x->new_ptr<ExpListAssign_t>(); 10112 auto assignment = x->new_ptr<ExpListAssign_t>();
9279 assignment->expList.set(with->valueList); 10113 assignment->expList.set(with->valueList);
9280 assignment->action.set(with->assigns); 10114 assignment->action.set(with->assign);
9281 if (needScope) { 10115 if (needScope) {
9282 extraScope = true; 10116 extraScope = true;
9283 temp.push_back(indent() + "do"s + nll(with)); 10117 temp.push_back(indent() + "do"s + nl(with));
9284 pushScope(); 10118 pushScope();
9285 } 10119 }
9286 transformAssignment(assignment, temp); 10120 transformAssignment(assignment, temp);
@@ -9296,7 +10130,7 @@ private:
9296 assignment->action.set(assign); 10130 assignment->action.set(assign);
9297 if (needScope) { 10131 if (needScope) {
9298 extraScope = true; 10132 extraScope = true;
9299 temp.push_back(indent() + "do"s + nll(with)); 10133 temp.push_back(indent() + "do"s + nl(with));
9300 pushScope(); 10134 pushScope();
9301 } 10135 }
9302 transformAssignment(assignment, temp); 10136 transformAssignment(assignment, temp);
@@ -9350,27 +10184,69 @@ private:
9350 }); 10184 });
9351 popScope(); 10185 popScope();
9352 if (extraScope) { 10186 if (extraScope) {
9353 temp.push_back(indent() + "do"s + nll(with)); 10187 temp.push_back(indent() + "do"s + nl(with));
9354 pushScope(); 10188 pushScope();
9355 } 10189 }
9356 } 10190 }
9357 _withVars.push(withVar); 10191 _withVars.push(withVar);
10192 std::string breakWithVar;
10193 if (assignList || returnValue) {
10194 auto breakLoopType = getBreakLoopType(with->body, withVar);
10195 if (hasBreakWithValue(breakLoopType)) {
10196 breakWithVar = withVar;
10197 }
10198 }
9358 if (with->eop) { 10199 if (with->eop) {
9359 auto ifNode = x->new_ptr<If_t>(); 10200 auto ifNode = x->new_ptr<If_t>();
9360 ifNode->type.set(toAst<IfType_t>("if"sv, x)); 10201 ifNode->type.set(toAst<IfType_t>("if"sv, x));
9361 ifNode->nodes.push_back(toAst<IfCond_t>(withVar + "~=nil"s, x)); 10202 ifNode->nodes.push_back(toAst<IfCond_t>(withVar + "~=nil"s, x));
9362 ifNode->nodes.push_back(with->body); 10203 ifNode->nodes.push_back(with->body);
9363 transformIf(ifNode, temp, ExpUsage::Common); 10204 if (breakWithVar.empty()) {
10205 transformIf(ifNode, temp, ExpUsage::Common);
10206 } else {
10207 auto simpleValue = x->new_ptr<SimpleValue_t>();
10208 simpleValue->value.set(ifNode);
10209 auto exp = newExp(simpleValue, x);
10210 auto expList = x->new_ptr<ExpList_t>();
10211 expList->exprs.push_back(exp);
10212 auto expListAssign = x->new_ptr<ExpListAssign_t>();
10213 expListAssign->expList.set(expList);
10214 auto stmt = x->new_ptr<Statement_t>();
10215 stmt->content.set(expListAssign);
10216 auto repeatNode = toAst<Repeat_t>("repeat\n\t--\nuntil true"s, x);
10217 auto block = x->new_ptr<Block_t>();
10218 block->statementOrComments.push_back(stmt);
10219 repeatNode->body.set(block);
10220 auto sVal = x->new_ptr<SimpleValue_t>();
10221 sVal->value.set(repeatNode);
10222 auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x);
10223 transformAssignment(asmt, temp);
10224 }
9364 } else { 10225 } else {
9365 bool transformed = false; 10226 bool transformed = false;
9366 if (!extraScope && assignList) { 10227 if (!breakWithVar.empty()) {
10228 auto repeatNode = toAst<Repeat_t>("repeat\n\t--\nuntil true"s, x);
10229 auto block = x->new_ptr<Block_t>();
10230 if (auto blk = with->body.as<Block_t>()) {
10231 block->statementOrComments.dup(blk->statementOrComments);
10232 } else {
10233 auto stmt = with->body.to<Statement_t>();
10234 block->statementOrComments.push_back(stmt);
10235 }
10236 repeatNode->body.set(block);
10237 auto sVal = x->new_ptr<SimpleValue_t>();
10238 sVal->value.set(repeatNode);
10239 auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x);
10240 transformAssignment(asmt, temp);
10241 transformed = true;
10242 } else if (!extraScope && assignList) {
9367 if (auto block = with->body.as<Block_t>()) { 10243 if (auto block = with->body.as<Block_t>()) {
9368 if (!block->statements.empty()) { 10244 if (!block->statementOrComments.empty()) {
9369 Statement_t* stmt = static_cast<Statement_t*>(block->statements.back()); 10245 Statement_t* stmt = lastStatementFrom(block);
9370 if (stmt->content.is<Return_t>()) { 10246 if (stmt && stmt->content.is<Return_t>()) {
9371 auto newBlock = with->body->new_ptr<Block_t>(); 10247 auto newBlock = with->body->new_ptr<Block_t>();
9372 newBlock->statements.dup(block->statements); 10248 newBlock->statementOrComments.dup(block->statementOrComments);
9373 newBlock->statements.pop_back(); 10249 newBlock->statementOrComments.pop_back();
9374 transform_plain_body(newBlock, temp, ExpUsage::Common); 10250 transform_plain_body(newBlock, temp, ExpUsage::Common);
9375 auto newBody = stmt->new_ptr<Body_t>(); 10251 auto newBody = stmt->new_ptr<Body_t>();
9376 newBody->content.set(stmt); 10252 newBody->content.set(stmt);
@@ -9408,12 +10284,12 @@ private:
9408 if (returnValue) { 10284 if (returnValue) {
9409 auto last = lastStatementFrom(with->body); 10285 auto last = lastStatementFrom(with->body);
9410 if (last && !last->content.is<Return_t>()) { 10286 if (last && !last->content.is<Return_t>()) {
9411 temp.push_back(indent() + "return "s + withVar + nll(with)); 10287 temp.push_back(indent() + "return "s + withVar + nl(with));
9412 } 10288 }
9413 } 10289 }
9414 if (extraScope) { 10290 if (extraScope) {
9415 popScope(); 10291 popScope();
9416 temp.push_back(indent() + "end"s + nll(with)); 10292 temp.push_back(indent() + "end"s + nl(with));
9417 } 10293 }
9418 out.push_back(join(temp)); 10294 out.push_back(join(temp));
9419 } 10295 }
@@ -9428,12 +10304,18 @@ private:
9428 switch (item->get_id()) { 10304 switch (item->get_id()) {
9429 case id<ClassDecl_t>(): { 10305 case id<ClassDecl_t>(): {
9430 auto classDecl = static_cast<ClassDecl_t*>(item); 10306 auto classDecl = static_cast<ClassDecl_t*>(item);
10307 std::string varName;
9431 if (classDecl->name) { 10308 if (classDecl->name) {
9432 if (auto var = classDecl->name->item.as<Variable_t>()) { 10309 if (auto var = classDecl->name->item.as<Variable_t>()) {
9433 addGlobalVar(variableToString(var), classDecl->name->item); 10310 varName = variableToString(var);
10311 addGlobalVar(varName, var);
9434 } 10312 }
9435 } 10313 }
10314 if (varName.empty()) {
10315 throw CompileError("missing name for class", classDecl);
10316 }
9436 transformClassDecl(classDecl, out, ExpUsage::Common); 10317 transformClassDecl(classDecl, out, ExpUsage::Common);
10318 markVarGlobalConst(varName);
9437 break; 10319 break;
9438 } 10320 }
9439 case id<GlobalOp_t>(): 10321 case id<GlobalOp_t>():
@@ -9447,9 +10329,11 @@ private:
9447 auto values = global->item.to<GlobalValues_t>(); 10329 auto values = global->item.to<GlobalValues_t>();
9448 if (values->valueList) { 10330 if (values->valueList) {
9449 auto expList = x->new_ptr<ExpList_t>(); 10331 auto expList = x->new_ptr<ExpList_t>();
10332 str_list varNames;
9450 for (auto name : values->nameList->names.objects()) { 10333 for (auto name : values->nameList->names.objects()) {
9451 auto var = static_cast<Variable_t*>(name); 10334 auto var = static_cast<Variable_t*>(name);
9452 addGlobalVar(variableToString(var), var); 10335 varNames.emplace_back(variableToString(var));
10336 addGlobalVar(varNames.back(), var);
9453 auto callable = x->new_ptr<Callable_t>(); 10337 auto callable = x->new_ptr<Callable_t>();
9454 callable->item.set(name); 10338 callable->item.set(name);
9455 auto chainValue = x->new_ptr<ChainValue_t>(); 10339 auto chainValue = x->new_ptr<ChainValue_t>();
@@ -9460,18 +10344,27 @@ private:
9460 auto assignment = x->new_ptr<ExpListAssign_t>(); 10344 auto assignment = x->new_ptr<ExpListAssign_t>();
9461 assignment->expList.set(expList); 10345 assignment->expList.set(expList);
9462 auto assign = x->new_ptr<Assign_t>(); 10346 auto assign = x->new_ptr<Assign_t>();
9463 if (auto expListLow = values->valueList.as<ExpListLow_t>()) { 10347 if (auto expList = values->valueList.as<ExpList_t>()) {
9464 assign->values.dup(expListLow->exprs); 10348 assign->values.dup(expList->exprs);
9465 } else { 10349 } else {
9466 auto tableBlock = values->valueList.to<TableBlock_t>(); 10350 auto tableBlock = values->valueList.to<TableBlock_t>();
9467 assign->values.push_back(tableBlock); 10351 assign->values.push_back(tableBlock);
9468 } 10352 }
9469 assignment->action.set(assign); 10353 assignment->action.set(assign);
9470 transformAssignment(assignment, out); 10354 transformAssignment(assignment, out);
10355 if (global->constAttrib) {
10356 for (const auto& name : varNames) {
10357 markVarGlobalConst(name);
10358 }
10359 }
9471 } else { 10360 } else {
9472 for (auto name : values->nameList->names.objects()) { 10361 for (auto name : values->nameList->names.objects()) {
9473 auto var = static_cast<Variable_t*>(name); 10362 auto var = static_cast<Variable_t*>(name);
9474 addGlobalVar(variableToString(var), var); 10363 auto varName = variableToString(var);
10364 addGlobalVar(varName, var);
10365 if (global->constAttrib) {
10366 markVarGlobalConst(varName);
10367 }
9475 } 10368 }
9476 } 10369 }
9477 break; 10370 break;
@@ -9608,7 +10501,7 @@ private:
9608 } 10501 }
9609 } 10502 }
9610 if (_info.exportDefault) { 10503 if (_info.exportDefault) {
9611 out.back().append(indent() + _info.moduleName + " = "s + names.back().first + nlr(exportNode)); 10504 out.back().append(indent() + _info.moduleName + " = "s + names.back().first + nl(exportNode));
9612 } else { 10505 } else {
9613 str_list lefts, rights; 10506 str_list lefts, rights;
9614 for (const auto& name : names) { 10507 for (const auto& name : names) {
@@ -9621,7 +10514,7 @@ private:
9621 lefts.push_back(_info.moduleName + "[\""s + realName + "\"]"s); 10514 lefts.push_back(_info.moduleName + "[\""s + realName + "\"]"s);
9622 rights.push_back(name.first); 10515 rights.push_back(name.first);
9623 } 10516 }
9624 out.back().append(indent() + join(lefts, ", "sv) + " = "s + join(rights, ", "sv) + nlr(exportNode)); 10517 out.back().append(indent() + join(lefts, ", "sv) + " = "s + join(rights, ", "sv) + nl(exportNode));
9625 } 10518 }
9626 } 10519 }
9627 } else { 10520 } else {
@@ -9705,12 +10598,12 @@ private:
9705 case id<CompForEach_t>(): 10598 case id<CompForEach_t>():
9706 transformCompForEach(static_cast<CompForEach_t*>(item), temp); 10599 transformCompForEach(static_cast<CompForEach_t*>(item), temp);
9707 break; 10600 break;
9708 case id<CompFor_t>(): 10601 case id<CompForNum_t>():
9709 transformCompFor(static_cast<CompFor_t*>(item), temp); 10602 transformCompForNum(static_cast<CompForNum_t*>(item), temp);
9710 break; 10603 break;
9711 case id<Exp_t>(): 10604 case id<Exp_t>():
9712 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure); 10605 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure);
9713 temp.back() = indent() + "if "s + temp.back() + " then"s + nll(item); 10606 temp.back() = indent() + "if "s + temp.back() + " then"s + nl(item);
9714 pushScope(); 10607 pushScope();
9715 break; 10608 break;
9716 default: YUEE("AST node mismatch", item); break; 10609 default: YUEE("AST node mismatch", item); break;
@@ -9723,27 +10616,27 @@ private:
9723 for (size_t i = 0; i < compInner->items.objects().size(); ++i) { 10616 for (size_t i = 0; i < compInner->items.objects().size(); ++i) {
9724 popScope(); 10617 popScope();
9725 } 10618 }
9726 _buf << indent() << "local "sv << tbl << " = { }"sv << nll(comp); 10619 _buf << indent() << "local "sv << tbl << " = { }"sv << nl(comp);
9727 _buf << join(temp); 10620 _buf << join(temp);
9728 pushScope(); 10621 pushScope();
9729 if (!comp->value) { 10622 if (!comp->value) {
9730 auto keyVar = getUnusedName("_key_"sv); 10623 auto keyVar = getUnusedName("_key_"sv);
9731 auto valVar = getUnusedName("_val_"sv); 10624 auto valVar = getUnusedName("_val_"sv);
9732 _buf << indent(int(temp.size()) - 1) << "local "sv << keyVar << ", "sv << valVar << " = "sv << kv.front() << nll(comp); 10625 _buf << indent(int(temp.size()) - 1) << "local "sv << keyVar << ", "sv << valVar << " = "sv << kv.front() << nl(comp);
9733 kv.front() = keyVar; 10626 kv.front() = keyVar;
9734 kv.push_back(valVar); 10627 kv.push_back(valVar);
9735 } 10628 }
9736 _buf << indent(int(temp.size()) - 1) << tbl << "["sv << kv.front() << "] = "sv << kv.back() << nll(comp); 10629 _buf << indent(int(temp.size()) - 1) << tbl << "["sv << kv.front() << "] = "sv << kv.back() << nl(comp);
9737 for (int ind = int(temp.size()) - 2; ind > -1; --ind) { 10630 for (int ind = int(temp.size()) - 2; ind > -1; --ind) {
9738 _buf << indent(ind) << "end"sv << nll(comp); 10631 _buf << indent(ind) << "end"sv << nl(comp);
9739 } 10632 }
9740 popScope(); 10633 popScope();
9741 _buf << indent() << "end"sv << nll(comp); 10634 _buf << indent() << "end"sv << nl(comp);
9742 switch (usage) { 10635 switch (usage) {
9743 case ExpUsage::Closure: 10636 case ExpUsage::Closure:
9744 out.push_back(clearBuf() + indent() + "return "s + tbl + nlr(comp)); 10637 out.push_back(clearBuf() + indent() + "return "s + tbl + nl(comp));
9745 popScope(); 10638 popScope();
9746 out.back().insert(0, anonFuncStart() + nll(comp)); 10639 out.back().insert(0, anonFuncStart() + nl(comp));
9747 out.back().append(indent() + anonFuncEnd()); 10640 out.back().append(indent() + anonFuncEnd());
9748 popAnonVarArg(); 10641 popAnonVarArg();
9749 popFunctionScope(); 10642 popFunctionScope();
@@ -9759,21 +10652,21 @@ private:
9759 out.back().append(temp.back()); 10652 out.back().append(temp.back());
9760 if (extraScope) { 10653 if (extraScope) {
9761 popScope(); 10654 popScope();
9762 out.back().insert(0, indent() + "do"s + nll(comp)); 10655 out.back().insert(0, indent() + "do"s + nl(comp));
9763 out.back().append(indent() + "end"s + nlr(comp)); 10656 out.back().append(indent() + "end"s + nl(comp));
9764 } 10657 }
9765 break; 10658 break;
9766 } 10659 }
9767 case ExpUsage::Return: 10660 case ExpUsage::Return:
9768 out.push_back(clearBuf() + indent() + "return "s + tbl + nlr(comp)); 10661 out.push_back(clearBuf() + indent() + "return "s + tbl + nl(comp));
9769 break; 10662 break;
9770 default: 10663 default:
9771 break; 10664 break;
9772 } 10665 }
9773 } 10666 }
9774 10667
9775 void transformCompFor(CompFor_t* comp, str_list& out) { 10668 void transformCompForNum(CompForNum_t* comp, str_list& out) {
9776 transformForHead(comp->varName, comp->startValue, comp->stopValue, comp->stepValue, out); 10669 transformForNumHead(comp->varName, comp->startValue, comp->stopValue, comp->stepValue, out);
9777 } 10670 }
9778 10671
9779 void transformTableBlockIndent(TableBlockIndent_t* table, str_list& out) { 10672 void transformTableBlockIndent(TableBlockIndent_t* table, str_list& out) {
@@ -9803,25 +10696,64 @@ private:
9803 funcStart = &temp.emplace_back(); 10696 funcStart = &temp.emplace_back();
9804 pushScope(); 10697 pushScope();
9805 } else { 10698 } else {
9806 temp.push_back(indent() + "do"s + nll(doNode)); 10699 temp.push_back(indent() + "do"s + nl(doNode));
9807 pushScope(); 10700 pushScope();
9808 } 10701 }
9809 transformBody(doNode->body, temp, usage, assignList); 10702 transformBody(doNode->body, temp, usage, assignList);
9810 if (usage == ExpUsage::Closure) { 10703 if (usage == ExpUsage::Closure) {
9811 popScope(); 10704 popScope();
9812 *funcStart = anonFuncStart() + nll(doNode); 10705 *funcStart = anonFuncStart() + nl(doNode);
9813 temp.push_back(indent() + anonFuncEnd()); 10706 temp.push_back(indent() + anonFuncEnd());
9814 popAnonVarArg(); 10707 popAnonVarArg();
9815 popFunctionScope(); 10708 popFunctionScope();
9816 } else { 10709 } else {
9817 popScope(); 10710 popScope();
9818 temp.push_back(indent() + "end"s + nlr(doNode)); 10711 temp.push_back(indent() + "end"s + nl(doNode));
9819 } 10712 }
9820 out.push_back(join(temp)); 10713 out.push_back(join(temp));
9821 } 10714 }
9822 10715
9823 void transformTry(Try_t* tryNode, str_list& out, ExpUsage usage) { 10716 void transformTry(Try_t* tryNode, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
9824 auto x = tryNode; 10717 auto x = tryNode;
10718 if (tryNode->eop && usage == ExpUsage::Assignment) {
10719 str_list rets;
10720 pushScope();
10721 auto okVar = getUnusedName("_ok_"sv);
10722 for (size_t i = 0; i < assignList->exprs.size(); i++) {
10723 auto retVar = getUnusedName("_ret_"sv);
10724 rets.emplace_back(retVar);
10725 addToScope(retVar);
10726 }
10727 popScope();
10728 auto varList = join(rets, ","sv);
10729 auto ifNode = toAst<If_t>("if "s + okVar + ',' + varList + ":=try nil then "s + varList, x);
10730 auto exp = ast_to<IfCond_t>(ifNode->nodes.front())->assignment->assign->values.front();
10731 auto sVal = simpleSingleValueFrom(exp);
10732 auto newTry = sVal->value.to<Try_t>();
10733 newTry->func.set(tryNode->func);
10734 newTry->catchBlock.set(tryNode->catchBlock);
10735 auto assignment = x->new_ptr<ExpListAssign_t>();
10736 assignment->expList.set(assignList);
10737 auto assign = x->new_ptr<Assign_t>();
10738 assign->values.push_back(ifNode);
10739 assignment->action.set(assign);
10740 transformAssignment(assignment, out);
10741 return;
10742 }
10743 if (tryNode->eop && usage != ExpUsage::Common) {
10744 auto okVar = getUnusedName("_ok_"sv);
10745 auto code = "do\n\t"s + okVar + ", ... = try nil\n\t... if "s + okVar;
10746 auto doNode = toAst<Do_t>(code, x);
10747 auto block = doNode->body->content.to<Block_t>();
10748 auto asmt = static_cast<Statement_t*>(block->statementOrComments.front())->content.to<ExpListAssign_t>();
10749 auto assign = asmt->action.to<Assign_t>();
10750 auto sVal = simpleSingleValueFrom(assign->values.back());
10751 auto newTry = sVal->value.to<Try_t>();
10752 newTry->func.set(tryNode->func);
10753 newTry->catchBlock.set(tryNode->catchBlock);
10754 transformDo(doNode, out, usage);
10755 return;
10756 }
9825 ast_ptr<true, Exp_t> errHandler; 10757 ast_ptr<true, Exp_t> errHandler;
9826 if (tryNode->catchBlock) { 10758 if (tryNode->catchBlock) {
9827 auto catchBlock = tryNode->catchBlock.get(); 10759 auto catchBlock = tryNode->catchBlock.get();
@@ -9837,8 +10769,8 @@ private:
9837 tryFunc.set(tryNode->func); 10769 tryFunc.set(tryNode->func);
9838 if (auto tryBlock = tryFunc.as<Block_t>()) { 10770 if (auto tryBlock = tryFunc.as<Block_t>()) {
9839 BLOCK_START 10771 BLOCK_START
9840 BREAK_IF(tryBlock->statements.size() != 1); 10772 BREAK_IF(countStatementFrom(tryBlock) != 1);
9841 auto stmt = static_cast<Statement_t*>(tryBlock->statements.front()); 10773 auto stmt = firstStatementFrom(tryBlock);
9842 auto expListAssign = stmt->content.as<ExpListAssign_t>(); 10774 auto expListAssign = stmt->content.as<ExpListAssign_t>();
9843 BREAK_IF(!expListAssign); 10775 BREAK_IF(!expListAssign);
9844 BREAK_IF(expListAssign->action); 10776 BREAK_IF(expListAssign->action);
@@ -9902,7 +10834,7 @@ private:
9902 auto stmt = x->new_ptr<Statement_t>(); 10834 auto stmt = x->new_ptr<Statement_t>();
9903 stmt->content.set(expListAssign); 10835 stmt->content.set(expListAssign);
9904 auto block = x->new_ptr<Block_t>(); 10836 auto block = x->new_ptr<Block_t>();
9905 block->statements.push_back(stmt); 10837 block->statementOrComments.push_back(stmt);
9906 tryFunc.set(block); 10838 tryFunc.set(block);
9907 } 10839 }
9908 } 10840 }
@@ -9930,7 +10862,7 @@ private:
9930 } 10862 }
9931 if (usage == ExpUsage::Common) { 10863 if (usage == ExpUsage::Common) {
9932 out.back().insert(0, indent()); 10864 out.back().insert(0, indent());
9933 out.back().append(nlr(x)); 10865 out.back().append(nl(x));
9934 } 10866 }
9935 return; 10867 return;
9936 } 10868 }
@@ -9955,7 +10887,7 @@ private:
9955 } 10887 }
9956 if (usage == ExpUsage::Common) { 10888 if (usage == ExpUsage::Common) {
9957 out.back().insert(0, indent()); 10889 out.back().insert(0, indent());
9958 out.back().append(nlr(x)); 10890 out.back().append(nl(x));
9959 } 10891 }
9960 return; 10892 return;
9961 } else if (auto value = singleValueFrom(tryFunc)) { 10893 } else if (auto value = singleValueFrom(tryFunc)) {
@@ -10016,7 +10948,7 @@ private:
10016 } 10948 }
10017 if (usage == ExpUsage::Common) { 10949 if (usage == ExpUsage::Common) {
10018 out.back().insert(0, indent()); 10950 out.back().insert(0, indent());
10019 out.back().append(nlr(x)); 10951 out.back().append(nl(x));
10020 } 10952 }
10021 return; 10953 return;
10022 BLOCK_END 10954 BLOCK_END
@@ -10035,13 +10967,13 @@ private:
10035 } 10967 }
10036 if (usage == ExpUsage::Common) { 10968 if (usage == ExpUsage::Common) {
10037 out.back().insert(0, indent()); 10969 out.back().insert(0, indent());
10038 out.back().append(nlr(x)); 10970 out.back().append(nl(x));
10039 } 10971 }
10040 } 10972 }
10041 10973
10042 void transformImportFrom(ImportFrom_t* importNode, str_list& out) { 10974 void transformImportFrom(ImportFrom_t* importNode, str_list& out) {
10043 str_list temp; 10975 str_list temp;
10044 auto x = importNode; 10976 auto x = importNode->item.get();
10045 auto objVar = singleVariableFrom(importNode->item, AccessType::Read); 10977 auto objVar = singleVariableFrom(importNode->item, AccessType::Read);
10046 ast_ptr<false, ExpListAssign_t> objAssign; 10978 ast_ptr<false, ExpListAssign_t> objAssign;
10047 if (objVar.empty()) { 10979 if (objVar.empty()) {
@@ -10111,11 +11043,11 @@ private:
10111 if (objAssign) { 11043 if (objAssign) {
10112 auto preDef = toLocalDecl(transformAssignDefs(expList, DefOp::Mark)); 11044 auto preDef = toLocalDecl(transformAssignDefs(expList, DefOp::Mark));
10113 if (!preDef.empty()) { 11045 if (!preDef.empty()) {
10114 temp.push_back(preDef + nll(importNode)); 11046 temp.push_back(preDef + nl(importNode));
10115 } 11047 }
10116 if (!currentScope().lastStatement) { 11048 if (!currentScope().lastStatement) {
10117 extraScope = true; 11049 extraScope = true;
10118 temp.push_back(indent() + "do"s + nll(importNode)); 11050 temp.push_back(indent() + "do"s + nl(importNode));
10119 pushScope(); 11051 pushScope();
10120 } 11052 }
10121 transformAssignment(objAssign, temp); 11053 transformAssignment(objAssign, temp);
@@ -10127,13 +11059,13 @@ private:
10127 if (objAssign) { 11059 if (objAssign) {
10128 if (extraScope) { 11060 if (extraScope) {
10129 popScope(); 11061 popScope();
10130 temp.push_back(indent() + "end"s + nlr(importNode)); 11062 temp.push_back(indent() + "end"s + nl(importNode));
10131 } 11063 }
10132 } 11064 }
10133 out.push_back(join(temp)); 11065 out.push_back(join(temp));
10134 auto vars = getAssignVars(assignment); 11066 auto vars = getAssignVars(assignment);
10135 for (const auto& var : vars) { 11067 for (const auto& var : vars) {
10136 markVarConst(var); 11068 markVarLocalConst(var);
10137 } 11069 }
10138 } 11070 }
10139 11071
@@ -10361,12 +11293,36 @@ private:
10361 transformAssignment(assignment, out); 11293 transformAssignment(assignment, out);
10362 if (auto var = ast_cast<Variable_t>(target)) { 11294 if (auto var = ast_cast<Variable_t>(target)) {
10363 auto moduleName = variableToString(var); 11295 auto moduleName = variableToString(var);
10364 markVarConst(moduleName); 11296 markVarLocalConst(moduleName);
10365 } else { 11297 } else {
10366 markDestructureConst(assignment); 11298 markDestructureConst(assignment);
10367 } 11299 }
10368 } 11300 }
10369 11301
11302 void transformImportGlobal(ImportGlobal_t* importNode, str_list& out) {
11303 auto uname = static_cast<UnicodeName_t*>(importNode->segs.front());
11304 auto var = _parser.toString(uname);
11305 auto isNormal = _parser.match<Name_t>(var) && _parser.match<Variable_t>(var);
11306 auto varName = unicodeVariableFrom(uname);
11307 str_list temp;
11308 auto it = ++importNode->segs.objects().begin();
11309 for (; it != importNode->segs.objects().end(); ++it) {
11310 temp.emplace_back(_parser.toString(*it));
11311 }
11312 temp.emplace_front(var);
11313 if (isLocal(varName) || !isNormal) {
11314 temp.emplace_front("_G"s);
11315 }
11316 std::string stmt;
11317 if (importNode->target) {
11318 stmt = "const "s + _parser.toString(importNode->target) + '=' + join(temp, "."sv);
11319 } else {
11320 stmt = "const "s + temp.back() + '=' + join(temp, "."sv);
11321 }
11322 auto localAttrib = toAst<LocalAttrib_t>(stmt, importNode);
11323 transformLocalAttrib(localAttrib, out);
11324 }
11325
10370 void transformImport(Import_t* import, str_list& out) { 11326 void transformImport(Import_t* import, str_list& out) {
10371 auto content = import->content.get(); 11327 auto content = import->content.get();
10372 switch (content->get_id()) { 11328 switch (content->get_id()) {
@@ -10379,6 +11335,9 @@ private:
10379 case id<FromImport_t>(): 11335 case id<FromImport_t>():
10380 transformFromImport(static_cast<FromImport_t*>(content), out); 11336 transformFromImport(static_cast<FromImport_t*>(content), out);
10381 break; 11337 break;
11338 case id<ImportGlobal_t>():
11339 transformImportGlobal(static_cast<ImportGlobal_t*>(content), out);
11340 break;
10382 default: YUEE("AST node mismatch", content); break; 11341 default: YUEE("AST node mismatch", content); break;
10383 } 11342 }
10384 } 11343 }
@@ -10390,7 +11349,7 @@ private:
10390 if (expList) { 11349 if (expList) {
10391 if (!currentScope().lastStatement) { 11350 if (!currentScope().lastStatement) {
10392 extraScope = true; 11351 extraScope = true;
10393 temp.push_back(indent() + "do"s + nll(whileNode)); 11352 temp.push_back(indent() + "do"s + nl(whileNode));
10394 pushScope(); 11353 pushScope();
10395 } 11354 }
10396 } 11355 }
@@ -10398,17 +11357,29 @@ private:
10398 addToScope(accumVar); 11357 addToScope(accumVar);
10399 auto lenVar = getUnusedName("_len_"sv); 11358 auto lenVar = getUnusedName("_len_"sv);
10400 addToScope(lenVar); 11359 addToScope(lenVar);
10401 temp.push_back(indent() + "local "s + accumVar + " = { }"s + nll(whileNode)); 11360 auto breakLoopType = getBreakLoopType(whileNode->body, accumVar);
10402 temp.push_back(indent() + "local "s + lenVar + " = 1"s + nll(whileNode)); 11361 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(whileNode);
11362 temp.emplace_back(clearBuf());
11363 _buf << indent() << "local "s << lenVar << " = 1"s << nl(whileNode);
11364 auto& lenAssign = temp.emplace_back(clearBuf());
10403 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 11365 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
10404 auto condStr = transformCondExp(whileNode->condition, isUntil); 11366 auto condStr = transformCondExp(whileNode->condition, isUntil);
10405 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); 11367 temp.push_back(indent() + "while "s + condStr + " do"s + nl(whileNode));
10406 pushScope(); 11368 pushScope();
10407 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); 11369 if (hasBreakWithValue(breakLoopType)) {
10408 auto lenLine = lenVar + " = "s + lenVar + " + 1"s + nlr(whileNode); 11370 lenAssign.clear();
10409 transformLoopBody(whileNode->body, temp, lenLine, ExpUsage::Assignment, assignLeft); 11371 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common);
11372 } else {
11373 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x);
11374 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, whileNode);
11375 assignLeft->followStmt = followStmt.get();
11376 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
11377 if (!assignLeft->followStmtProcessed) {
11378 lenAssign.clear();
11379 }
11380 }
10410 popScope(); 11381 popScope();
10411 temp.push_back(indent() + "end"s + nlr(whileNode)); 11382 temp.push_back(indent() + "end"s + nl(whileNode));
10412 if (expList) { 11383 if (expList) {
10413 auto assign = x->new_ptr<Assign_t>(); 11384 auto assign = x->new_ptr<Assign_t>();
10414 assign->values.push_back(toAst<Exp_t>(accumVar, x)); 11385 assign->values.push_back(toAst<Exp_t>(accumVar, x));
@@ -10418,10 +11389,10 @@ private:
10418 transformAssignment(assignment, temp); 11389 transformAssignment(assignment, temp);
10419 if (extraScope) popScope(); 11390 if (extraScope) popScope();
10420 } else { 11391 } else {
10421 temp.push_back(indent() + "return "s + accumVar + nlr(whileNode)); 11392 temp.push_back(indent() + "return "s + accumVar + nl(whileNode));
10422 } 11393 }
10423 if (expList && extraScope) { 11394 if (expList && extraScope) {
10424 temp.push_back(indent() + "end"s + nlr(whileNode)); 11395 temp.push_back(indent() + "end"s + nl(whileNode));
10425 } 11396 }
10426 out.push_back(join(temp)); 11397 out.push_back(join(temp));
10427 } 11398 }
@@ -10442,20 +11413,31 @@ private:
10442 addToScope(accumVar); 11413 addToScope(accumVar);
10443 auto lenVar = getUnusedName("_len_"sv); 11414 auto lenVar = getUnusedName("_len_"sv);
10444 addToScope(lenVar); 11415 addToScope(lenVar);
10445 temp.push_back(indent() + "local "s + accumVar + " = { }"s + nll(whileNode)); 11416 auto breakLoopType = getBreakLoopType(whileNode->body, accumVar);
10446 temp.push_back(indent() + "local "s + lenVar + " = 1"s + nll(whileNode)); 11417 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(whileNode);
11418 temp.emplace_back(clearBuf());
11419 auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nl(whileNode));
10447 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 11420 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
10448 auto condStr = transformCondExp(whileNode->condition, isUntil); 11421 auto condStr = transformCondExp(whileNode->condition, isUntil);
10449 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); 11422 temp.push_back(indent() + "while "s + condStr + " do"s + nl(whileNode));
10450 pushScope(); 11423 pushScope();
10451 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); 11424 if (hasBreakWithValue(breakLoopType)) {
10452 auto lenLine = lenVar + " = "s + lenVar + " + 1"s + nlr(whileNode); 11425 lenAssign.clear();
10453 transformLoopBody(whileNode->body, temp, lenLine, ExpUsage::Assignment, assignLeft); 11426 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common);
11427 } else {
11428 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x);
11429 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, whileNode);
11430 assignLeft->followStmt = followStmt.get();
11431 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
11432 if (!assignLeft->followStmtProcessed) {
11433 lenAssign.clear();
11434 }
11435 }
10454 popScope(); 11436 popScope();
10455 temp.push_back(indent() + "end"s + nlr(whileNode)); 11437 temp.push_back(indent() + "end"s + nl(whileNode));
10456 temp.push_back(indent() + "return "s + accumVar + nlr(whileNode)); 11438 temp.push_back(indent() + "return "s + accumVar + nl(whileNode));
10457 popScope(); 11439 popScope();
10458 funcStart = anonFuncStart() + nll(whileNode); 11440 funcStart = anonFuncStart() + nl(whileNode);
10459 temp.push_back(indent() + anonFuncEnd()); 11441 temp.push_back(indent() + anonFuncEnd());
10460 popAnonVarArg(); 11442 popAnonVarArg();
10461 popFunctionScope(); 11443 popFunctionScope();
@@ -10485,9 +11467,7 @@ private:
10485 expListAssign->expList.set(expList); 11467 expListAssign->expList.set(expList);
10486 auto stmt = x->new_ptr<Statement_t>(); 11468 auto stmt = x->new_ptr<Statement_t>();
10487 stmt->content.set(expListAssign); 11469 stmt->content.set(expListAssign);
10488 auto body = x->new_ptr<Body_t>(); 11470 repeat->body.set(stmt);
10489 body->content.set(stmt);
10490 repeat->body.set(body);
10491 transformRepeat(repeat, out); 11471 transformRepeat(repeat, out);
10492 return; 11472 return;
10493 } 11473 }
@@ -10495,14 +11475,115 @@ private:
10495 pushScope(); 11475 pushScope();
10496 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 11476 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
10497 auto condStr = transformCondExp(whileNode->condition, isUntil); 11477 auto condStr = transformCondExp(whileNode->condition, isUntil);
10498 transformLoopBody(whileNode->body, temp, Empty, ExpUsage::Common); 11478 auto breakLoopType = getBreakLoopType(whileNode->body, Empty);
11479 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common);
10499 popScope(); 11480 popScope();
10500 _buf << indent() << "while "sv << condStr << " do"sv << nll(whileNode); 11481 _buf << indent() << "while "sv << condStr << " do"sv << nl(whileNode);
10501 _buf << temp.back(); 11482 _buf << temp.back();
10502 _buf << indent() << "end"sv << nlr(whileNode); 11483 _buf << indent() << "end"sv << nl(whileNode);
10503 out.push_back(clearBuf()); 11484 out.push_back(clearBuf());
10504 } 11485 }
10505 11486
11487 void transformRepeatInPlace(Repeat_t* repeatNode, str_list& out, ExpList_t* expList = nullptr) {
11488 auto x = repeatNode;
11489 str_list temp;
11490 bool extraScope = false;
11491 if (expList) {
11492 if (!currentScope().lastStatement) {
11493 extraScope = true;
11494 temp.push_back(indent() + "do"s + nl(repeatNode));
11495 pushScope();
11496 }
11497 }
11498 auto accumVar = getUnusedName("_accum_"sv);
11499 addToScope(accumVar);
11500 auto lenVar = getUnusedName("_len_"sv);
11501 addToScope(lenVar);
11502 auto breakLoopType = getBreakLoopType(repeatNode->body, accumVar);
11503 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(repeatNode);
11504 temp.emplace_back(clearBuf());
11505 _buf << indent() << "local "s << lenVar << " = 1"s << nl(repeatNode);
11506 auto& lenAssign = temp.emplace_back(clearBuf());
11507 auto condStr = transformCondExp(repeatNode->condition, false);
11508 temp.push_back(indent() + "repeat"s + nl(repeatNode));
11509 pushScope();
11510 if (hasBreakWithValue(breakLoopType)) {
11511 lenAssign.clear();
11512 transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Common);
11513 } else {
11514 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x);
11515 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, repeatNode);
11516 assignLeft->followStmt = followStmt.get();
11517 transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
11518 if (!assignLeft->followStmtProcessed) {
11519 lenAssign.clear();
11520 }
11521 }
11522 popScope();
11523 temp.push_back(indent() + "until "s + condStr + nl(repeatNode));
11524 if (expList) {
11525 auto assign = x->new_ptr<Assign_t>();
11526 assign->values.push_back(toAst<Exp_t>(accumVar, x));
11527 auto assignment = x->new_ptr<ExpListAssign_t>();
11528 assignment->expList.set(expList);
11529 assignment->action.set(assign);
11530 transformAssignment(assignment, temp);
11531 if (extraScope) popScope();
11532 } else {
11533 temp.push_back(indent() + "return "s + accumVar + nl(repeatNode));
11534 }
11535 if (expList && extraScope) {
11536 temp.push_back(indent() + "end"s + nl(repeatNode));
11537 }
11538 out.push_back(join(temp));
11539 }
11540
11541 void transformRepeatClosure(Repeat_t* repeatNode, str_list& out) {
11542 auto x = repeatNode;
11543 auto simpleValue = x->new_ptr<SimpleValue_t>();
11544 simpleValue->value.set(repeatNode);
11545 if (transformAsUpValueFunc(newExp(simpleValue, x), out)) {
11546 return;
11547 }
11548 str_list temp;
11549 pushAnonFunctionScope();
11550 pushAnonVarArg();
11551 std::string& funcStart = temp.emplace_back();
11552 pushScope();
11553 auto accumVar = getUnusedName("_accum_"sv);
11554 addToScope(accumVar);
11555 auto lenVar = getUnusedName("_len_"sv);
11556 addToScope(lenVar);
11557 auto breakLoopType = getBreakLoopType(repeatNode->body, accumVar);
11558 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(repeatNode);
11559 temp.emplace_back(clearBuf());
11560 auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nl(repeatNode));
11561 auto condStr = transformCondExp(repeatNode->condition, false);
11562 temp.push_back(indent() + "repeat"s + nl(repeatNode));
11563 pushScope();
11564 if (hasBreakWithValue(breakLoopType)) {
11565 lenAssign.clear();
11566 transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Common);
11567 } else {
11568 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x);
11569 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, repeatNode);
11570 assignLeft->followStmt = followStmt.get();
11571 transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
11572 if (!assignLeft->followStmtProcessed) {
11573 lenAssign.clear();
11574 }
11575 }
11576 popScope();
11577 temp.push_back(indent() + "until "s + condStr + nl(repeatNode));
11578 temp.push_back(indent() + "return "s + accumVar + nl(repeatNode));
11579 popScope();
11580 funcStart = anonFuncStart() + nl(repeatNode);
11581 temp.push_back(indent() + anonFuncEnd());
11582 popAnonVarArg();
11583 popFunctionScope();
11584 out.push_back(join(temp));
11585 }
11586
10506 void transformRepeat(Repeat_t* repeat, str_list& out) { 11587 void transformRepeat(Repeat_t* repeat, str_list& out) {
10507 str_list temp; 11588 str_list temp;
10508 pushScope(); 11589 pushScope();
@@ -10513,9 +11594,9 @@ private:
10513 temp.push_back(condVar); 11594 temp.push_back(condVar);
10514 } 11595 }
10515 popScope(); 11596 popScope();
10516 _buf << indent() << "repeat"sv << nll(repeat); 11597 _buf << indent() << "repeat"sv << nl(repeat);
10517 _buf << temp.front(); 11598 _buf << temp.front();
10518 _buf << indent() << "until "sv << temp.back() << nlr(repeat); 11599 _buf << indent() << "until "sv << temp.back() << nl(repeat);
10519 out.push_back(clearBuf()); 11600 out.push_back(clearBuf());
10520 } 11601 }
10521 11602
@@ -10536,12 +11617,28 @@ private:
10536 pushScope(); 11617 pushScope();
10537 } 11618 }
10538 bool extraScope = false; 11619 bool extraScope = false;
11620 if (switchNode->assignment) {
11621 if (needScope) {
11622 extraScope = true;
11623 temp.push_back(indent() + "do"s + nl(x));
11624 pushScope();
11625 }
11626 auto asmt = x->new_ptr<ExpListAssign_t>();
11627 auto expList = x->new_ptr<ExpList_t>();
11628 expList->exprs.push_back(switchNode->target);
11629 if (switchNode->assignment->expList) {
11630 expList->exprs.dup(switchNode->assignment->expList->exprs);
11631 }
11632 asmt->expList.set(expList);
11633 asmt->action.set(switchNode->assignment->assign);
11634 transformAssignment(asmt, temp);
11635 }
10539 auto objVar = singleVariableFrom(switchNode->target, AccessType::Read); 11636 auto objVar = singleVariableFrom(switchNode->target, AccessType::Read);
10540 if (objVar.empty() || !isLocal(objVar)) { 11637 if (objVar.empty() || !isLocal(objVar)) {
10541 if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) { 11638 if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) {
10542 if (needScope) { 11639 if (needScope && !extraScope) {
10543 extraScope = true; 11640 extraScope = true;
10544 temp.push_back(indent() + "do"s + nll(x)); 11641 temp.push_back(indent() + "do"s + nl(x));
10545 pushScope(); 11642 pushScope();
10546 } 11643 }
10547 } 11644 }
@@ -10571,13 +11668,13 @@ private:
10571 } 11668 }
10572 if (tableMatching) { 11669 if (tableMatching) {
10573 if (!firstBranch) { 11670 if (!firstBranch) {
10574 temp.push_back(indent() + "else"s + nll(branch)); 11671 temp.push_back(indent() + "else"s + nl(branch));
10575 pushScope(); 11672 pushScope();
10576 addScope++; 11673 addScope++;
10577 } 11674 }
10578 if (tabCheckVar.empty()) { 11675 if (tabCheckVar.empty()) {
10579 if (!extraScope && needScope) { 11676 if (!extraScope && needScope) {
10580 temp.push_back(indent() + "do"s + nll(branch)); 11677 temp.push_back(indent() + "do"s + nl(branch));
10581 pushScope(); 11678 pushScope();
10582 extraScope = true; 11679 extraScope = true;
10583 } 11680 }
@@ -10585,20 +11682,21 @@ private:
10585 forceAddToScope(typeVar); 11682 forceAddToScope(typeVar);
10586 tabCheckVar = getUnusedName("_tab_"sv); 11683 tabCheckVar = getUnusedName("_tab_"sv);
10587 forceAddToScope(tabCheckVar); 11684 forceAddToScope(tabCheckVar);
10588 temp.push_back(indent() + "local "s + typeVar + " = "s + globalVar("type"sv, branch, AccessType::Read) + '(' + objVar + ')' + nll(branch)); 11685 temp.push_back(indent() + "local "s + typeVar + " = "s + globalVar("type"sv, branch, AccessType::Read) + '(' + objVar + ')' + nl(branch));
10589 temp.push_back(indent() + "local "s + tabCheckVar + " = \"table\" == "s + typeVar + " or \"userdata\" == "s + typeVar + nll(branch)); 11686 temp.push_back(indent() + "local "s + tabCheckVar + " = \"table\" == "s + typeVar + " or \"userdata\" == "s + typeVar + nl(branch));
10590 } 11687 }
10591 std::string matchVar; 11688 std::string matchVar;
10592 bool lastBranch = branches.back() == branch_ && !switchNode->lastBranch; 11689 bool lastBranch = branches.back() == branch_ && !switchNode->lastBranch;
10593 if (!lastBranch) { 11690 if (!lastBranch) {
10594 matchVar = getUnusedName("_match_"sv); 11691 matchVar = getUnusedName("_match_"sv);
10595 forceAddToScope(matchVar); 11692 forceAddToScope(matchVar);
10596 temp.push_back(indent() + "local "s + matchVar + " = false"s + nll(branch)); 11693 temp.push_back(indent() + "local "s + matchVar + " = false"s + nl(branch));
10597 } 11694 }
10598 temp.back().append(indent() + "if "s + tabCheckVar + " then"s + nll(branch)); 11695 temp.back().append(indent() + "if "s + tabCheckVar + " then"s + nl(branch));
10599 pushScope(); 11696 pushScope();
10600 auto assignment = assignmentFrom(static_cast<Exp_t*>(valueList->exprs.front()), toAst<Exp_t>(objVar, branch), branch); 11697 auto chainValue = toAst<ChainValue_t>(objVar, branch);
10601 auto info = extractDestructureInfo(assignment, true, false); 11698 auto assignment = assignmentFrom(static_cast<Exp_t*>(valueList->exprs.front()), newExp(chainValue, branch), branch);
11699 auto info = extractDestructureInfo(assignment, true, true);
10602 transformAssignment(assignment, temp, true); 11700 transformAssignment(assignment, temp, true);
10603 str_list conds; 11701 str_list conds;
10604 for (const auto& des : info.destructures) { 11702 for (const auto& des : info.destructures) {
@@ -10608,27 +11706,50 @@ private:
10608 const auto& destruct = std::get<Destructure>(des); 11706 const auto& destruct = std::get<Destructure>(des);
10609 for (const auto& item : destruct.items) { 11707 for (const auto& item : destruct.items) {
10610 if (!item.defVal) { 11708 if (!item.defVal) {
10611 transformExp(item.target, conds, ExpUsage::Closure); 11709 if (!isAssignable(item.target)) {
10612 conds.back().append(" ~= nil"s); 11710 auto callable = chainValue->items.front();
11711 auto chain = callable->new_ptr<ChainValue_t>();
11712 chain->items.push_back(callable);
11713 chain->items.dup(item.structure->items);
11714 if (specialChainValue(chain) == ChainType::Common) {
11715 transformChainValue(chain, conds, ExpUsage::Closure);
11716 auto vStr = conds.back();
11717 conds.pop_back();
11718 transformExp(item.target, conds, ExpUsage::Closure);
11719 conds.back().append(" == "s);
11720 conds.back().append(vStr);
11721 } else {
11722 auto varName = getUnusedName("_val_"sv);
11723 auto vExp = toAst<Exp_t>(varName, chain);
11724 auto asmt = assignmentFrom(vExp, newExp(chain, chain), chain);
11725 transformAssignment(asmt, temp);
11726 transformExp(item.target, conds, ExpUsage::Closure);
11727 conds.back().append(" == "s);
11728 conds.back().append(varName);
11729 }
11730 } else {
11731 transformExp(item.target, conds, ExpUsage::Closure);
11732 conds.back().append(" ~= nil"s);
11733 }
10613 } 11734 }
10614 } 11735 }
10615 } 11736 }
10616 if (!conds.empty()) { 11737 if (!conds.empty()) {
10617 temp.push_back(indent() + "if "s + join(conds, " and "sv) + " then"s + nll(branch)); 11738 temp.push_back(indent() + "if "s + join(conds, " and "sv) + " then"s + nl(branch));
10618 pushScope(); 11739 pushScope();
10619 } 11740 }
10620 if (!lastBranch) { 11741 if (!lastBranch) {
10621 temp.push_back(indent() + matchVar + " = true"s + nll(branch)); 11742 temp.push_back(indent() + matchVar + " = true"s + nl(branch));
10622 } 11743 }
10623 transform_plain_body(branch->body, temp, usage, assignList); 11744 transform_plain_body(branch->body, temp, usage, assignList);
10624 if (!conds.empty()) { 11745 if (!conds.empty()) {
10625 popScope(); 11746 popScope();
10626 temp.push_back(indent() + "end"s + nll(branch)); 11747 temp.push_back(indent() + "end"s + nl(branch));
10627 } 11748 }
10628 if (!lastBranch) { 11749 if (!lastBranch) {
10629 popScope(); 11750 popScope();
10630 temp.push_back(indent() + "end"s + nll(branch)); 11751 temp.push_back(indent() + "end"s + nl(branch));
10631 temp.push_back(indent() + "if not "s + matchVar + " then"s + nll(branch)); 11752 temp.push_back(indent() + "if not "s + matchVar + " then"s + nl(branch));
10632 pushScope(); 11753 pushScope();
10633 addScope++; 11754 addScope++;
10634 } else { 11755 } else {
@@ -10648,7 +11769,7 @@ private:
10648 } 11769 }
10649 temp.back().append(' ' + tmp.back() + " == "s + (exp == exprs.back() ? objVar : objVar + " or"s)); 11770 temp.back().append(' ' + tmp.back() + " == "s + (exp == exprs.back() ? objVar : objVar + " or"s));
10650 } 11771 }
10651 temp.back().append(" then"s + nll(branch)); 11772 temp.back().append(" then"s + nl(branch));
10652 pushScope(); 11773 pushScope();
10653 transform_plain_body(branch->body, temp, usage, assignList); 11774 transform_plain_body(branch->body, temp, usage, assignList);
10654 popScope(); 11775 popScope();
@@ -10656,7 +11777,7 @@ private:
10656 } 11777 }
10657 if (switchNode->lastBranch) { 11778 if (switchNode->lastBranch) {
10658 if (!firstBranch) { 11779 if (!firstBranch) {
10659 temp.push_back(indent() + "else"s + nll(switchNode->lastBranch)); 11780 temp.push_back(indent() + "else"s + nl(switchNode->lastBranch));
10660 pushScope(); 11781 pushScope();
10661 } else { 11782 } else {
10662 addScope--; 11783 addScope--;
@@ -10666,20 +11787,20 @@ private:
10666 } 11787 }
10667 while (addScope > 0) { 11788 while (addScope > 0) {
10668 addScope--; 11789 addScope--;
10669 temp.push_back(indent() + "end"s + nlr(switchNode)); 11790 temp.push_back(indent() + "end"s + nl(switchNode));
10670 popScope(); 11791 popScope();
10671 } 11792 }
10672 temp.push_back(indent() + "end"s + nlr(switchNode)); 11793 temp.push_back(indent() + "end"s + nl(switchNode));
10673 if (usage == ExpUsage::Closure) { 11794 if (usage == ExpUsage::Closure) {
10674 popFunctionScope(); 11795 popFunctionScope();
10675 popScope(); 11796 popScope();
10676 *funcStart = anonFuncStart() + nll(switchNode); 11797 *funcStart = anonFuncStart() + nl(switchNode);
10677 temp.push_back(indent() + anonFuncEnd()); 11798 temp.push_back(indent() + anonFuncEnd());
10678 popAnonVarArg(); 11799 popAnonVarArg();
10679 } 11800 }
10680 if (extraScope) { 11801 if (extraScope) {
10681 popScope(); 11802 popScope();
10682 temp.push_back(indent() + "end"s + nlr(switchNode)); 11803 temp.push_back(indent() + "end"s + nl(switchNode));
10683 } 11804 }
10684 out.push_back(join(temp)); 11805 out.push_back(join(temp));
10685 } 11806 }
@@ -10698,7 +11819,7 @@ private:
10698 } 11819 }
10699 auto preDefine = toLocalDecl(defs); 11820 auto preDefine = toLocalDecl(defs);
10700 if (!preDefine.empty()) { 11821 if (!preDefine.empty()) {
10701 out.push_back(preDefine + nll(local)); 11822 out.push_back(preDefine + nl(local));
10702 } 11823 }
10703 } 11824 }
10704 } 11825 }
@@ -10727,8 +11848,8 @@ private:
10727 auto assignment = x->new_ptr<ExpListAssign_t>(); 11848 auto assignment = x->new_ptr<ExpListAssign_t>();
10728 assignment->expList.set(expList); 11849 assignment->expList.set(expList);
10729 auto assign = x->new_ptr<Assign_t>(); 11850 auto assign = x->new_ptr<Assign_t>();
10730 if (auto expListLow = values->valueList.as<ExpListLow_t>()) { 11851 if (auto expList = values->valueList.as<ExpList_t>()) {
10731 assign->values.dup(expListLow->exprs); 11852 assign->values.dup(expList->exprs);
10732 } else { 11853 } else {
10733 auto tableBlock = values->valueList.to<TableBlock_t>(); 11854 auto tableBlock = values->valueList.to<TableBlock_t>();
10734 assign->values.push_back(tableBlock); 11855 assign->values.push_back(tableBlock);
@@ -10736,7 +11857,7 @@ private:
10736 assignment->action.set(assign); 11857 assignment->action.set(assign);
10737 bool oneLined = transformAssignment(assignment, temp); 11858 bool oneLined = transformAssignment(assignment, temp);
10738 for (auto val : assign->values.objects()) { 11859 for (auto val : assign->values.objects()) {
10739 if (auto value = singleValueFrom(val)) { 11860 if (auto value = singleValueFrom(val, true)) {
10740 if (auto spValue = value->item.as<SimpleValue_t>()) { 11861 if (auto spValue = value->item.as<SimpleValue_t>()) {
10741 if (auto funLit = spValue->value.as<FunLit_t>()) { 11862 if (auto funLit = spValue->value.as<FunLit_t>()) {
10742 if (!funLit->noRecursion) { 11863 if (!funLit->noRecursion) {
@@ -10903,11 +12024,11 @@ private:
10903 } 12024 }
10904 str_list temp; 12025 str_list temp;
10905 if (localAttrib->forceLocal) { 12026 if (localAttrib->forceLocal) {
10906 temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x)); 12027 temp.push_back(indent() + "local "s + join(vars, ", "sv) + nl(x));
10907 } 12028 }
10908 transformAssignment(assignment, temp); 12029 transformAssignment(assignment, temp);
10909 for (const auto& name : vars) { 12030 for (const auto& name : vars) {
10910 markVarConst(name); 12031 markVarLocalConst(name);
10911 } 12032 }
10912 if (localAttrib->attrib.is<CloseAttrib_t>()) { 12033 if (localAttrib->attrib.is<CloseAttrib_t>()) {
10913 str_list leftVars, rightVars; 12034 str_list leftVars, rightVars;
@@ -10949,13 +12070,13 @@ private:
10949 auto rit = items.begin(); 12070 auto rit = items.begin();
10950 str_list tmp; 12071 str_list tmp;
10951 while (lit != vars.end()) { 12072 while (lit != vars.end()) {
10952 tmp.push_back(indent() + "local "s + *lit + (target >= 504 ? " <close> = "s : " = "s) + *rit + nll(x)); 12073 tmp.push_back(indent() + "local "s + *lit + (target >= 504 ? " <close> = "s : " = "s) + *rit + nl(x));
10953 lit++; 12074 lit++;
10954 rit++; 12075 rit++;
10955 } 12076 }
10956 temp.push_back(join(tmp)); 12077 temp.push_back(join(tmp));
10957 } else { 12078 } else {
10958 temp.push_back(indent() + "local "s + join(vars, ", "sv) + " = "s + join(items, ", "sv) + nll(x)); 12079 temp.push_back(indent() + "local "s + join(vars, ", "sv) + " = "s + join(items, ", "sv) + nl(x));
10959 str_list leftVars; 12080 str_list leftVars;
10960 pushScope(); 12081 pushScope();
10961 for (size_t i = 0; i < vars.size(); i++) { 12082 for (size_t i = 0; i < vars.size(); i++) {
@@ -10976,10 +12097,10 @@ private:
10976 for (auto item : assignA->values.objects()) { 12097 for (auto item : assignA->values.objects()) {
10977 transformAssignItem(item, items); 12098 transformAssignItem(item, items);
10978 } 12099 }
10979 temp.push_back(indent() + "local "s + join(leftVars, ", "sv) + " = "s + join(items, ", "sv) + nll(x)); 12100 temp.push_back(indent() + "local "s + join(leftVars, ", "sv) + " = "s + join(items, ", "sv) + nl(x));
10980 } 12101 }
10981 for (const auto& var : vars) { 12102 for (const auto& var : vars) {
10982 markVarConst(var); 12103 markVarLocalConst(var);
10983 } 12104 }
10984 } 12105 }
10985 if (!listB->exprs.empty()) { 12106 if (!listB->exprs.empty()) {
@@ -11001,22 +12122,28 @@ private:
11001 vars.push_back(item.targetVar); 12122 vars.push_back(item.targetVar);
11002 } 12123 }
11003 } 12124 }
11004 temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x)); 12125 temp.push_back(indent() + "local "s + join(vars, ", "sv) + nl(x));
11005 transformAssignment(assignment, temp); 12126 transformAssignment(assignment, temp);
11006 for (const auto& name : vars) { 12127 for (const auto& name : vars) {
11007 markVarConst(name); 12128 markVarLocalConst(name);
11008 } 12129 }
11009 } 12130 }
11010 out.push_back(join(temp)); 12131 out.push_back(join(temp));
11011 } 12132 }
11012 12133
11013 void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) { 12134 void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) {
11014 auto keyword = _parser.toString(breakLoop); 12135 auto isBreak = breakLoop->type.is<Break_t>();
12136 auto keyword = isBreak ? "break"s : "continue"s;
11015 if (_enableBreakLoop.empty() || !_enableBreakLoop.top()) { 12137 if (_enableBreakLoop.empty() || !_enableBreakLoop.top()) {
11016 throw CompileError(keyword + " is not inside a loop"s, breakLoop); 12138 throw CompileError(keyword + " is not inside a loop"s, breakLoop);
11017 } 12139 }
11018 if (keyword == "break"sv) { 12140 if (isBreak) {
11019 out.push_back(indent() + keyword + nll(breakLoop)); 12141 if (breakLoop->value) {
12142 auto exp = toAst<Exp_t>(breakLoop->varBWV, breakLoop->value);
12143 auto assignment = assignmentFrom(exp, breakLoop->value, breakLoop);
12144 transformAssignment(assignment, out);
12145 }
12146 out.push_back(indent() + keyword + nl(breakLoop));
11020 return; 12147 return;
11021 } 12148 }
11022 if (_continueVars.empty()) throw CompileError("continue is not inside a loop"sv, breakLoop); 12149 if (_continueVars.empty()) throw CompileError("continue is not inside a loop"sv, breakLoop);
@@ -11029,8 +12156,8 @@ private:
11029 if (!temp.empty()) { 12156 if (!temp.empty()) {
11030 _buf << temp.back(); 12157 _buf << temp.back();
11031 } 12158 }
11032 _buf << indent() << item.var << " = true"sv << nll(breakLoop); 12159 _buf << indent() << item.var << " = true"sv << nl(breakLoop);
11033 _buf << indent() << "break"sv << nll(breakLoop); 12160 _buf << indent() << "break"sv << nl(breakLoop);
11034 out.push_back(clearBuf()); 12161 out.push_back(clearBuf());
11035 } else { 12162 } else {
11036 transformGoto(toAst<Goto_t>("goto "s + item.var, breakLoop), temp); 12163 transformGoto(toAst<Goto_t>("goto "s + item.var, breakLoop), temp);
@@ -11042,7 +12169,7 @@ private:
11042 if (getLuaTarget(label) < 502) { 12169 if (getLuaTarget(label) < 502) {
11043 throw CompileError("label statement is not available when not targeting Lua version 5.2 or higher"sv, label); 12170 throw CompileError("label statement is not available when not targeting Lua version 5.2 or higher"sv, label);
11044 } 12171 }
11045 auto labelStr = unicodeVariableFrom(label->label->name); 12172 auto labelStr = unicodeVariableFrom(label->label);
11046 int currentScope = _gotoScopes.top(); 12173 int currentScope = _gotoScopes.top();
11047 if (static_cast<int>(_labels.size()) <= currentScope) { 12174 if (static_cast<int>(_labels.size()) <= currentScope) {
11048 _labels.resize(currentScope + 1, std::nullopt); 12175 _labels.resize(currentScope + 1, std::nullopt);
@@ -11056,16 +12183,16 @@ private:
11056 throw CompileError("label '"s + labelStr + "' already defined at line "s + std::to_string(it->second.line), label); 12183 throw CompileError("label '"s + labelStr + "' already defined at line "s + std::to_string(it->second.line), label);
11057 } 12184 }
11058 scope[labelStr] = {label->m_begin.m_line, static_cast<int>(_scopes.size())}; 12185 scope[labelStr] = {label->m_begin.m_line, static_cast<int>(_scopes.size())};
11059 out.push_back(indent() + "::"s + labelStr + "::"s + nll(label)); 12186 out.push_back(indent() + "::"s + labelStr + "::"s + nl(label));
11060 } 12187 }
11061 12188
11062 void transformGoto(Goto_t* gotoNode, str_list& out) { 12189 void transformGoto(Goto_t* gotoNode, str_list& out) {
11063 if (getLuaTarget(gotoNode) < 502) { 12190 if (getLuaTarget(gotoNode) < 502) {
11064 throw CompileError("goto statement is not available when not targeting Lua version 5.2 or higher"sv, gotoNode); 12191 throw CompileError("goto statement is not available when not targeting Lua version 5.2 or higher"sv, gotoNode);
11065 } 12192 }
11066 auto labelStr = unicodeVariableFrom(gotoNode->label->name); 12193 auto labelStr = unicodeVariableFrom(gotoNode->label);
11067 gotos.push_back({gotoNode, labelStr, _gotoScopes.top(), static_cast<int>(_scopes.size())}); 12194 gotos.push_back({gotoNode, labelStr, _gotoScopes.top(), static_cast<int>(_scopes.size())});
11068 out.push_back(indent() + "goto "s + labelStr + nll(gotoNode)); 12195 out.push_back(indent() + "goto "s + labelStr + nl(gotoNode));
11069 } 12196 }
11070 12197
11071 void transformShortTabAppending(ShortTabAppending_t* tab, str_list& out) { 12198 void transformShortTabAppending(ShortTabAppending_t* tab, str_list& out) {
@@ -11129,13 +12256,13 @@ private:
11129 temp.push_back(getPreDefineLine(assignment)); 12256 temp.push_back(getPreDefineLine(assignment));
11130 } 12257 }
11131 assignments.push_front(assignmentFrom(newValue, value, value)); 12258 assignments.push_front(assignmentFrom(newValue, value, value));
11132 temp.push_back(indent() + "do"s + nll(x)); 12259 temp.push_back(indent() + "do"s + nl(x));
11133 pushScope(); 12260 pushScope();
11134 for (auto item : assignments.objects()) { 12261 for (auto item : assignments.objects()) {
11135 transformAssignment(static_cast<ExpListAssign_t*>(item), temp); 12262 transformAssignment(static_cast<ExpListAssign_t*>(item), temp);
11136 } 12263 }
11137 popScope(); 12264 popScope();
11138 temp.push_back(indent() + "end"s + nll(x)); 12265 temp.push_back(indent() + "end"s + nl(x));
11139 out.push_back(join(temp)); 12266 out.push_back(join(temp));
11140 } 12267 }
11141}; 12268};
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
3Permission 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: 3Permission 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
56using GlobalVars = std::vector<GlobalVar>; 58using GlobalVars = std::vector<GlobalVar>;
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp
index 77c5901..f564f6a 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
3Permission 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: 3Permission 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
45YueParser::YueParser() { 63YueParser::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
106 invalid_interpolation_error = pl::user(true_(), [](const item_t& item) {
107 throw ParserError("invalid string interpolation"sv, item.begin);
108 return false;
109 });
110
111 confusing_unary_not_error = pl::user(true_(), [](const item_t& item) {
112 throw ParserError("deprecated use for unary operator 'not' to be here"sv, item.begin);
113 return false;
114 });
115
116 table_key_pair_error = pl::user(true_(), [](const item_t& item) {
117 throw ParserError("can not put hash pair in a list"sv, item.begin);
118 return false;
119 });
120 123
121 if_assignment_syntax_error = pl::user(true_(), [](const item_t& item) { 124 empty_block_error = expect_error(
122 throw ParserError("use := for if-assignment expression"sv, item.begin); 125 "expected a valid statement or indented block"sv
123 return false; 126 );
124 }); 127 export_expression_error = expect_error(
128 "invalid export expression"sv
129 );
130 invalid_interpolation_error = expect_error(
131 "invalid string interpolation"sv
132 );
133 confusing_unary_not_error = expect_error(
134 "deprecated use for unary operator 'not' to be here"sv
135 );
136 table_key_pair_error = expect_error(
137 "can not put hash pair in a list"sv
138 );
139 assignment_expression_syntax_error = expect_error(
140 "use := for assignment expression"sv
141 );
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 | ExpList | 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,28 +453,41 @@ 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);
466
467 ImportAllGlobal = key("global");
344 468
345 Import = key("import") >> space >> (ImportAs | ImportFrom) | FromImport; 469 Import = key("import") >> space >> (ImportAllGlobal | ImportGlobal | ImportAs | ImportFrom | invalid_import_syntax_error) | FromImport;
346 470
347 Label = "::" >> LabelName >> "::"; 471 Label = "::" >> (and_(LuaKeyword >> "::") >> keyword_as_label_error | UnicodeName >> "::");
348 472
349 Goto = key("goto") >> space >> LabelName; 473 Goto = key("goto") >> space >> (and_(LuaKeyword >> not_alpha_num) >> keyword_as_label_error | UnicodeName);
350 474
351 ShortTabAppending = "[]" >> space >> Assign; 475 ShortTabAppending = "[]" >> space >> Assign;
352 476
353 BreakLoop = (expr("break") | "continue") >> not_alpha_num; 477 Break = key("break");
478 Continue = key("continue");
479 BreakLoop = (Break >> -(space >> Exp) | Continue) >> not_alpha_num;
354 480
355 Return = key("return") >> -(space >> (TableBlock | ExpListLow)); 481 Return = key("return") >> -(space >> (TableBlock | ExpList));
356 482
357 with_exp = ExpList >> -(space >> Assign); 483 must_exp = Exp | expected_expression_error;
358 484
359 With = key("with") >> -ExistentialOp >> space >> disable_do_chain_arg_table_block_rule(with_exp) >> space >> body_with("do"); 485 with_exp = ExpList >> -(space >> (':' >> Assign | and_('=') >> assignment_expression_syntax_error)) | expected_expression_error;
486
487 With = key("with") >> -ExistentialOp >> space >> (
488 disable_do_chain_arg_table_block_rule(with_exp) >> space >> body_with("do") |
489 invalid_with_syntax_error
490 );
360 SwitchCase = key("when") >> space >> disable_chain_rule(disable_arg_table_block_rule(SwitchList)) >> space >> body_with("then"); 491 SwitchCase = key("when") >> space >> disable_chain_rule(disable_arg_table_block_rule(SwitchList)) >> space >> body_with("then");
361 switch_else = key("else") >> space >> body; 492 switch_else = key("else") >> space >> body;
362 493
@@ -368,9 +499,11 @@ YueParser::YueParser() {
368 499
369 SwitchList = Seperator >> ( 500 SwitchList = Seperator >> (
370 and_(SimpleTable | TableLit) >> Exp | 501 and_(SimpleTable | TableLit) >> Exp |
371 exp_not_tab >> *(space >> ',' >> space >> exp_not_tab) 502 exp_not_tab >> *(space >> ',' >> space >> exp_not_tab) |
503 expected_expression_error
372 ); 504 );
373 Switch = key("switch") >> space >> Exp >> 505 Switch = key("switch") >> space >>
506 must_exp >> -(space >> Assignment) >>
374 space >> Seperator >> ( 507 space >> Seperator >> (
375 SwitchCase >> space >> ( 508 SwitchCase >> space >> (
376 switch_block | 509 switch_block |
@@ -379,45 +512,53 @@ YueParser::YueParser() {
379 +space_break >> advance_match >> space >> SwitchCase >> switch_block >> pop_indent 512 +space_break >> advance_match >> space >> SwitchCase >> switch_block >> pop_indent
380 ); 513 );
381 514
382 Assignment = -(',' >> space >> ExpList >> space) >> (':' >> Assign | and_('=') >> if_assignment_syntax_error); 515 Assignment = -(',' >> space >> ExpList >> space) >> (':' >> Assign | and_('=') >> assignment_expression_syntax_error);
383 IfCond = disable_chain_rule(disable_arg_table_block_rule(Exp >> -(space >> Assignment))); 516 IfCond = disable_chain_rule(disable_arg_table_block_rule(Exp >> -(space >> Assignment))) | expected_expression_error;
384 if_else_if = -(line_break >> *space_break >> check_indent_match) >> space >> key("elseif") >> space >> IfCond >> space >> body_with("then"); 517 if_else_if = -(line_break >> *space_break >> check_indent_match) >> space >> key("elseif") >> space >> IfCond >> space >> body_with("then");
385 if_else = -(line_break >> *space_break >> check_indent_match) >> space >> key("else") >> space >> body; 518 if_else = -(line_break >> *space_break >> check_indent_match) >> space >> key("else") >> space >> body;
386 IfType = (expr("if") | "unless") >> not_alpha_num; 519 IfType = (expr("if") | "unless") >> not_alpha_num;
387 If = IfType >> space >> IfCond >> space >> opt_body_with("then") >> *if_else_if >> -if_else; 520 If = IfType >> space >> IfCond >> space >> opt_body_with("then") >> *if_else_if >> -if_else;
388 521
389 WhileType = (expr("while") | "until") >> not_alpha_num; 522 WhileType = (expr("while") | pl::user("until", [](const item_t& item) {
390 While = WhileType >> space >> disable_do_chain_arg_table_block_rule(Exp >> -(space >> Assignment)) >> space >> opt_body_with("do"); 523 State* st = reinterpret_cast<State*>(item.user_data);
391 Repeat = key("repeat") >> space >> Body >> line_break >> *space_break >> check_indent_match >> space >> key("until") >> space >> Exp; 524 return st->noUntilStack.empty() || !st->noUntilStack.back();
525 })) >> not_alpha_num;
526 While = key(WhileType) >> space >> (disable_do_chain_arg_table_block_rule(Exp >> -(space >> Assignment)) | expected_expression_error) >> space >> opt_body_with("do");
527 Repeat = key("repeat") >> space >> (
528 in_block >> line_break >> *space_break >> check_indent_match |
529 disable_until_rule(Statement)
530 ) >> space >> key("until") >> space >> must_exp;
392 531
393 for_key = pl::user(key("for"), [](const item_t& item) { 532 for_key = pl::user(key("for"), [](const item_t& item) {
394 State* st = reinterpret_cast<State*>(item.user_data); 533 State* st = reinterpret_cast<State*>(item.user_data);
395 return st->noForStack.empty() || !st->noForStack.top(); 534 return st->noForStack.empty() || !st->noForStack.back();
396 }); 535 });
397 ForStepValue = ',' >> space >> Exp; 536 ForStepValue = ',' >> space >> must_exp;
398 for_args = Variable >> space >> '=' >> space >> Exp >> space >> ',' >> space >> Exp >> space >> -ForStepValue; 537 for_args = Variable >> space >> '=' >> space >> must_exp >> space >> ',' >> space >> must_exp >> space >> -ForStepValue;
399 538
400 For = for_key >> space >> disable_do_chain_arg_table_block_rule(for_args) >> space >> opt_body_with("do"); 539 ForNum = disable_do_chain_arg_table_block_rule(for_args) >> space >> opt_body_with("do");
401 540
402 for_in = StarExp | ExpList; 541 for_in = StarExp | ExpList | expected_expression_error;
403 542
404 ForEach = for_key >> space >> AssignableNameList >> space >> key("in") >> space >> 543 ForEach = AssignableNameList >> space >> key("in") >> space >>
405 disable_do_chain_arg_table_block_rule(for_in) >> space >> opt_body_with("do"); 544 disable_do_chain_arg_table_block_rule(for_in) >> space >> opt_body_with("do");
406 545
546 For = for_key >> space >> (ForNum | ForEach);
547
407 Do = pl::user(key("do"), [](const item_t& item) { 548 Do = pl::user(key("do"), [](const item_t& item) {
408 State* st = reinterpret_cast<State*>(item.user_data); 549 State* st = reinterpret_cast<State*>(item.user_data);
409 return st->noDoStack.empty() || !st->noDoStack.top(); 550 return st->noDoStack.empty() || !st->noDoStack.back();
410 }) >> space >> Body; 551 }) >> space >> Body;
411 552
412 disable_do = pl::user(true_(), [](const item_t& item) { 553 disable_do = pl::user(true_(), [](const item_t& item) {
413 State* st = reinterpret_cast<State*>(item.user_data); 554 State* st = reinterpret_cast<State*>(item.user_data);
414 st->noDoStack.push(true); 555 st->noDoStack.push_back(true);
415 return true; 556 return true;
416 }); 557 });
417 558
418 enable_do = pl::user(true_(), [](const item_t& item) { 559 enable_do = pl::user(true_(), [](const item_t& item) {
419 State* st = reinterpret_cast<State*>(item.user_data); 560 State* st = reinterpret_cast<State*>(item.user_data);
420 st->noDoStack.pop(); 561 st->noDoStack.pop_back();
421 return true; 562 return true;
422 }); 563 });
423 564
@@ -435,46 +576,58 @@ YueParser::YueParser() {
435 576
436 disable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) { 577 disable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) {
437 State* st = reinterpret_cast<State*>(item.user_data); 578 State* st = reinterpret_cast<State*>(item.user_data);
438 st->noDoStack.push(true); 579 st->noDoStack.push_back(true);
439 st->noChainBlockStack.push(true); 580 st->noChainBlockStack.push_back(true);
440 st->noTableBlockStack.push(true); 581 st->noTableBlockStack.push_back(true);
441 return true; 582 return true;
442 }); 583 });
443 584
444 enable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) { 585 enable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) {
445 State* st = reinterpret_cast<State*>(item.user_data); 586 State* st = reinterpret_cast<State*>(item.user_data);
446 st->noDoStack.pop(); 587 st->noDoStack.pop_back();
447 st->noChainBlockStack.pop(); 588 st->noChainBlockStack.pop_back();
448 st->noTableBlockStack.pop(); 589 st->noTableBlockStack.pop_back();
449 return true; 590 return true;
450 }); 591 });
451 592
452 disable_arg_table_block = pl::user(true_(), [](const item_t& item) { 593 disable_arg_table_block = pl::user(true_(), [](const item_t& item) {
453 State* st = reinterpret_cast<State*>(item.user_data); 594 State* st = reinterpret_cast<State*>(item.user_data);
454 st->noTableBlockStack.push(true); 595 st->noTableBlockStack.push_back(true);
455 return true; 596 return true;
456 }); 597 });
457 598
458 enable_arg_table_block = pl::user(true_(), [](const item_t& item) { 599 enable_arg_table_block = pl::user(true_(), [](const item_t& item) {
459 State* st = reinterpret_cast<State*>(item.user_data); 600 State* st = reinterpret_cast<State*>(item.user_data);
460 st->noTableBlockStack.pop(); 601 st->noTableBlockStack.pop_back();
461 return true; 602 return true;
462 }); 603 });
463 604
464 disable_for = pl::user(true_(), [](const item_t& item) { 605 disable_for = pl::user(true_(), [](const item_t& item) {
465 State* st = reinterpret_cast<State*>(item.user_data); 606 State* st = reinterpret_cast<State*>(item.user_data);
466 st->noForStack.push(true); 607 st->noForStack.push_back(true);
467 return true; 608 return true;
468 }); 609 });
469 610
470 enable_for = pl::user(true_(), [](const item_t& item) { 611 enable_for = pl::user(true_(), [](const item_t& item) {
471 State* st = reinterpret_cast<State*>(item.user_data); 612 State* st = reinterpret_cast<State*>(item.user_data);
472 st->noForStack.pop(); 613 st->noForStack.pop_back();
614 return true;
615 });
616
617 disable_until = pl::user(true_(), [](const item_t& item) {
618 State* st = reinterpret_cast<State*>(item.user_data);
619 st->noUntilStack.push_back(true);
620 return true;
621 });
622
623 enable_until = pl::user(true_(), [](const item_t& item) {
624 State* st = reinterpret_cast<State*>(item.user_data);
625 st->noUntilStack.pop_back();
473 return true; 626 return true;
474 }); 627 });
475 628
476 CatchBlock = line_break >> *space_break >> check_indent_match >> space >> key("catch") >> space >> Variable >> space >> in_block; 629 CatchBlock = line_break >> *space_break >> check_indent_match >> space >> key("catch") >> space >> must_variable >> space >> (in_block | invalid_try_syntax_error);
477 Try = key("try") >> space >> (in_block | Exp) >> -CatchBlock; 630 Try = key("try") >> -ExistentialOp >> space >> (in_block | Exp | invalid_try_syntax_error) >> -CatchBlock;
478 631
479 list_value = 632 list_value =
480 and_( 633 and_(
@@ -496,28 +649,33 @@ YueParser::YueParser() {
496 649
497 list_lit_lines = +space_break >> list_lit_line >> *(-(space >> ',') >> space_break >> list_lit_line) >> -(space >> ','); 650 list_lit_lines = +space_break >> list_lit_line >> *(-(space >> ',') >> space_break >> list_lit_line) >> -(space >> ',');
498 651
652 end_brackets_expression = ']' | brackets_expression_error;
653
499 Comprehension = '[' >> not_('[') >> 654 Comprehension = '[' >> not_('[') >>
500 Seperator >> space >> ( 655 Seperator >> space >> (
501 disable_for_rule(list_value) >> space >> ( 656 disable_for_rule(list_value) >> space >> (
502 CompInner >> space >> ']' | 657 CompFor >> space >> end_brackets_expression |
503 (list_value_list >> -(space >> ',') | space >> ',') >> -list_lit_lines >> white >> ']' 658 (list_value_list >> -(space >> ',') | space >> ',') >> -list_lit_lines >> white >> end_brackets_expression
504 ) | 659 ) |
505 list_lit_lines >> white >> ']' | 660 list_lit_lines >> white >> end_brackets_expression |
506 white >> ']' >> not_(space >> '=') 661 white >> ']' >> not_(space >> '=')
507 ); 662 );
508 663
509 CompValue = ',' >> space >> Exp; 664 end_braces_expression = '}' | braces_expression_error;
510 TblComprehension = and_('{') >> ('{' >> space >> disable_for_rule(Exp >> space >> -(CompValue >> space)) >> CompInner >> space >> '}' | braces_expression_error); 665
666 CompValue = ',' >> space >> must_exp;
667 TblComprehension = '{' >> space >> disable_for_rule(Exp >> space >> -(CompValue >> space)) >> (CompFor | braces_expression_error) >> space >> end_braces_expression;
511 668
512 CompInner = Seperator >> (CompForEach | CompFor) >> *(space >> comp_clause); 669 CompFor = key("for") >> space >> Seperator >> (CompForNum | CompForEach) >> *(space >> comp_clause);
513 StarExp = '*' >> space >> Exp; 670 StarExp = '*' >> space >> must_exp;
514 CompForEach = key("for") >> space >> AssignableNameList >> space >> key("in") >> space >> (StarExp | Exp); 671 CompForEach = AssignableNameList >> space >> key("in") >> space >> (StarExp | must_exp);
515 CompFor = key("for") >> space >> Variable >> space >> '=' >> space >> Exp >> space >> ',' >> space >> Exp >> -ForStepValue; 672 CompForNum = Variable >> space >> '=' >> space >> must_exp >> space >> ',' >> space >> must_exp >> -ForStepValue;
516 comp_clause = CompFor | CompForEach | key("when") >> space >> Exp; 673 comp_clause = key("when") >> space >> must_exp | key("for") >> space >> (CompForNum | CompForEach);
517 674
518 Assign = '=' >> space >> Seperator >> ( 675 Assign = '=' >> space >> Seperator >> (
519 With | If | Switch | TableBlock | 676 With | If | Switch | TableBlock |
520 Exp >> *(space >> set(",;") >> space >> Exp) 677 (SpreadListExp | Exp) >> *(space >> set(",") >> space >> (SpreadListExp | Exp)) |
678 expected_expression_error
521 ); 679 );
522 680
523 UpdateOp = 681 UpdateOp =
@@ -525,7 +683,7 @@ YueParser::YueParser() {
525 ">>" | "<<" | "??" | 683 ">>" | "<<" | "??" |
526 set("+-*/%&|^"); 684 set("+-*/%&|^");
527 685
528 Update = UpdateOp >> '=' >> space >> Exp; 686 Update = UpdateOp >> '=' >> space >> must_exp;
529 687
530 Assignable = AssignableChain | Variable | SelfItem; 688 Assignable = AssignableChain | Variable | SelfItem;
531 689
@@ -546,35 +704,38 @@ YueParser::YueParser() {
546 UnaryExp = *(UnaryOperator >> space) >> expo_exp >> -(space >> In); 704 UnaryExp = *(UnaryOperator >> space) >> expo_exp >> -(space >> In);
547 705
548 pipe_operator = "|>"; 706 pipe_operator = "|>";
549 pipe_value = pipe_operator >> *space_break >> space >> UnaryExp; 707 pipe_value = pipe_operator >> *space_break >> space >> must_unary_exp;
550 pipe_exp = UnaryExp >> *(space >> pipe_value); 708 pipe_exp = UnaryExp >> *(space >> pipe_value);
551 709
552 BinaryOperator = 710 BinaryOperator = (
553 key("or") | 711 key("or") |
554 key("and") | 712 key("and") |
555 "<=" | ">=" | "~=" | "!=" | "==" | 713 "<=" | ">=" | "~=" | "!=" | "==" |
556 ".." | "<<" | ">>" | "//" | 714 ".." | "<<" | ">>" | "//" |
557 set("+-*/%><|&~"); 715 set("+*/%>|&~") |
716 '-' >> not_('>') |
717 '<' >> not_('-')
718 ) >> not_('=');
558 719
559 ExpOpValue = BinaryOperator >> *space_break >> space >> pipe_exp; 720 ExpOpValue = BinaryOperator >> *space_break >> space >> (pipe_exp | expected_expression_error);
560 Exp = Seperator >> pipe_exp >> *(space >> ExpOpValue) >> -(space >> "??" >> space >> Exp); 721 Exp = Seperator >> pipe_exp >> *(space >> ExpOpValue) >> -(space >> "??" >> not_('=') >> *space_break >> space >> must_exp);
561 722
562 disable_chain = pl::user(true_(), [](const item_t& item) { 723 disable_chain = pl::user(true_(), [](const item_t& item) {
563 State* st = reinterpret_cast<State*>(item.user_data); 724 State* st = reinterpret_cast<State*>(item.user_data);
564 st->noChainBlockStack.push(true); 725 st->noChainBlockStack.push_back(true);
565 return true; 726 return true;
566 }); 727 });
567 728
568 enable_chain = pl::user(true_(), [](const item_t& item) { 729 enable_chain = pl::user(true_(), [](const item_t& item) {
569 State* st = reinterpret_cast<State*>(item.user_data); 730 State* st = reinterpret_cast<State*>(item.user_data);
570 st->noChainBlockStack.pop(); 731 st->noChainBlockStack.pop_back();
571 return true; 732 return true;
572 }); 733 });
573 734
574 chain_line = check_indent_match >> space >> (chain_dot_chain | colon_chain) >> -InvokeArgs; 735 chain_line = check_indent_match >> space >> (chain_dot_chain | colon_chain) >> -InvokeArgs;
575 chain_block = pl::user(true_(), [](const item_t& item) { 736 chain_block = pl::user(true_(), [](const item_t& item) {
576 State* st = reinterpret_cast<State*>(item.user_data); 737 State* st = reinterpret_cast<State*>(item.user_data);
577 return st->noChainBlockStack.empty() || !st->noChainBlockStack.top(); 738 return st->noChainBlockStack.empty() || !st->noChainBlockStack.back();
578 }) >> +space_break >> advance_match >> ensure( 739 }) >> +space_break >> advance_match >> ensure(
579 chain_line >> *(+space_break >> chain_line), pop_indent); 740 chain_line >> *(+space_break >> chain_line), pop_indent);
580 ChainValue = 741 ChainValue =
@@ -589,7 +750,7 @@ YueParser::YueParser() {
589 st->expLevel++; 750 st->expLevel++;
590 const int max_exp_level = 100; 751 const int max_exp_level = 100;
591 if (st->expLevel > max_exp_level) { 752 if (st->expLevel > max_exp_level) {
592 throw ParserError("nesting expressions exceeds 100 levels"sv, item.begin); 753 RaiseError("nesting expressions exceeds 100 levels"sv, item);
593 } 754 }
594 return true; 755 return true;
595 }); 756 });
@@ -604,14 +765,22 @@ YueParser::YueParser() {
604 Value = inc_exp_level >> ensure(SimpleValue | SimpleTable | ChainValue | String, dec_exp_level); 765 Value = inc_exp_level >> ensure(SimpleValue | SimpleTable | ChainValue | String, dec_exp_level);
605 766
606 single_string_inner = '\\' >> set("'\\") | not_('\'') >> any_char; 767 single_string_inner = '\\' >> set("'\\") | not_('\'') >> any_char;
607 SingleString = '\'' >> *single_string_inner >> '\''; 768 SingleString = '\'' >> *single_string_inner >> ('\'' | unclosed_single_string_error);
608 769
609 interp = "#{" >> space >> (Exp >> space >> '}' | invalid_interpolation_error); 770 interp = "#{" >> space >> (Exp >> space >> '}' | invalid_interpolation_error);
610 double_string_plain = '\\' >> set("\"\\#") | not_('"') >> any_char; 771 double_string_plain = '\\' >> set("\"\\#") | not_('"') >> any_char;
611 DoubleStringInner = +(not_("#{") >> double_string_plain); 772 DoubleStringInner = +(not_("#{") >> double_string_plain);
612 DoubleStringContent = DoubleStringInner | interp; 773 DoubleStringContent = DoubleStringInner | interp;
613 DoubleString = '"' >> Seperator >> *DoubleStringContent >> '"'; 774 DoubleString = '"' >> Seperator >> *DoubleStringContent >> ('"' | unclosed_double_string_error);
614 String = DoubleString | SingleString | LuaString; 775
776 YAMLIndent = +set(" \t");
777 YAMLLineInner = +('\\' >> set("\"\\#") | not_("#{" | stop) >> any_char);
778 YAMLLineContent = YAMLLineInner | interp;
779 YAMLLine = check_indent_match >> YAMLIndent >> +(YAMLLineContent) |
780 advance_match >> YAMLIndent >> ensure(+YAMLLineContent, pop_indent);
781 YAMLMultiline = '|' >> space >> Seperator >> +(*set(" \t") >> line_break) >> advance_match >> ensure(YAMLLine >> *(+(*set(" \t") >> line_break) >> YAMLLine), pop_indent);
782
783 String = DoubleString | SingleString | LuaString | YAMLMultiline;
615 784
616 lua_string_open = '[' >> *expr('=') >> '['; 785 lua_string_open = '[' >> *expr('=') >> '[';
617 lua_string_close = ']' >> *expr('=') >> ']'; 786 lua_string_close = ']' >> *expr('=') >> ']';
@@ -631,15 +800,15 @@ YueParser::YueParser() {
631 800
632 LuaStringContent = *(not_(LuaStringClose) >> any_char); 801 LuaStringContent = *(not_(LuaStringClose) >> any_char);
633 802
634 LuaString = LuaStringOpen >> -line_break >> LuaStringContent >> LuaStringClose; 803 LuaString = LuaStringOpen >> -line_break >> LuaStringContent >> (LuaStringClose | unclosed_lua_string_error);
635 804
636 Parens = '(' >> *space_break >> space >> Exp >> *space_break >> space >> ')'; 805 Parens = '(' >> (*space_break >> space >> Exp >> *space_break >> space >> ')' | parenthesis_error);
637 Callable = Variable | SelfItem | MacroName | Parens; 806 Callable = Variable | SelfItem | MacroName | Parens;
638 807
639 fn_args_value_list = Exp >> *(space >> ',' >> space >> Exp); 808 fn_args_value_list = Exp >> *(space >> ',' >> space >> Exp);
640 809
641 fn_args_lit_line = ( 810 fn_args_lit_line = (
642 push_indent_match >> (space >> fn_args_value_list >> pop_indent | pop_indent) 811 push_indent_match >> ensure(space >> fn_args_value_list, pop_indent)
643 ) | ( 812 ) | (
644 space 813 space
645 ); 814 );
@@ -649,14 +818,14 @@ YueParser::YueParser() {
649 fn_args = 818 fn_args =
650 '(' >> -(space >> fn_args_value_list >> -(space >> ',')) >> 819 '(' >> -(space >> fn_args_value_list >> -(space >> ',')) >>
651 -fn_args_lit_lines >> 820 -fn_args_lit_lines >>
652 white >> ')' | space >> '!' >> not_('='); 821 white >> -(and_(',') >> unexpected_comma_error) >>')' | space >> '!' >> not_('=');
653 822
654 meta_index = Name | index | String; 823 meta_index = Name | index | String;
655 Metatable = '<' >> space >> '>'; 824 Metatable = '<' >> space >> '>';
656 Metamethod = '<' >> space >> meta_index >> space >> '>'; 825 Metamethod = '<' >> space >> meta_index >> space >> '>';
657 826
658 ExistentialOp = '?' >> not_('?'); 827 ExistentialOp = '?' >> not_('?');
659 TableAppendingOp = and_('[') >> ("[]" | brackets_expression_error); 828 TableAppendingOp = and_('[') >> "[]";
660 PlainItem = +any_char; 829 PlainItem = +any_char;
661 830
662 chain_call = ( 831 chain_call = (
@@ -681,7 +850,8 @@ YueParser::YueParser() {
681 chain_with_colon = +chain_item >> -colon_chain; 850 chain_with_colon = +chain_item >> -colon_chain;
682 chain_items = chain_with_colon | colon_chain; 851 chain_items = chain_with_colon | colon_chain;
683 852
684 index = '[' >> not_('[') >> space >> Exp >> space >> ']'; 853 index = '[' >> not_('[') >> space >> (ReversedIndex >> and_(space >> ']') | Exp) >> space >> ']';
854 ReversedIndex = '#' >> space >> -('-' >> space >> Exp);
685 chain_item = 855 chain_item =
686 Invoke >> -ExistentialOp | 856 Invoke >> -ExistentialOp |
687 DotChainItem >> -ExistentialOp | 857 DotChainItem >> -ExistentialOp |
@@ -720,10 +890,8 @@ YueParser::YueParser() {
720 SpreadExp | 890 SpreadExp |
721 NormalDef; 891 NormalDef;
722 892
723 table_value_list = table_value >> *(space >> ',' >> space >> table_value);
724
725 table_lit_line = ( 893 table_lit_line = (
726 push_indent_match >> (space >> table_value_list >> pop_indent | pop_indent) 894 push_indent_match >> (space >> not_(line_break | '}') >> (table_value | expected_expression_error) >> *(space >> ',' >> space >> table_value) >> pop_indent | pop_indent)
727 ) | ( 895 ) | (
728 space 896 space
729 ); 897 );
@@ -732,13 +900,15 @@ YueParser::YueParser() {
732 900
733 TableLit = 901 TableLit =
734 '{' >> Seperator >> 902 '{' >> Seperator >>
735 -(space >> table_value_list >> -(space >> ',')) >> 903 -(space >> table_value >> *(space >> ',' >> space >> table_value) >> -(space >> ',')) >>
736 -table_lit_lines >> 904 (
737 white >> '}'; 905 table_lit_lines >> white >> end_braces_expression |
906 white >> '}'
907 );
738 908
739 table_block_inner = Seperator >> key_value_line >> *(+space_break >> key_value_line); 909 table_block_inner = Seperator >> key_value_line >> *(+space_break >> key_value_line);
740 TableBlock = +space_break >> advance_match >> ensure(table_block_inner, pop_indent); 910 TableBlock = +space_break >> advance_match >> ensure(table_block_inner, pop_indent);
741 TableBlockIndent = '*' >> Seperator >> disable_arg_table_block_rule( 911 TableBlockIndent = ('*' | '-' >> space_one) >> Seperator >> disable_arg_table_block_rule(
742 space >> key_value_list >> -(space >> ',') >> 912 space >> key_value_list >> -(space >> ',') >>
743 -(+space_break >> advance_match >> space >> ensure(key_value_list >> -(space >> ',') >> *(+space_break >> key_value_line), pop_indent))); 913 -(+space_break >> advance_match >> space >> ensure(key_value_list >> -(space >> ',') >> *(+space_break >> key_value_line), pop_indent)));
744 914
@@ -753,13 +923,18 @@ YueParser::YueParser() {
753 ClassDecl = 923 ClassDecl =
754 key("class") >> not_(':') >> disable_arg_table_block_rule( 924 key("class") >> not_(':') >> disable_arg_table_block_rule(
755 -(space >> Assignable) >> 925 -(space >> Assignable) >>
756 -(space >> key("extends") >> prevent_indent >> space >> ensure(Exp, pop_indent)) >> 926 -(space >> key("extends") >> prevent_indent >> space >> ensure(must_exp, pop_indent)) >>
757 -(space >> key("using") >> prevent_indent >> space >> ensure(ExpList, pop_indent)) 927 -(space >> key("using") >> prevent_indent >> space >> ensure(ExpList | expected_expression_error, pop_indent))
758 ) >> -ClassBlock; 928 ) >> -ClassBlock;
759 929
760 GlobalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpListLow)); 930 GlobalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpList | expected_expression_error));
761 GlobalOp = expr('*') | '^'; 931 GlobalOp = expr('*') | '^';
762 Global = key("global") >> space >> (ClassDecl | GlobalOp | GlobalValues); 932 Global = key("global") >> space >> (
933 -(ConstAttrib >> space) >> ClassDecl |
934 GlobalOp |
935 -(ConstAttrib >> space) >> GlobalValues |
936 invalid_global_declaration_error
937 );
763 938
764 ExportDefault = key("default"); 939 ExportDefault = key("default");
765 940
@@ -771,10 +946,10 @@ YueParser::YueParser() {
771 pl::user(space >> ExportDefault >> space >> Exp, [](const item_t& item) { 946 pl::user(space >> ExportDefault >> space >> Exp, [](const item_t& item) {
772 State* st = reinterpret_cast<State*>(item.user_data); 947 State* st = reinterpret_cast<State*>(item.user_data);
773 if (st->exportDefault) { 948 if (st->exportDefault) {
774 throw ParserError("export default has already been declared"sv, item.begin); 949 RaiseError("export default has already been declared"sv, item);
775 } 950 }
776 if (st->exportCount > 1) { 951 if (st->exportCount > 1) {
777 throw ParserError("there are items already being exported"sv, item.begin); 952 RaiseError("there are items already being exported"sv, item);
778 } 953 }
779 st->exportDefault = true; 954 st->exportDefault = true;
780 return true; 955 return true;
@@ -782,17 +957,17 @@ YueParser::YueParser() {
782 not_(space >> ExportDefault) >> pl::user(true_(), [](const item_t& item) { 957 not_(space >> ExportDefault) >> pl::user(true_(), [](const item_t& item) {
783 State* st = reinterpret_cast<State*>(item.user_data); 958 State* st = reinterpret_cast<State*>(item.user_data);
784 if (st->exportDefault && st->exportCount > 1) { 959 if (st->exportDefault && st->exportCount > 1) {
785 throw ParserError("can not export any more items when 'export default' is declared"sv, item.begin); 960 RaiseError("can not export any more items when 'export default' is declared"sv, item);
786 } 961 }
787 return true; 962 return true;
788 }) >> ( 963 }) >> (
789 and_(set(".[")) >> ((pl::user(and_('.' >> Metatable), [](const item_t& item) { 964 and_(set(".[")) >> ((pl::user(and_('.' >> Metatable), [](const item_t& item) {
790 State* st = reinterpret_cast<State*>(item.user_data); 965 State* st = reinterpret_cast<State*>(item.user_data);
791 if (st->exportMetatable) { 966 if (st->exportMetatable) {
792 throw ParserError("module metatable duplicated"sv, item.begin); 967 RaiseError("module metatable duplicated"sv, item);
793 } 968 }
794 if (st->exportMetamethod) { 969 if (st->exportMetamethod) {
795 throw ParserError("metatable should be exported before metamethod"sv, item.begin); 970 RaiseError("metatable should be exported before metamethod"sv, item);
796 } 971 }
797 st->exportMetatable = true; 972 st->exportMetatable = true;
798 return true; 973 return true;
@@ -807,8 +982,9 @@ YueParser::YueParser() {
807 State* st = reinterpret_cast<State*>(item.user_data); 982 State* st = reinterpret_cast<State*>(item.user_data);
808 st->exportMacro = true; 983 st->exportMacro = true;
809 return true; 984 return true;
810 }) 985 }) |
811 ) >> not_(space >> StatementAppendix); 986 invalid_export_syntax_error
987 );
812 988
813 VariablePair = ':' >> Variable; 989 VariablePair = ':' >> Variable;
814 990
@@ -817,13 +993,13 @@ YueParser::YueParser() {
817 KeyName | 993 KeyName |
818 '[' >> not_('[') >> space >> Exp >> space >> ']' | 994 '[' >> not_('[') >> space >> Exp >> space >> ']' |
819 String 995 String
820 ) >> ':' >> not_(':') >> space >> 996 ) >> ':' >> not_(':' | '=' >> not_('>')) >> space >>
821 (Exp | TableBlock | +space_break >> space >> Exp); 997 (Exp | TableBlock | +space_break >> space >> Exp | expected_expression_error);
822 998
823 MetaVariablePair = ":<" >> space >> Variable >> space >> '>'; 999 MetaVariablePair = ":<" >> space >> must_variable >> space >> '>';
824 1000
825 MetaNormalPair = '<' >> space >> -meta_index >> space >> ">:" >> space >> 1001 MetaNormalPair = '<' >> space >> -meta_index >> space >> ">:" >> space >>
826 (Exp | TableBlock | +space_break >> space >> Exp); 1002 (Exp | TableBlock | +space_break >> space >> Exp | expected_expression_error);
827 1003
828 destruct_def = -(space >> '=' >> space >> Exp); 1004 destruct_def = -(space >> '=' >> space >> Exp);
829 VariablePairDef = VariablePair >> destruct_def; 1005 VariablePairDef = VariablePair >> destruct_def;
@@ -841,66 +1017,83 @@ YueParser::YueParser() {
841 key_value_line = check_indent_match >> space >> ( 1017 key_value_line = check_indent_match >> space >> (
842 key_value_list >> -(space >> ',') | 1018 key_value_list >> -(space >> ',') |
843 TableBlockIndent | 1019 TableBlockIndent |
844 '*' >> space >> (SpreadExp | Exp | TableBlock) 1020 ('*' | '-' >> space_one) >> space >> (SpreadExp | Exp | TableBlock)
845 ); 1021 );
846 1022
847 fn_arg_def_list = FnArgDef >> *(space >> ',' >> space >> FnArgDef); 1023 fn_arg_def_list = FnArgDef >> *(space >> ',' >> space >> FnArgDef);
848 1024
849 fn_arg_def_lit_line = ( 1025 fn_arg_def_lit_line = (
850 push_indent_match >> (space >> fn_arg_def_list >> pop_indent | pop_indent) 1026 push_indent_match >> ensure(space >> fn_arg_def_list, pop_indent)
851 ) | ( 1027 ) | (
852 space 1028 space
853 ); 1029 );
854 1030
855 fn_arg_def_lit_lines = fn_arg_def_lit_line >> *(-(space >> ',') >> space_break >> fn_arg_def_lit_line); 1031 fn_arg_def_lit_lines = fn_arg_def_lit_line >> *(-(space >> ',') >> space_break >> fn_arg_def_lit_line);
856 1032
857 FnArgDef = (Variable | SelfItem >> -ExistentialOp) >> -(space >> '=' >> space >> Exp); 1033 FnArgDef = (Variable | SelfItem >> -ExistentialOp) >> -(space >> '`' >> space >> Name) >> -(space >> '=' >> space >> Exp) | TableLit | SimpleTable;
858 1034
859 FnArgDefList = Seperator >> ( 1035 check_vararg_position = and_(white >> (')' | key("using"))) | white >> -(',' >> white) >> vararg_position_error;
860 fn_arg_def_lit_lines >> -(-(space >> ',') >> white >> VarArg) | 1036
861 white >> VarArg 1037 var_arg_def = (
862 ); 1038 VarArgDef |
1039 +space_break >> push_indent_match >> ensure(space >> VarArgDef >> -(space >> '`' >> space >> Name), pop_indent)
1040 ) >> check_vararg_position;
1041
1042 FnArgDefList = Seperator >>
1043 -fn_arg_def_list >>
1044 -(-(space >> ',') >> +space_break >> fn_arg_def_lit_lines) >>
1045 -(-(space >> ',') >> space >> var_arg_def);
863 1046
864 OuterVarShadow = key("using") >> space >> (NameList | key("nil")); 1047 OuterVarShadow = key("using") >> space >> (key("nil") | NameList);
865 1048
866 FnArgsDef = '(' >> *space_break >> -FnArgDefList >> -(white >> OuterVarShadow) >> white >> ')'; 1049 outer_var_shadow_def = OuterVarShadow |
1050 +space_break >> push_indent_match >> ensure(space >> OuterVarShadow, pop_indent);
1051
1052 FnArgsDef = '(' >> space >> -FnArgDefList >> -(space >> outer_var_shadow_def) >> white >> -(and_(',') >> unexpected_comma_error) >> ')';
867 FnArrow = expr("->") | "=>"; 1053 FnArrow = expr("->") | "=>";
868 FunLit = pl::user(true_(), [](const item_t& item) { 1054 FunLit = pl::user(true_(), [](const item_t& item) {
869 State* st = reinterpret_cast<State*>(item.user_data); 1055 State* st = reinterpret_cast<State*>(item.user_data);
870 return st->fnArrowAvailable; 1056 return st->fnArrowAvailable;
871 }) >> -(FnArgsDef >> 1057 }) >> -(FnArgsDef >>
872 -(':' >> space >> 1058 -(':' >> space >>
873 disable_fun_lit >> ensure(ExpListLow | DefaultValue, enable_fun_lit) 1059 disable_fun_lit >> ensure(ExpList | DefaultValue, enable_fun_lit)
874 ) 1060 )
875 ) >> space >> FnArrow >> -(space >> Body); 1061 ) >> space >> FnArrow >> -(space >> Body);
876 1062
877 MacroName = '$' >> UnicodeName; 1063 MacroName = '$' >> UnicodeName;
878 macro_args_def = '(' >> white >> -FnArgDefList >> white >> ')'; 1064 macro_args_def = '(' >> space >> -FnArgDefList >> white >> -(and_(',') >> unexpected_comma_error) >> ')';
879 MacroLit = -(macro_args_def >> space) >> "->" >> space >> Body; 1065 MacroLit = -(macro_args_def >> space) >> "->" >> space >> Body;
880 MacroFunc = MacroName >> (Invoke | InvokeArgs); 1066 MacroFunc = MacroName >> (Invoke | InvokeArgs);
881 Macro = key("macro") >> space >> UnicodeName >> space >> '=' >> space >> (MacroLit | MacroFunc); 1067 Macro = key("macro") >> space >> (
1068 UnicodeName >> space >> '=' >> space >> (MacroLit | MacroFunc | invalid_macro_definition_error) |
1069 invalid_macro_definition_error
1070 );
882 MacroInPlace = '$' >> space >> "->" >> space >> Body; 1071 MacroInPlace = '$' >> space >> "->" >> space >> Body;
883 1072
884 NameList = Seperator >> Variable >> *(space >> ',' >> space >> Variable); 1073 must_variable = Variable | and_(LuaKeyword >> not_alpha_num) >> keyword_as_identifier_syntax_error | expected_indentifier_error;
885 NameOrDestructure = Variable | TableLit | Comprehension; 1074
1075 NameList = Seperator >> must_variable >> *(space >> ',' >> space >> must_variable);
1076 NameOrDestructure = Variable | TableLit | Comprehension | SimpleTable | expected_expression_error;
886 AssignableNameList = Seperator >> NameOrDestructure >> *(space >> ',' >> space >> NameOrDestructure); 1077 AssignableNameList = Seperator >> NameOrDestructure >> *(space >> ',' >> space >> NameOrDestructure);
887 1078
888 FnArrowBack = '<' >> set("-="); 1079 FnArrowBack = '<' >> set("-=");
889 Backcall = -(FnArgsDef >> space) >> FnArrowBack >> space >> ChainValue; 1080 Backcall = -(FnArgsDef >> space) >> FnArrowBack >> space >> ChainValue;
1081 SubBackcall = FnArrowBack >> space >> ChainValue;
1082
1083 must_unary_exp = UnaryExp | expected_expression_error;
890 1084
891 PipeBody = Seperator >> 1085 PipeBody = Seperator >>
892 pipe_operator >> space >> UnaryExp >> 1086 pipe_operator >> space >> must_unary_exp >>
893 *(+space_break >> check_indent_match >> space >> pipe_operator >> space >> UnaryExp); 1087 *(+space_break >> check_indent_match >> space >> pipe_operator >> space >> must_unary_exp);
894 1088
895 ExpList = Seperator >> Exp >> *(space >> ',' >> space >> Exp); 1089 ExpList = Seperator >> Exp >> *(space >> ',' >> space >> Exp);
896 ExpListLow = Seperator >> Exp >> *(space >> set(",;") >> space >> Exp);
897 1090
898 arg_line = check_indent_match >> space >> Exp >> *(space >> ',' >> space >> Exp); 1091 arg_line = check_indent_match >> space >> Exp >> *(space >> ',' >> space >> Exp);
899 arg_block = arg_line >> *(space >> ',' >> space_break >> arg_line) >> pop_indent; 1092 arg_block = arg_line >> *(space >> ',' >> space_break >> arg_line) >> pop_indent;
900 1093
901 arg_table_block = pl::user(true_(), [](const item_t& item) { 1094 arg_table_block = pl::user(true_(), [](const item_t& item) {
902 State* st = reinterpret_cast<State*>(item.user_data); 1095 State* st = reinterpret_cast<State*>(item.user_data);
903 return st->noTableBlockStack.empty() || !st->noTableBlockStack.top(); 1096 return st->noTableBlockStack.empty() || !st->noTableBlockStack.back();
904 }) >> TableBlock; 1097 }) >> TableBlock;
905 1098
906 invoke_args_with_table = 1099 invoke_args_with_table =
@@ -909,103 +1102,84 @@ YueParser::YueParser() {
909 space_break >> advance_match >> arg_block >> -(-(space >> ',') >> arg_table_block) 1102 space_break >> advance_match >> arg_block >> -(-(space >> ',') >> arg_table_block)
910 ) | arg_table_block; 1103 ) | arg_table_block;
911 1104
912 leading_spaces_error = pl::user(+space_one >> '(' >> space >> Exp >> +(space >> ',' >> space >> Exp) >> space >> ')', [](const item_t& item) {
913 throw ParserError("write invoke arguments in parentheses without leading spaces or just leading spaces without parentheses"sv, item.begin);
914 return false;
915 });
916
917 InvokeArgs = 1105 InvokeArgs =
918 not_(set("-~") | "[]") >> space >> Seperator >> ( 1106 not_(set("-~") | "[]") >> space >> Seperator >> (
919 Exp >> *(space >> ',' >> space >> Exp) >> -(space >> invoke_args_with_table) | 1107 Exp >> *(space >> ',' >> space >> Exp) >> -(space >> invoke_args_with_table) |
920 arg_table_block | 1108 arg_table_block
921 leading_spaces_error
922 ); 1109 );
923 1110
924 ConstValue = (expr("nil") | "true" | "false") >> not_alpha_num; 1111 ConstValue = (expr("nil") | "true" | "false") >> not_alpha_num;
925 1112
926 braces_expression_error = pl::user(true_(), [](const item_t& item) {
927 throw ParserError("syntax error in brace expression"sv, item.begin);
928 return false;
929 });
930
931 brackets_expression_error = pl::user(true_(), [](const item_t& item) {
932 throw ParserError("syntax error in bracket expression"sv, item.begin);
933 return false;
934 });
935
936 slice_expression_error = pl::user(true_(), [](const item_t& item) {
937 throw ParserError("syntax error in slice expression"sv, item.begin);
938 return false;
939 });
940
941 SimpleValue = 1113 SimpleValue =
942 TableLit | ConstValue | If | Switch | Try | With | 1114 TableLit | ConstValue | If | Switch | Try | With |
943 ClassDecl | ForEach | For | While | Do | 1115 ClassDecl | For | While | Repeat | Do |
944 UnaryValue | TblComprehension | Comprehension | 1116 UnaryValue | TblComprehension | Comprehension |
945 FunLit | Num | VarArg; 1117 FunLit | Num | VarArg;
946 1118
947 ExpListAssign = ExpList >> -(space >> (Update | Assign)) >> not_(space >> '='); 1119 ExpListAssign = ExpList >> -(space >> (Update | Assign | SubBackcall)) >> not_(space >> '=');
948 1120
949 IfLine = IfType >> space >> IfCond; 1121 IfLine = IfType >> space >> IfCond;
950 WhileLine = WhileType >> space >> Exp; 1122 WhileLine = WhileType >> space >> Exp;
951 1123
952 YueLineComment = *(not_(set("\r\n")) >> any_char);
953 yue_line_comment = "--" >> YueLineComment >> and_(stop);
954 MultilineCommentInner = multi_line_content;
955 YueMultilineComment = multi_line_open >> MultilineCommentInner >> multi_line_close;
956 yue_comment = check_indent >> (
957 (
958 YueMultilineComment >>
959 *(set(" \t") | YueMultilineComment) >>
960 -yue_line_comment
961 ) | yue_line_comment
962 ) >> and_(line_break);
963
964 ChainAssign = Seperator >> Exp >> +(space >> '=' >> space >> Exp >> space >> and_('=')) >> space >> Assign; 1124 ChainAssign = Seperator >> Exp >> +(space >> '=' >> space >> Exp >> space >> and_('=')) >> space >> Assign;
965 1125
966 StatementAppendix = (IfLine | WhileLine | CompInner) >> space; 1126 StatementAppendix = IfLine | WhileLine | CompFor;
967 Statement = 1127 Statement = (
968 Seperator >> 1128 (
969 -( 1129 Import | Export | Global | Macro | MacroInPlace | Label
970 yue_comment >> 1130 ) | (
971 *(line_break >> yue_comment) >> 1131 Local | While | Repeat | For | Return |
972 line_break >> 1132 BreakLoop | Goto | ShortTabAppending |
973 check_indent_match
974 ) >>
975 space >> (
976 Import | While | Repeat | For | ForEach |
977 Return | Local | Global | Export | Macro |
978 MacroInPlace | BreakLoop | Label | Goto | ShortTabAppending |
979 LocalAttrib | Backcall | PipeBody | ExpListAssign | ChainAssign | 1133 LocalAttrib | Backcall | PipeBody | ExpListAssign | ChainAssign |
980 StatementAppendix >> empty_block_error 1134 StatementAppendix >> empty_block_error |
981 ) >> 1135 and_(key("else") | key("elseif") | key("when")) >> dangling_clause_error
982 space >> 1136 ) >> space >> -StatementAppendix
983 -StatementAppendix; 1137 ) >> space;
984 1138
985 StatementSep = white >> (set("('\"") | "[[" | "[="); 1139 StatementSep = white >> (set("('\"") | "[[" | "[=");
986 1140
987 Body = in_block | Statement; 1141 Body = in_block | Statement;
988 1142
989 empty_line_break = 1143 YueLineComment = *(not_(set("\r\n")) >> any_char);
990 check_indent >> (multi_line_comment >> space | comment) >> and_(stop) | 1144 yue_line_comment = "--" >> YueLineComment >> and_(stop);
991 advance >> ensure(multi_line_comment >> space | comment, pop_indent) >> and_(stop) | 1145 YueMultilineComment = multi_line_content;
992 plain_space >> and_(line_break); 1146 yue_multiline_comment = multi_line_open >> YueMultilineComment >> multi_line_close;
1147 comment_line =
1148 yue_multiline_comment >> *(set(" \t") | yue_multiline_comment) >> plain_space >> -yue_line_comment |
1149 yue_line_comment;
1150 YueComment =
1151 check_indent >> comment_line >> and_(stop) |
1152 advance >> ensure(comment_line, pop_indent) >> and_(stop);
1153
1154 EmptyLine = plain_space >> and_(stop);
993 1155
994 indentation_error = pl::user(not_(pipe_operator | eof()), [](const item_t& item) { 1156 indentation_error = pl::user(not_(pipe_operator | eof()), [](const item_t& item) {
995 throw ParserError("unexpected indent"sv, item.begin); 1157 RaiseError("unexpected indent"sv, item);
996 return false; 1158 return false;
997 }); 1159 });
998 1160
999 line = ( 1161 is_lax = pl::user(true_(), [](const item_t& item) {
1000 check_indent_match >> Statement | 1162 State* st = reinterpret_cast<State*>(item.user_data);
1001 empty_line_break | 1163 return st->lax;
1164 });
1165
1166 line = *(EmptyLine >> line_break) >> (
1167 check_indent_match >> space >> Statement >> *(';' >> space >> (Statement | not_(';'))) |
1168 YueComment |
1002 advance_match >> ensure(space >> (indentation_error | Statement), pop_indent) 1169 advance_match >> ensure(space >> (indentation_error | Statement), pop_indent)
1003 ); 1170 );
1004 Block = Seperator >> line >> *(+line_break >> line); 1171 Block = Seperator >> (
1172 is_lax >> lax_line >> *(line_break >> lax_line) |
1173 line >> *(line_break >> line)
1174 );
1005 1175
1006 shebang = "#!" >> *(not_(stop) >> any_char); 1176 shebang = "#!" >> *(not_(stop) >> any_char);
1007 BlockEnd = Block >> white >> stop; 1177 BlockEnd = Block >> plain_white >> stop;
1008 File = -shebang >> -Block >> white >> stop; 1178 File = -shebang >> -Block >> plain_white >> stop;
1179
1180 lax_line = advance_match >> ensure(*(not_(stop) >> any()), pop_indent) |
1181 line >> and_(stop) |
1182 check_indent_match >> *(not_(stop) >> any());
1009} 1183}
1010// clang-format on 1184// clang-format on
1011 1185
@@ -1016,7 +1190,7 @@ bool YueParser::startWith(std::string_view codes, rule& r) {
1016 } 1190 }
1017 try { 1191 try {
1018 if (!codes.empty()) { 1192 if (!codes.empty()) {
1019 converted = std::make_unique<input>(_converter.from_bytes(&codes.front(), &codes.back() + 1)); 1193 converted = std::make_unique<input>(utf8_decode({&codes.front(), &codes.back() + 1}));
1020 } else { 1194 } else {
1021 converted = std::make_unique<input>(); 1195 converted = std::make_unique<input>();
1022 } 1196 }
@@ -1035,24 +1209,25 @@ bool YueParser::startWith(std::string_view codes, rule& r) {
1035 return true; 1209 return true;
1036} 1210}
1037 1211
1038ParseInfo YueParser::parse(std::string_view codes, rule& r) { 1212ParseInfo YueParser::parse(std::string_view codes, rule& r, bool lax) {
1039 ParseInfo res; 1213 ParseInfo res;
1040 if (codes.substr(0, 3) == "\xEF\xBB\xBF"sv) { 1214 if (codes.substr(0, 3) == "\xEF\xBB\xBF"sv) {
1041 codes = codes.substr(3); 1215 codes = codes.substr(3);
1042 } 1216 }
1043 try { 1217 try {
1044 if (!codes.empty()) { 1218 if (!codes.empty()) {
1045 res.codes = std::make_unique<input>(_converter.from_bytes(&codes.front(), &codes.back() + 1)); 1219 res.codes = std::make_unique<input>(utf8_decode({&codes.front(), &codes.back() + 1}));
1046 } else { 1220 } else {
1047 res.codes = std::make_unique<input>(); 1221 res.codes = std::make_unique<input>();
1048 } 1222 }
1049 } catch (const std::range_error&) { 1223 } catch (const std::exception&) {
1050 res.error = {"invalid text encoding"s, 1, 1}; 1224 res.error = {"invalid text encoding"s, 1, 1};
1051 return res; 1225 return res;
1052 } 1226 }
1053 error_list errors; 1227 error_list errors;
1054 try { 1228 try {
1055 State state; 1229 State state;
1230 state.lax = lax;
1056 res.node.set(::yue::parse(*(res.codes), r, errors, &state)); 1231 res.node.set(::yue::parse(*(res.codes), r, errors, &state));
1057 if (state.exportCount > 0) { 1232 if (state.exportCount > 0) {
1058 int index = 0; 1233 int index = 0;
@@ -1090,29 +1265,31 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) {
1090 return res; 1265 return res;
1091} 1266}
1092 1267
1093ParseInfo YueParser::parse(std::string_view astName, std::string_view codes) { 1268ParseInfo YueParser::parse(std::string_view astName, std::string_view codes, bool lax) {
1094 auto it = _rules.find(astName); 1269 auto it = _rules.find(astName);
1095 if (it != _rules.end()) { 1270 if (it != _rules.end()) {
1096 return parse(codes, *it->second); 1271 return parse(codes, *it->second, lax);
1097 } 1272 }
1098 return {}; 1273 ParseInfo info{};
1274 info.error = ParseInfo::Error{"invalid rule: "s + std::string{astName}, 1, 1};
1275 return info;
1099} 1276}
1100 1277
1101bool YueParser::match(std::string_view astName, std::string_view codes) { 1278bool YueParser::match(std::string_view astName, std::string_view codes) {
1102 auto it = _rules.find(astName); 1279 auto it = _rules.find(astName);
1103 if (it != _rules.end()) { 1280 if (it != _rules.end()) {
1104 auto rEnd = rule(*it->second >> eof()); 1281 auto rEnd = rule(*it->second >> eof());
1105 return parse(codes, rEnd).node; 1282 return parse(codes, rEnd, false).node;
1106 } 1283 }
1107 return false; 1284 return false;
1108} 1285}
1109 1286
1110std::string YueParser::toString(ast_node* node) { 1287std::string YueParser::toString(ast_node* node) {
1111 return _converter.to_bytes(std::wstring(node->m_begin.m_it, node->m_end.m_it)); 1288 return utf8_encode({node->m_begin.m_it, node->m_end.m_it});
1112} 1289}
1113 1290
1114std::string YueParser::toString(input::iterator begin, input::iterator end) { 1291std::string YueParser::toString(input::iterator begin, input::iterator end) {
1115 return _converter.to_bytes(std::wstring(begin, end)); 1292 return utf8_encode({begin, end});
1116} 1293}
1117 1294
1118bool YueParser::hasAST(std::string_view name) const { 1295bool YueParser::hasAST(std::string_view name) const {
@@ -1138,6 +1315,24 @@ void trim(std::string& str) {
1138 str.erase(0, str.find_first_not_of(" \t\r\n")); 1315 str.erase(0, str.find_first_not_of(" \t\r\n"));
1139 str.erase(str.find_last_not_of(" \t\r\n") + 1); 1316 str.erase(str.find_last_not_of(" \t\r\n") + 1);
1140} 1317}
1318
1319std::string toLuaDoubleString(const std::string& input) {
1320 std::string luaStr = "\"";
1321 for (char c : input) {
1322 switch (c) {
1323 case '\"': luaStr += "\\\""; break;
1324 case '\\': luaStr += "\\\\"; break;
1325 case '\n': luaStr += "\\n"; break;
1326 case '\r': luaStr += "\\r"; break;
1327 case '\t': luaStr += "\\t"; break;
1328 default:
1329 luaStr += c;
1330 break;
1331 }
1332 }
1333 luaStr += "\"";
1334 return luaStr;
1335}
1141} // namespace Utils 1336} // namespace Utils
1142 1337
1143std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCol, int lineOffset) const { 1338std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCol, int lineOffset) const {
@@ -1171,7 +1366,7 @@ std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCo
1171 } 1366 }
1172 ++it; 1367 ++it;
1173 } 1368 }
1174 auto line = Converter{}.to_bytes(std::wstring(begin, end)); 1369 auto line = utf8_encode({begin, end});
1175 while (col < static_cast<int>(line.size()) 1370 while (col < static_cast<int>(line.size())
1176 && (line[col] == ' ' || line[col] == '\t')) { 1371 && (line[col] == ' ' || line[col] == '\t')) {
1177 col++; 1372 col++;
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h
index 7281ec3..df9f39c 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
3Permission 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: 3Permission 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;
74class YueParser { 74class YueParser {
75public: 75public:
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
103protected: 103protected:
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
134private: 137private:
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,18 @@ 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(is_lax);
323 NONE_AST_RULE(lax_line);
287 324
288 AST_RULE(Num); 325 AST_RULE(Num);
289 AST_RULE(Name); 326 AST_RULE(Name);
290 AST_RULE(UnicodeName); 327 AST_RULE(UnicodeName);
291 AST_RULE(Variable); 328 AST_RULE(Variable);
292 AST_RULE(LabelName);
293 AST_RULE(LuaKeyword); 329 AST_RULE(LuaKeyword);
294 AST_RULE(Self); 330 AST_RULE(Self);
295 AST_RULE(SelfName); 331 AST_RULE(SelfName);
@@ -298,6 +334,7 @@ private:
298 AST_RULE(SelfItem); 334 AST_RULE(SelfItem);
299 AST_RULE(KeyName); 335 AST_RULE(KeyName);
300 AST_RULE(VarArg); 336 AST_RULE(VarArg);
337 AST_RULE(VarArgDef);
301 AST_RULE(Seperator); 338 AST_RULE(Seperator);
302 AST_RULE(NameList); 339 AST_RULE(NameList);
303 AST_RULE(LocalFlag); 340 AST_RULE(LocalFlag);
@@ -315,14 +352,16 @@ private:
315 AST_RULE(ImportAllMacro); 352 AST_RULE(ImportAllMacro);
316 AST_RULE(ImportTabLit); 353 AST_RULE(ImportTabLit);
317 AST_RULE(ImportAs); 354 AST_RULE(ImportAs);
355 AST_RULE(ImportGlobal);
356 AST_RULE(ImportAllGlobal);
318 AST_RULE(Import); 357 AST_RULE(Import);
319 AST_RULE(Label); 358 AST_RULE(Label);
320 AST_RULE(Goto); 359 AST_RULE(Goto);
321 AST_RULE(ShortTabAppending); 360 AST_RULE(ShortTabAppending);
322 AST_RULE(FnArrowBack); 361 AST_RULE(FnArrowBack);
323 AST_RULE(Backcall); 362 AST_RULE(Backcall);
363 AST_RULE(SubBackcall);
324 AST_RULE(PipeBody); 364 AST_RULE(PipeBody);
325 AST_RULE(ExpListLow);
326 AST_RULE(ExpList); 365 AST_RULE(ExpList);
327 AST_RULE(Return); 366 AST_RULE(Return);
328 AST_RULE(With); 367 AST_RULE(With);
@@ -338,6 +377,7 @@ private:
338 AST_RULE(Repeat); 377 AST_RULE(Repeat);
339 AST_RULE(ForStepValue); 378 AST_RULE(ForStepValue);
340 AST_RULE(For); 379 AST_RULE(For);
380 AST_RULE(ForNum);
341 AST_RULE(ForEach); 381 AST_RULE(ForEach);
342 AST_RULE(Do); 382 AST_RULE(Do);
343 AST_RULE(CatchBlock); 383 AST_RULE(CatchBlock);
@@ -347,8 +387,8 @@ private:
347 AST_RULE(TblComprehension); 387 AST_RULE(TblComprehension);
348 AST_RULE(StarExp); 388 AST_RULE(StarExp);
349 AST_RULE(CompForEach); 389 AST_RULE(CompForEach);
390 AST_RULE(CompForNum);
350 AST_RULE(CompFor); 391 AST_RULE(CompFor);
351 AST_RULE(CompInner);
352 AST_RULE(Assign); 392 AST_RULE(Assign);
353 AST_RULE(UpdateOp); 393 AST_RULE(UpdateOp);
354 AST_RULE(Update); 394 AST_RULE(Update);
@@ -359,6 +399,7 @@ private:
359 AST_RULE(ExpOpValue); 399 AST_RULE(ExpOpValue);
360 AST_RULE(Exp); 400 AST_RULE(Exp);
361 AST_RULE(Callable); 401 AST_RULE(Callable);
402 AST_RULE(ReversedIndex);
362 AST_RULE(ChainValue); 403 AST_RULE(ChainValue);
363 AST_RULE(SimpleTable); 404 AST_RULE(SimpleTable);
364 AST_RULE(SimpleValue); 405 AST_RULE(SimpleValue);
@@ -371,6 +412,11 @@ private:
371 AST_RULE(DoubleStringInner); 412 AST_RULE(DoubleStringInner);
372 AST_RULE(DoubleStringContent); 413 AST_RULE(DoubleStringContent);
373 AST_RULE(DoubleString); 414 AST_RULE(DoubleString);
415 AST_RULE(YAMLIndent);
416 AST_RULE(YAMLLineInner);
417 AST_RULE(YAMLLineContent);
418 AST_RULE(YAMLLine);
419 AST_RULE(YAMLMultiline);
374 AST_RULE(String); 420 AST_RULE(String);
375 AST_RULE(Parens); 421 AST_RULE(Parens);
376 AST_RULE(DotChainItem); 422 AST_RULE(DotChainItem);
@@ -427,13 +473,16 @@ private:
427 AST_RULE(ExpListAssign); 473 AST_RULE(ExpListAssign);
428 AST_RULE(IfLine); 474 AST_RULE(IfLine);
429 AST_RULE(WhileLine); 475 AST_RULE(WhileLine);
476 AST_RULE(Break);
477 AST_RULE(Continue);
430 AST_RULE(BreakLoop); 478 AST_RULE(BreakLoop);
431 AST_RULE(StatementAppendix); 479 AST_RULE(StatementAppendix);
432 AST_RULE(Statement); 480 AST_RULE(Statement);
433 AST_RULE(StatementSep); 481 AST_RULE(StatementSep);
434 AST_RULE(YueLineComment); 482 AST_RULE(YueLineComment);
435 AST_RULE(MultilineCommentInner);
436 AST_RULE(YueMultilineComment); 483 AST_RULE(YueMultilineComment);
484 AST_RULE(YueComment);
485 AST_RULE(EmptyLine);
437 AST_RULE(ChainAssign); 486 AST_RULE(ChainAssign);
438 AST_RULE(Body); 487 AST_RULE(Body);
439 AST_RULE(Block); 488 AST_RULE(Block);
@@ -444,6 +493,7 @@ private:
444namespace Utils { 493namespace Utils {
445void replace(std::string& str, std::string_view from, std::string_view to); 494void replace(std::string& str, std::string_view from, std::string_view to);
446void trim(std::string& str); 495void trim(std::string& str);
496std::string toLuaDoubleString(const std::string& input);
447} // namespace Utils 497} // namespace Utils
448 498
449} // namespace yue 499} // 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
3Permission 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: 3Permission 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 }