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
-rwxr-xr-xsrc/3rdParty/utf8cpp.h1277
-rw-r--r--src/yue.cpp45
-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.cpp264
-rw-r--r--src/yuescript/yue_ast.h159
-rw-r--r--src/yuescript/yue_compiler.cpp2037
-rw-r--r--src/yuescript/yue_compiler.h4
-rw-r--r--src/yuescript/yue_parser.cpp683
-rw-r--r--src/yuescript/yue_parser.h84
-rw-r--r--src/yuescript/yuescript.cpp41
14 files changed, 4575 insertions, 1003 deletions
diff --git a/src/3rdParty/colib/LICENSE b/src/3rdParty/colib/LICENSE
new file mode 100755
index 0000000..e0eddeb
--- /dev/null
+++ b/src/3rdParty/colib/LICENSE
@@ -0,0 +1,21 @@
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/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..b93f75e 100644
--- a/src/yue.cpp
+++ b/src/yue.cpp
@@ -1,4 +1,4 @@
1/* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> 1/* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com>
2 2
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) {
@@ -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 fdb1d20..14d8db8 100644
--- a/src/yuescript/yue_ast.cpp
+++ b/src/yuescript/yue_ast.cpp
@@ -1,4 +1,4 @@
1/* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> 1/* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com>
2 2
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,7 +174,7 @@ 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*) const { 180std::string GlobalOp_t::to_string(void*) const {
@@ -203,14 +210,18 @@ std::string YueLineComment_t::to_string(void* ud) const {
203 auto info = reinterpret_cast<YueFormat*>(ud); 210 auto info = reinterpret_cast<YueFormat*>(ud);
204 return "--"s + info->convert(this); 211 return "--"s + info->convert(this);
205} 212}
206std::string MultilineCommentInner_t::to_string(void* ud) const { 213std::string YueMultilineComment_t::to_string(void* ud) const {
207 auto info = reinterpret_cast<YueFormat*>(ud); 214 auto info = reinterpret_cast<YueFormat*>(ud);
208 return info->convert(this); 215 return "--[["s + info->convert(this) + "]]"s;
209} 216}
210std::string Variable_t::to_string(void* ud) const { 217std::string YueComment_t::to_string(void* ud) const {
211 return name->to_string(ud); 218 if (comment) {
219 return comment->to_string(ud);
220 } else {
221 return {};
222 }
212} 223}
213std::string LabelName_t::to_string(void* ud) const { 224std::string Variable_t::to_string(void* ud) const {
214 return name->to_string(ud); 225 return name->to_string(ud);
215} 226}
216std::string LuaKeyword_t::to_string(void* ud) const { 227std::string LuaKeyword_t::to_string(void* ud) const {
@@ -304,6 +315,17 @@ std::string ImportAs_t::to_string(void* ud) const {
304 } 315 }
305 return join(temp, " "s); 316 return join(temp, " "s);
306} 317}
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}
307std::string Import_t::to_string(void* ud) const { 329std::string Import_t::to_string(void* ud) const {
308 if (ast_is<FromImport_t>(content)) { 330 if (ast_is<FromImport_t>(content)) {
309 return content->to_string(ud); 331 return content->to_string(ud);
@@ -372,8 +394,8 @@ std::string With_t::to_string(void* ud) const {
372 str_list temp{ 394 str_list temp{
373 eop ? "with?"s : "with"s, 395 eop ? "with?"s : "with"s,
374 valueList->to_string(ud)}; 396 valueList->to_string(ud)};
375 if (assigns) { 397 if (assign) {
376 temp.push_back(assigns->to_string(ud)); 398 temp.push_back(':' + assign->to_string(ud));
377 } 399 }
378 if (body.is<Statement_t>()) { 400 if (body.is<Statement_t>()) {
379 return join(temp, " "sv) + " do "s + body->to_string(ud); 401 return join(temp, " "sv) + " do "s + body->to_string(ud);
@@ -419,6 +441,9 @@ std::string SwitchCase_t::to_string(void* ud) const {
419std::string Switch_t::to_string(void* ud) const { 441std::string Switch_t::to_string(void* ud) const {
420 auto info = reinterpret_cast<YueFormat*>(ud); 442 auto info = reinterpret_cast<YueFormat*>(ud);
421 str_list temp{"switch "s + target->to_string(ud)}; 443 str_list temp{"switch "s + target->to_string(ud)};
444 if (assignment) {
445 temp.back().append(assignment->to_string(ud));
446 }
422 info->pushScope(); 447 info->pushScope();
423 for (auto branch : branches.objects()) { 448 for (auto branch : branches.objects()) {
424 temp.emplace_back(info->ind() + branch->to_string(ud)); 449 temp.emplace_back(info->ind() + branch->to_string(ud));
@@ -462,41 +487,75 @@ std::string If_t::to_string(void* ud) const {
462 temp.back() += " then"s; 487 temp.back() += " then"s;
463 } 488 }
464 ++it; 489 ++it;
465 bool condition = true; 490 enum class NType {
491 Cond,
492 Stat,
493 Block
494 };
495 NType lastType = NType::Cond;
466 for (; it != nodes.objects().end(); ++it) { 496 for (; it != nodes.objects().end(); ++it) {
467 auto node = *it; 497 auto node = *it;
468 switch (node->get_id()) { 498 switch (node->get_id()) {
469 case id<IfCond_t>(): 499 case id<IfCond_t>():
470 temp.emplace_back(info->ind() + "elseif "s + node->to_string(ud)); 500 temp.emplace_back(info->ind() + "elseif "s + node->to_string(ud));
471 condition = true; 501 lastType = NType::Cond;
472 break; 502 break;
473 case id<Statement_t>(): { 503 case id<Statement_t>(): {
474 if (condition) { 504 switch (lastType) {
475 temp.back() += " then "s + node->to_string(ud); 505 case NType::Cond:
476 } else { 506 temp.back() += " then "s + node->to_string(ud);
477 temp.emplace_back(info->ind() + "else "s + node->to_string(ud)); 507 break;
508 case NType::Stat:
509 if (temp.back().back() == '\n') {
510 temp.emplace_back(info->ind() + "else "s + node->to_string(ud));
511 } else {
512 temp.back() += " else "s + node->to_string(ud);
513 }
514 break;
515 case NType::Block:
516 temp.emplace_back(info->ind() + "else "s + node->to_string(ud));
517 break;
478 } 518 }
479 condition = false; 519 lastType = NType::Stat;
480 break; 520 break;
481 } 521 }
482 case id<Block_t>(): { 522 case id<Block_t>(): {
483 if (condition) { 523 switch (lastType) {
484 info->pushScope(); 524 case NType::Cond: {
485 temp.emplace_back(node->to_string(ud)); 525 info->pushScope();
486 if (temp.back().empty()) { 526 temp.emplace_back(node->to_string(ud));
487 temp.back() = info->ind() + "--"s; 527 if (temp.back().empty()) {
528 temp.back() = info->ind() + "--"s;
529 }
530 info->popScope();
531 break;
532 }
533 case NType::Stat: {
534 if (temp.back().back() == '\n') {
535 temp.emplace_back(info->ind() + "else"s);
536 } else {
537 temp.back() += " else"s;
538 }
539 info->pushScope();
540 temp.emplace_back(node->to_string(ud));
541 if (temp.back().empty()) {
542 temp.back() = info->ind() + "--"s;
543 }
544 info->popScope();
545 break;
488 } 546 }
489 info->popScope(); 547 case NType::Block: {
490 } else { 548 temp.emplace_back(info->ind() + "else"s);
491 temp.emplace_back(info->ind() + "else"s); 549 info->pushScope();
492 info->pushScope(); 550 temp.emplace_back(node->to_string(ud));
493 temp.emplace_back(node->to_string(ud)); 551 if (temp.back().empty()) {
494 if (temp.back().empty()) { 552 temp.back() = info->ind() + "--"s;
495 temp.back() = info->ind() + "--"s; 553 }
554 info->popScope();
555 break;
496 } 556 }
497 info->popScope();
498 } 557 }
499 condition = false; 558 lastType = NType::Block;
500 break; 559 break;
501 } 560 }
502 } 561 }
@@ -524,10 +583,10 @@ std::string While_t::to_string(void* ud) const {
524} 583}
525std::string Repeat_t::to_string(void* ud) const { 584std::string Repeat_t::to_string(void* ud) const {
526 auto info = reinterpret_cast<YueFormat*>(ud); 585 auto info = reinterpret_cast<YueFormat*>(ud);
527 str_list temp; 586 if (body.is<Statement_t>()) {
528 if (body->content.is<Statement_t>()) { 587 return "repeat "s + body->to_string(ud) + " until "s + condition->to_string(ud);
529 temp.emplace_back("repeat "s + body->to_string(ud));
530 } else { 588 } else {
589 str_list temp;
531 temp.emplace_back("repeat"s); 590 temp.emplace_back("repeat"s);
532 info->pushScope(); 591 info->pushScope();
533 temp.emplace_back(body->to_string(ud)); 592 temp.emplace_back(body->to_string(ud));
@@ -535,14 +594,14 @@ std::string Repeat_t::to_string(void* ud) const {
535 temp.back() = info->ind() + "--"s; 594 temp.back() = info->ind() + "--"s;
536 } 595 }
537 info->popScope(); 596 info->popScope();
597 temp.emplace_back(info->ind() + "until "s + condition->to_string(ud));
598 return join(temp, "\n"sv);
538 } 599 }
539 temp.emplace_back(info->ind() + "until "s + condition->to_string(ud));
540 return join(temp, "\n"sv);
541} 600}
542std::string ForStepValue_t::to_string(void* ud) const { 601std::string ForStepValue_t::to_string(void* ud) const {
543 return value->to_string(ud); 602 return value->to_string(ud);
544} 603}
545std::string For_t::to_string(void* ud) const { 604std::string ForNum_t::to_string(void* ud) const {
546 auto info = reinterpret_cast<YueFormat*>(ud); 605 auto info = reinterpret_cast<YueFormat*>(ud);
547 auto line = "for "s + varName->to_string(ud) + " = "s + startValue->to_string(ud) + ", "s + stopValue->to_string(ud); 606 auto line = "for "s + varName->to_string(ud) + " = "s + startValue->to_string(ud) + ", "s + stopValue->to_string(ud);
548 if (stepValue) { 607 if (stepValue) {
@@ -581,6 +640,9 @@ std::string ForEach_t::to_string(void* ud) const {
581 return line + '\n' + block; 640 return line + '\n' + block;
582 } 641 }
583} 642}
643std::string For_t::to_string(void* ud) const {
644 return forLoop->to_string(ud);
645}
584std::string Do_t::to_string(void* ud) const { 646std::string Do_t::to_string(void* ud) const {
585 auto info = reinterpret_cast<YueFormat*>(ud); 647 auto info = reinterpret_cast<YueFormat*>(ud);
586 if (body->content.is<Statement_t>()) { 648 if (body->content.is<Statement_t>()) {
@@ -609,10 +671,13 @@ std::string CatchBlock_t::to_string(void* ud) const {
609std::string Try_t::to_string(void* ud) const { 671std::string Try_t::to_string(void* ud) const {
610 auto info = reinterpret_cast<YueFormat*>(ud); 672 auto info = reinterpret_cast<YueFormat*>(ud);
611 str_list temp; 673 str_list temp;
674 temp.emplace_back("try"s);
675 if (eop) {
676 temp.back() += eop->to_string(ud);
677 }
612 if (func.is<Exp_t>()) { 678 if (func.is<Exp_t>()) {
613 temp.emplace_back("try "s + func->to_string(ud)); 679 temp.back() += (" "s + func->to_string(ud));
614 } else { 680 } else {
615 temp.emplace_back("try"s);
616 info->pushScope(); 681 info->pushScope();
617 temp.emplace_back(func->to_string(ud)); 682 temp.emplace_back(func->to_string(ud));
618 if (temp.back().empty()) { 683 if (temp.back().empty()) {
@@ -729,7 +794,7 @@ static bool isInBlockExp(ast_node* node, bool last = false) {
729 return false; 794 return false;
730} 795}
731std::string Comprehension_t::to_string(void* ud) const { 796std::string Comprehension_t::to_string(void* ud) const {
732 if (items.size() != 2 || !ast_is<CompInner_t>(items.back())) { 797 if (items.size() != 2 || !ast_is<CompFor_t>(items.back())) {
733 if (items.size() == 1) { 798 if (items.size() == 1) {
734 str_list temp; 799 str_list temp;
735 for (const auto& item : items.objects()) { 800 for (const auto& item : items.objects()) {
@@ -796,14 +861,14 @@ std::string StarExp_t::to_string(void* ud) const {
796std::string CompForEach_t::to_string(void* ud) const { 861std::string CompForEach_t::to_string(void* ud) const {
797 return "for "s + nameList->to_string(ud) + " in "s + loopValue->to_string(ud); 862 return "for "s + nameList->to_string(ud) + " in "s + loopValue->to_string(ud);
798} 863}
799std::string CompFor_t::to_string(void* ud) const { 864std::string CompForNum_t::to_string(void* ud) const {
800 auto line = "for "s + varName->to_string(ud) + " = "s + startValue->to_string(ud) + ", "s + stopValue->to_string(ud); 865 auto line = "for "s + varName->to_string(ud) + " = "s + startValue->to_string(ud) + ", "s + stopValue->to_string(ud);
801 if (stepValue) { 866 if (stepValue) {
802 line += stepValue->to_string(ud); 867 line += stepValue->to_string(ud);
803 } 868 }
804 return line; 869 return line;
805} 870}
806std::string CompInner_t::to_string(void* ud) const { 871std::string CompFor_t::to_string(void* ud) const {
807 str_list temp; 872 str_list temp;
808 for (auto item : items.objects()) { 873 for (auto item : items.objects()) {
809 if (ast_is<Exp_t>(item)) { 874 if (ast_is<Exp_t>(item)) {
@@ -864,6 +929,12 @@ std::string Exp_t::to_string(void* ud) const {
864 } 929 }
865 return join(temp, " "sv); 930 return join(temp, " "sv);
866} 931}
932std::string ReversedIndex_t::to_string(void* ud) const {
933 if (modifier) {
934 return "[# - "s + modifier->to_string(ud) + ']';
935 }
936 return "[#]"s;
937}
867std::string Callable_t::to_string(void* ud) const { 938std::string Callable_t::to_string(void* ud) const {
868 return item->to_string(ud); 939 return item->to_string(ud);
869} 940}
@@ -950,6 +1021,51 @@ std::string DoubleString_t::to_string(void* ud) const {
950 } 1021 }
951 return '"' + join(temp) + '"'; 1022 return '"' + join(temp) + '"';
952} 1023}
1024std::string YAMLIndent_t::to_string(void* ud) const {
1025 auto info = reinterpret_cast<YueFormat*>(ud);
1026 return info->convert(this);
1027}
1028std::string YAMLLineInner_t::to_string(void* ud) const {
1029 auto info = reinterpret_cast<YueFormat*>(ud);
1030 return info->convert(this);
1031}
1032std::string YAMLLineContent_t::to_string(void* ud) const {
1033 if (content.is<Exp_t>()) {
1034 return "#{"s + content->to_string(ud) + '}';
1035 }
1036 return content->to_string(ud);
1037}
1038std::string YAMLLine_t::to_string(void* ud) const {
1039 str_list temp;
1040 for (auto seg : segments.objects()) {
1041 temp.emplace_back(seg->to_string(ud));
1042 }
1043 return join(temp);
1044}
1045std::string YAMLMultiline_t::to_string(void* ud) const {
1046 auto info = reinterpret_cast<YueFormat*>(ud);
1047 int currentIndent = info->indent;
1048 str_list temp;
1049 int lastIndent = -1;
1050 for (auto line_ : lines.objects()) {
1051 auto line = static_cast<YAMLLine_t*>(line_);
1052 auto indent = line->indent->to_string(ud);
1053 int ind = 0;
1054 for (auto c : indent) {
1055 if (c == ' ') ind++;
1056 if (c == '\t') ind += 4;
1057 }
1058 if (lastIndent < ind) {
1059 info->pushScope();
1060 } else if (lastIndent > ind) {
1061 info->popScope();
1062 }
1063 lastIndent = ind;
1064 temp.emplace_back(indent + line->to_string(ud));
1065 }
1066 info->indent = currentIndent;
1067 return "|\n" + join(temp, "\n"sv) + '\n';
1068}
953std::string String_t::to_string(void* ud) const { 1069std::string String_t::to_string(void* ud) const {
954 return str->to_string(ud); 1070 return str->to_string(ud);
955} 1071}
@@ -1248,6 +1364,9 @@ std::string FnArgDef_t::to_string(void* ud) const {
1248 if (op) { 1364 if (op) {
1249 line += op->to_string(ud); 1365 line += op->to_string(ud);
1250 } 1366 }
1367 if (label) {
1368 line += '`' + label->to_string(ud);
1369 }
1251 if (defaultValue) { 1370 if (defaultValue) {
1252 line += " = "s + defaultValue->to_string(ud); 1371 line += " = "s + defaultValue->to_string(ud);
1253 } 1372 }
@@ -1270,6 +1389,9 @@ std::string FnArgDefList_t::to_string(void* ud) const {
1270 } 1389 }
1271 if (varArg) { 1390 if (varArg) {
1272 temp.emplace_back(info->ind() + varArg->to_string(ud)); 1391 temp.emplace_back(info->ind() + varArg->to_string(ud));
1392 if (label) {
1393 temp.back().append('`' + label->to_string(ud));
1394 }
1273 } 1395 }
1274 return join(temp, "\n"sv); 1396 return join(temp, "\n"sv);
1275 } else { 1397 } else {
@@ -1278,6 +1400,9 @@ std::string FnArgDefList_t::to_string(void* ud) const {
1278 } 1400 }
1279 if (varArg) { 1401 if (varArg) {
1280 temp.emplace_back(varArg->to_string(ud)); 1402 temp.emplace_back(varArg->to_string(ud));
1403 if (label) {
1404 temp.back().append('`' + label->to_string(ud));
1405 }
1281 } 1406 }
1282 return join(temp, ", "sv); 1407 return join(temp, ", "sv);
1283 } 1408 }
@@ -1488,37 +1613,17 @@ std::string StatementAppendix_t::to_string(void* ud) const {
1488 return item->to_string(ud); 1613 return item->to_string(ud);
1489} 1614}
1490std::string Statement_t::to_string(void* ud) const { 1615std::string Statement_t::to_string(void* ud) const {
1491 std::string line; 1616 if (appendix) {
1492 if (!comments.empty()) { 1617 return content->to_string(ud) + ' ' + appendix->to_string(ud);
1493 auto info = reinterpret_cast<YueFormat*>(ud);
1494 str_list temp;
1495 for (ast_node* comment : comments.objects()) {
1496 if (comment == comments.front()) {
1497 temp.push_back(comment->to_string(ud));
1498 } else {
1499 temp.push_back(info->ind() + comment->to_string(ud));
1500 }
1501 }
1502 if (appendix) {
1503 temp.push_back(info->ind() + content->to_string(ud) + ' ' + appendix->to_string(ud));
1504 return join(temp, "\n"sv);
1505 } else {
1506 temp.push_back(info->ind() + content->to_string(ud));
1507 return join(temp, "\n"sv);
1508 }
1509 } else { 1618 } else {
1510 if (appendix) { 1619 return content->to_string(ud);
1511 return content->to_string(ud) + ' ' + appendix->to_string(ud);
1512 } else {
1513 return content->to_string(ud);
1514 }
1515 } 1620 }
1516} 1621}
1517std::string StatementSep_t::to_string(void*) const { 1622std::string StatementSep_t::to_string(void*) const {
1518 return {}; 1623 return {};
1519} 1624}
1520std::string YueMultilineComment_t::to_string(void* ud) const { 1625std::string EmptyLine_t::to_string(void*) const {
1521 return "--[["s + inner->to_string(ud) + "]]"s; 1626 return {};
1522} 1627}
1523std::string ChainAssign_t::to_string(void* ud) const { 1628std::string ChainAssign_t::to_string(void* ud) const {
1524 str_list temp; 1629 str_list temp;
@@ -1533,14 +1638,22 @@ std::string Body_t::to_string(void* ud) const {
1533std::string Block_t::to_string(void* ud) const { 1638std::string Block_t::to_string(void* ud) const {
1534 auto info = reinterpret_cast<YueFormat*>(ud); 1639 auto info = reinterpret_cast<YueFormat*>(ud);
1535 str_list temp; 1640 str_list temp;
1536 for (auto stmt_ : statements.objects()) { 1641 for (auto stmt_ : statementOrComments.objects()) {
1537 auto stmt = static_cast<Statement_t*>(stmt_); 1642 if (auto stmt = ast_cast<Statement_t>(stmt_)) {
1538 if (stmt->content.is<PipeBody_t>()) { 1643 if (stmt->content.is<PipeBody_t>()) {
1539 info->pushScope(); 1644 info->pushScope();
1540 temp.emplace_back(stmt->to_string(ud)); 1645 temp.emplace_back(stmt->to_string(ud));
1541 info->popScope(); 1646 info->popScope();
1542 } else { 1647 } else {
1543 temp.emplace_back(info->ind() + stmt->to_string(ud)); 1648 temp.emplace_back(info->ind() + stmt->to_string(ud));
1649 }
1650 } else if (info->reserveComment) {
1651 if (auto comment = ast_cast<YueComment_t>(stmt_)) {
1652 temp.emplace_back(info->ind() + comment->to_string(ud));
1653 } else {
1654 auto empty = ast_to<EmptyLine_t>(stmt_);
1655 temp.emplace_back(empty->to_string(ud));
1656 }
1544 } 1657 }
1545 } 1658 }
1546 return join(temp, "\n"sv); 1659 return join(temp, "\n"sv);
@@ -1559,3 +1672,4 @@ std::string File_t::to_string(void* ud) const {
1559} // namespace yue 1672} // namespace yue
1560 1673
1561} // namespace parserlib 1674} // namespace parserlib
1675
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h
index 0c15fac..ba4186d 100644
--- a/src/yuescript/yue_ast.h
+++ b/src/yuescript/yue_ast.h
@@ -1,4 +1,4 @@
1/* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> 1/* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com>
2 2
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
@@ -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
@@ -233,18 +233,25 @@ AST_NODE(ImportAs)
233 AST_MEMBER(ImportAs, &literal, &target) 233 AST_MEMBER(ImportAs, &literal, &target)
234AST_END(ImportAs) 234AST_END(ImportAs)
235 235
236AST_NODE(ImportGlobal)
237 ast_ptr<true, Seperator_t> sep;
238 ast_list<true, UnicodeName_t> segs;
239 ast_ptr<false, Variable_t> target;
240 AST_MEMBER(ImportGlobal, &sep, &segs, &target)
241AST_END(ImportGlobal)
242
236AST_NODE(Import) 243AST_NODE(Import)
237 ast_sel<true, ImportAs_t, ImportFrom_t, FromImport_t> content; 244 ast_sel<true, ImportAs_t, ImportFrom_t, FromImport_t, ImportGlobal_t> content;
238 AST_MEMBER(Import, &content) 245 AST_MEMBER(Import, &content)
239AST_END(Import) 246AST_END(Import)
240 247
241AST_NODE(Label) 248AST_NODE(Label)
242 ast_ptr<true, LabelName_t> label; 249 ast_ptr<true, UnicodeName_t> label;
243 AST_MEMBER(Label, &label) 250 AST_MEMBER(Label, &label)
244AST_END(Label) 251AST_END(Label)
245 252
246AST_NODE(Goto) 253AST_NODE(Goto)
247 ast_ptr<true, LabelName_t> label; 254 ast_ptr<true, UnicodeName_t> label;
248 AST_MEMBER(Goto, &label) 255 AST_MEMBER(Goto, &label)
249AST_END(Goto) 256AST_END(Goto)
250 257
@@ -287,9 +294,9 @@ AST_END(Return)
287AST_NODE(With) 294AST_NODE(With)
288 ast_ptr<false, ExistentialOp_t> eop; 295 ast_ptr<false, ExistentialOp_t> eop;
289 ast_ptr<true, ExpList_t> valueList; 296 ast_ptr<true, ExpList_t> valueList;
290 ast_ptr<false, Assign_t> assigns; 297 ast_ptr<false, Assign_t> assign;
291 ast_sel<true, Block_t, Statement_t> body; 298 ast_sel<true, Block_t, Statement_t> body;
292 AST_MEMBER(With, &eop, &valueList, &assigns, &body) 299 AST_MEMBER(With, &eop, &valueList, &assign, &body)
293AST_END(With) 300AST_END(With)
294 301
295AST_NODE(SwitchList) 302AST_NODE(SwitchList)
@@ -304,20 +311,21 @@ AST_NODE(SwitchCase)
304 AST_MEMBER(SwitchCase, &condition, &body) 311 AST_MEMBER(SwitchCase, &condition, &body)
305AST_END(SwitchCase) 312AST_END(SwitchCase)
306 313
314AST_NODE(Assignment)
315 ast_ptr<false, ExpList_t> expList;
316 ast_ptr<true, Assign_t> assign;
317 AST_MEMBER(Assignment, &expList, &assign)
318AST_END(Assignment)
319
307AST_NODE(Switch) 320AST_NODE(Switch)
308 ast_ptr<true, Exp_t> target; 321 ast_ptr<true, Exp_t> target;
322 ast_ptr<false, Assignment_t> assignment;
309 ast_ptr<true, Seperator_t> sep; 323 ast_ptr<true, Seperator_t> sep;
310 ast_list<true, SwitchCase_t> branches; 324 ast_list<true, SwitchCase_t> branches;
311 ast_sel<false, Block_t, Statement_t> lastBranch; 325 ast_sel<false, Block_t, Statement_t> lastBranch;
312 AST_MEMBER(Switch, &target, &sep, &branches, &lastBranch) 326 AST_MEMBER(Switch, &target, &assignment, &sep, &branches, &lastBranch)
313AST_END(Switch) 327AST_END(Switch)
314 328
315AST_NODE(Assignment)
316 ast_ptr<false, ExpList_t> expList;
317 ast_ptr<true, Assign_t> assign;
318 AST_MEMBER(Assignment, &expList, &assign)
319AST_END(Assignment)
320
321AST_NODE(IfCond) 329AST_NODE(IfCond)
322 ast_ptr<true, Exp_t> condition; 330 ast_ptr<true, Exp_t> condition;
323 ast_ptr<false, Assignment_t> assignment; 331 ast_ptr<false, Assignment_t> assignment;
@@ -345,7 +353,7 @@ AST_NODE(While)
345AST_END(While) 353AST_END(While)
346 354
347AST_NODE(Repeat) 355AST_NODE(Repeat)
348 ast_ptr<true, Body_t> body; 356 ast_sel<true, Block_t, Statement_t> body;
349 ast_ptr<true, Exp_t> condition; 357 ast_ptr<true, Exp_t> condition;
350 AST_MEMBER(Repeat, &body, &condition) 358 AST_MEMBER(Repeat, &body, &condition)
351AST_END(Repeat) 359AST_END(Repeat)
@@ -355,14 +363,14 @@ AST_NODE(ForStepValue)
355 AST_MEMBER(ForStepValue, &value) 363 AST_MEMBER(ForStepValue, &value)
356AST_END(ForStepValue) 364AST_END(ForStepValue)
357 365
358AST_NODE(For) 366AST_NODE(ForNum)
359 ast_ptr<true, Variable_t> varName; 367 ast_ptr<true, Variable_t> varName;
360 ast_ptr<true, Exp_t> startValue; 368 ast_ptr<true, Exp_t> startValue;
361 ast_ptr<true, Exp_t> stopValue; 369 ast_ptr<true, Exp_t> stopValue;
362 ast_ptr<false, ForStepValue_t> stepValue; 370 ast_ptr<false, ForStepValue_t> stepValue;
363 ast_sel<true, Block_t, Statement_t> body; 371 ast_sel<true, Block_t, Statement_t> body;
364 AST_MEMBER(For, &varName, &startValue, &stopValue, &stepValue, &body) 372 AST_MEMBER(ForNum, &varName, &startValue, &stopValue, &stepValue, &body)
365AST_END(For) 373AST_END(ForNum)
366 374
367AST_NODE(ForEach) 375AST_NODE(ForEach)
368 ast_ptr<true, AssignableNameList_t> nameList; 376 ast_ptr<true, AssignableNameList_t> nameList;
@@ -371,6 +379,11 @@ AST_NODE(ForEach)
371 AST_MEMBER(ForEach, &nameList, &loopValue, &body) 379 AST_MEMBER(ForEach, &nameList, &loopValue, &body)
372AST_END(ForEach) 380AST_END(ForEach)
373 381
382AST_NODE(For)
383 ast_sel<true, ForEach_t, ForNum_t> forLoop;
384 AST_MEMBER(For, &forLoop)
385AST_END(For)
386
374AST_NODE(Do) 387AST_NODE(Do)
375 ast_ptr<true, Body_t> body; 388 ast_ptr<true, Body_t> body;
376 AST_MEMBER(Do, &body) 389 AST_MEMBER(Do, &body)
@@ -383,14 +396,15 @@ AST_NODE(CatchBlock)
383AST_END(CatchBlock) 396AST_END(CatchBlock)
384 397
385AST_NODE(Try) 398AST_NODE(Try)
399 ast_ptr<false, ExistentialOp_t> eop;
386 ast_sel<true, Block_t, Exp_t> func; 400 ast_sel<true, Block_t, Exp_t> func;
387 ast_ptr<false, CatchBlock_t> catchBlock; 401 ast_ptr<false, CatchBlock_t> catchBlock;
388 AST_MEMBER(Try, &func, &catchBlock) 402 AST_MEMBER(Try, &eop, &func, &catchBlock)
389AST_END(Try) 403AST_END(Try)
390 404
391AST_NODE(Comprehension) 405AST_NODE(Comprehension)
392 ast_ptr<true, Seperator_t> sep; 406 ast_ptr<true, Seperator_t> sep;
393 ast_sel_list<false, NormalDef_t, SpreadListExp_t, CompInner_t, 407 ast_sel_list<false, NormalDef_t, SpreadListExp_t, CompFor_t,
394 /*non-syntax-rule*/ Statement_t> items; 408 /*non-syntax-rule*/ Statement_t> items;
395 AST_MEMBER(Comprehension, &sep, &items) 409 AST_MEMBER(Comprehension, &sep, &items)
396AST_END(Comprehension) 410AST_END(Comprehension)
@@ -403,7 +417,7 @@ AST_END(CompValue)
403AST_NODE(TblComprehension) 417AST_NODE(TblComprehension)
404 ast_ptr<true, Exp_t> key; 418 ast_ptr<true, Exp_t> key;
405 ast_ptr<false, CompValue_t> value; 419 ast_ptr<false, CompValue_t> value;
406 ast_ptr<true, CompInner_t> forLoop; 420 ast_ptr<true, CompFor_t> forLoop;
407 AST_MEMBER(TblComprehension, &key, &value, &forLoop) 421 AST_MEMBER(TblComprehension, &key, &value, &forLoop)
408AST_END(TblComprehension) 422AST_END(TblComprehension)
409 423
@@ -418,23 +432,23 @@ AST_NODE(CompForEach)
418 AST_MEMBER(CompForEach, &nameList, &loopValue) 432 AST_MEMBER(CompForEach, &nameList, &loopValue)
419AST_END(CompForEach) 433AST_END(CompForEach)
420 434
421AST_NODE(CompFor) 435AST_NODE(CompForNum)
422 ast_ptr<true, Variable_t> varName; 436 ast_ptr<true, Variable_t> varName;
423 ast_ptr<true, Exp_t> startValue; 437 ast_ptr<true, Exp_t> startValue;
424 ast_ptr<true, Exp_t> stopValue; 438 ast_ptr<true, Exp_t> stopValue;
425 ast_ptr<false, ForStepValue_t> stepValue; 439 ast_ptr<false, ForStepValue_t> stepValue;
426 AST_MEMBER(CompFor, &varName, &startValue, &stopValue, &stepValue) 440 AST_MEMBER(CompForNum, &varName, &startValue, &stopValue, &stepValue)
427AST_END(CompFor) 441AST_END(CompForNum)
428 442
429AST_NODE(CompInner) 443AST_NODE(CompFor)
430 ast_ptr<true, Seperator_t> sep; 444 ast_ptr<true, Seperator_t> sep;
431 ast_sel_list<true, CompFor_t, CompForEach_t, Exp_t> items; 445 ast_sel_list<true, CompForNum_t, CompForEach_t, Exp_t> items;
432 AST_MEMBER(CompInner, &sep, &items) 446 AST_MEMBER(CompFor, &sep, &items)
433AST_END(CompInner) 447AST_END(CompFor)
434 448
435AST_NODE(Assign) 449AST_NODE(Assign)
436 ast_ptr<true, Seperator_t> sep; 450 ast_ptr<true, Seperator_t> sep;
437 ast_sel_list<true, With_t, If_t, Switch_t, TableBlock_t, Exp_t> values; 451 ast_sel_list<true, With_t, If_t, Switch_t, TableBlock_t, Exp_t, SpreadListExp_t> values;
438 AST_MEMBER(Assign, &sep, &values) 452 AST_MEMBER(Assign, &sep, &values)
439AST_END(Assign) 453AST_END(Assign)
440 454
@@ -549,8 +563,8 @@ AST_NODE(SimpleValue)
549 ast_sel<true, 563 ast_sel<true,
550 TableLit_t, ConstValue_t, 564 TableLit_t, ConstValue_t,
551 If_t, Switch_t, With_t, ClassDecl_t, 565 If_t, Switch_t, With_t, ClassDecl_t,
552 ForEach_t, For_t, While_t, Do_t, Try_t, 566 For_t, While_t, Repeat_t,
553 UnaryValue_t, 567 Do_t, Try_t, UnaryValue_t,
554 TblComprehension_t, Comprehension_t, 568 TblComprehension_t, Comprehension_t,
555 FunLit_t, Num_t, VarArg_t> value; 569 FunLit_t, Num_t, VarArg_t> value;
556 AST_MEMBER(SimpleValue, &value) 570 AST_MEMBER(SimpleValue, &value)
@@ -589,8 +603,31 @@ AST_NODE(DoubleString)
589 AST_MEMBER(DoubleString, &sep, &segments) 603 AST_MEMBER(DoubleString, &sep, &segments)
590AST_END(DoubleString) 604AST_END(DoubleString)
591 605
606AST_LEAF(YAMLIndent)
607AST_END(YAMLIndent)
608
609AST_LEAF(YAMLLineInner)
610AST_END(YAMLLineInner)
611
612AST_NODE(YAMLLineContent)
613 ast_sel<true, YAMLLineInner_t, Exp_t> content;
614 AST_MEMBER(YAMLLineContent, &content)
615AST_END(YAMLLineContent)
616
617AST_NODE(YAMLLine)
618 ast_ptr<true, YAMLIndent_t> indent;
619 ast_list<true, YAMLLineContent_t> segments;
620 AST_MEMBER(YAMLLine, &indent, &segments)
621AST_END(YAMLLine)
622
623AST_NODE(YAMLMultiline)
624 ast_ptr<true, Seperator_t> sep;
625 ast_list<true, YAMLLine_t> lines;
626 AST_MEMBER(YAMLMultiline, &sep, &lines)
627AST_END(YAMLMultiline)
628
592AST_NODE(String) 629AST_NODE(String)
593 ast_sel<true, DoubleString_t, SingleString_t, LuaString_t> str; 630 ast_sel<true, DoubleString_t, SingleString_t, LuaString_t, YAMLMultiline_t> str;
594 AST_MEMBER(String, &str) 631 AST_MEMBER(String, &str)
595AST_END(String) 632AST_END(String)
596 633
@@ -641,9 +678,14 @@ AST_END(TableAppendingOp)
641AST_LEAF(PlainItem) 678AST_LEAF(PlainItem)
642AST_END(PlainItem) 679AST_END(PlainItem)
643 680
681AST_NODE(ReversedIndex)
682 ast_ptr<false, Exp_t> modifier;
683 AST_MEMBER(ReversedIndex, &modifier)
684AST_END(ReversedIndex)
685
644AST_NODE(ChainValue) 686AST_NODE(ChainValue)
645 ast_ptr<true, Seperator_t> sep; 687 ast_ptr<true, Seperator_t> sep;
646 ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Slice_t, Exp_t, String_t, InvokeArgs_t, ExistentialOp_t, TableAppendingOp_t, 688 ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Slice_t, Exp_t, String_t, InvokeArgs_t, ExistentialOp_t, TableAppendingOp_t, ReversedIndex_t,
647 /*non-syntax-rule*/ PlainItem_t> items; 689 /*non-syntax-rule*/ PlainItem_t> items;
648 AST_MEMBER(ChainValue, &sep, &items) 690 AST_MEMBER(ChainValue, &sep, &items)
649AST_END(ChainValue) 691AST_END(ChainValue)
@@ -743,17 +785,19 @@ AST_NODE(Export)
743AST_END(Export) 785AST_END(Export)
744 786
745AST_NODE(FnArgDef) 787AST_NODE(FnArgDef)
746 ast_sel<true, Variable_t, SelfItem_t> name; 788 ast_sel<true, Variable_t, SelfItem_t, SimpleTable_t, TableLit_t> name;
747 ast_ptr<false, ExistentialOp_t> op; 789 ast_ptr<false, ExistentialOp_t> op;
790 ast_ptr<false, Name_t> label;
748 ast_ptr<false, Exp_t> defaultValue; 791 ast_ptr<false, Exp_t> defaultValue;
749 AST_MEMBER(FnArgDef, &name, &op, &defaultValue) 792 AST_MEMBER(FnArgDef, &name, &op, &label, &defaultValue)
750AST_END(FnArgDef) 793AST_END(FnArgDef)
751 794
752AST_NODE(FnArgDefList) 795AST_NODE(FnArgDefList)
753 ast_ptr<true, Seperator_t> sep; 796 ast_ptr<true, Seperator_t> sep;
754 ast_list<false, FnArgDef_t> definitions; 797 ast_list<false, FnArgDef_t> definitions;
755 ast_ptr<false, VarArg_t> varArg; 798 ast_ptr<false, VarArgDef_t> varArg;
756 AST_MEMBER(FnArgDefList, &sep, &definitions, &varArg) 799 ast_ptr<false, Name_t> label;
800 AST_MEMBER(FnArgDefList, &sep, &definitions, &varArg, &label)
757AST_END(FnArgDefList) 801AST_END(FnArgDefList)
758 802
759AST_NODE(OuterVarShadow) 803AST_NODE(OuterVarShadow)
@@ -809,7 +853,7 @@ AST_NODE(Macro)
809AST_END(Macro) 853AST_END(Macro)
810 854
811AST_NODE(NameOrDestructure) 855AST_NODE(NameOrDestructure)
812 ast_sel<true, Variable_t, TableLit_t, Comprehension_t> item; 856 ast_sel<true, Variable_t, SimpleTable_t, TableLit_t, Comprehension_t> item;
813 AST_MEMBER(NameOrDestructure, &item) 857 AST_MEMBER(NameOrDestructure, &item)
814AST_END(NameOrDestructure) 858AST_END(NameOrDestructure)
815 859
@@ -885,7 +929,7 @@ AST_NODE(PipeBody)
885AST_END(PipeBody) 929AST_END(PipeBody)
886 930
887AST_NODE(StatementAppendix) 931AST_NODE(StatementAppendix)
888 ast_sel<true, IfLine_t, WhileLine_t, CompInner_t> item; 932 ast_sel<true, IfLine_t, WhileLine_t, CompFor_t> item;
889 AST_MEMBER(StatementAppendix, &item) 933 AST_MEMBER(StatementAppendix, &item)
890AST_END(StatementAppendix) 934AST_END(StatementAppendix)
891 935
@@ -895,14 +939,17 @@ AST_END(StatementSep)
895AST_LEAF(YueLineComment) 939AST_LEAF(YueLineComment)
896AST_END(YueLineComment) 940AST_END(YueLineComment)
897 941
898AST_LEAF(MultilineCommentInner) 942AST_LEAF(YueMultilineComment)
899AST_END(MultilineCommentInner)
900
901AST_NODE(YueMultilineComment)
902 ast_ptr<true, MultilineCommentInner_t> inner;
903 AST_MEMBER(YueMultilineComment, &inner)
904AST_END(YueMultilineComment) 943AST_END(YueMultilineComment)
905 944
945AST_NODE(YueComment)
946 ast_sel<true, YueLineComment_t, YueMultilineComment_t> comment;
947 AST_MEMBER(YueComment, &comment)
948AST_END(YueComment)
949
950AST_LEAF(EmptyLine)
951AST_END(EmptyLine)
952
906AST_NODE(ChainAssign) 953AST_NODE(ChainAssign)
907 ast_ptr<true, Seperator_t> sep; 954 ast_ptr<true, Seperator_t> sep;
908 ast_list<true, Exp_t> exprs; 955 ast_list<true, Exp_t> exprs;
@@ -911,16 +958,14 @@ AST_NODE(ChainAssign)
911AST_END(ChainAssign) 958AST_END(ChainAssign)
912 959
913AST_NODE(Statement) 960AST_NODE(Statement)
914 ast_ptr<true, Seperator_t> sep;
915 ast_sel_list<false, YueLineComment_t, YueMultilineComment_t> comments;
916 ast_sel<true, 961 ast_sel<true,
917 Import_t, While_t, Repeat_t, For_t, ForEach_t, 962 Import_t, While_t, Repeat_t, For_t,
918 Return_t, Local_t, Global_t, Export_t, Macro_t, MacroInPlace_t, 963 Return_t, Local_t, Global_t, Export_t, Macro_t, MacroInPlace_t,
919 BreakLoop_t, Label_t, Goto_t, ShortTabAppending_t, 964 BreakLoop_t, Label_t, Goto_t, ShortTabAppending_t,
920 Backcall_t, LocalAttrib_t, PipeBody_t, ExpListAssign_t, ChainAssign_t 965 Backcall_t, LocalAttrib_t, PipeBody_t, ExpListAssign_t, ChainAssign_t
921 > content; 966 > content;
922 ast_ptr<false, StatementAppendix_t> appendix; 967 ast_ptr<false, StatementAppendix_t> appendix;
923 AST_MEMBER(Statement, &sep, &comments, &content, &appendix) 968 AST_MEMBER(Statement, &content, &appendix)
924AST_END(Statement) 969AST_END(Statement)
925 970
926AST_NODE(Body) 971AST_NODE(Body)
@@ -930,8 +975,8 @@ AST_END(Body)
930 975
931AST_NODE(Block) 976AST_NODE(Block)
932 ast_ptr<true, Seperator_t> sep; 977 ast_ptr<true, Seperator_t> sep;
933 ast_list<false, Statement_t> statements; 978 ast_sel_list<false, Statement_t, YueComment_t, EmptyLine_t> statementOrComments;
934 AST_MEMBER(Block, &sep, &statements) 979 AST_MEMBER(Block, &sep, &statementOrComments)
935AST_END(Block) 980AST_END(Block)
936 981
937AST_NODE(BlockEnd) 982AST_NODE(BlockEnd)
@@ -950,9 +995,9 @@ struct YueFormat {
950 int indent = 0; 995 int indent = 0;
951 bool spaceOverTab = false; 996 bool spaceOverTab = false;
952 int tabSpaces = 4; 997 int tabSpaces = 4;
998 bool reserveComment = true;
953 std::string toString(ast_node* node); 999 std::string toString(ast_node* node);
954 1000
955 Converter converter{};
956 void pushScope(); 1001 void pushScope();
957 void popScope(); 1002 void popScope();
958 std::string convert(const ast_node* node); 1003 std::string convert(const ast_node* node);
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index 7abc929..cffa7a8 100644
--- a/src/yuescript/yue_compiler.cpp
+++ b/src/yuescript/yue_compiler.cpp
@@ -1,4 +1,4 @@
1/* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> 1/* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com>
2 2
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.28.3"sv; 81const std::string_view version = "0.30.4"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";
@@ -875,6 +876,10 @@ private:
875 return false; 876 return false;
876 } 877 }
877 878
879 bool isListComp(Comprehension_t* comp) const {
880 return comp->items.size() == 2 && ast_is<CompFor_t>(comp->items.back());
881 }
882
878 void markVarLocalConst(const std::string& name) { 883 void markVarLocalConst(const std::string& name) {
879 auto& scope = _scopes.back(); 884 auto& scope = _scopes.back();
880 scope.vars->insert_or_assign(name, VarType::LocalConst); 885 scope.vars->insert_or_assign(name, VarType::LocalConst);
@@ -967,7 +972,7 @@ private:
967 } 972 }
968 } 973 }
969 974
970 const std::string nll(ast_node* node) const { 975 const std::string nl(ast_node* node) const {
971 if (_config.reserveLineNumber) { 976 if (_config.reserveLineNumber) {
972 return " -- "s + std::to_string(node->m_begin.m_line + _config.lineOffset) + _newLine; 977 return " -- "s + std::to_string(node->m_begin.m_line + _config.lineOffset) + _newLine;
973 } else { 978 } else {
@@ -975,14 +980,6 @@ private:
975 } 980 }
976 } 981 }
977 982
978 const std::string nlr(ast_node* node) const {
979 if (_config.reserveLineNumber) {
980 return " -- "s + std::to_string(node->m_end.m_line + _config.lineOffset) + _newLine;
981 } else {
982 return _newLine;
983 }
984 }
985
986 void incIndentOffset() { 983 void incIndentOffset() {
987 _indentOffset++; 984 _indentOffset++;
988 } 985 }
@@ -1169,14 +1166,22 @@ private:
1169 return nullptr; 1166 return nullptr;
1170 } 1167 }
1171 1168
1172 Statement_t* lastStatementFrom(const node_container& stmts) const { 1169 Statement_t* lastStatementFrom(const node_container& statementOrComments) const {
1173 if (!stmts.empty()) { 1170 if (!statementOrComments.empty()) {
1174 auto it = stmts.end(); 1171 for (auto it = statementOrComments.rbegin(); it != statementOrComments.rend(); ++it) {
1175 --it; 1172 if (auto stmt = ast_cast<Statement_t>(*it)) {
1176 while (!static_cast<Statement_t*>(*it)->content && it != stmts.begin()) { 1173 return stmt;
1177 --it; 1174 }
1175 }
1176 }
1177 return nullptr;
1178 }
1179
1180 Statement_t* firstStatementFrom(Block_t* block) const {
1181 for (auto stmt_ : block->statementOrComments.objects()) {
1182 if (auto stmt = ast_cast<Statement_t>(stmt_)) {
1183 return stmt;
1178 } 1184 }
1179 return static_cast<Statement_t*>(*it);
1180 } 1185 }
1181 return nullptr; 1186 return nullptr;
1182 } 1187 }
@@ -1185,16 +1190,26 @@ private:
1185 if (auto stmt = body->content.as<Statement_t>()) { 1190 if (auto stmt = body->content.as<Statement_t>()) {
1186 return stmt; 1191 return stmt;
1187 } else { 1192 } else {
1188 const auto& stmts = body->content.to<Block_t>()->statements.objects(); 1193 const auto& stmts = body->content.to<Block_t>()->statementOrComments.objects();
1189 return lastStatementFrom(stmts); 1194 return lastStatementFrom(stmts);
1190 } 1195 }
1191 } 1196 }
1192 1197
1193 Statement_t* lastStatementFrom(Block_t* block) const { 1198 Statement_t* lastStatementFrom(Block_t* block) const {
1194 const auto& stmts = block->statements.objects(); 1199 const auto& stmts = block->statementOrComments.objects();
1195 return lastStatementFrom(stmts); 1200 return lastStatementFrom(stmts);
1196 } 1201 }
1197 1202
1203 int countStatementFrom(Block_t* block) const {
1204 int count = 0;
1205 for (auto stmt_ : block->statementOrComments.objects()) {
1206 if (ast_is<Statement_t>(stmt_)) {
1207 count++;
1208 }
1209 }
1210 return count;
1211 }
1212
1198 Exp_t* lastExpFromAssign(ast_node* action) { 1213 Exp_t* lastExpFromAssign(ast_node* action) {
1199 switch (action->get_id()) { 1214 switch (action->get_id()) {
1200 case id<Update_t>(): { 1215 case id<Update_t>(): {
@@ -1258,7 +1273,7 @@ private:
1258 1273
1259 template <class T> 1274 template <class T>
1260 ast_ptr<false, T> toAst(std::string_view codes, ast_node* parent) { 1275 ast_ptr<false, T> toAst(std::string_view codes, ast_node* parent) {
1261 auto res = _parser.parse<T>(std::string(codes)); 1276 auto res = _parser.parse<T>(std::string(codes), false);
1262 if (res.error) { 1277 if (res.error) {
1263 throw CompileError(res.error.value().msg, parent); 1278 throw CompileError(res.error.value().msg, parent);
1264 } 1279 }
@@ -1281,6 +1296,8 @@ private:
1281 Common, 1296 Common,
1282 EndWithColon, 1297 EndWithColon,
1283 EndWithEOP, 1298 EndWithEOP,
1299 EndWithSlice,
1300 HasRIndex,
1284 HasEOP, 1301 HasEOP,
1285 HasKeyword, 1302 HasKeyword,
1286 HasUnicode, 1303 HasUnicode,
@@ -1299,6 +1316,9 @@ private:
1299 if (ast_is<ExistentialOp_t>(chainValue->items.back())) { 1316 if (ast_is<ExistentialOp_t>(chainValue->items.back())) {
1300 return ChainType::EndWithEOP; 1317 return ChainType::EndWithEOP;
1301 } 1318 }
1319 if (ast_is<Slice_t>(chainValue->items.back())) {
1320 return ChainType::EndWithSlice;
1321 }
1302 if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) { 1322 if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) {
1303 if (dot->name.is<Metatable_t>()) { 1323 if (dot->name.is<Metatable_t>()) {
1304 return ChainType::Metatable; 1324 return ChainType::Metatable;
@@ -1324,6 +1344,8 @@ private:
1324 } 1344 }
1325 } else if (ast_is<ExistentialOp_t>(item)) { 1345 } else if (ast_is<ExistentialOp_t>(item)) {
1326 return ChainType::HasEOP; 1346 return ChainType::HasEOP;
1347 } else if (ast_is<ReversedIndex_t>(item)) {
1348 return ChainType::HasRIndex;
1327 } 1349 }
1328 } 1350 }
1329 return type; 1351 return type;
@@ -1353,10 +1375,10 @@ private:
1353 std::ostringstream buf; 1375 std::ostringstream buf;
1354 for (auto it = uname->m_begin.m_it; it != uname->m_end.m_it; ++it) { 1376 for (auto it = uname->m_begin.m_it; it != uname->m_end.m_it; ++it) {
1355 auto ch = *it; 1377 auto ch = *it;
1356 if (ch > 255) { 1378 if (ch <= 0x7F && ((ch == '_') || ((ch | 0x20) >= 'a' && (ch | 0x20) <= 'z') || (ch >= '0' && ch <= '9'))) {
1357 buf << "_u"sv << std::hex << static_cast<int>(ch);
1358 } else {
1359 buf << static_cast<char>(ch); 1379 buf << static_cast<char>(ch);
1380 } else {
1381 buf << "_u"sv << std::hex << static_cast<uint32_t>(ch);
1360 } 1382 }
1361 } 1383 }
1362 return buf.str(); 1384 return buf.str();
@@ -1438,6 +1460,7 @@ private:
1438 case id<DotChainItem_t>(): 1460 case id<DotChainItem_t>():
1439 case id<Exp_t>(): 1461 case id<Exp_t>():
1440 case id<TableAppendingOp_t>(): 1462 case id<TableAppendingOp_t>():
1463 case id<ReversedIndex_t>():
1441 return true; 1464 return true;
1442 } 1465 }
1443 } 1466 }
@@ -1455,7 +1478,7 @@ private:
1455 if (simpleValue->value.is<TableLit_t>()) { 1478 if (simpleValue->value.is<TableLit_t>()) {
1456 return true; 1479 return true;
1457 } else if (auto comp = simpleValue->value.as<Comprehension_t>()) { 1480 } else if (auto comp = simpleValue->value.as<Comprehension_t>()) {
1458 if (comp->items.size() != 2 || !ast_is<CompInner_t>(comp->items.back())) { 1481 if (!isListComp(comp)) {
1459 return true; 1482 return true;
1460 } 1483 }
1461 } 1484 }
@@ -1596,7 +1619,7 @@ private:
1596 if (accessType == AccessType::Read && _funcLevel > 1) { 1619 if (accessType == AccessType::Read && _funcLevel > 1) {
1597 accessType = AccessType::Capture; 1620 accessType = AccessType::Capture;
1598 } 1621 }
1599 _globals[key] = {str, x->m_begin.m_line, x->m_begin.m_col, accessType}; 1622 _globals[key] = {str, x->m_begin.m_line, x->m_begin.m_col, accessType, isSolidDefined(str)};
1600 } 1623 }
1601 } 1624 }
1602 } 1625 }
@@ -1638,24 +1661,31 @@ private:
1638 return; 1661 return;
1639 } 1662 }
1640 1663
1641 void transformStatement(Statement_t* statement, str_list& out) { 1664 void transformComment(YueComment_t* comment, str_list& out) {
1642 auto x = statement; 1665 if (!_config.reserveComment) {
1643 if (_config.reserveComment && !x->comments.empty()) { 1666 return;
1644 for (ast_node* node : x->comments.objects()) { 1667 }
1645 switch (node->get_id()) { 1668 auto node = comment->comment.get();
1646 case id<YueLineComment_t>(): { 1669 if (!node) {
1647 auto comment = ast_cast<YueLineComment_t>(node); 1670 out.push_back("\n"s);
1648 out.push_back(indent() + "--"s + _parser.toString(comment) + '\n'); 1671 return;
1649 break; 1672 }
1650 } 1673 switch (node->get_id()) {
1651 case id<YueMultilineComment_t>(): { 1674 case id<YueLineComment_t>(): {
1652 auto comment = ast_cast<YueMultilineComment_t>(node); 1675 auto content = static_cast<YueLineComment_t*>(node);
1653 out.push_back(indent() + _parser.toString(comment) + '\n'); 1676 out.push_back(indent() + "--"s + _parser.toString(content) + '\n');
1654 break; 1677 break;
1655 } 1678 }
1656 } 1679 case id<YueMultilineComment_t>(): {
1680 auto content = static_cast<YueMultilineComment_t*>(node);
1681 out.push_back(indent() + "--[["s + _parser.toString(content) + "]]\n"s);
1682 break;
1657 } 1683 }
1658 } 1684 }
1685 }
1686
1687 void transformStatement(Statement_t* statement, str_list& out) {
1688 auto x = statement;
1659 if (statement->appendix) { 1689 if (statement->appendix) {
1660 if (auto assignment = assignmentFrom(statement)) { 1690 if (auto assignment = assignmentFrom(statement)) {
1661 auto preDefine = getPreDefineLine(assignment); 1691 auto preDefine = getPreDefineLine(assignment);
@@ -1719,7 +1749,7 @@ private:
1719 throw CompileError("while-loop line decorator is not supported here"sv, appendix->item.get()); 1749 throw CompileError("while-loop line decorator is not supported here"sv, appendix->item.get());
1720 break; 1750 break;
1721 } 1751 }
1722 case id<CompInner_t>(): { 1752 case id<CompFor_t>(): {
1723 throw CompileError("for-loop line decorator is not supported here"sv, appendix->item.get()); 1753 throw CompileError("for-loop line decorator is not supported here"sv, appendix->item.get());
1724 break; 1754 break;
1725 } 1755 }
@@ -1780,8 +1810,8 @@ private:
1780 statement->content.set(expListAssign); 1810 statement->content.set(expListAssign);
1781 break; 1811 break;
1782 } 1812 }
1783 case id<CompInner_t>(): { 1813 case id<CompFor_t>(): {
1784 auto compInner = appendix->item.to<CompInner_t>(); 1814 auto compInner = appendix->item.to<CompFor_t>();
1785 auto comp = x->new_ptr<Comprehension_t>(); 1815 auto comp = x->new_ptr<Comprehension_t>();
1786 auto stmt = x->new_ptr<Statement_t>(); 1816 auto stmt = x->new_ptr<Statement_t>();
1787 stmt->content.set(statement->content); 1817 stmt->content.set(statement->content);
@@ -1846,11 +1876,12 @@ private:
1846 case id<ForEach_t>(): transformForEach(static_cast<ForEach_t*>(value), out); break; 1876 case id<ForEach_t>(): transformForEach(static_cast<ForEach_t*>(value), out); break;
1847 case id<For_t>(): transformFor(static_cast<For_t*>(value), out); break; 1877 case id<For_t>(): transformFor(static_cast<For_t*>(value), out); break;
1848 case id<While_t>(): transformWhile(static_cast<While_t*>(value), out); break; 1878 case id<While_t>(): transformWhile(static_cast<While_t*>(value), out); break;
1879 case id<Repeat_t>(): transformRepeat(static_cast<Repeat_t*>(value), out); break;
1849 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Common); break; 1880 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Common); break;
1850 case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Common); break; 1881 case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Common); break;
1851 case id<Comprehension_t>(): { 1882 case id<Comprehension_t>(): {
1852 auto comp = static_cast<Comprehension_t*>(value); 1883 auto comp = static_cast<Comprehension_t*>(value);
1853 if (comp->items.size() == 2 && ast_is<CompInner_t>(comp->items.back())) { 1884 if (isListComp(comp)) {
1854 transformCompCommon(comp, out); 1885 transformCompCommon(comp, out);
1855 } else { 1886 } else {
1856 specialSingleValue = false; 1887 specialSingleValue = false;
@@ -1974,7 +2005,7 @@ private:
1974 return indent() + "local "s + join(defs, ", "sv); 2005 return indent() + "local "s + join(defs, ", "sv);
1975 } 2006 }
1976 2007
1977 std::string getDestrucureDefine(ExpListAssign_t* assignment) { 2008 std::string getDestructureDefine(ExpListAssign_t* assignment) {
1978 auto info = extractDestructureInfo(assignment, true, false); 2009 auto info = extractDestructureInfo(assignment, true, false);
1979 if (!info.destructures.empty()) { 2010 if (!info.destructures.empty()) {
1980 str_list defs; 2011 str_list defs;
@@ -2005,8 +2036,31 @@ private:
2005 return clearBuf(); 2036 return clearBuf();
2006 } 2037 }
2007 2038
2039 str_list getArgDestructureList(ExpListAssign_t* assignment) {
2040 str_list defs;
2041 auto info = extractDestructureInfo(assignment, true, false);
2042 if (!info.destructures.empty()) {
2043 for (const auto& des : info.destructures) {
2044 if (std::holds_alternative<Destructure>(des)) {
2045 const auto& destruct = std::get<Destructure>(des);
2046 for (const auto& item : destruct.items) {
2047 if (item.targetVar.empty()) {
2048 throw CompileError("can only destruct argument to variable"sv, item.target);
2049 } else {
2050 defs.push_back(item.targetVar);
2051 }
2052 }
2053 } else {
2054 const auto& assignment = std::get<AssignmentPtr>(des);
2055 YUEE("AST node mismatch", assignment.ptr);
2056 }
2057 }
2058 }
2059 return defs;
2060 }
2061
2008 std::string getPreDefine(ExpListAssign_t* assignment) { 2062 std::string getPreDefine(ExpListAssign_t* assignment) {
2009 auto preDefine = getDestrucureDefine(assignment); 2063 auto preDefine = getDestructureDefine(assignment);
2010 if (preDefine.empty()) { 2064 if (preDefine.empty()) {
2011 preDefine = toLocalDecl(transformAssignDefs(assignment->expList, DefOp::Mark)); 2065 preDefine = toLocalDecl(transformAssignDefs(assignment->expList, DefOp::Mark));
2012 } 2066 }
@@ -2015,7 +2069,7 @@ private:
2015 2069
2016 std::string getPreDefineLine(ExpListAssign_t* assignment) { 2070 std::string getPreDefineLine(ExpListAssign_t* assignment) {
2017 auto preDefine = getPreDefine(assignment); 2071 auto preDefine = getPreDefine(assignment);
2018 if (!preDefine.empty()) preDefine += nll(assignment); 2072 if (!preDefine.empty()) preDefine += nl(assignment);
2019 return preDefine; 2073 return preDefine;
2020 } 2074 }
2021 2075
@@ -2171,14 +2225,14 @@ private:
2171 temp.push_back(getPreDefineLine(assignment)); 2225 temp.push_back(getPreDefineLine(assignment));
2172 bool needScope = !currentScope().lastStatement; 2226 bool needScope = !currentScope().lastStatement;
2173 if (needScope) { 2227 if (needScope) {
2174 temp.push_back(indent() + "do"s + nll(assignment)); 2228 temp.push_back(indent() + "do"s + nl(assignment));
2175 pushScope(); 2229 pushScope();
2176 } 2230 }
2177 transformAssignment(preAssignment, temp); 2231 transformAssignment(preAssignment, temp);
2178 transformAssignment(assignment, temp); 2232 transformAssignment(assignment, temp);
2179 if (needScope) { 2233 if (needScope) {
2180 popScope(); 2234 popScope();
2181 temp.push_back(indent() + "end"s + nll(assignment)); 2235 temp.push_back(indent() + "end"s + nl(assignment));
2182 } 2236 }
2183 out.push_back(join(temp)); 2237 out.push_back(join(temp));
2184 return false; 2238 return false;
@@ -2223,7 +2277,8 @@ private:
2223 BREAK_IF(!value); 2277 BREAK_IF(!value);
2224 auto chainValue = value->item.as<ChainValue_t>(); 2278 auto chainValue = value->item.as<ChainValue_t>();
2225 BREAK_IF(!chainValue); 2279 BREAK_IF(!chainValue);
2226 if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) { 2280 auto last = chainValue->items.back();
2281 if (auto dot = ast_cast<DotChainItem_t>(last)) {
2227 BREAK_IF(!dot->name.is<Metatable_t>()); 2282 BREAK_IF(!dot->name.is<Metatable_t>());
2228 str_list temp; 2283 str_list temp;
2229 auto [beforeAssignment, afterAssignment] = splitAssignment(); 2284 auto [beforeAssignment, afterAssignment] = splitAssignment();
@@ -2247,14 +2302,14 @@ private:
2247 throw CompileError("right value missing"sv, values.front()); 2302 throw CompileError("right value missing"sv, values.front());
2248 } 2303 }
2249 transformAssignItem(*vit, args); 2304 transformAssignItem(*vit, args);
2250 _buf << indent() << globalVar("setmetatable"sv, x, AccessType::Read) << '(' << join(args, ", "sv) << ')' << nll(x); 2305 _buf << indent() << globalVar("setmetatable"sv, x, AccessType::Read) << '(' << join(args, ", "sv) << ')' << nl(x);
2251 temp.push_back(clearBuf()); 2306 temp.push_back(clearBuf());
2252 if (!afterAssignment->expList->exprs.empty()) { 2307 if (!afterAssignment->expList->exprs.empty()) {
2253 transformAssignment(afterAssignment, temp); 2308 transformAssignment(afterAssignment, temp);
2254 } 2309 }
2255 out.push_back(join(temp)); 2310 out.push_back(join(temp));
2256 return false; 2311 return false;
2257 } else if (ast_is<TableAppendingOp_t>(chainValue->items.back())) { 2312 } else if (ast_is<TableAppendingOp_t>(last)) {
2258 str_list temp; 2313 str_list temp;
2259 auto [beforeAssignment, afterAssignment] = splitAssignment(); 2314 auto [beforeAssignment, afterAssignment] = splitAssignment();
2260 if (!beforeAssignment->expList->exprs.empty()) { 2315 if (!beforeAssignment->expList->exprs.empty()) {
@@ -2276,7 +2331,7 @@ private:
2276 if (varName.empty() || !isLocal(varName)) { 2331 if (varName.empty() || !isLocal(varName)) {
2277 if (needScope) { 2332 if (needScope) {
2278 extraScoped = true; 2333 extraScoped = true;
2279 temp.push_back(indent() + "do"s + nll(x)); 2334 temp.push_back(indent() + "do"s + nl(x));
2280 pushScope(); 2335 pushScope();
2281 } 2336 }
2282 auto objVar = getUnusedName("_obj_"sv); 2337 auto objVar = getUnusedName("_obj_"sv);
@@ -2288,19 +2343,69 @@ private:
2288 transformAssignment(newAssignment, temp); 2343 transformAssignment(newAssignment, temp);
2289 varName = objVar; 2344 varName = objVar;
2290 } 2345 }
2291 auto newAssignment = x->new_ptr<ExpListAssign_t>(); 2346 if (auto spread = ast_cast<SpreadListExp_t>(*vit)) {
2292 newAssignment->expList.set(toAst<ExpList_t>(varName + "[#"s + varName + "+1]"s, x)); 2347 auto lenVar = getUnusedName("_len_"sv);
2293 auto assign = x->new_ptr<Assign_t>(); 2348 forceAddToScope(lenVar);
2294 if (vit == values.end()) { 2349 temp.push_back(indent() + "local "s + lenVar + " = #"s + varName + " + 1"s + nl(spread));
2295 throw CompileError("right value missing"sv, values.front()); 2350 auto elmVar = getUnusedName("_elm_"sv);
2351 _buf << varName << '[' << lenVar << "],"s << lenVar << "="s << elmVar << ',' << lenVar << "+1 for "s << elmVar << " in *nil"s;
2352 auto stmt = toAst<Statement_t>(clearBuf(), spread);
2353 auto comp = stmt->appendix->item.to<CompFor_t>();
2354 ast_to<CompForEach_t>(comp->items.front())->loopValue.to<StarExp_t>()->value.set(spread->exp);
2355 transformStatement(stmt, temp);
2356 } else {
2357 auto newAssignment = x->new_ptr<ExpListAssign_t>();
2358 newAssignment->expList.set(toAst<ExpList_t>(varName + "[#"s + varName + "+1]"s, x));
2359 auto assign = x->new_ptr<Assign_t>();
2360 if (vit == values.end()) {
2361 throw CompileError("right value missing"sv, values.front());
2362 }
2363 assign->values.push_back(*vit);
2364 newAssignment->action.set(assign);
2365 transformAssignment(newAssignment, temp);
2296 } 2366 }
2297 assign->values.push_back(*vit);
2298 newAssignment->action.set(assign);
2299 transformAssignment(newAssignment, temp);
2300 if (extraScoped) { 2367 if (extraScoped) {
2301 popScope(); 2368 popScope();
2302 temp.push_back(indent() + "end"s + nlr(x)); 2369 temp.push_back(indent() + "end"s + nl(x));
2370 }
2371 if (!afterAssignment->expList->exprs.empty()) {
2372 transformAssignment(afterAssignment, temp);
2373 }
2374 out.push_back(join(temp));
2375 return false;
2376 } else if (ast_is<ReversedIndex_t>(last)) {
2377 if (chainValue->items.size() == 1) {
2378 if (_withVars.empty()) {
2379 throw CompileError("short dot/colon syntax must be called within a with block"sv, x);
2380 } else {
2381 break;
2382 }
2383 }
2384 auto tmpChain = chainValue->new_ptr<ChainValue_t>();
2385 tmpChain->items.dup(chainValue->items);
2386 tmpChain->items.pop_back();
2387 auto tmpLeft = newExp(tmpChain, tmpChain);
2388 auto leftVar = singleVariableFrom(tmpLeft, AccessType::Read);
2389 if (!leftVar.empty() && isLocal(leftVar)) {
2390 break;
2391 }
2392 leftVar = getUnusedName("_obj_"sv);
2393 auto tmpAsmt = assignmentFrom(toAst<Exp_t>(leftVar, tmpLeft), tmpLeft, tmpLeft);
2394 str_list temp;
2395 transformAssignment(tmpAsmt, temp);
2396 auto [beforeAssignment, afterAssignment] = splitAssignment();
2397 if (!beforeAssignment->expList->exprs.empty()) {
2398 transformAssignment(beforeAssignment, temp);
2303 } 2399 }
2400 if (vit == values.end()) {
2401 throw CompileError("right value missing"sv, values.front());
2402 }
2403 auto newChain = chainValue->new_ptr<ChainValue_t>();
2404 newChain->items.push_back(toAst<Callable_t>(leftVar, newChain));
2405 newChain->items.push_back(chainValue->items.back());
2406 auto newLeft = newExp(newChain, newChain);
2407 auto newAsmt = assignmentFrom(newLeft, *vit, newLeft);
2408 transformAssignment(newAsmt, temp);
2304 if (!afterAssignment->expList->exprs.empty()) { 2409 if (!afterAssignment->expList->exprs.empty()) {
2305 transformAssignment(afterAssignment, temp); 2410 transformAssignment(afterAssignment, temp);
2306 } 2411 }
@@ -2329,6 +2434,17 @@ private:
2329 out.back().insert(0, preDefine); 2434 out.back().insert(0, preDefine);
2330 return false; 2435 return false;
2331 } 2436 }
2437 case id<Try_t>(): {
2438 auto tryNode = static_cast<Try_t*>(value);
2439 if (tryNode->eop) {
2440 auto assignList = assignment->expList.get();
2441 std::string preDefine = getPreDefineLine(assignment);
2442 transformTry(tryNode, out, ExpUsage::Assignment, assignList);
2443 out.back().insert(0, preDefine);
2444 return false;
2445 }
2446 break;
2447 }
2332 case id<Switch_t>(): { 2448 case id<Switch_t>(): {
2333 auto switchNode = static_cast<Switch_t*>(value); 2449 auto switchNode = static_cast<Switch_t*>(value);
2334 auto assignList = assignment->expList.get(); 2450 auto assignList = assignment->expList.get();
@@ -2356,7 +2472,7 @@ private:
2356 case id<Comprehension_t>(): { 2472 case id<Comprehension_t>(): {
2357 auto comp = static_cast<Comprehension_t*>(value); 2473 auto comp = static_cast<Comprehension_t*>(value);
2358 auto expList = assignment->expList.get(); 2474 auto expList = assignment->expList.get();
2359 if (comp->items.size() == 2 && ast_is<CompInner_t>(comp->items.back())) { 2475 if (isListComp(comp)) {
2360 std::string preDefine = getPreDefineLine(assignment); 2476 std::string preDefine = getPreDefineLine(assignment);
2361 transformComprehension(comp, out, ExpUsage::Assignment, expList); 2477 transformComprehension(comp, out, ExpUsage::Assignment, expList);
2362 out.back().insert(0, preDefine); 2478 out.back().insert(0, preDefine);
@@ -2400,6 +2516,13 @@ private:
2400 out.back().insert(0, preDefine); 2516 out.back().insert(0, preDefine);
2401 return false; 2517 return false;
2402 } 2518 }
2519 case id<Repeat_t>(): {
2520 auto expList = assignment->expList.get();
2521 std::string preDefine = getPreDefineLine(assignment);
2522 transformRepeatInPlace(static_cast<Repeat_t*>(value), out, expList);
2523 out.back().insert(0, preDefine);
2524 return false;
2525 }
2403 case id<TableLit_t>(): { 2526 case id<TableLit_t>(): {
2404 auto tableLit = static_cast<TableLit_t*>(value); 2527 auto tableLit = static_cast<TableLit_t*>(value);
2405 if (hasSpreadExp(tableLit->values.objects())) { 2528 if (hasSpreadExp(tableLit->values.objects())) {
@@ -2452,12 +2575,14 @@ private:
2452 switch (type) { 2575 switch (type) {
2453 case ChainType::HasEOP: 2576 case ChainType::HasEOP:
2454 case ChainType::EndWithColon: 2577 case ChainType::EndWithColon:
2578 case ChainType::EndWithSlice:
2455 case ChainType::MetaFieldInvocation: { 2579 case ChainType::MetaFieldInvocation: {
2456 std::string preDefine = getPreDefineLine(assignment); 2580 std::string preDefine = getPreDefineLine(assignment);
2457 transformChainValue(chainValue, out, ExpUsage::Assignment, expList, false, optionalDestruct); 2581 transformChainValue(chainValue, out, ExpUsage::Assignment, expList, false, optionalDestruct);
2458 out.back().insert(0, preDefine); 2582 out.back().insert(0, preDefine);
2459 return false; 2583 return false;
2460 } 2584 }
2585 case ChainType::HasRIndex:
2461 case ChainType::HasKeyword: 2586 case ChainType::HasKeyword:
2462 case ChainType::HasUnicode: 2587 case ChainType::HasUnicode:
2463 case ChainType::Macro: 2588 case ChainType::Macro:
@@ -2512,11 +2637,11 @@ private:
2512 checkConst(def, x); 2637 checkConst(def, x);
2513 addToScope(def); 2638 addToScope(def);
2514 } 2639 }
2515 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nll(x)); 2640 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nl(x));
2516 } 2641 }
2517 if (needScope) { 2642 if (needScope) {
2518 extraScope = true; 2643 extraScope = true;
2519 temp.push_back(indent() + "do"s + nll(x)); 2644 temp.push_back(indent() + "do"s + nl(x));
2520 pushScope(); 2645 pushScope();
2521 } 2646 }
2522 } 2647 }
@@ -2568,13 +2693,13 @@ private:
2568 continue; 2693 continue;
2569 } 2694 }
2570 if (extraScope) { 2695 if (extraScope) {
2571 temp.push_back(indent() + "do"s + nll(x)); 2696 temp.push_back(indent() + "do"s + nl(x));
2572 pushScope(); 2697 pushScope();
2573 } 2698 }
2574 if (!pair.targetVar.empty()) { 2699 if (!pair.targetVar.empty()) {
2575 checkConst(pair.targetVar, x); 2700 checkConst(pair.targetVar, x);
2576 if (addToScope(pair.targetVar)) { 2701 if (addToScope(pair.targetVar)) {
2577 _buf << indent() << "local "sv << pair.targetVar << nll(x); 2702 _buf << indent() << "local "sv << pair.targetVar << nl(x);
2578 temp.push_back(clearBuf()); 2703 temp.push_back(clearBuf());
2579 } 2704 }
2580 } 2705 }
@@ -2584,7 +2709,7 @@ private:
2584 objVar = destruct.valueVar; 2709 objVar = destruct.valueVar;
2585 } else { 2710 } else {
2586 if (needScope) { 2711 if (needScope) {
2587 temp.push_back(indent() + "do"s + nll(x)); 2712 temp.push_back(indent() + "do"s + nl(x));
2588 pushScope(); 2713 pushScope();
2589 } 2714 }
2590 objVar = getUnusedName("_obj_"sv); 2715 objVar = getUnusedName("_obj_"sv);
@@ -2600,7 +2725,7 @@ private:
2600 if (!isLocalValue) { 2725 if (!isLocalValue) {
2601 if (needScope) { 2726 if (needScope) {
2602 popScope(); 2727 popScope();
2603 _buf << indent() << "end"sv << nlr(x); 2728 _buf << indent() << "end"sv << nl(x);
2604 temp.push_back(clearBuf()); 2729 temp.push_back(clearBuf());
2605 } 2730 }
2606 } 2731 }
@@ -2638,9 +2763,9 @@ private:
2638 checkConst(def, x); 2763 checkConst(def, x);
2639 addToScope(def); 2764 addToScope(def);
2640 } 2765 }
2641 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nll(x)); 2766 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nl(x));
2642 } 2767 }
2643 temp.push_back(indent() + "do"s + nll(x)); 2768 temp.push_back(indent() + "do"s + nl(x));
2644 pushScope(); 2769 pushScope();
2645 } 2770 }
2646 } else { 2771 } else {
@@ -2649,11 +2774,11 @@ private:
2649 checkConst(def, x); 2774 checkConst(def, x);
2650 addToScope(def); 2775 addToScope(def);
2651 } 2776 }
2652 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nll(x)); 2777 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nl(x));
2653 } 2778 }
2654 if (needScope) { 2779 if (needScope) {
2655 extraScope = true; 2780 extraScope = true;
2656 temp.push_back(indent() + "do"s + nll(x)); 2781 temp.push_back(indent() + "do"s + nl(x));
2657 pushScope(); 2782 pushScope();
2658 } 2783 }
2659 auto valVar = getUnusedName("_obj_"sv); 2784 auto valVar = getUnusedName("_obj_"sv);
@@ -2668,7 +2793,7 @@ private:
2668 if (destruct.inlineAssignment) { 2793 if (destruct.inlineAssignment) {
2669 if (needScope && !extraScope) { 2794 if (needScope && !extraScope) {
2670 extraScope = true; 2795 extraScope = true;
2671 temp.push_back(indent() + "do"s + nll(x)); 2796 temp.push_back(indent() + "do"s + nl(x));
2672 pushScope(); 2797 pushScope();
2673 } 2798 }
2674 transformAssignment(destruct.inlineAssignment, temp); 2799 transformAssignment(destruct.inlineAssignment, temp);
@@ -2733,13 +2858,13 @@ private:
2733 } 2858 }
2734 if (extraScope) { 2859 if (extraScope) {
2735 popScope(); 2860 popScope();
2736 _buf << indent() << "end"sv << nlr(x); 2861 _buf << indent() << "end"sv << nl(x);
2737 temp.push_back(clearBuf()); 2862 temp.push_back(clearBuf());
2738 } 2863 }
2739 } 2864 }
2740 if (extraScope) { 2865 if (extraScope) {
2741 popScope(); 2866 popScope();
2742 temp.push_back(indent() + "end"s + nlr(x)); 2867 temp.push_back(indent() + "end"s + nl(x));
2743 } 2868 }
2744 out.push_back(join(temp)); 2869 out.push_back(join(temp));
2745 if (assignment->expList->followStmt) { 2870 if (assignment->expList->followStmt) {
@@ -2757,6 +2882,7 @@ private:
2757 case id<Switch_t>(): transformSwitch(static_cast<Switch_t*>(value), out, ExpUsage::Closure); break; 2882 case id<Switch_t>(): transformSwitch(static_cast<Switch_t*>(value), out, ExpUsage::Closure); break;
2758 case id<TableBlock_t>(): transformTableBlock(static_cast<TableBlock_t*>(value), out); break; 2883 case id<TableBlock_t>(): transformTableBlock(static_cast<TableBlock_t*>(value), out); break;
2759 case id<Exp_t>(): transformExp(static_cast<Exp_t*>(value), out, ExpUsage::Closure); break; 2884 case id<Exp_t>(): transformExp(static_cast<Exp_t*>(value), out, ExpUsage::Closure); break;
2885 case id<SpreadListExp_t>(): throw CompileError("can only be used for ranged table append assignments"sv, value); break;
2760 default: YUEE("AST node mismatch", value); break; 2886 default: YUEE("AST node mismatch", value); break;
2761 } 2887 }
2762 } 2888 }
@@ -2771,7 +2897,7 @@ private:
2771 if (auto tbA = item->get_by_path<TableLit_t>()) { 2897 if (auto tbA = item->get_by_path<TableLit_t>()) {
2772 tableItems = &tbA->values.objects(); 2898 tableItems = &tbA->values.objects();
2773 } else if (auto tbB = item->get_by_path<Comprehension_t>()) { 2899 } else if (auto tbB = item->get_by_path<Comprehension_t>()) {
2774 if (tbB->items.size() == 2 && ast_is<CompInner_t>(tbB->items.back())) { 2900 if (isListComp(tbB)) {
2775 throw CompileError("invalid destructure value"sv, tbB); 2901 throw CompileError("invalid destructure value"sv, tbB);
2776 } 2902 }
2777 tableItems = &tbB->items.objects(); 2903 tableItems = &tbB->items.objects();
@@ -2802,7 +2928,7 @@ private:
2802 } 2928 }
2803 case id<Comprehension_t>(): { 2929 case id<Comprehension_t>(): {
2804 auto table = static_cast<Comprehension_t*>(node); 2930 auto table = static_cast<Comprehension_t*>(node);
2805 if (table->items.size() == 2 && ast_is<CompInner_t>(table->items.back())) { 2931 if (isListComp(table)) {
2806 throw CompileError("invalid destructure value"sv, table); 2932 throw CompileError("invalid destructure value"sv, table);
2807 } 2933 }
2808 tableItems = &table->items.objects(); 2934 tableItems = &table->items.objects();
@@ -2813,17 +2939,19 @@ private:
2813 if (!tableItems) throw CompileError("invalid destructure value"sv, node); 2939 if (!tableItems) throw CompileError("invalid destructure value"sv, node);
2814 std::list<DestructItem> pairs; 2940 std::list<DestructItem> pairs;
2815 int index = 0; 2941 int index = 0;
2942 int count = 0;
2943 bool hasSpread = false;
2816 auto subMetaDestruct = node->new_ptr<TableLit_t>(); 2944 auto subMetaDestruct = node->new_ptr<TableLit_t>();
2817 for (auto pair : *tableItems) { 2945 for (auto pair : *tableItems) {
2818 switch (pair->get_id()) { 2946 switch (pair->get_id()) {
2819 case id<Exp_t>(): 2947 case id<Exp_t>():
2820 case id<NormalDef_t>(): { 2948 case id<NormalDef_t>(): {
2949 ++index;
2821 Exp_t* defVal = nullptr; 2950 Exp_t* defVal = nullptr;
2822 if (auto nd = ast_cast<NormalDef_t>(pair)) { 2951 if (auto nd = ast_cast<NormalDef_t>(pair)) {
2823 pair = nd->item.get(); 2952 pair = nd->item.get();
2824 defVal = nd->defVal.get(); 2953 defVal = nd->defVal.get();
2825 } 2954 }
2826 ++index;
2827 bool assignable = false; 2955 bool assignable = false;
2828 try { 2956 try {
2829 assignable = isAssignable(static_cast<Exp_t*>(pair)); 2957 assignable = isAssignable(static_cast<Exp_t*>(pair));
@@ -2834,13 +2962,19 @@ private:
2834 if (optional) break; 2962 if (optional) break;
2835 throw CompileError("can't destructure value"sv, pair); 2963 throw CompileError("can't destructure value"sv, pair);
2836 } 2964 }
2965 ast_ptr<true, ast_node> indexItem;
2966 if (hasSpread) {
2967 int rIndex = count - index;
2968 indexItem.set(toAst<ReversedIndex_t>('#' + (rIndex == 0 ? Empty : "-"s + std::to_string(rIndex)), pair));
2969 } else {
2970 indexItem.set(toAst<Exp_t>(std::to_string(index), pair));
2971 }
2837 if (optional && varDefOnly && !assignable) { 2972 if (optional && varDefOnly && !assignable) {
2838 if (defVal) { 2973 if (defVal) {
2839 throw CompileError("default value is not supported here"sv, defVal); 2974 throw CompileError("default value is not supported here"sv, defVal);
2840 } 2975 }
2841 auto exp = static_cast<Exp_t*>(pair); 2976 auto exp = static_cast<Exp_t*>(pair);
2842 auto chain = exp->new_ptr<ChainValue_t>(); 2977 auto chain = exp->new_ptr<ChainValue_t>();
2843 auto indexItem = toAst<Exp_t>(std::to_string(index), exp);
2844 chain->items.push_back(indexItem); 2978 chain->items.push_back(indexItem);
2845 pairs.push_back({exp, Empty, chain, nullptr}); 2979 pairs.push_back({exp, Empty, chain, nullptr});
2846 break; 2980 break;
@@ -2855,7 +2989,6 @@ private:
2855 throw CompileError("default value is not supported here"sv, defVal); 2989 throw CompileError("default value is not supported here"sv, defVal);
2856 } 2990 }
2857 } 2991 }
2858 auto indexItem = toAst<Exp_t>(std::to_string(index), value);
2859 for (auto& p : subPairs) { 2992 for (auto& p : subPairs) {
2860 if (sep) p.structure->items.push_front(sep); 2993 if (sep) p.structure->items.push_front(sep);
2861 p.structure->items.push_front(indexItem); 2994 p.structure->items.push_front(indexItem);
@@ -2866,7 +2999,6 @@ private:
2866 auto varName = singleVariableFrom(exp, AccessType::None); 2999 auto varName = singleVariableFrom(exp, AccessType::None);
2867 if (varName == "_"sv) break; 3000 if (varName == "_"sv) break;
2868 auto chain = exp->new_ptr<ChainValue_t>(); 3001 auto chain = exp->new_ptr<ChainValue_t>();
2869 auto indexItem = toAst<Exp_t>(std::to_string(index), exp);
2870 chain->items.push_back(indexItem); 3002 chain->items.push_back(indexItem);
2871 pairs.push_back({exp, 3003 pairs.push_back({exp,
2872 varName, 3004 varName,
@@ -2991,7 +3123,13 @@ private:
2991 auto tb = static_cast<TableBlockIndent_t*>(pair); 3123 auto tb = static_cast<TableBlockIndent_t*>(pair);
2992 ++index; 3124 ++index;
2993 auto subPairs = destructFromExp(tb, varDefOnly, optional); 3125 auto subPairs = destructFromExp(tb, varDefOnly, optional);
2994 auto indexItem = toAst<Exp_t>(std::to_string(index), tb); 3126 ast_ptr<true, ast_node> indexItem;
3127 if (hasSpread) {
3128 int rIndex = count - index;
3129 indexItem.set(toAst<ReversedIndex_t>('#' + (rIndex == 0 ? Empty : "-"s + std::to_string(rIndex)), tb));
3130 } else {
3131 indexItem.set(toAst<Exp_t>(std::to_string(index), tb));
3132 }
2995 for (auto& p : subPairs) { 3133 for (auto& p : subPairs) {
2996 if (sep) p.structure->items.push_front(sep); 3134 if (sep) p.structure->items.push_front(sep);
2997 p.structure->items.push_front(indexItem); 3135 p.structure->items.push_front(indexItem);
@@ -3048,6 +3186,42 @@ private:
3048 subMetaDestruct->values.push_back(newPairDef); 3186 subMetaDestruct->values.push_back(newPairDef);
3049 break; 3187 break;
3050 } 3188 }
3189 case id<SpreadListExp_t>():
3190 case id<SpreadExp_t>(): {
3191 ++index;
3192 if (hasSpread) {
3193 throw CompileError("duplicated spread expression"sv, pair);
3194 }
3195 hasSpread = true;
3196 for (auto item : *tableItems) {
3197 if (ast_is<
3198 SpreadListExp_t, SpreadExp_t,
3199 TableBlockIndent_t,
3200 Exp_t, NormalDef_t>(item)) {
3201 count++;
3202 }
3203 }
3204 Exp_t* exp = nullptr;
3205 if (auto se = ast_cast<SpreadExp_t>(pair)) {
3206 exp = se->exp.get();
3207 } else {
3208 exp = ast_to<SpreadListExp_t>(pair)->exp.get();
3209 }
3210 auto varName = singleVariableFrom(exp, AccessType::None);
3211 if (varName == "_"sv) break;
3212 int start = index;
3213 int stop = index - count - 1;
3214 auto chain = exp->new_ptr<ChainValue_t>();
3215 auto slice = toAst<Slice_t>(
3216 '[' + (start == 1 ? Empty : std::to_string(start)) + ',' + (stop == -1 ? Empty : std::to_string(stop)) + ']', exp);
3217 chain->items.push_back(slice);
3218 auto nil = toAst<Exp_t>("nil"sv, slice);
3219 pairs.push_back({exp,
3220 varName,
3221 chain,
3222 nil.get()});
3223 break;
3224 }
3051 default: YUEE("AST node mismatch", pair); break; 3225 default: YUEE("AST node mismatch", pair); break;
3052 } 3226 }
3053 } 3227 }
@@ -3125,7 +3299,7 @@ private:
3125 if (auto tab = sVal->value.as<TableLit_t>()) { 3299 if (auto tab = sVal->value.as<TableLit_t>()) {
3126 destructNode = tab; 3300 destructNode = tab;
3127 } else if (auto comp = sVal->value.as<Comprehension_t>()) { 3301 } else if (auto comp = sVal->value.as<Comprehension_t>()) {
3128 if (comp->items.size() != 2 || !ast_is<CompInner_t>(comp->items.back())) { 3302 if (!isListComp(comp)) {
3129 destructNode = comp; 3303 destructNode = comp;
3130 } 3304 }
3131 } 3305 }
@@ -3512,7 +3686,7 @@ private:
3512 _buf << defs; 3686 _buf << defs;
3513 else 3687 else
3514 _buf << indent() << left; 3688 _buf << indent() << left;
3515 _buf << " = "sv << left << ' ' << op << ' ' << right << nll(assignment); 3689 _buf << " = "sv << left << ' ' << op << ' ' << right << nl(assignment);
3516 out.push_back(clearBuf()); 3690 out.push_back(clearBuf());
3517 break; 3691 break;
3518 } 3692 }
@@ -3559,9 +3733,9 @@ private:
3559 transformExpList(expList, temp); 3733 transformExpList(expList, temp);
3560 std::string left = std::move(temp.back()); 3734 std::string left = std::move(temp.back());
3561 temp.pop_back(); 3735 temp.pop_back();
3562 out.push_back(indent() + left + " = "s + join(temp, ", "sv) + nll(assignment)); 3736 out.push_back(indent() + left + " = "s + join(temp, ", "sv) + nl(assignment));
3563 } else { 3737 } else {
3564 out.push_back(preDefine + " = "s + join(temp, ", "sv) + nll(assignment)); 3738 out.push_back(preDefine + " = "s + join(temp, ", "sv) + nl(assignment));
3565 } 3739 }
3566 } else { 3740 } else {
3567 std::string preDefine = toLocalDecl(defs); 3741 std::string preDefine = toLocalDecl(defs);
@@ -3577,7 +3751,7 @@ private:
3577 for (auto value : assign->values.objects()) { 3751 for (auto value : assign->values.objects()) {
3578 transformAssignItem(value, temp); 3752 transformAssignItem(value, temp);
3579 } 3753 }
3580 out.push_back((preDefine.empty() ? Empty : preDefine + nll(assignment)) + indent() + left + " = "s + join(temp, ", "sv) + nll(assignment)); 3754 out.push_back((preDefine.empty() ? Empty : preDefine + nl(assignment)) + indent() + left + " = "s + join(temp, ", "sv) + nl(assignment));
3581 } 3755 }
3582 break; 3756 break;
3583 } 3757 }
@@ -3678,7 +3852,7 @@ private:
3678 if (usage != ExpUsage::Closure) { 3852 if (usage != ExpUsage::Closure) {
3679 if (!currentScope().lastStatement) { 3853 if (!currentScope().lastStatement) {
3680 extraScope = true; 3854 extraScope = true;
3681 temp.push_back(indent() + "do"s + nll(asmt)); 3855 temp.push_back(indent() + "do"s + nl(asmt));
3682 pushScope(); 3856 pushScope();
3683 } 3857 }
3684 } 3858 }
@@ -3711,7 +3885,7 @@ private:
3711 if (usage != ExpUsage::Closure) { 3885 if (usage != ExpUsage::Closure) {
3712 if (!currentScope().lastStatement) { 3886 if (!currentScope().lastStatement) {
3713 extraScope = true; 3887 extraScope = true;
3714 temp.push_back(indent() + "do"s + nll(asmt)); 3888 temp.push_back(indent() + "do"s + nl(asmt));
3715 pushScope(); 3889 pushScope();
3716 } 3890 }
3717 } 3891 }
@@ -3740,12 +3914,12 @@ private:
3740 if (pair != ifCondPairs.front()) { 3914 if (pair != ifCondPairs.front()) {
3741 _buf << "else"sv; 3915 _buf << "else"sv;
3742 } 3916 }
3743 _buf << "if "sv << condStr << " then"sv << nll(condition); 3917 _buf << "if "sv << condStr << " then"sv << nl(condition);
3744 temp.push_back(clearBuf()); 3918 temp.push_back(clearBuf());
3745 } 3919 }
3746 if (pair.second) { 3920 if (pair.second) {
3747 if (!pair.first) { 3921 if (!pair.first) {
3748 temp.push_back(indent() + "else"s + nll(pair.second)); 3922 temp.push_back(indent() + "else"s + nl(pair.second));
3749 } 3923 }
3750 pushScope(); 3924 pushScope();
3751 if (pair == ifCondPairs.front() && extraAssignment) { 3925 if (pair == ifCondPairs.front() && extraAssignment) {
@@ -3755,17 +3929,17 @@ private:
3755 popScope(); 3929 popScope();
3756 } 3930 }
3757 if (!pair.first) { 3931 if (!pair.first) {
3758 temp.push_back(indent() + "end"s + nll(nodes.front())); 3932 temp.push_back(indent() + "end"s + nl(nodes.front()));
3759 break; 3933 break;
3760 } 3934 }
3761 } 3935 }
3762 if (extraScope) { 3936 if (extraScope) {
3763 popScope(); 3937 popScope();
3764 temp.push_back(indent() + "end"s + nlr(nodes.front())); 3938 temp.push_back(indent() + "end"s + nl(nodes.front()));
3765 } 3939 }
3766 if (usage == ExpUsage::Closure) { 3940 if (usage == ExpUsage::Closure) {
3767 popScope(); 3941 popScope();
3768 *funcStart = anonFuncStart() + nll(nodes.front()); 3942 *funcStart = anonFuncStart() + nl(nodes.front());
3769 temp.push_back(indent() + anonFuncEnd()); 3943 temp.push_back(indent() + anonFuncEnd());
3770 popAnonVarArg(); 3944 popAnonVarArg();
3771 popFunctionScope(); 3945 popFunctionScope();
@@ -3860,7 +4034,7 @@ private:
3860 } else { 4034 } else {
3861 transformExp(arg, out, ExpUsage::Closure); 4035 transformExp(arg, out, ExpUsage::Closure);
3862 out.back().insert(0, indent()); 4036 out.back().insert(0, indent());
3863 out.back().append(nlr(x)); 4037 out.back().append(nl(x));
3864 } 4038 }
3865 return; 4039 return;
3866 } 4040 }
@@ -3984,7 +4158,7 @@ private:
3984 auto stmt = exp->new_ptr<Statement_t>(); 4158 auto stmt = exp->new_ptr<Statement_t>();
3985 stmt->content.set(preDefine); 4159 stmt->content.set(preDefine);
3986 preDefine.set(nullptr); 4160 preDefine.set(nullptr);
3987 block->statements.push_back(stmt); 4161 block->statementOrComments.push_back(stmt);
3988 auto simpleValue = exp->new_ptr<SimpleValue_t>(); 4162 auto simpleValue = exp->new_ptr<SimpleValue_t>();
3989 simpleValue->value.set(ifNode); 4163 simpleValue->value.set(ifNode);
3990 auto explist = exp->new_ptr<ExpList_t>(); 4164 auto explist = exp->new_ptr<ExpList_t>();
@@ -3993,7 +4167,7 @@ private:
3993 expListAssign->expList.set(explist); 4167 expListAssign->expList.set(explist);
3994 stmt = exp->new_ptr<Statement_t>(); 4168 stmt = exp->new_ptr<Statement_t>();
3995 stmt->content.set(expListAssign); 4169 stmt->content.set(expListAssign);
3996 block->statements.push_back(stmt); 4170 block->statementOrComments.push_back(stmt);
3997 nodes->push_back(block); 4171 nodes->push_back(block);
3998 nodes = &ifNode->nodes; 4172 nodes = &ifNode->nodes;
3999 } else { 4173 } else {
@@ -4001,7 +4175,7 @@ private:
4001 auto stmt = exp->new_ptr<Statement_t>(); 4175 auto stmt = exp->new_ptr<Statement_t>();
4002 stmt->content.set(preDefine); 4176 stmt->content.set(preDefine);
4003 preDefine.set(nullptr); 4177 preDefine.set(nullptr);
4004 block->statements.push_back(stmt); 4178 block->statementOrComments.push_back(stmt);
4005 auto simpleValue = exp->new_ptr<SimpleValue_t>(); 4179 auto simpleValue = exp->new_ptr<SimpleValue_t>();
4006 simpleValue->value.set(ifNode); 4180 simpleValue->value.set(ifNode);
4007 auto explist = exp->new_ptr<ExpList_t>(); 4181 auto explist = exp->new_ptr<ExpList_t>();
@@ -4010,7 +4184,7 @@ private:
4010 expListAssign->expList.set(explist); 4184 expListAssign->expList.set(explist);
4011 stmt = exp->new_ptr<Statement_t>(); 4185 stmt = exp->new_ptr<Statement_t>();
4012 stmt->content.set(expListAssign); 4186 stmt->content.set(expListAssign);
4013 block->statements.push_back(stmt); 4187 block->statementOrComments.push_back(stmt);
4014 auto body = exp->new_ptr<Body_t>(); 4188 auto body = exp->new_ptr<Body_t>();
4015 body->content.set(block); 4189 body->content.set(block);
4016 auto doNode = exp->new_ptr<Do_t>(); 4190 auto doNode = exp->new_ptr<Do_t>();
@@ -4172,7 +4346,7 @@ private:
4172 auto stmt = x->new_ptr<Statement_t>(); 4346 auto stmt = x->new_ptr<Statement_t>();
4173 stmt->content.set(expListAssign); 4347 stmt->content.set(expListAssign);
4174 auto blk = x->new_ptr<Block_t>(); 4348 auto blk = x->new_ptr<Block_t>();
4175 blk->statements.push_back(stmt); 4349 blk->statementOrComments.push_back(stmt);
4176 newBlock.set(blk); 4350 newBlock.set(blk);
4177 } 4351 }
4178 if (!globals.empty()) { 4352 if (!globals.empty()) {
@@ -4264,15 +4438,25 @@ private:
4264 4438
4265 std::optional<std::pair<std::string, str_list>> upValueFuncFromExp(Exp_t* exp, str_list* ensureArgListInTheEnd, bool blockRewrite) { 4439 std::optional<std::pair<std::string, str_list>> upValueFuncFromExp(Exp_t* exp, str_list* ensureArgListInTheEnd, bool blockRewrite) {
4266 if (checkUpValueFuncAvailable(exp)) { 4440 if (checkUpValueFuncAvailable(exp)) {
4441 auto block = exp->new_ptr<Block_t>();
4442 if (auto sVal = simpleSingleValueFrom(exp)) {
4443 if (auto doNode = sVal->value.as<Do_t>()) {
4444 if (auto blk = doNode->body->content.as<Block_t>()) {
4445 block->statementOrComments.dup(blk->statementOrComments);
4446 } else {
4447 block->statementOrComments.push_back(doNode->body->content.to<Statement_t>());
4448 }
4449 return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false, blockRewrite);
4450 }
4451 }
4267 auto returnNode = exp->new_ptr<Return_t>(); 4452 auto returnNode = exp->new_ptr<Return_t>();
4268 returnNode->explicitReturn = false; 4453 returnNode->explicitReturn = false;
4269 auto returnList = exp->new_ptr<ExpListLow_t>(); 4454 auto returnList = exp->new_ptr<ExpListLow_t>();
4270 returnList->exprs.push_back(exp); 4455 returnList->exprs.push_back(exp);
4271 returnNode->valueList.set(returnList); 4456 returnNode->valueList.set(returnList);
4272 auto block = exp->new_ptr<Block_t>();
4273 auto stmt = exp->new_ptr<Statement_t>(); 4457 auto stmt = exp->new_ptr<Statement_t>();
4274 stmt->content.set(returnNode); 4458 stmt->content.set(returnNode);
4275 block->statements.push_back(stmt); 4459 block->statementOrComments.push_back(stmt);
4276 return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false, blockRewrite); 4460 return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false, blockRewrite);
4277 } 4461 }
4278 return std::nullopt; 4462 return std::nullopt;
@@ -4329,7 +4513,7 @@ private:
4329 bool extraScope = !currentScope().lastStatement; 4513 bool extraScope = !currentScope().lastStatement;
4330 if (forAssignment) { 4514 if (forAssignment) {
4331 if (extraScope) { 4515 if (extraScope) {
4332 temp.push_back(indent() + "do"s + nll(x)); 4516 temp.push_back(indent() + "do"s + nl(x));
4333 pushScope(); 4517 pushScope();
4334 } 4518 }
4335 } 4519 }
@@ -4352,9 +4536,9 @@ private:
4352 case ExpUsage::Return: 4536 case ExpUsage::Return:
4353 case ExpUsage::Closure: { 4537 case ExpUsage::Closure: {
4354 prepareValue(); 4538 prepareValue();
4355 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); 4539 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nl(x);
4356 _buf << indent(1) << "return "s << objVar << nll(x); 4540 _buf << indent(1) << "return "s << objVar << nl(x);
4357 _buf << indent() << "else"s << nll(x); 4541 _buf << indent() << "else"s << nl(x);
4358 temp.push_back(clearBuf()); 4542 temp.push_back(clearBuf());
4359 auto ret = x->new_ptr<Return_t>(); 4543 auto ret = x->new_ptr<Return_t>();
4360 ret->explicitReturn = false; 4544 ret->explicitReturn = false;
@@ -4364,10 +4548,10 @@ private:
4364 incIndentOffset(); 4548 incIndentOffset();
4365 transformReturn(ret, temp); 4549 transformReturn(ret, temp);
4366 decIndentOffset(); 4550 decIndentOffset();
4367 temp.push_back(indent() + "end"s + nll(x)); 4551 temp.push_back(indent() + "end"s + nl(x));
4368 if (usage == ExpUsage::Closure) { 4552 if (usage == ExpUsage::Closure) {
4369 popScope(); 4553 popScope();
4370 *funcStart = anonFuncStart() + nll(x); 4554 *funcStart = anonFuncStart() + nl(x);
4371 temp.push_back(indent() + anonFuncEnd()); 4555 temp.push_back(indent() + anonFuncEnd());
4372 popAnonVarArg(); 4556 popAnonVarArg();
4373 popFunctionScope(); 4557 popFunctionScope();
@@ -4384,14 +4568,14 @@ private:
4384 assign->values.push_back(exp); 4568 assign->values.push_back(exp);
4385 temp.push_back(getPreDefineLine(assignment)); 4569 temp.push_back(getPreDefineLine(assignment));
4386 extraScope = prepareValue(true); 4570 extraScope = prepareValue(true);
4387 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); 4571 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nl(x);
4388 temp.push_back(clearBuf()); 4572 temp.push_back(clearBuf());
4389 pushScope(); 4573 pushScope();
4390 assign->values.clear(); 4574 assign->values.clear();
4391 assign->values.push_back(toAst<Exp_t>(objVar, x)); 4575 assign->values.push_back(toAst<Exp_t>(objVar, x));
4392 transformAssignment(assignment, temp); 4576 transformAssignment(assignment, temp);
4393 popScope(); 4577 popScope();
4394 temp.push_back(indent() + "else"s + nll(x)); 4578 temp.push_back(indent() + "else"s + nl(x));
4395 assign->values.clear(); 4579 assign->values.clear();
4396 assign->values.push_back(exp->nilCoalesed); 4580 assign->values.push_back(exp->nilCoalesed);
4397 } else { 4581 } else {
@@ -4399,17 +4583,17 @@ private:
4399 assign->values.push_back(exp->nilCoalesed); 4583 assign->values.push_back(exp->nilCoalesed);
4400 temp.push_back(getPreDefineLine(assignment)); 4584 temp.push_back(getPreDefineLine(assignment));
4401 transformExp(left, temp, ExpUsage::Closure); 4585 transformExp(left, temp, ExpUsage::Closure);
4402 _buf << indent() << "if "sv << temp.back() << " == nil then"sv << nll(x); 4586 _buf << indent() << "if "sv << temp.back() << " == nil then"sv << nl(x);
4403 temp.pop_back(); 4587 temp.pop_back();
4404 temp.push_back(clearBuf()); 4588 temp.push_back(clearBuf());
4405 } 4589 }
4406 pushScope(); 4590 pushScope();
4407 transformAssignment(assignment, temp); 4591 transformAssignment(assignment, temp);
4408 popScope(); 4592 popScope();
4409 temp.push_back(indent() + "end"s + nlr(x)); 4593 temp.push_back(indent() + "end"s + nl(x));
4410 if (extraScope) { 4594 if (extraScope) {
4411 popScope(); 4595 popScope();
4412 temp.push_back(indent() + "end"s + nlr(x)); 4596 temp.push_back(indent() + "end"s + nl(x));
4413 } 4597 }
4414 break; 4598 break;
4415 } 4599 }
@@ -4439,7 +4623,7 @@ private:
4439 if (accessType == AccessType::Read && _funcLevel > 1) { 4623 if (accessType == AccessType::Read && _funcLevel > 1) {
4440 accessType = AccessType::Capture; 4624 accessType = AccessType::Capture;
4441 } 4625 }
4442 _globals[key] = {out.back(), item->m_begin.m_line, item->m_begin.m_col, accessType}; 4626 _globals[key] = {out.back(), item->m_begin.m_line, item->m_begin.m_col, accessType, isSolidDefined(out.back())};
4443 } 4627 }
4444 } 4628 }
4445 break; 4629 break;
@@ -4471,6 +4655,7 @@ private:
4471 case id<ForEach_t>(): transformForEachClosure(static_cast<ForEach_t*>(value), out); break; 4655 case id<ForEach_t>(): transformForEachClosure(static_cast<ForEach_t*>(value), out); break;
4472 case id<For_t>(): transformForClosure(static_cast<For_t*>(value), out); break; 4656 case id<For_t>(): transformForClosure(static_cast<For_t*>(value), out); break;
4473 case id<While_t>(): transformWhileClosure(static_cast<While_t*>(value), out); break; 4657 case id<While_t>(): transformWhileClosure(static_cast<While_t*>(value), out); break;
4658 case id<Repeat_t>(): transformRepeatClosure(static_cast<Repeat_t*>(value), out); break;
4474 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Closure); break; 4659 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Closure); break;
4475 case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Closure); break; 4660 case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Closure); break;
4476 case id<UnaryValue_t>(): transformUnaryValue(static_cast<UnaryValue_t*>(value), out); break; 4661 case id<UnaryValue_t>(): transformUnaryValue(static_cast<UnaryValue_t*>(value), out); break;
@@ -4507,11 +4692,11 @@ private:
4507 switch (content->get_id()) { 4692 switch (content->get_id()) {
4508 case id<Block_t>(): { 4693 case id<Block_t>(): {
4509 auto block = static_cast<Block_t*>(content); 4694 auto block = static_cast<Block_t*>(content);
4510 newBlock->statements.dup(block->statements); 4695 newBlock->statementOrComments.dup(block->statementOrComments);
4511 break; 4696 break;
4512 } 4697 }
4513 case id<Statement_t>(): { 4698 case id<Statement_t>(): {
4514 newBlock->statements.push_back(content); 4699 newBlock->statementOrComments.push_back(content);
4515 break; 4700 break;
4516 } 4701 }
4517 default: YUEE("AST node mismatch", content); break; 4702 default: YUEE("AST node mismatch", content); break;
@@ -4523,7 +4708,7 @@ private:
4523 returnNode->valueList.set(funLit->defaultReturn); 4708 returnNode->valueList.set(funLit->defaultReturn);
4524 auto stmt = newBlock->new_ptr<Statement_t>(); 4709 auto stmt = newBlock->new_ptr<Statement_t>();
4525 stmt->content.set(returnNode); 4710 stmt->content.set(returnNode);
4526 newBlock->statements.push_back(stmt); 4711 newBlock->statementOrComments.push_back(stmt);
4527 } 4712 }
4528 transformBlock(newBlock, temp, ExpUsage::Common); 4713 transformBlock(newBlock, temp, ExpUsage::Common);
4529 } else { 4714 } else {
@@ -4545,7 +4730,7 @@ private:
4545 } 4730 }
4546 _buf << args << ')'; 4731 _buf << args << ')';
4547 if (!initArgs.empty() || !bodyCodes.empty()) { 4732 if (!initArgs.empty() || !bodyCodes.empty()) {
4548 _buf << nlr(argsDef) << initArgs << bodyCodes; 4733 _buf << nl(argsDef) << initArgs << bodyCodes;
4549 popScope(); 4734 popScope();
4550 _buf << indent() << "end"sv; 4735 _buf << indent() << "end"sv;
4551 } else { 4736 } else {
@@ -4556,7 +4741,7 @@ private:
4556 auto& bodyCodes = temp.back(); 4741 auto& bodyCodes = temp.back();
4557 _buf << "function("sv << (isFatArrow ? "self"s : Empty) << ')'; 4742 _buf << "function("sv << (isFatArrow ? "self"s : Empty) << ')';
4558 if (!bodyCodes.empty()) { 4743 if (!bodyCodes.empty()) {
4559 _buf << nll(funLit) << bodyCodes; 4744 _buf << nl(funLit) << bodyCodes;
4560 popScope(); 4745 popScope();
4561 _buf << indent() << "end"sv; 4746 _buf << indent() << "end"sv;
4562 } else { 4747 } else {
@@ -4573,7 +4758,7 @@ private:
4573 auto x = body; 4758 auto x = body;
4574 if (auto stmt = body->content.as<Statement_t>()) { 4759 if (auto stmt = body->content.as<Statement_t>()) {
4575 auto block = x->new_ptr<Block_t>(); 4760 auto block = x->new_ptr<Block_t>();
4576 block->statements.push_back(stmt); 4761 block->statementOrComments.push_back(stmt);
4577 transformBlock(block, out, usage, assignList); 4762 transformBlock(block, out, usage, assignList);
4578 } else { 4763 } else {
4579 transformBlock(body->content.to<Block_t>(), out, usage, assignList); 4764 transformBlock(body->content.to<Block_t>(), out, usage, assignList);
@@ -4585,13 +4770,15 @@ private:
4585 out.push_back(Empty); 4770 out.push_back(Empty);
4586 return; 4771 return;
4587 } 4772 }
4588 const auto& nodes = block->statements.objects(); 4773 const auto& nodes = block->statementOrComments.objects();
4774 auto lastStmt = lastStatementFrom(nodes);
4589 LocalMode mode = LocalMode::None; 4775 LocalMode mode = LocalMode::None;
4590 Local_t *any = nullptr, *capital = nullptr; 4776 Local_t *any = nullptr, *capital = nullptr;
4591 for (auto it = nodes.begin(); it != nodes.end(); ++it) { 4777 for (auto it = nodes.begin(); it != nodes.end(); ++it) {
4592 auto node = *it; 4778 auto node = *it;
4593 auto stmt = static_cast<Statement_t*>(node); 4779 auto stmt = ast_cast<Statement_t>(node);
4594 if (!stmt->appendix && stmt->content.is<Return_t>() && stmt != nodes.back()) { 4780 if (!stmt) continue;
4781 if (!stmt->appendix && stmt->content.is<Return_t>() && stmt != lastStmt) {
4595 throw CompileError("'return' statement must be the last line in the block"sv, stmt->content); 4782 throw CompileError("'return' statement must be the last line in the block"sv, stmt->content);
4596 } else if (auto pipeBody = stmt->content.as<PipeBody_t>()) { 4783 } else if (auto pipeBody = stmt->content.as<PipeBody_t>()) {
4597 auto x = stmt; 4784 auto x = stmt;
@@ -4600,6 +4787,16 @@ private:
4600 BREAK_IF(it == nodes.begin()); 4787 BREAK_IF(it == nodes.begin());
4601 auto last = it; 4788 auto last = it;
4602 --last; 4789 --last;
4790 bool found = true;
4791 while (!ast_is<Statement_t>(*last)) {
4792 if (last == nodes.begin()) {
4793 found = false;
4794 break;
4795 } else {
4796 --last;
4797 }
4798 }
4799 BREAK_IF(!found);
4603 auto lst = static_cast<Statement_t*>(*last); 4800 auto lst = static_cast<Statement_t*>(*last);
4604 if (lst->appendix) { 4801 if (lst->appendix) {
4605 throw CompileError("statement decorator must be placed at the end of pipe chain"sv, lst->appendix.get()); 4802 throw CompileError("statement decorator must be placed at the end of pipe chain"sv, lst->appendix.get());
@@ -4617,9 +4814,17 @@ private:
4617 stmt->content.set(nullptr); 4814 stmt->content.set(nullptr);
4618 auto next = it; 4815 auto next = it;
4619 ++next; 4816 ++next;
4817 Statement_t* nextStmt = nullptr;
4818 while (next != nodes.end()) {
4819 nextStmt = ast_cast<Statement_t>(*next);
4820 if (nextStmt) {
4821 break;
4822 }
4823 ++next;
4824 }
4620 BLOCK_START 4825 BLOCK_START
4621 BREAK_IF(next == nodes.end()); 4826 BREAK_IF(!nextStmt);
4622 BREAK_IF(!static_cast<Statement_t*>(*next)->content.as<PipeBody_t>()); 4827 BREAK_IF(!nextStmt->content.as<PipeBody_t>());
4623 throw CompileError("indent mismatch in pipe chain"sv, *next); 4828 throw CompileError("indent mismatch in pipe chain"sv, *next);
4624 BLOCK_END 4829 BLOCK_END
4625 } else if (auto backcall = stmt->content.as<Backcall_t>()) { 4830 } else if (auto backcall = stmt->content.as<Backcall_t>()) {
@@ -4627,7 +4832,7 @@ private:
4627 auto newBlock = x->new_ptr<Block_t>(); 4832 auto newBlock = x->new_ptr<Block_t>();
4628 if (it != nodes.begin()) { 4833 if (it != nodes.begin()) {
4629 for (auto i = nodes.begin(); i != it; ++i) { 4834 for (auto i = nodes.begin(); i != it; ++i) {
4630 newBlock->statements.push_back(*i); 4835 newBlock->statementOrComments.push_back(*i);
4631 } 4836 }
4632 } 4837 }
4633 x = backcall; 4838 x = backcall;
@@ -4638,7 +4843,7 @@ private:
4638 ++next; 4843 ++next;
4639 if (next != nodes.end()) { 4844 if (next != nodes.end()) {
4640 for (auto i = next; i != nodes.end(); ++i) { 4845 for (auto i = next; i != nodes.end(); ++i) {
4641 block->statements.push_back(*i); 4846 block->statementOrComments.push_back(*i);
4642 } 4847 }
4643 } 4848 }
4644 auto body = x->new_ptr<Body_t>(); 4849 auto body = x->new_ptr<Body_t>();
@@ -4690,7 +4895,7 @@ private:
4690 expListAssign->expList.set(expList); 4895 expListAssign->expList.set(expList);
4691 newStmt->content.set(expListAssign); 4896 newStmt->content.set(expListAssign);
4692 newStmt->appendix.set(stmt->appendix); 4897 newStmt->appendix.set(stmt->appendix);
4693 newBlock->statements.push_back(newStmt); 4898 newBlock->statementOrComments.push_back(newStmt);
4694 } 4899 }
4695 transformBlock(newBlock, out, usage, assignList, isRoot); 4900 transformBlock(newBlock, out, usage, assignList, isRoot);
4696 return; 4901 return;
@@ -4717,7 +4922,7 @@ private:
4717 throw CompileError("while-loop line decorator is not supported here"sv, appendix->item.get()); 4922 throw CompileError("while-loop line decorator is not supported here"sv, appendix->item.get());
4718 break; 4923 break;
4719 } 4924 }
4720 case id<CompInner_t>(): { 4925 case id<CompFor_t>(): {
4721 throw CompileError("for-loop line decorator is not supported here"sv, appendix->item.get()); 4926 throw CompileError("for-loop line decorator is not supported here"sv, appendix->item.get());
4722 break; 4927 break;
4723 } 4928 }
@@ -4746,7 +4951,7 @@ private:
4746 auto newBlock = x->new_ptr<Block_t>(); 4951 auto newBlock = x->new_ptr<Block_t>();
4747 if (it != nodes.begin()) { 4952 if (it != nodes.begin()) {
4748 for (auto i = nodes.begin(); i != it; ++i) { 4953 for (auto i = nodes.begin(); i != it; ++i) {
4749 newBlock->statements.push_back(*i); 4954 newBlock->statementOrComments.push_back(*i);
4750 } 4955 }
4751 } 4956 }
4752 x = expListAssign; 4957 x = expListAssign;
@@ -4756,7 +4961,7 @@ private:
4756 ++next; 4961 ++next;
4757 if (next != nodes.end()) { 4962 if (next != nodes.end()) {
4758 for (auto i = next; i != nodes.end(); ++i) { 4963 for (auto i = next; i != nodes.end(); ++i) {
4759 followingBlock->statements.push_back(*i); 4964 followingBlock->statementOrComments.push_back(*i);
4760 } 4965 }
4761 } 4966 }
4762 } 4967 }
@@ -4784,17 +4989,13 @@ private:
4784 newAssignment->action.set(newAssign); 4989 newAssignment->action.set(newAssign);
4785 auto newStatement = x->new_ptr<Statement_t>(); 4990 auto newStatement = x->new_ptr<Statement_t>();
4786 newStatement->content.set(newAssignment); 4991 newStatement->content.set(newAssignment);
4787 followingBlock->statements.push_front(newStatement); 4992 followingBlock->statementOrComments.push_front(newStatement);
4788 } 4993 }
4789 argNames.push_back("..."s); 4994 argNames.push_back("..."s);
4790 auto newBody = x->new_ptr<Body_t>(); 4995 auto newBody = x->new_ptr<Body_t>();
4791 newBody->content.set(followingBlock); 4996 newBody->content.set(followingBlock);
4792 { 4997 {
4793 auto doNode = x->new_ptr<Do_t>(); 4998 if (auto result = upValueFuncFromBlock(followingBlock.get(), &argNames, false, true)) {
4794 doNode->body.set(newBody);
4795 auto simpleValue = x->new_ptr<SimpleValue_t>();
4796 simpleValue->value.set(doNode);
4797 if (auto result = upValueFuncFromExp(newExp(simpleValue, x), &argNames, true)) {
4798 auto [funcName, args] = std::move(*result); 4999 auto [funcName, args] = std::move(*result);
4799 str_list finalArgs; 5000 str_list finalArgs;
4800 for (const auto& arg : args) { 5001 for (const auto& arg : args) {
@@ -4802,9 +5003,14 @@ private:
4802 finalArgs.push_back(arg); 5003 finalArgs.push_back(arg);
4803 } 5004 }
4804 } 5005 }
4805 newBlock->statements.push_back(toAst<Statement_t>(funcName + ' ' + join(finalArgs, ","sv), x)); 5006 auto lastNewStmt = toAst<Statement_t>(funcName + ' ' + (finalArgs.empty() ? "nil"s : join(finalArgs, ","sv)), x);
4806 auto sVal = singleValueFrom(static_cast<Statement_t*>(newBlock->statements.back())->content.to<ExpListAssign_t>()->expList); 5007 newBlock->statementOrComments.push_back(lastNewStmt);
4807 ast_to<InvokeArgs_t>(sVal->item.to<ChainValue_t>()->items.back())->args.dup(newInvoke->args); 5008 auto sVal = singleValueFrom(lastNewStmt->content.to<ExpListAssign_t>()->expList);
5009 auto invokArgs = ast_to<InvokeArgs_t>(sVal->item.to<ChainValue_t>()->items.back());
5010 if (finalArgs.empty()) {
5011 invokArgs->args.clear();
5012 }
5013 invokArgs->args.dup(newInvoke->args);
4808 transformBlock(newBlock, out, usage, assignList, isRoot); 5014 transformBlock(newBlock, out, usage, assignList, isRoot);
4809 return; 5015 return;
4810 } 5016 }
@@ -4829,7 +5035,7 @@ private:
4829 newItemListAssign->expList.set(newItemList); 5035 newItemListAssign->expList.set(newItemList);
4830 auto newItemStatement = x->new_ptr<Statement_t>(); 5036 auto newItemStatement = x->new_ptr<Statement_t>();
4831 newItemStatement->content.set(newItemListAssign); 5037 newItemStatement->content.set(newItemListAssign);
4832 newBlock->statements.push_back(newItemStatement); 5038 newBlock->statementOrComments.push_back(newItemStatement);
4833 transformBlock(newBlock, out, usage, assignList, isRoot); 5039 transformBlock(newBlock, out, usage, assignList, isRoot);
4834 return; 5040 return;
4835 BLOCK_END 5041 BLOCK_END
@@ -4838,11 +5044,11 @@ private:
4838 auto newBlock = x->new_ptr<Block_t>(); 5044 auto newBlock = x->new_ptr<Block_t>();
4839 if (it != nodes.begin()) { 5045 if (it != nodes.begin()) {
4840 for (auto i = nodes.begin(); i != it; ++i) { 5046 for (auto i = nodes.begin(); i != it; ++i) {
4841 newBlock->statements.push_back(*i); 5047 newBlock->statementOrComments.push_back(*i);
4842 } 5048 }
4843 } 5049 }
4844 localAttrib->attrib.set(localAttrib->new_ptr<ConstAttrib_t>()); 5050 localAttrib->attrib.set(localAttrib->new_ptr<ConstAttrib_t>());
4845 newBlock->statements.push_back(*it); 5051 newBlock->statementOrComments.push_back(*it);
4846 x = localAttrib; 5052 x = localAttrib;
4847 auto followingBlock = x->new_ptr<Block_t>(); 5053 auto followingBlock = x->new_ptr<Block_t>();
4848 { 5054 {
@@ -4850,7 +5056,7 @@ private:
4850 ++next; 5056 ++next;
4851 if (next != nodes.end()) { 5057 if (next != nodes.end()) {
4852 for (auto i = next; i != nodes.end(); ++i) { 5058 for (auto i = next; i != nodes.end(); ++i) {
4853 followingBlock->statements.push_back(*i); 5059 followingBlock->statementOrComments.push_back(*i);
4854 } 5060 }
4855 } 5061 }
4856 } 5062 }
@@ -4872,13 +5078,13 @@ private:
4872 auto value = singleValueFrom(pCallExp); 5078 auto value = singleValueFrom(pCallExp);
4873 value->item.to<SimpleValue_t>()->value.to<Try_t>()->func.set(followingBlock); 5079 value->item.to<SimpleValue_t>()->value.to<Try_t>()->func.set(followingBlock);
4874 for (const auto& stmt : getCloses) { 5080 for (const auto& stmt : getCloses) {
4875 newBlock->statements.push_back(toAst<Statement_t>(stmt, x)); 5081 newBlock->statementOrComments.push_back(toAst<Statement_t>(stmt, x));
4876 } 5082 }
4877 newBlock->statements.push_back(pCallStmt); 5083 newBlock->statementOrComments.push_back(pCallStmt);
4878 for (const auto& stmt : doCloses) { 5084 for (const auto& stmt : doCloses) {
4879 newBlock->statements.push_back(toAst<Statement_t>(stmt, x)); 5085 newBlock->statementOrComments.push_back(toAst<Statement_t>(stmt, x));
4880 } 5086 }
4881 newBlock->statements.push_back(toAst<Statement_t>("if "s + okVar + " then return ... else error ..."s, x)); 5087 newBlock->statementOrComments.push_back(toAst<Statement_t>("if "s + okVar + " then return ... else error ..."s, x));
4882 transformBlock(newBlock, out, usage, assignList, isRoot); 5088 transformBlock(newBlock, out, usage, assignList, isRoot);
4883 return; 5089 return;
4884 } else if (auto expListAssign = stmt->content.as<ExpListAssign_t>(); 5090 } else if (auto expListAssign = stmt->content.as<ExpListAssign_t>();
@@ -4887,7 +5093,7 @@ private:
4887 auto newBlock = x->new_ptr<Block_t>(); 5093 auto newBlock = x->new_ptr<Block_t>();
4888 if (it != nodes.begin()) { 5094 if (it != nodes.begin()) {
4889 for (auto i = nodes.begin(); i != it; ++i) { 5095 for (auto i = nodes.begin(); i != it; ++i) {
4890 newBlock->statements.push_back(*i); 5096 newBlock->statementOrComments.push_back(*i);
4891 } 5097 }
4892 } 5098 }
4893 auto doBackcall = static_cast<SubBackcall_t*>(expListAssign->action.get()); 5099 auto doBackcall = static_cast<SubBackcall_t*>(expListAssign->action.get());
@@ -4904,12 +5110,11 @@ private:
4904 backcall->value.set(doBackcall->value); 5110 backcall->value.set(doBackcall->value);
4905 auto newStmt = backcall->new_ptr<Statement_t>(); 5111 auto newStmt = backcall->new_ptr<Statement_t>();
4906 newStmt->content.set(backcall); 5112 newStmt->content.set(backcall);
4907 newStmt->comments.dup(stmt->comments);
4908 newStmt->appendix.set(stmt->appendix); 5113 newStmt->appendix.set(stmt->appendix);
4909 newBlock->statements.push_back(newStmt); 5114 newBlock->statementOrComments.push_back(newStmt);
4910 auto ait = it; 5115 auto ait = it;
4911 for (auto i = ++ait; i != nodes.end(); ++i) { 5116 for (auto i = ++ait; i != nodes.end(); ++i) {
4912 newBlock->statements.push_back(*i); 5117 newBlock->statementOrComments.push_back(*i);
4913 } 5118 }
4914 transformBlock(newBlock, out, usage, assignList, isRoot); 5119 transformBlock(newBlock, out, usage, assignList, isRoot);
4915 return; 5120 return;
@@ -5021,7 +5226,7 @@ private:
5021 } 5226 }
5022 } 5227 }
5023 if (isRoot && !_info.moduleName.empty() && !_info.exportMacro) { 5228 if (isRoot && !_info.moduleName.empty() && !_info.exportMacro) {
5024 block->statements.push_front(toAst<Statement_t>(_info.moduleName + (_info.exportDefault ? "=nil"s : (_info.exportMetatable ? "=<>:{}"s : "={}"s)), block)); 5229 block->statementOrComments.push_front(toAst<Statement_t>(_info.moduleName + (_info.exportDefault ? "=nil"s : (_info.exportMetatable ? "=<>:{}"s : "={}"s)), block));
5025 } 5230 }
5026 switch (usage) { 5231 switch (usage) {
5027 case ExpUsage::Closure: 5232 case ExpUsage::Closure:
@@ -5058,7 +5263,7 @@ private:
5058 break; 5263 break;
5059 } 5264 }
5060 } 5265 }
5061 bool lastAssignable = (expListFrom(last) || ast_is<For_t, ForEach_t, While_t>(last->content)); 5266 bool lastAssignable = (expListFrom(last) || ast_is<For_t, While_t>(last->content));
5062 if (lastAssignable) { 5267 if (lastAssignable) {
5063 auto x = last; 5268 auto x = last;
5064 auto newAssignment = x->new_ptr<ExpListAssign_t>(); 5269 auto newAssignment = x->new_ptr<ExpListAssign_t>();
@@ -5083,37 +5288,54 @@ private:
5083 } 5288 }
5084 if (!nodes.empty()) { 5289 if (!nodes.empty()) {
5085 str_list temp; 5290 str_list temp;
5291 auto lastStmt = lastStatementFrom(nodes);
5086 for (auto node : nodes) { 5292 for (auto node : nodes) {
5087 currentScope().lastStatement = (node == nodes.back()) && currentScope().mode == GlobalMode::None; 5293 if (auto comment = ast_cast<YueComment_t>(node)) {
5088 transformStatement(static_cast<Statement_t*>(node), temp); 5294 transformComment(comment, temp);
5089 if (isRoot && !_rootDefs.empty()) { 5295 continue;
5090 auto last = std::move(temp.back()); 5296 }
5091 temp.pop_back(); 5297 if (!ast_is<Statement_t>(node)) {
5092 temp.insert(temp.end(), _rootDefs.begin(), _rootDefs.end()); 5298 continue;
5093 _rootDefs.clear(); 5299 }
5094 temp.push_back(std::move(last)); 5300 auto transformNode = [&]() {
5095 } 5301 currentScope().lastStatement = (node == lastStmt) && currentScope().mode == GlobalMode::None;
5096 if (!temp.empty() && _parser.startWith<StatementSep_t>(temp.back())) { 5302 transformStatement(static_cast<Statement_t*>(node), temp);
5097 auto rit = ++temp.rbegin(); 5303 if (isRoot && !_rootDefs.empty()) {
5098 if (rit != temp.rend() && !rit->empty()) { 5304 auto last = std::move(temp.back());
5099 auto index = std::string::npos; 5305 temp.pop_back();
5100 if (_config.reserveLineNumber) { 5306 temp.insert(temp.end(), _rootDefs.begin(), _rootDefs.end());
5101 index = rit->rfind(" -- "sv); 5307 _rootDefs.clear();
5102 } else { 5308 temp.push_back(std::move(last));
5103 index = rit->find_last_not_of('\n'); 5309 }
5104 if (index != std::string::npos) index++; 5310 if (!temp.empty() && _parser.startWith<StatementSep_t>(temp.back())) {
5105 } 5311 auto rit = ++temp.rbegin();
5106 if (index != std::string::npos) { 5312 if (rit != temp.rend() && !rit->empty()) {
5107 auto ending = rit->substr(0, index); 5313 auto index = std::string::npos;
5108 auto ind = ending.find_last_of(" \t\n"sv); 5314 if (_config.reserveLineNumber) {
5109 if (ind != std::string::npos) { 5315 index = rit->rfind(" -- "sv);
5110 ending = ending.substr(ind + 1); 5316 } else {
5317 index = rit->find_last_not_of('\n');
5318 if (index != std::string::npos) index++;
5111 } 5319 }
5112 if (LuaKeywords.find(ending) == LuaKeywords.end()) { 5320 if (index != std::string::npos) {
5113 rit->insert(index, ";"sv); 5321 auto ending = rit->substr(0, index);
5322 auto ind = ending.find_last_of(" \t\n"sv);
5323 if (ind != std::string::npos) {
5324 ending = ending.substr(ind + 1);
5325 }
5326 if (LuaKeywords.find(ending) == LuaKeywords.end()) {
5327 rit->insert(index, ";"sv);
5328 }
5114 } 5329 }
5115 } 5330 }
5116 } 5331 }
5332 };
5333 if (_config.lax) {
5334 try {
5335 transformNode();
5336 } catch (const CompileError&) { }
5337 } else {
5338 transformNode();
5117 } 5339 }
5118 } 5340 }
5119 out.push_back(join(temp)); 5341 out.push_back(join(temp));
@@ -5121,7 +5343,7 @@ private:
5121 out.push_back(Empty); 5343 out.push_back(Empty);
5122 } 5344 }
5123 if (isRoot && !_info.moduleName.empty() && !_info.exportMacro) { 5345 if (isRoot && !_info.moduleName.empty() && !_info.exportMacro) {
5124 out.back().append(indent() + "return "s + _info.moduleName + nlr(block)); 5346 out.back().append(indent() + "return "s + _info.moduleName + nl(block));
5125 } 5347 }
5126 } 5348 }
5127 5349
@@ -5322,18 +5544,29 @@ private:
5322 auto macroLit = macro->decl.to<MacroLit_t>(); 5544 auto macroLit = macro->decl.to<MacroLit_t>();
5323 auto argsDef = macroLit->argsDef.get(); 5545 auto argsDef = macroLit->argsDef.get();
5324 str_list newArgs; 5546 str_list newArgs;
5547 str_list argChecks;
5548 bool hasCheck = false;
5325 if (argsDef) { 5549 if (argsDef) {
5326 for (auto def_ : argsDef->definitions.objects()) { 5550 for (auto def_ : argsDef->definitions.objects()) {
5327 auto def = static_cast<FnArgDef_t*>(def_); 5551 auto def = static_cast<FnArgDef_t*>(def_);
5328 if (def->name.is<SelfItem_t>()) { 5552 if (def->name.is<SelfItem_t>()) {
5329 throw CompileError("self name is not supported for macro function argument"sv, def->name); 5553 throw CompileError("self name is not supported for macro function argument"sv, def->name);
5330 } else { 5554 } else {
5555 if (def->op) throw CompileError("invalid existence checking"sv, def->op);
5556 if (def->label) {
5557 hasCheck = true;
5558 const auto& astName = argChecks.emplace_back(_parser.toString(def->label));
5559 if (!_parser.hasAST(astName)) {
5560 throw CompileError("invalid AST name"sv, def->label);
5561 }
5562 } else {
5563 argChecks.emplace_back();
5564 }
5331 std::string defVal; 5565 std::string defVal;
5332 if (def->defaultValue) { 5566 if (def->defaultValue) {
5333 defVal = _parser.toString(def->defaultValue); 5567 defVal = _parser.toString(def->defaultValue);
5334 Utils::trim(defVal); 5568 Utils::trim(defVal);
5335 defVal.insert(0, "=[==========["sv); 5569 defVal = '=' + Utils::toLuaDoubleString(defVal);
5336 defVal.append("]==========]"sv);
5337 } 5570 }
5338 newArgs.emplace_back(_parser.toString(def->name) + defVal); 5571 newArgs.emplace_back(_parser.toString(def->name) + defVal);
5339 } 5572 }
@@ -5341,6 +5574,14 @@ private:
5341 if (argsDef->varArg) { 5574 if (argsDef->varArg) {
5342 newArgs.emplace_back(_parser.toString(argsDef->varArg)); 5575 newArgs.emplace_back(_parser.toString(argsDef->varArg));
5343 } 5576 }
5577 if (argsDef->label) {
5578 hasCheck = true;
5579 const auto& astName = _parser.toString(argsDef->label);
5580 if (!_parser.hasAST(astName)) {
5581 throw CompileError("invalid AST name"sv, argsDef->label);
5582 }
5583 argChecks.emplace_back("..."s + astName);
5584 }
5344 } 5585 }
5345 std::string macroCodes = "_ENV=require('yue').macro_env\n("s + join(newArgs, ","sv) + ")->"s + _parser.toString(macroLit->body); 5586 std::string macroCodes = "_ENV=require('yue').macro_env\n("s + join(newArgs, ","sv) + ")->"s + _parser.toString(macroLit->body);
5346 auto chunkName = "=(macro "s + macroName + ')'; 5587 auto chunkName = "=(macro "s + macroName + ')';
@@ -5371,6 +5612,24 @@ private:
5371 throw CompileError("failed to generate macro function\n"s + err, macroLit); 5612 throw CompileError("failed to generate macro function\n"s + err, macroLit);
5372 } // cur true macro 5613 } // cur true macro
5373 lua_remove(L, -2); // cur macro 5614 lua_remove(L, -2); // cur macro
5615 if (hasCheck) {
5616 lua_createtable(L, 0, 0); // cur macro checks
5617 int i = 1;
5618 for (const auto& check : argChecks) {
5619 if (check.empty()) {
5620 lua_pushboolean(L, 0);
5621 lua_rawseti(L, -2, i);
5622 } else {
5623 lua_pushlstring(L, check.c_str(), check.size());
5624 lua_rawseti(L, -2, i);
5625 }
5626 i++;
5627 }
5628 lua_createtable(L, 2, 0); // cur macro checks macrotab
5629 lua_insert(L, -3); // cur macrotab macro checks
5630 lua_rawseti(L, -3, 1); // macrotab[1] = checks, cur macrotab macro
5631 lua_rawseti(L, -2, 2); // macrotab[2] = macro, cur macrotab
5632 } // cur macro
5374 if (exporting && _config.exporting && !_config.module.empty()) { 5633 if (exporting && _config.exporting && !_config.module.empty()) {
5375 pushModuleTable(_config.module); // cur macro module 5634 pushModuleTable(_config.module); // cur macro module
5376 lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro module name 5635 lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro module name
@@ -5445,11 +5704,11 @@ private:
5445 case id<While_t>(): 5704 case id<While_t>():
5446 transformWhileInPlace(static_cast<While_t*>(value), out); 5705 transformWhileInPlace(static_cast<While_t*>(value), out);
5447 return; 5706 return;
5448 case id<For_t>(): 5707 case id<Repeat_t>():
5449 transformForInPlace(static_cast<For_t*>(value), out); 5708 transformRepeatInPlace(static_cast<Repeat_t*>(value), out);
5450 return; 5709 return;
5451 case id<ForEach_t>(): 5710 case id<For_t>():
5452 transformForEachInPlace(static_cast<ForEach_t*>(value), out); 5711 transformForInPlace(static_cast<For_t*>(value), out, nullptr);
5453 return; 5712 return;
5454 case id<If_t>(): 5713 case id<If_t>():
5455 transformIf(static_cast<If_t*>(value), out, ExpUsage::Return); 5714 transformIf(static_cast<If_t*>(value), out, ExpUsage::Return);
@@ -5469,12 +5728,12 @@ private:
5469 } 5728 }
5470 } 5729 }
5471 transformValue(singleValue, out); 5730 transformValue(singleValue, out);
5472 out.back() = indent() + "return "s + out.back() + nlr(returnNode); 5731 out.back() = indent() + "return "s + out.back() + nl(returnNode);
5473 return; 5732 return;
5474 } else { 5733 } else {
5475 str_list temp; 5734 str_list temp;
5476 transformExpListLow(valueList, temp); 5735 transformExpListLow(valueList, temp);
5477 out.push_back(indent() + "return "s + temp.back() + nlr(returnNode)); 5736 out.push_back(indent() + "return "s + temp.back() + nl(returnNode));
5478 } 5737 }
5479 } else if (auto tableBlock = returnNode->valueList.as<TableBlock_t>()) { 5738 } else if (auto tableBlock = returnNode->valueList.as<TableBlock_t>()) {
5480 const auto& values = tableBlock->values.objects(); 5739 const auto& values = tableBlock->values.objects();
@@ -5482,10 +5741,10 @@ private:
5482 transformSpreadTable(values, out, ExpUsage::Return, nullptr, false); 5741 transformSpreadTable(values, out, ExpUsage::Return, nullptr, false);
5483 } else { 5742 } else {
5484 transformTable(values, out); 5743 transformTable(values, out);
5485 out.back() = indent() + "return "s + out.back() + nlr(returnNode); 5744 out.back() = indent() + "return "s + out.back() + nl(returnNode);
5486 } 5745 }
5487 } else { 5746 } else {
5488 out.push_back(indent() + "return"s + nll(returnNode)); 5747 out.push_back(indent() + "return"s + nl(returnNode));
5489 } 5748 }
5490 } 5749 }
5491 5750
@@ -5516,6 +5775,7 @@ private:
5516 bool checkExistence = false; 5775 bool checkExistence = false;
5517 std::string name; 5776 std::string name;
5518 std::string assignSelf; 5777 std::string assignSelf;
5778 ast_ptr<false, ExpListAssign_t> assignment;
5519 }; 5779 };
5520 std::list<ArgItem> argItems; 5780 std::list<ArgItem> argItems;
5521 str_list temp; 5781 str_list temp;
@@ -5525,7 +5785,11 @@ private:
5525 auto def = static_cast<FnArgDef_t*>(_def); 5785 auto def = static_cast<FnArgDef_t*>(_def);
5526 auto& arg = argItems.emplace_back(); 5786 auto& arg = argItems.emplace_back();
5527 switch (def->name->get_id()) { 5787 switch (def->name->get_id()) {
5528 case id<Variable_t>(): arg.name = variableToString(static_cast<Variable_t*>(def->name.get())); break; 5788 case id<Variable_t>(): {
5789 if (def->op) throw CompileError("invalid existence checking"sv, def->op);
5790 arg.name = variableToString(static_cast<Variable_t*>(def->name.get()));
5791 break;
5792 }
5529 case id<SelfItem_t>(): { 5793 case id<SelfItem_t>(): {
5530 assignSelf = true; 5794 assignSelf = true;
5531 if (def->op) { 5795 if (def->op) {
@@ -5566,6 +5830,22 @@ private:
5566 } 5830 }
5567 break; 5831 break;
5568 } 5832 }
5833 case id<TableLit_t>(): {
5834 arg.name = getUnusedName("_arg_"sv);
5835 auto simpleValue = def->new_ptr<SimpleValue_t>();
5836 simpleValue->value.set(def->name);
5837 auto asmt = assignmentFrom(newExp(simpleValue, def), toAst<Exp_t>(arg.name, def), def);
5838 arg.assignment = asmt;
5839 break;
5840 }
5841 case id<SimpleTable_t>(): {
5842 arg.name = getUnusedName("_arg_"sv);
5843 auto value = def->new_ptr<Value_t>();
5844 value->item.set(def->name);
5845 auto asmt = assignmentFrom(newExp(value, def), toAst<Exp_t>(arg.name, def), def);
5846 arg.assignment = asmt;
5847 break;
5848 }
5569 default: YUEE("AST node mismatch", def->name.get()); break; 5849 default: YUEE("AST node mismatch", def->name.get()); break;
5570 } 5850 }
5571 forceAddToScope(arg.name); 5851 forceAddToScope(arg.name);
@@ -5579,23 +5859,46 @@ private:
5579 assignment->action.set(assign); 5859 assignment->action.set(assign);
5580 transformAssignment(assignment, temp); 5860 transformAssignment(assignment, temp);
5581 popScope(); 5861 popScope();
5582 _buf << indent() << "if "sv << arg.name << " == nil then"sv << nll(def); 5862 _buf << indent() << "if "sv << arg.name << " == nil then"sv << nl(def);
5583 _buf << temp.back(); 5863 _buf << temp.back();
5584 _buf << indent() << "end"sv << nll(def); 5864 _buf << indent() << "end"sv << nl(def);
5585 temp.back() = clearBuf(); 5865 temp.back() = clearBuf();
5586 } 5866 }
5587 if (varNames.empty()) 5867 if (arg.assignment) {
5868 auto names = getArgDestructureList(arg.assignment);
5869 for (const auto& name : names) {
5870 forceAddToScope(name);
5871 }
5872 temp.emplace_back(indent() + "local "s + join(names, ", "sv) + nl(def));
5873 transformAssignment(arg.assignment, temp);
5874 }
5875 if (varNames.empty()) {
5588 varNames = arg.name; 5876 varNames = arg.name;
5589 else 5877 } else {
5590 varNames.append(", "s + arg.name); 5878 varNames.append(", "s + arg.name);
5879 }
5591 } 5880 }
5592 if (argDefList->varArg) { 5881 if (argDefList->varArg) {
5882 std::string varStr;
5883 if (auto varName = argDefList->varArg->name.get()) {
5884 varStr = variableToString(varName);
5885 int target = getLuaTarget(varName);
5886 forceAddToScope(varStr);
5887 if (target < 505) {
5888 temp.push_back(indent() + "local "s + varStr + " = {"s + nl(varName));
5889 temp.push_back(indent(1) + "n = "s + globalVar("select", varName, AccessType::Read) + "(\"#\", ...),"s + nl(varName));
5890 temp.push_back(indent(1) + "..."s + nl(varName));
5891 temp.push_back(indent() + '}' + nl(varName));
5892 varStr.clear();
5893 }
5894 }
5593 auto& arg = argItems.emplace_back(); 5895 auto& arg = argItems.emplace_back();
5594 arg.name = "..."sv; 5896 arg.name = "..."sv;
5595 if (varNames.empty()) 5897 if (varNames.empty()) {
5596 varNames = arg.name; 5898 varNames = arg.name + varStr;
5597 else 5899 } else {
5598 varNames.append(", "s + arg.name); 5900 varNames.append(", "s + arg.name + varStr);
5901 }
5599 _varArgs.top().hasVar = true; 5902 _varArgs.top().hasVar = true;
5600 } 5903 }
5601 if (assignSelf) { 5904 if (assignSelf) {
@@ -5664,6 +5967,45 @@ private:
5664 } 5967 }
5665 } 5968 }
5666 5969
5970 bool transformChainEndWithSlice(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) {
5971 auto x = chainList.front();
5972 if (ast_is<Slice_t>(chainList.back())) {
5973 auto comp = x->new_ptr<Comprehension_t>();
5974 {
5975 auto chainValue = x->new_ptr<ChainValue_t>();
5976 for (auto item : chainList) {
5977 chainValue->items.push_back(item);
5978 }
5979 auto itemVar = getUnusedName("_item_"sv);
5980 auto expCode = YueFormat{}.toString(chainValue);
5981 auto compCode = '[' + itemVar + " for "s + itemVar + " in *"s + expCode + ']';
5982 comp.set(toAst<Comprehension_t>(compCode, x));
5983 }
5984 switch (usage) {
5985 case ExpUsage::Assignment: {
5986 auto simpleValue = x->new_ptr<SimpleValue_t>();
5987 simpleValue->value.set(comp);
5988 auto exp = newExp(simpleValue, x);
5989 auto assignment = x->new_ptr<ExpListAssign_t>();
5990 assignment->expList.set(assignList);
5991 auto assign = x->new_ptr<Assign_t>();
5992 assign->values.push_back(exp);
5993 assignment->action.set(assign);
5994 transformAssignment(assignment, out);
5995 break;
5996 }
5997 case ExpUsage::Return:
5998 transformComprehension(comp, out, ExpUsage::Return);
5999 break;
6000 default:
6001 transformComprehension(comp, out, ExpUsage::Closure);
6002 break;
6003 }
6004 return true;
6005 }
6006 return false;
6007 }
6008
5667 bool transformChainEndWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) { 6009 bool transformChainEndWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) {
5668 auto x = chainList.front(); 6010 auto x = chainList.front();
5669 if (ast_is<ExistentialOp_t>(chainList.back())) { 6011 if (ast_is<ExistentialOp_t>(chainList.back())) {
@@ -5698,7 +6040,7 @@ private:
5698 case ExpUsage::Return: 6040 case ExpUsage::Return:
5699 transformParens(parens, out); 6041 transformParens(parens, out);
5700 out.back().insert(0, indent() + "return "s); 6042 out.back().insert(0, indent() + "return "s);
5701 out.back().append(nlr(x)); 6043 out.back().append(nl(x));
5702 break; 6044 break;
5703 default: 6045 default:
5704 transformParens(parens, out); 6046 transformParens(parens, out);
@@ -5769,7 +6111,7 @@ private:
5769 } 6111 }
5770 } 6112 }
5771 if (isScoped) { 6113 if (isScoped) {
5772 temp.push_back(indent() + "do"s + nll(x)); 6114 temp.push_back(indent() + "do"s + nl(x));
5773 pushScope(); 6115 pushScope();
5774 } 6116 }
5775 objVar = getUnusedName("_obj_"sv); 6117 objVar = getUnusedName("_obj_"sv);
@@ -5829,9 +6171,9 @@ private:
5829 _buf << typeVar << "=type "sv << objVar; 6171 _buf << typeVar << "=type "sv << objVar;
5830 auto typeAssign = toAst<ExpListAssign_t>(clearBuf(), partOne); 6172 auto typeAssign = toAst<ExpListAssign_t>(clearBuf(), partOne);
5831 transformAssignment(typeAssign, temp); 6173 transformAssignment(typeAssign, temp);
5832 _buf << indent() << "if \"table\" == " << typeVar << " or \"userdata\" == "sv << typeVar << " then"sv << nll(x); 6174 _buf << indent() << "if \"table\" == " << typeVar << " or \"userdata\" == "sv << typeVar << " then"sv << nl(x);
5833 } else { 6175 } else {
5834 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); 6176 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nl(x);
5835 } 6177 }
5836 temp.push_back(clearBuf()); 6178 temp.push_back(clearBuf());
5837 pushScope(); 6179 pushScope();
@@ -5867,15 +6209,15 @@ private:
5867 } 6209 }
5868 } 6210 }
5869 popScope(); 6211 popScope();
5870 temp.push_back(indent() + "end"s + nlr(x)); 6212 temp.push_back(indent() + "end"s + nl(x));
5871 switch (usage) { 6213 switch (usage) {
5872 case ExpUsage::Return: 6214 case ExpUsage::Return:
5873 temp.push_back(indent() + "return nil"s + nlr(x)); 6215 temp.push_back(indent() + "return nil"s + nl(x));
5874 break; 6216 break;
5875 case ExpUsage::Closure: 6217 case ExpUsage::Closure:
5876 temp.push_back(indent() + "return nil"s + nlr(x)); 6218 temp.push_back(indent() + "return nil"s + nl(x));
5877 popScope(); 6219 popScope();
5878 *funcStart = anonFuncStart() + nll(x); 6220 *funcStart = anonFuncStart() + nl(x);
5879 temp.push_back(indent() + anonFuncEnd()); 6221 temp.push_back(indent() + anonFuncEnd());
5880 popAnonVarArg(); 6222 popAnonVarArg();
5881 popFunctionScope(); 6223 popFunctionScope();
@@ -5885,7 +6227,7 @@ private:
5885 } 6227 }
5886 if (isScoped) { 6228 if (isScoped) {
5887 popScope(); 6229 popScope();
5888 temp.push_back(indent() + "end"s + nlr(x)); 6230 temp.push_back(indent() + "end"s + nl(x));
5889 } 6231 }
5890 out.push_back(join(temp)); 6232 out.push_back(join(temp));
5891 return true; 6233 return true;
@@ -5902,7 +6244,7 @@ private:
5902 switch (usage) { 6244 switch (usage) {
5903 case ExpUsage::Assignment: 6245 case ExpUsage::Assignment:
5904 if (isScoped) { 6246 if (isScoped) {
5905 temp.push_back(indent() + "do"s + nll(x)); 6247 temp.push_back(indent() + "do"s + nl(x));
5906 pushScope(); 6248 pushScope();
5907 } 6249 }
5908 break; 6250 break;
@@ -5980,12 +6322,12 @@ private:
5980 case ExpUsage::Assignment: 6322 case ExpUsage::Assignment:
5981 if (isScoped) { 6323 if (isScoped) {
5982 popScope(); 6324 popScope();
5983 temp.push_back(indent() + "end"s + nlr(x)); 6325 temp.push_back(indent() + "end"s + nl(x));
5984 } 6326 }
5985 break; 6327 break;
5986 case ExpUsage::Closure: 6328 case ExpUsage::Closure:
5987 popScope(); 6329 popScope();
5988 *funcStart = anonFuncStart() + nll(x); 6330 *funcStart = anonFuncStart() + nl(x);
5989 temp.push_back(indent() + anonFuncEnd()); 6331 temp.push_back(indent() + anonFuncEnd());
5990 popAnonVarArg(); 6332 popAnonVarArg();
5991 popFunctionScope(); 6333 popFunctionScope();
@@ -6061,7 +6403,7 @@ private:
6061 pushScope(); 6403 pushScope();
6062 } else if (usage != ExpUsage::Return) { 6404 } else if (usage != ExpUsage::Return) {
6063 if (isScoped) { 6405 if (isScoped) {
6064 temp.push_back(indent() + "do"s + nll(x)); 6406 temp.push_back(indent() + "do"s + nl(x));
6065 pushScope(); 6407 pushScope();
6066 } 6408 }
6067 } 6409 }
@@ -6098,7 +6440,7 @@ private:
6098 returnNode->valueList.set(values); 6440 returnNode->valueList.set(values);
6099 transformReturn(returnNode, temp); 6441 transformReturn(returnNode, temp);
6100 popScope(); 6442 popScope();
6101 *funcStart = anonFuncStart() + nll(x); 6443 *funcStart = anonFuncStart() + nl(x);
6102 temp.push_back(indent() + anonFuncEnd()); 6444 temp.push_back(indent() + anonFuncEnd());
6103 popAnonVarArg(); 6445 popAnonVarArg();
6104 popFunctionScope(); 6446 popFunctionScope();
@@ -6122,7 +6464,7 @@ private:
6122 transformAssignment(assignment, temp); 6464 transformAssignment(assignment, temp);
6123 if (isScoped) { 6465 if (isScoped) {
6124 popScope(); 6466 popScope();
6125 temp.push_back(indent() + "end"s + nlr(x)); 6467 temp.push_back(indent() + "end"s + nl(x));
6126 } 6468 }
6127 break; 6469 break;
6128 } 6470 }
@@ -6130,7 +6472,7 @@ private:
6130 transformExp(newChainExp, temp, usage); 6472 transformExp(newChainExp, temp, usage);
6131 if (isScoped) { 6473 if (isScoped) {
6132 popScope(); 6474 popScope();
6133 temp.push_back(indent() + "end"s + nlr(x)); 6475 temp.push_back(indent() + "end"s + nl(x));
6134 } 6476 }
6135 break; 6477 break;
6136 } 6478 }
@@ -6181,7 +6523,7 @@ private:
6181 case id<ColonChainItem_t>(): 6523 case id<ColonChainItem_t>():
6182 case id<Exp_t>(): 6524 case id<Exp_t>():
6183 if (_withVars.empty()) { 6525 if (_withVars.empty()) {
6184 throw CompileError("short dot/colon and indexing syntax must be called within a with block"sv, x); 6526 throw CompileError("short dot/colon/indexing syntax must be called within a with block"sv, x);
6185 } else { 6527 } else {
6186 temp.push_back(_withVars.top()); 6528 temp.push_back(_withVars.top());
6187 } 6529 }
@@ -6235,7 +6577,7 @@ private:
6235 assignment->action.set(assign); 6577 assignment->action.set(assign);
6236 auto stmt = x->new_ptr<Statement_t>(); 6578 auto stmt = x->new_ptr<Statement_t>();
6237 stmt->content.set(assignment); 6579 stmt->content.set(assignment);
6238 block->statements.push_back(stmt); 6580 block->statementOrComments.push_back(stmt);
6239 } 6581 }
6240 } 6582 }
6241 ast_ptr<false, Exp_t> nexp; 6583 ast_ptr<false, Exp_t> nexp;
@@ -6281,7 +6623,7 @@ private:
6281 expListAssign->expList.set(expList); 6623 expListAssign->expList.set(expList);
6282 auto stmt = x->new_ptr<Statement_t>(); 6624 auto stmt = x->new_ptr<Statement_t>();
6283 stmt->content.set(expListAssign); 6625 stmt->content.set(expListAssign);
6284 block->statements.push_back(stmt); 6626 block->statementOrComments.push_back(stmt);
6285 } 6627 }
6286 switch (usage) { 6628 switch (usage) {
6287 case ExpUsage::Common: 6629 case ExpUsage::Common:
@@ -6295,7 +6637,7 @@ private:
6295 default: 6637 default:
6296 break; 6638 break;
6297 } 6639 }
6298 if (block->statements.size() == 1) { 6640 if (block->statementOrComments.size() == 1) {
6299 transformExp(nexp, out, usage, assignList); 6641 transformExp(nexp, out, usage, assignList);
6300 } else { 6642 } else {
6301 auto body = x->new_ptr<Body_t>(); 6643 auto body = x->new_ptr<Body_t>();
@@ -6327,6 +6669,120 @@ private:
6327 } 6669 }
6328 return; 6670 return;
6329 } 6671 }
6672 break;
6673 }
6674 case id<ReversedIndex_t>(): {
6675 auto rIndex = static_cast<ReversedIndex_t*>(*it);
6676 auto current = it;
6677 auto prevChain = x->new_ptr<ChainValue_t>();
6678 for (auto i = chainList.begin(); i != current; ++i) {
6679 prevChain->items.push_back(*i);
6680 }
6681 auto var = singleVariableFrom(prevChain, AccessType::None);
6682 if (!var.empty() && isLocal(var)) {
6683 auto indexNode = toAst<Exp_t>('#' + var, rIndex);
6684 if (rIndex->modifier) {
6685 auto opValue = rIndex->new_ptr<ExpOpValue_t>();
6686 opValue->op.set(toAst<BinaryOperator_t>("-"sv, rIndex));
6687 opValue->pipeExprs.dup(rIndex->modifier->pipeExprs);
6688 indexNode->opValues.push_back(opValue);
6689 indexNode->opValues.dup(rIndex->modifier->opValues);
6690 indexNode->nilCoalesed.set(rIndex->modifier->nilCoalesed);
6691 }
6692 prevChain->items.push_back(indexNode);
6693 auto next = current;
6694 ++next;
6695 for (auto i = next; i != chainList.end(); ++i) {
6696 prevChain->items.push_back(*i);
6697 }
6698 if (usage == ExpUsage::Assignment) {
6699 auto assignment = x->new_ptr<ExpListAssign_t>();
6700 assignment->expList.set(assignList);
6701 auto assign = x->new_ptr<Assign_t>();
6702 assign->values.push_back(newExp(prevChain, x));
6703 assignment->action.set(assign);
6704 transformAssignment(assignment, out);
6705 return;
6706 }
6707 transformChainValue(prevChain, out, usage, assignList);
6708 return;
6709 } else {
6710 auto itemVar = getUnusedName("_item_"sv);
6711 auto asmt = assignmentFrom(toAst<Exp_t>(itemVar, x), newExp(prevChain, x), x);
6712 auto stmt1 = x->new_ptr<Statement_t>();
6713 stmt1->content.set(asmt);
6714 auto newChain = x->new_ptr<ChainValue_t>();
6715 newChain->items.push_back(toAst<Callable_t>(itemVar, x));
6716 auto indexNode = toAst<Exp_t>('#' + itemVar, rIndex);
6717 if (rIndex->modifier) {
6718 auto opValue = rIndex->new_ptr<ExpOpValue_t>();
6719 opValue->op.set(toAst<BinaryOperator_t>("-"sv, rIndex));
6720 opValue->pipeExprs.dup(rIndex->modifier->pipeExprs);
6721 indexNode->opValues.push_back(opValue);
6722 indexNode->opValues.dup(rIndex->modifier->opValues);
6723 indexNode->nilCoalesed.set(rIndex->modifier->nilCoalesed);
6724 }
6725 newChain->items.push_back(indexNode);
6726 auto expList = x->new_ptr<ExpList_t>();
6727 expList->exprs.push_back(newExp(newChain, x));
6728 auto expListAssign = x->new_ptr<ExpListAssign_t>();
6729 expListAssign->expList.set(expList);
6730 auto stmt2 = x->new_ptr<Statement_t>();
6731 stmt2->content.set(expListAssign);
6732 auto block = x->new_ptr<Block_t>();
6733 block->statementOrComments.push_back(stmt1);
6734 block->statementOrComments.push_back(stmt2);
6735 auto body = x->new_ptr<Body_t>();
6736 body->content.set(block);
6737 auto doNode = x->new_ptr<Do_t>();
6738 doNode->body.set(body);
6739 if (usage == ExpUsage::Assignment) {
6740 auto next = current;
6741 ++next;
6742 for (auto i = next; i != chainList.end(); ++i) {
6743 newChain->items.push_back(*i);
6744 }
6745 auto assignment = x->new_ptr<ExpListAssign_t>();
6746 assignment->expList.set(assignList);
6747 auto assign = x->new_ptr<Assign_t>();
6748 auto sVal = x->new_ptr<SimpleValue_t>();
6749 sVal->value.set(doNode);
6750 assign->values.push_back(newExp(sVal, x));
6751 assignment->action.set(assign);
6752 transformAssignment(assignment, out);
6753 return;
6754 }
6755 if (usage == ExpUsage::Closure) {
6756 auto next = current;
6757 ++next;
6758 if (next != chainList.end()) {
6759 doNode->new_ptr<ChainValue_t>();
6760 auto dVal = doNode->new_ptr<SimpleValue_t>();
6761 dVal->value.set(doNode);
6762 auto dExp = newExp(dVal, dVal);
6763 auto dParen = dExp->new_ptr<Parens_t>();
6764 dParen->extra = true;
6765 dParen->expr.set(dExp);
6766 auto dCallable = dExp->new_ptr<Callable_t>();
6767 dCallable->item.set(dParen);
6768 auto dChain = doNode->new_ptr<ChainValue_t>();
6769 dChain->items.push_back(dCallable);
6770 for (auto i = next; i != chainList.end(); ++i) {
6771 dChain->items.push_back(*i);
6772 }
6773 transformExp(newExp(dChain, dExp), out, usage);
6774 return;
6775 }
6776 }
6777 auto next = current;
6778 ++next;
6779 for (auto i = next; i != chainList.end(); ++i) {
6780 newChain->items.push_back(*i);
6781 }
6782 transformDo(doNode, out, usage);
6783 return;
6784 }
6785 break;
6330 } 6786 }
6331 } 6787 }
6332 } 6788 }
@@ -6376,10 +6832,10 @@ private:
6376 } 6832 }
6377 switch (usage) { 6833 switch (usage) {
6378 case ExpUsage::Common: 6834 case ExpUsage::Common:
6379 out.push_back(indent() + join(temp) + nll(x)); 6835 out.push_back(indent() + join(temp) + nl(x));
6380 break; 6836 break;
6381 case ExpUsage::Return: 6837 case ExpUsage::Return:
6382 out.push_back(indent() + "return "s + join(temp) + nll(x)); 6838 out.push_back(indent() + "return "s + join(temp) + nl(x));
6383 break; 6839 break;
6384 case ExpUsage::Assignment: YUEE("invalid expression usage", x); break; 6840 case ExpUsage::Assignment: YUEE("invalid expression usage", x); break;
6385 default: 6841 default:
@@ -6511,7 +6967,7 @@ private:
6511 } 6967 }
6512 } 6968 }
6513 } 6969 }
6514 int len = lua_objlen(L, -1); 6970 int len = static_cast<int>(lua_objlen(L, -1));
6515 lua_pushnil(L); // cur nil 6971 lua_pushnil(L); // cur nil
6516 for (int i = len; i >= 1; i--) { 6972 for (int i = len; i >= 1; i--) {
6517 lua_pop(L, 1); // cur 6973 lua_pop(L, 1); // cur
@@ -6523,7 +6979,25 @@ private:
6523 break; 6979 break;
6524 } 6980 }
6525 } 6981 }
6526 if (!lua_isfunction(L, -1)) { 6982 str_list checks;
6983 if (lua_istable(L, -1)) {
6984 lua_rawgeti(L, -1, 1); // cur macrotab checks
6985 int len = static_cast<int>(lua_objlen(L, -1));
6986 for (int i = 1; i <= len; i++) {
6987 lua_rawgeti(L, -1, i);
6988 if (lua_toboolean(L, -1) == 0) {
6989 checks.emplace_back();
6990 } else {
6991 size_t str_len = 0;
6992 auto str = lua_tolstring(L, -1, &str_len);
6993 checks.emplace_back(std::string{str, str_len});
6994 }
6995 lua_pop(L, 1);
6996 }
6997 lua_pop(L, 1);
6998 lua_rawgeti(L, -1, 2); // cur macrotab macroFunc
6999 lua_remove(L, -2); // cur macroFunc
7000 } else if (!lua_isfunction(L, -1)) {
6527 auto code = expandBuiltinMacro(macroName, x); 7001 auto code = expandBuiltinMacro(macroName, x);
6528 if (!code.empty()) return code; 7002 if (!code.empty()) return code;
6529 if (macroName == "is_ast"sv) { 7003 if (macroName == "is_ast"sv) {
@@ -6568,11 +7042,34 @@ private:
6568 } // cur macroFunc 7042 } // cur macroFunc
6569 pushYue("pcall"sv); // cur macroFunc pcall 7043 pushYue("pcall"sv); // cur macroFunc pcall
6570 lua_insert(L, -2); // cur pcall macroFunc 7044 lua_insert(L, -2); // cur pcall macroFunc
6571 if (!lua_checkstack(L, argStrs.size())) { 7045 if (!lua_checkstack(L, static_cast<int>(argStrs.size()))) {
6572 throw CompileError("too much macro params"s, x); 7046 throw CompileError("too much macro params"s, x);
6573 } 7047 }
7048 auto checkIt = checks.begin();
7049 node_container::const_iterator argIt;
7050 if (args) {
7051 argIt = args->begin();
7052 }
6574 for (const auto& arg : argStrs) { 7053 for (const auto& arg : argStrs) {
7054 if (checkIt != checks.end()) {
7055 if (checkIt->empty()) {
7056 ++checkIt;
7057 } else {
7058 if ((*checkIt)[0] == '.') {
7059 auto astName = checkIt->substr(3);
7060 if (!_parser.match(astName, arg)) {
7061 throw CompileError("expecting \""s + astName + "\", AST mismatch"s, *argIt);
7062 }
7063 } else {
7064 if (!_parser.match(*checkIt, arg)) {
7065 throw CompileError("expecting \""s + *checkIt + "\", AST mismatch"s, *argIt);
7066 }
7067 ++checkIt;
7068 }
7069 }
7070 }
6575 lua_pushlstring(L, arg.c_str(), arg.size()); 7071 lua_pushlstring(L, arg.c_str(), arg.size());
7072 ++argIt;
6576 } // cur pcall macroFunc args... 7073 } // cur pcall macroFunc args...
6577 bool success = lua_pcall(L, static_cast<int>(argStrs.size()), 1, 0) == 0; 7074 bool success = lua_pcall(L, static_cast<int>(argStrs.size()), 1, 0) == 0;
6578 if (!success) { // cur err 7075 if (!success) { // cur err
@@ -6664,8 +7161,8 @@ private:
6664 throw CompileError("lua macro is not expanding to valid block\n"s + err, x); 7161 throw CompileError("lua macro is not expanding to valid block\n"s + err, x);
6665 } 7162 }
6666 if (!codes.empty()) { 7163 if (!codes.empty()) {
6667 codes.insert(0, indent() + "do"s + nll(chainValue)); 7164 codes.insert(0, indent() + "do"s + nl(chainValue));
6668 codes.append(_newLine + indent() + "end"s + nlr(chainValue)); 7165 codes.append(_newLine + indent() + "end"s + nl(chainValue));
6669 } 7166 }
6670 return {nullptr, nullptr, std::move(codes), std::move(localVars)}; 7167 return {nullptr, nullptr, std::move(codes), std::move(localVars)};
6671 } else { 7168 } else {
@@ -6702,14 +7199,14 @@ private:
6702 } else { 7199 } else {
6703 if (!codes.empty()) { 7200 if (!codes.empty()) {
6704 if (isBlock) { 7201 if (isBlock) {
6705 info = _parser.parse<BlockEnd_t>(codes); 7202 info = _parser.parse<BlockEnd_t>(codes, false);
6706 if (info.error) { 7203 if (info.error) {
6707 throw CompileError("failed to expand macro as block: "s + info.error.value().msg, x); 7204 throw CompileError("failed to expand macro as block: "s + info.error.value().msg, x);
6708 } 7205 }
6709 } else { 7206 } else {
6710 info = _parser.parse<Exp_t>(codes); 7207 info = _parser.parse<Exp_t>(codes, false);
6711 if (!info.node && allowBlockMacroReturn) { 7208 if (!info.node && allowBlockMacroReturn) {
6712 info = _parser.parse<BlockEnd_t>(codes); 7209 info = _parser.parse<BlockEnd_t>(codes, false);
6713 if (info.error) { 7210 if (info.error) {
6714 throw CompileError("failed to expand macro as expr or block: "s + info.error.value().msg, x); 7211 throw CompileError("failed to expand macro as expr or block: "s + info.error.value().msg, x);
6715 } 7212 }
@@ -6754,7 +7251,7 @@ private:
6754 auto stmt = x->new_ptr<Statement_t>(); 7251 auto stmt = x->new_ptr<Statement_t>();
6755 stmt->content.set(exps); 7252 stmt->content.set(exps);
6756 auto block = x->new_ptr<Block_t>(); 7253 auto block = x->new_ptr<Block_t>();
6757 block->statements.push_back(stmt); 7254 block->statementOrComments.push_back(stmt);
6758 info.node.set(block); 7255 info.node.set(block);
6759 } else { 7256 } else {
6760 info.node.set(exp); 7257 info.node.set(exp);
@@ -6791,7 +7288,7 @@ private:
6791 return; 7288 return;
6792 } 7289 }
6793 if (usage == ExpUsage::Common || (usage == ExpUsage::Return && node.is<Block_t>())) { 7290 if (usage == ExpUsage::Common || (usage == ExpUsage::Return && node.is<Block_t>())) {
6794 if (node.to<Block_t>()->statements.empty()) { 7291 if (node.to<Block_t>()->statementOrComments.empty()) {
6795 out.push_back(Empty); 7292 out.push_back(Empty);
6796 } else { 7293 } else {
6797 auto doBody = node->new_ptr<Body_t>(); 7294 auto doBody = node->new_ptr<Body_t>();
@@ -6845,6 +7342,9 @@ private:
6845 if (transformChainEndWithColonItem(chainList, out, usage, assignList)) { 7342 if (transformChainEndWithColonItem(chainList, out, usage, assignList)) {
6846 return; 7343 return;
6847 } 7344 }
7345 if (transformChainEndWithSlice(chainList, out, usage, assignList)) {
7346 return;
7347 }
6848 transformChainList(chainList, out, usage, assignList); 7348 transformChainList(chainList, out, usage, assignList);
6849 } 7349 }
6850 7350
@@ -6941,7 +7441,7 @@ private:
6941 } 7441 }
6942 } 7442 }
6943 } else if (auto comp = sval->value.as<Comprehension_t>()) { 7443 } else if (auto comp = sval->value.as<Comprehension_t>()) {
6944 if (comp->items.size() != 2 || !ast_is<CompInner_t>(comp->items.back())) { 7444 if (!isListComp(comp)) {
6945 discrete = inExp->new_ptr<ExpList_t>(); 7445 discrete = inExp->new_ptr<ExpList_t>();
6946 for (ast_node* val : comp->items.objects()) { 7446 for (ast_node* val : comp->items.objects()) {
6947 if (auto def = ast_cast<NormalDef_t>(val)) { 7447 if (auto def = ast_cast<NormalDef_t>(val)) {
@@ -6970,7 +7470,7 @@ private:
6970 auto assignment = assignmentFrom(toAst<Exp_t>(checkVar, inExp), newExp(inExp, inExp), inExp); 7470 auto assignment = assignmentFrom(toAst<Exp_t>(checkVar, inExp), newExp(inExp, inExp), inExp);
6971 auto stmt = x->new_ptr<Statement_t>(); 7471 auto stmt = x->new_ptr<Statement_t>();
6972 stmt->content.set(assignment); 7472 stmt->content.set(assignment);
6973 block->statements.push_back(stmt); 7473 block->statementOrComments.push_back(stmt);
6974 } 7474 }
6975 if (varName.empty()) { 7475 if (varName.empty()) {
6976 auto newUnaryExp = x->new_ptr<UnaryExp_t>(); 7476 auto newUnaryExp = x->new_ptr<UnaryExp_t>();
@@ -6982,7 +7482,7 @@ private:
6982 auto assignment = assignmentFrom(assignExp, exp, x); 7482 auto assignment = assignmentFrom(assignExp, exp, x);
6983 auto stmt = x->new_ptr<Statement_t>(); 7483 auto stmt = x->new_ptr<Statement_t>();
6984 stmt->content.set(assignment); 7484 stmt->content.set(assignment);
6985 block->statements.push_back(stmt); 7485 block->statementOrComments.push_back(stmt);
6986 } 7486 }
6987 auto findVar = getUnusedName("_find_"); 7487 auto findVar = getUnusedName("_find_");
6988 auto itemVar = getUnusedName("_item_"); 7488 auto itemVar = getUnusedName("_item_");
@@ -6998,7 +7498,7 @@ private:
6998 } 7498 }
6999 auto blockStr = clearBuf(); 7499 auto blockStr = clearBuf();
7000 auto checkBlock = toAst<Block_t>(blockStr, inExp); 7500 auto checkBlock = toAst<Block_t>(blockStr, inExp);
7001 block->statements.dup(checkBlock->statements); 7501 block->statementOrComments.dup(checkBlock->statementOrComments);
7002 auto body = x->new_ptr<Body_t>(); 7502 auto body = x->new_ptr<Body_t>();
7003 body->content.set(block); 7503 body->content.set(block);
7004 auto doNode = x->new_ptr<Do_t>(); 7504 auto doNode = x->new_ptr<Do_t>();
@@ -7018,16 +7518,16 @@ private:
7018 } else { 7518 } else {
7019 auto arrayCheck = [&](bool exist) { 7519 auto arrayCheck = [&](bool exist) {
7020 auto indexVar = getUnusedName("_index_"); 7520 auto indexVar = getUnusedName("_index_");
7021 _buf << indent() << "for "sv << indexVar << " = 1, #"sv << checkVar << " do"sv << nll(x); 7521 _buf << indent() << "for "sv << indexVar << " = 1, #"sv << checkVar << " do"sv << nl(x);
7022 incIndentOffset(); 7522 incIndentOffset();
7023 _buf << indent() << "if "sv << checkVar << '[' << indexVar << "] == "sv << varName << " then"sv << nll(x); 7523 _buf << indent() << "if "sv << checkVar << '[' << indexVar << "] == "sv << varName << " then"sv << nl(x);
7024 incIndentOffset(); 7524 incIndentOffset();
7025 _buf << indent() << "return "sv << (exist ? "true"sv : "false"sv) << nll(x); 7525 _buf << indent() << "return "sv << (exist ? "true"sv : "false"sv) << nl(x);
7026 decIndentOffset(); 7526 decIndentOffset();
7027 _buf << indent() << "end"sv << nll(x); 7527 _buf << indent() << "end"sv << nl(x);
7028 decIndentOffset(); 7528 decIndentOffset();
7029 _buf << indent() << "end"sv << nll(x); 7529 _buf << indent() << "end"sv << nl(x);
7030 _buf << indent() << "return "sv << (exist ? "false"sv : "true"sv) << nll(x); 7530 _buf << indent() << "return "sv << (exist ? "false"sv : "true"sv) << nl(x);
7031 temp.push_back(clearBuf()); 7531 temp.push_back(clearBuf());
7032 }; 7532 };
7033 bool useShortCheck = (usage == ExpUsage::Closure) && !varName.empty() && !checkVar.empty() && isLocal(checkVar); 7533 bool useShortCheck = (usage == ExpUsage::Closure) && !varName.empty() && !checkVar.empty() && isLocal(checkVar);
@@ -7043,7 +7543,7 @@ private:
7043 pushAnonVarArg(); 7543 pushAnonVarArg();
7044 pushScope(); 7544 pushScope();
7045 arrayCheck(true); 7545 arrayCheck(true);
7046 temp.push_front("(#"s + checkVar + " > 0 and "s + anonFuncStart() + nll(x)); 7546 temp.push_front("(#"s + checkVar + " > 0 and "s + anonFuncStart() + nl(x));
7047 popScope(); 7547 popScope();
7048 temp.push_back(indent() + anonFuncEnd() + ')'); 7548 temp.push_back(indent() + anonFuncEnd() + ')');
7049 if (unary_exp->inExp->not_) { 7549 if (unary_exp->inExp->not_) {
@@ -7080,7 +7580,7 @@ private:
7080 arrayCheck(!unary_exp->inExp->not_); 7580 arrayCheck(!unary_exp->inExp->not_);
7081 } else { 7581 } else {
7082 arrayCheck(!unary_exp->inExp->not_); 7582 arrayCheck(!unary_exp->inExp->not_);
7083 temp.push_front(anonFuncStart() + nll(x)); 7583 temp.push_front(anonFuncStart() + nl(x));
7084 popScope(); 7584 popScope();
7085 temp.push_back(indent() + anonFuncEnd()); 7585 temp.push_back(indent() + anonFuncEnd());
7086 popAnonVarArg(); 7586 popAnonVarArg();
@@ -7120,7 +7620,7 @@ private:
7120 pushScope(); 7620 pushScope();
7121 } else if (usage == ExpUsage::Assignment) { 7621 } else if (usage == ExpUsage::Assignment) {
7122 if (isScoped) { 7622 if (isScoped) {
7123 temp.push_back(indent() + "do"s + nll(x)); 7623 temp.push_back(indent() + "do"s + nl(x));
7124 pushScope(); 7624 pushScope();
7125 } 7625 }
7126 } 7626 }
@@ -7160,10 +7660,10 @@ private:
7160 if (unary_exp->inExp->not_) { 7660 if (unary_exp->inExp->not_) {
7161 _buf << ")"sv; 7661 _buf << ")"sv;
7162 } 7662 }
7163 _buf << nll(x); 7663 _buf << nl(x);
7164 temp.push_back(clearBuf()); 7664 temp.push_back(clearBuf());
7165 if (usage == ExpUsage::Closure) { 7665 if (usage == ExpUsage::Closure) {
7166 temp.push_front(anonFuncStart() + nll(x)); 7666 temp.push_front(anonFuncStart() + nl(x));
7167 popScope(); 7667 popScope();
7168 temp.push_back(indent() + anonFuncEnd()); 7668 temp.push_back(indent() + anonFuncEnd());
7169 out.push_back(join(temp)); 7669 out.push_back(join(temp));
@@ -7172,7 +7672,7 @@ private:
7172 } else if (usage == ExpUsage::Assignment) { 7672 } else if (usage == ExpUsage::Assignment) {
7173 if (isScoped) { 7673 if (isScoped) {
7174 popScope(); 7674 popScope();
7175 temp.push_back(indent() + "end"s + nll(x)); 7675 temp.push_back(indent() + "end"s + nl(x));
7176 } 7676 }
7177 out.push_back(join(temp)); 7677 out.push_back(join(temp));
7178 } else { 7678 } else {
@@ -7206,7 +7706,7 @@ private:
7206 } 7706 }
7207 _buf << ')'; 7707 _buf << ')';
7208 if (usage == ExpUsage::Assignment || usage == ExpUsage::Return) { 7708 if (usage == ExpUsage::Assignment || usage == ExpUsage::Return) {
7209 _buf << nll(discrete); 7709 _buf << nl(discrete);
7210 } 7710 }
7211 out.push_back(clearBuf()); 7711 out.push_back(clearBuf());
7212 } 7712 }
@@ -7326,7 +7826,7 @@ private:
7326 forceAddToScope(tableVar); 7826 forceAddToScope(tableVar);
7327 auto it = values.begin(); 7827 auto it = values.begin();
7328 if (ast_is<SpreadExp_t, SpreadListExp_t>(*it)) { 7828 if (ast_is<SpreadExp_t, SpreadListExp_t>(*it)) {
7329 temp.push_back(indent() + "local "s + tableVar + " = { }"s + nll(x)); 7829 temp.push_back(indent() + "local "s + tableVar + " = { }"s + nl(x));
7330 } else { 7830 } else {
7331 auto initialTab = x->new_ptr<TableLit_t>(); 7831 auto initialTab = x->new_ptr<TableLit_t>();
7332 while (it != values.end() && !ast_is<SpreadExp_t, SpreadListExp_t>(*it)) { 7832 while (it != values.end() && !ast_is<SpreadExp_t, SpreadListExp_t>(*it)) {
@@ -7334,7 +7834,7 @@ private:
7334 ++it; 7834 ++it;
7335 } 7835 }
7336 transformTable(initialTab->values.objects(), temp); 7836 transformTable(initialTab->values.objects(), temp);
7337 temp.back() = indent() + "local "s + tableVar + " = "s + temp.back() + nll(*it); 7837 temp.back() = indent() + "local "s + tableVar + " = "s + temp.back() + nl(*it);
7338 } 7838 }
7339 for (; it != values.end(); ++it) { 7839 for (; it != values.end(); ++it) {
7340 auto item = *it; 7840 auto item = *it;
@@ -7354,14 +7854,14 @@ private:
7354 transformAssignment(assignment, temp); 7854 transformAssignment(assignment, temp);
7355 } 7855 }
7356 forceAddToScope(indexVar); 7856 forceAddToScope(indexVar);
7357 temp.push_back(indent() + "local "s + indexVar + " = 1"s + nll(item)); 7857 temp.push_back(indent() + "local "s + indexVar + " = 1"s + nl(item));
7358 _buf << "for "sv << keyVar << ',' << valueVar << " in pairs "sv << objVar 7858 _buf << "for "sv << keyVar << ',' << valueVar << " in pairs "sv << objVar
7359 << "\n\tif "sv << indexVar << "=="sv << keyVar 7859 << "\n\tif "sv << indexVar << "=="sv << keyVar
7360 << "\n\t\t"sv << tableVar << "[]="sv << valueVar 7860 << "\n\t\t"sv << tableVar << "[]="sv << valueVar
7361 << "\n\t\t"sv << indexVar << "+=1"sv 7861 << "\n\t\t"sv << indexVar << "+=1"sv
7362 << "\n\telse "sv << tableVar << '[' << keyVar << "]="sv << valueVar; 7862 << "\n\telse "sv << tableVar << '[' << keyVar << "]="sv << valueVar;
7363 auto forEach = toAst<ForEach_t>(clearBuf(), item); 7863 auto forNode = toAst<For_t>(clearBuf(), item);
7364 transformForEach(forEach, temp); 7864 transformFor(forNode, temp);
7365 break; 7865 break;
7366 } 7866 }
7367 case id<SpreadListExp_t>(): { 7867 case id<SpreadListExp_t>(): {
@@ -7378,12 +7878,12 @@ private:
7378 transformAssignment(assignment, temp); 7878 transformAssignment(assignment, temp);
7379 } 7879 }
7380 forceAddToScope(indexVar); 7880 forceAddToScope(indexVar);
7381 temp.push_back(indent() + "local "s + indexVar + " = #"s + tableVar + " + 1"s + nll(item)); 7881 temp.push_back(indent() + "local "s + indexVar + " = #"s + tableVar + " + 1"s + nl(item));
7382 _buf << "for "sv << valueVar << " in *"sv << objVar 7882 _buf << "for "sv << valueVar << " in *"sv << objVar
7383 << "\n\t"sv << tableVar << '[' << indexVar << "]="sv << valueVar 7883 << "\n\t"sv << tableVar << '[' << indexVar << "]="sv << valueVar
7384 << "\n\t"sv << indexVar << "+=1"sv; 7884 << "\n\t"sv << indexVar << "+=1"sv;
7385 auto forEach = toAst<ForEach_t>(clearBuf(), item); 7885 auto forNode = toAst<For_t>(clearBuf(), item);
7386 transformForEach(forEach, temp); 7886 transformFor(forNode, temp);
7387 break; 7887 break;
7388 } 7888 }
7389 case id<VariablePair_t>(): 7889 case id<VariablePair_t>():
@@ -7561,9 +8061,9 @@ private:
7561 break; 8061 break;
7562 case ExpUsage::Closure: { 8062 case ExpUsage::Closure: {
7563 out.push_back(join(temp)); 8063 out.push_back(join(temp));
7564 out.back().append(indent() + "return "s + tableVar + nlr(x)); 8064 out.back().append(indent() + "return "s + tableVar + nl(x));
7565 popScope(); 8065 popScope();
7566 out.back().insert(0, anonFuncStart() + nll(x)); 8066 out.back().insert(0, anonFuncStart() + nl(x));
7567 out.back().append(indent() + anonFuncEnd()); 8067 out.back().append(indent() + anonFuncEnd());
7568 popAnonVarArg(); 8068 popAnonVarArg();
7569 popFunctionScope(); 8069 popFunctionScope();
@@ -7579,13 +8079,13 @@ private:
7579 if (extraScope) popScope(); 8079 if (extraScope) popScope();
7580 out.push_back(join(temp)); 8080 out.push_back(join(temp));
7581 if (extraScope) { 8081 if (extraScope) {
7582 out.back() = indent() + "do"s + nll(x) + out.back() + indent() + "end"s + nlr(x); 8082 out.back() = indent() + "do"s + nl(x) + out.back() + indent() + "end"s + nl(x);
7583 } 8083 }
7584 break; 8084 break;
7585 } 8085 }
7586 case ExpUsage::Return: 8086 case ExpUsage::Return:
7587 out.push_back(join(temp)); 8087 out.push_back(join(temp));
7588 out.back().append(indent() + "return "s + tableVar + nlr(x)); 8088 out.back().append(indent() + "return "s + tableVar + nl(x));
7589 break; 8089 break;
7590 default: 8090 default:
7591 break; 8091 break;
@@ -7706,11 +8206,11 @@ private:
7706 default: YUEE("AST node mismatch", item); break; 8206 default: YUEE("AST node mismatch", item); break;
7707 } 8207 }
7708 if (!isMetamethod) { 8208 if (!isMetamethod) {
7709 temp.back() = indent() + (value == values.back() ? temp.back() : temp.back() + ',') + nll(value); 8209 temp.back() = indent() + (value == values.back() ? temp.back() : temp.back() + ',') + nl(value);
7710 } 8210 }
7711 } 8211 }
7712 if (metatable->pairs.empty() && !metatableItem) { 8212 if (metatable->pairs.empty() && !metatableItem) {
7713 out.push_back('{' + nll(x) + join(temp)); 8213 out.push_back('{' + nl(x) + join(temp));
7714 decIndentOffset(); 8214 decIndentOffset();
7715 out.back() += (indent() + '}'); 8215 out.back() += (indent() + '}');
7716 } else { 8216 } else {
@@ -7720,7 +8220,7 @@ private:
7720 decIndentOffset(); 8220 decIndentOffset();
7721 tabStr += "{ }"sv; 8221 tabStr += "{ }"sv;
7722 } else { 8222 } else {
7723 tabStr += ('{' + nll(x) + join(temp)); 8223 tabStr += ('{' + nl(x) + join(temp));
7724 decIndentOffset(); 8224 decIndentOffset();
7725 tabStr += (indent() + '}'); 8225 tabStr += (indent() + '}');
7726 } 8226 }
@@ -7764,18 +8264,18 @@ private:
7764 void transformCompCommon(Comprehension_t* comp, str_list& out) { 8264 void transformCompCommon(Comprehension_t* comp, str_list& out) {
7765 str_list temp; 8265 str_list temp;
7766 auto x = comp; 8266 auto x = comp;
7767 auto compInner = static_cast<CompInner_t*>(comp->items.back()); 8267 auto compFor = static_cast<CompFor_t*>(comp->items.back());
7768 for (auto item : compInner->items.objects()) { 8268 for (auto item : compFor->items.objects()) {
7769 switch (item->get_id()) { 8269 switch (item->get_id()) {
7770 case id<CompForEach_t>(): 8270 case id<CompForEach_t>():
7771 transformCompForEach(static_cast<CompForEach_t*>(item), temp); 8271 transformCompForEach(static_cast<CompForEach_t*>(item), temp);
7772 break; 8272 break;
7773 case id<CompFor_t>(): 8273 case id<CompForNum_t>():
7774 transformCompFor(static_cast<CompFor_t*>(item), temp); 8274 transformCompForNum(static_cast<CompForNum_t*>(item), temp);
7775 break; 8275 break;
7776 case id<Exp_t>(): 8276 case id<Exp_t>():
7777 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure); 8277 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure);
7778 temp.back() = indent() + "if "s + temp.back() + " then"s + nll(item); 8278 temp.back() = indent() + "if "s + temp.back() + " then"s + nl(item);
7779 pushScope(); 8279 pushScope();
7780 break; 8280 break;
7781 default: YUEE("AST node mismatch", item); break; 8281 default: YUEE("AST node mismatch", item); break;
@@ -7795,16 +8295,16 @@ private:
7795 auto value = std::move(temp.back()); 8295 auto value = std::move(temp.back());
7796 temp.pop_back(); 8296 temp.pop_back();
7797 _buf << join(temp) << value; 8297 _buf << join(temp) << value;
7798 for (size_t i = 0; i < compInner->items.objects().size(); ++i) { 8298 for (size_t i = 0; i < compFor->items.objects().size(); ++i) {
7799 popScope(); 8299 popScope();
7800 _buf << indent() << "end"sv << nll(comp); 8300 _buf << indent() << "end"sv << nl(comp);
7801 } 8301 }
7802 out.push_back(clearBuf()); 8302 out.push_back(clearBuf());
7803 } 8303 }
7804 8304
7805 void transformComprehension(Comprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { 8305 void transformComprehension(Comprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
7806 auto x = comp; 8306 auto x = comp;
7807 if (comp->items.size() != 2 || !ast_is<CompInner_t>(comp->items.back())) { 8307 if (!isListComp(comp)) {
7808 switch (usage) { 8308 switch (usage) {
7809 case ExpUsage::Assignment: { 8309 case ExpUsage::Assignment: {
7810 auto tableLit = x->new_ptr<TableLit_t>(); 8310 auto tableLit = x->new_ptr<TableLit_t>();
@@ -7843,9 +8343,16 @@ private:
7843 } 8343 }
7844 return; 8344 return;
7845 } 8345 }
7846 auto def = ast_cast<NormalDef_t>(comp->items.front()); 8346 ast_node* value = nullptr;
7847 if (!def || def->defVal) { 8347 bool isSpread = ast_is<SpreadListExp_t>(comp->items.front());
7848 throw CompileError("invalid comprehension expression", comp->items.front()); 8348 if (isSpread) {
8349 value = comp->items.front();
8350 } else {
8351 auto def = ast_cast<NormalDef_t>(comp->items.front());
8352 if (!def || def->defVal) {
8353 throw CompileError("invalid comprehension expression", comp->items.front());
8354 }
8355 value = def->item.get();
7849 } 8356 }
7850 bool extraScope = false; 8357 bool extraScope = false;
7851 switch (usage) { 8358 switch (usage) {
@@ -7869,31 +8376,33 @@ private:
7869 default: 8376 default:
7870 break; 8377 break;
7871 } 8378 }
7872 auto value = def->item.get(); 8379 auto compFor = static_cast<CompFor_t*>(comp->items.back());
7873 auto compInner = static_cast<CompInner_t*>(comp->items.back());
7874 str_list temp; 8380 str_list temp;
7875 std::string accumVar = getUnusedName("_accum_"sv); 8381 std::string accumVar = getUnusedName("_accum_"sv);
7876 std::string lenVar = getUnusedName("_len_"sv);
7877 addToScope(accumVar); 8382 addToScope(accumVar);
7878 addToScope(lenVar); 8383 std::string lenVar;
7879 for (auto item : compInner->items.objects()) { 8384 if (!isSpread) {
8385 lenVar = getUnusedName("_len_"sv);
8386 addToScope(lenVar);
8387 }
8388 for (auto item : compFor->items.objects()) {
7880 switch (item->get_id()) { 8389 switch (item->get_id()) {
7881 case id<CompForEach_t>(): 8390 case id<CompForEach_t>():
7882 transformCompForEach(static_cast<CompForEach_t*>(item), temp); 8391 transformCompForEach(static_cast<CompForEach_t*>(item), temp);
7883 break; 8392 break;
7884 case id<CompFor_t>(): 8393 case id<CompForNum_t>():
7885 transformCompFor(static_cast<CompFor_t*>(item), temp); 8394 transformCompForNum(static_cast<CompForNum_t*>(item), temp);
7886 break; 8395 break;
7887 case id<Exp_t>(): 8396 case id<Exp_t>():
7888 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure); 8397 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure);
7889 temp.back() = indent() + "if "s + temp.back() + " then"s + nll(item); 8398 temp.back() = indent() + "if "s + temp.back() + " then"s + nl(item);
7890 pushScope(); 8399 pushScope();
7891 break; 8400 break;
7892 default: YUEE("AST node mismatch", item); break; 8401 default: YUEE("AST node mismatch", item); break;
7893 } 8402 }
7894 } 8403 }
7895 { 8404 {
7896 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); 8405 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + (isSpread ? "]"s : lenVar + ']'), x);
7897 auto assign = x->new_ptr<Assign_t>(); 8406 auto assign = x->new_ptr<Assign_t>();
7898 assign->values.push_back(value); 8407 assign->values.push_back(value);
7899 auto assignment = x->new_ptr<ExpListAssign_t>(); 8408 auto assignment = x->new_ptr<ExpListAssign_t>();
@@ -7903,25 +8412,30 @@ private:
7903 } 8412 }
7904 auto assignStr = std::move(temp.back()); 8413 auto assignStr = std::move(temp.back());
7905 temp.pop_back(); 8414 temp.pop_back();
7906 for (size_t i = 0; i < compInner->items.objects().size(); ++i) { 8415 for (size_t i = 0; i < compFor->items.objects().size(); ++i) {
7907 popScope(); 8416 popScope();
7908 } 8417 }
7909 _buf << indent() << "local "sv << accumVar << " = { }"sv << nll(comp); 8418 _buf << indent() << "local "sv << accumVar << " = { }"sv << nl(comp);
7910 _buf << indent() << "local "sv << lenVar << " = 1"sv << nll(comp); 8419 if (isSpread) {
7911 _buf << join(temp); 8420 _buf << join(temp);
7912 _buf << assignStr; 8421 _buf << assignStr;
7913 _buf << indent(int(temp.size())) << lenVar << " = "sv << lenVar << " + 1"sv << nll(comp); 8422 } else {
8423 _buf << indent() << "local "sv << lenVar << " = 1"sv << nl(comp);
8424 _buf << join(temp);
8425 _buf << assignStr;
8426 _buf << indent(int(temp.size())) << lenVar << " = "sv << lenVar << " + 1"sv << nl(comp);
8427 }
7914 for (int ind = int(temp.size()) - 1; ind > -1; --ind) { 8428 for (int ind = int(temp.size()) - 1; ind > -1; --ind) {
7915 _buf << indent(ind) << "end"sv << nll(comp); 8429 _buf << indent(ind) << "end"sv << nl(comp);
7916 } 8430 }
7917 switch (usage) { 8431 switch (usage) {
7918 case ExpUsage::Common: 8432 case ExpUsage::Common:
7919 break; 8433 break;
7920 case ExpUsage::Closure: { 8434 case ExpUsage::Closure: {
7921 out.push_back(clearBuf()); 8435 out.push_back(clearBuf());
7922 out.back().append(indent() + "return "s + accumVar + nlr(comp)); 8436 out.back().append(indent() + "return "s + accumVar + nl(comp));
7923 popScope(); 8437 popScope();
7924 out.back().insert(0, anonFuncStart() + nll(comp)); 8438 out.back().insert(0, anonFuncStart() + nl(comp));
7925 out.back().append(indent() + anonFuncEnd()); 8439 out.back().append(indent() + anonFuncEnd());
7926 popAnonVarArg(); 8440 popAnonVarArg();
7927 popFunctionScope(); 8441 popFunctionScope();
@@ -7938,13 +8452,13 @@ private:
7938 out.back().append(temp.back()); 8452 out.back().append(temp.back());
7939 if (extraScope) { 8453 if (extraScope) {
7940 popScope(); 8454 popScope();
7941 out.back() = indent() + "do"s + nll(comp) + out.back() + indent() + "end"s + nlr(comp); 8455 out.back() = indent() + "do"s + nl(comp) + out.back() + indent() + "end"s + nl(comp);
7942 } 8456 }
7943 break; 8457 break;
7944 } 8458 }
7945 case ExpUsage::Return: 8459 case ExpUsage::Return:
7946 out.push_back(clearBuf()); 8460 out.push_back(clearBuf());
7947 out.back().append(indent() + "return "s + accumVar + nlr(comp)); 8461 out.back().append(indent() + "return "s + accumVar + nl(comp));
7948 break; 8462 break;
7949 default: 8463 default:
7950 break; 8464 break;
@@ -7952,6 +8466,11 @@ private:
7952 } 8466 }
7953 8467
7954 bool transformForEachHead(AssignableNameList_t* nameList, ast_node* loopTarget, str_list& out, bool inClosure) { 8468 bool transformForEachHead(AssignableNameList_t* nameList, ast_node* loopTarget, str_list& out, bool inClosure) {
8469 enum class NumState {
8470 Unknown,
8471 Positive,
8472 Negtive
8473 };
7955 auto x = nameList; 8474 auto x = nameList;
7956 str_list temp; 8475 str_list temp;
7957 str_list vars; 8476 str_list vars;
@@ -7970,13 +8489,8 @@ private:
7970 varConstAfter = vars.back(); 8489 varConstAfter = vars.back();
7971 } 8490 }
7972 break; 8491 break;
7973 case id<TableLit_t>(): { 8492 case id<SimpleTable_t>():
7974 auto desVar = getUnusedName("_des_"sv); 8493 case id<TableLit_t>():
7975 destructPairs.emplace_back(item, toAst<Exp_t>(desVar, x));
7976 vars.push_back(desVar);
7977 varAfter.push_back(desVar);
7978 break;
7979 }
7980 case id<Comprehension_t>(): { 8494 case id<Comprehension_t>(): {
7981 auto desVar = getUnusedName("_des_"sv); 8495 auto desVar = getUnusedName("_des_"sv);
7982 destructPairs.emplace_back(item, toAst<Exp_t>(desVar, x)); 8496 destructPairs.emplace_back(item, toAst<Exp_t>(desVar, x));
@@ -8018,15 +8532,35 @@ private:
8018 for (auto item : chainList) { 8532 for (auto item : chainList) {
8019 chain->items.push_back(item); 8533 chain->items.push_back(item);
8020 } 8534 }
8021 std::string startValue("1"sv); 8535 std::string startValue;
8536 NumState startStatus = NumState::Unknown;
8022 if (auto exp = slice->startValue.as<Exp_t>()) { 8537 if (auto exp = slice->startValue.as<Exp_t>()) {
8023 transformExp(exp, temp, ExpUsage::Closure); 8538 transformExp(exp, temp, ExpUsage::Closure);
8539 if (temp.back().at(0) == '-') {
8540 if (_parser.match<Num_t>(temp.back().substr(1))) {
8541 startStatus = NumState::Negtive;
8542 }
8543 } else {
8544 if (_parser.match<Num_t>(temp.back())) {
8545 startStatus = NumState::Positive;
8546 }
8547 }
8024 startValue = std::move(temp.back()); 8548 startValue = std::move(temp.back());
8025 temp.pop_back(); 8549 temp.pop_back();
8026 } 8550 }
8027 std::string stopValue; 8551 std::string stopValue;
8552 NumState stopStatus = NumState::Unknown;
8028 if (auto exp = slice->stopValue.as<Exp_t>()) { 8553 if (auto exp = slice->stopValue.as<Exp_t>()) {
8029 transformExp(exp, temp, ExpUsage::Closure); 8554 transformExp(exp, temp, ExpUsage::Closure);
8555 if (temp.back().at(0) == '-') {
8556 if (_parser.match<Num_t>(temp.back().substr(1))) {
8557 stopStatus = NumState::Negtive;
8558 }
8559 } else {
8560 if (_parser.match<Num_t>(temp.back())) {
8561 stopStatus = NumState::Positive;
8562 }
8563 }
8030 stopValue = std::move(temp.back()); 8564 stopValue = std::move(temp.back());
8031 temp.pop_back(); 8565 temp.pop_back();
8032 } 8566 }
@@ -8040,38 +8574,94 @@ private:
8040 std::string prefix; 8574 std::string prefix;
8041 if (!inClosure && needScope) { 8575 if (!inClosure && needScope) {
8042 extraScope = true; 8576 extraScope = true;
8043 prefix = indent() + "do"s + nll(x); 8577 prefix = indent() + "do"s + nl(x);
8044 pushScope(); 8578 pushScope();
8045 } 8579 }
8046 listVar = getUnusedName("_list_"sv); 8580 listVar = getUnusedName("_list_"sv);
8047 varBefore.push_back(listVar); 8581 varBefore.push_back(listVar);
8048 transformChainValue(chain, temp, ExpUsage::Closure); 8582 transformChainValue(chain, temp, ExpUsage::Closure);
8049 _buf << prefix << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList); 8583 _buf << prefix << indent() << "local "sv << listVar << " = "sv << temp.back() << nl(nameList);
8584 }
8585 if (startValue.empty()) {
8586 startValue = "1"s;
8587 startStatus = NumState::Positive;
8588 }
8589 std::string minVar;
8590 if (startStatus != NumState::Positive) {
8591 std::string prefix;
8592 if (!extraScope && !inClosure && needScope) {
8593 extraScope = true;
8594 prefix = indent() + "do"s + nl(x);
8595 pushScope();
8596 }
8597 minVar = getUnusedName("_min_"sv);
8598 varBefore.push_back(minVar);
8599 if (startStatus == NumState::Negtive) {
8600 _buf << prefix << indent() << "local "sv << minVar << " = "sv << "#"sv << listVar << " + "sv << startValue << " + 1"sv << nl(nameList);
8601 } else {
8602 _buf << prefix << indent() << "local "sv << minVar << " = "sv << startValue << nl(nameList);
8603 }
8604 }
8605 bool defaultStop = false;
8606 if (stopValue.empty()) {
8607 stopValue = "#"s + listVar;
8608 defaultStop = true;
8050 } 8609 }
8051 std::string maxVar; 8610 std::string maxVar;
8052 if (!stopValue.empty()) { 8611 if (stopStatus != NumState::Positive) {
8053 std::string prefix; 8612 std::string prefix;
8054 if (!extraScope && !inClosure && needScope) { 8613 if (!extraScope && !inClosure && needScope) {
8055 extraScope = true; 8614 extraScope = true;
8056 prefix = indent() + "do"s + nll(x); 8615 prefix = indent() + "do"s + nl(x);
8057 pushScope(); 8616 pushScope();
8058 } 8617 }
8059 maxVar = getUnusedName("_max_"sv); 8618 maxVar = getUnusedName("_max_"sv);
8060 varBefore.push_back(maxVar); 8619 varBefore.push_back(maxVar);
8061 _buf << prefix << indent() << "local "sv << maxVar << " = "sv << stopValue << nll(nameList); 8620 if (stopStatus == NumState::Negtive) {
8621 _buf << indent() << "local "sv << maxVar << " = "sv << "#"sv << listVar << " + "sv << stopValue << " + 1"sv << nl(nameList);
8622 } else {
8623 _buf << prefix << indent() << "local "sv << maxVar << " = "sv << stopValue << nl(nameList);
8624 }
8625 }
8626 if (startStatus == NumState::Unknown) {
8627 _buf << indent() << minVar << " = "sv << minVar << " < 0 and #"sv << listVar << " + "sv << minVar << " + 1 or "sv << minVar << nl(nameList);
8628 }
8629 if (!defaultStop && stopStatus == NumState::Unknown) {
8630 _buf << indent() << maxVar << " = "sv << maxVar << " < 0 and #"sv << listVar << " + "sv << maxVar << " + 1 or "sv << maxVar << nl(nameList);
8062 } 8631 }
8063 _buf << indent() << "for "sv << indexVar << " = "sv; 8632 _buf << indent() << "for "sv << indexVar << " = "sv;
8064 _buf << startValue << ", "sv; 8633 if (startValue.empty()) {
8634 _buf << "1"sv;
8635 } else {
8636 switch (startStatus) {
8637 case NumState::Unknown:
8638 case NumState::Negtive:
8639 _buf << minVar;
8640 break;
8641 case NumState::Positive:
8642 _buf << startValue;
8643 break;
8644 }
8645 }
8646 _buf << ", "sv;
8065 if (stopValue.empty()) { 8647 if (stopValue.empty()) {
8066 _buf << "#"sv << listVar; 8648 _buf << "#"sv << listVar;
8067 } else { 8649 } else {
8068 _buf << maxVar << " < 0 and #"sv << listVar << " + "sv << maxVar << " or "sv << maxVar; 8650 switch (stopStatus) {
8651 case NumState::Unknown:
8652 case NumState::Negtive:
8653 _buf << maxVar;
8654 break;
8655 case NumState::Positive:
8656 _buf << stopValue;
8657 break;
8658 }
8069 } 8659 }
8070 if (!stepValue.empty()) { 8660 if (!stepValue.empty()) {
8071 _buf << ", "sv << stepValue; 8661 _buf << ", "sv << stepValue;
8072 } 8662 }
8073 _buf << " do"sv << nlr(loopTarget); 8663 _buf << " do"sv << nl(loopTarget);
8074 _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nll(nameList); 8664 _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nl(nameList);
8075 out.push_back(clearBuf()); 8665 out.push_back(clearBuf());
8076 BLOCK_END 8666 BLOCK_END
8077 bool newListVal = false; 8667 bool newListVal = false;
@@ -8082,21 +8672,21 @@ private:
8082 } 8672 }
8083 if (!endWithSlice) { 8673 if (!endWithSlice) {
8084 transformExp(star_exp->value, temp, ExpUsage::Closure); 8674 transformExp(star_exp->value, temp, ExpUsage::Closure);
8085 if (newListVal) _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList); 8675 if (newListVal) _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nl(nameList);
8086 _buf << indent() << "for "sv << indexVar << " = 1, #"sv << listVar << " do"sv << nlr(loopTarget); 8676 _buf << indent() << "for "sv << indexVar << " = 1, #"sv << listVar << " do"sv << nl(loopTarget);
8087 _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nll(nameList); 8677 _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nl(nameList);
8088 out.push_back(clearBuf()); 8678 out.push_back(clearBuf());
8089 } 8679 }
8090 break; 8680 break;
8091 } 8681 }
8092 case id<Exp_t>(): 8682 case id<Exp_t>():
8093 transformExp(static_cast<Exp_t*>(loopTarget), temp, ExpUsage::Closure); 8683 transformExp(static_cast<Exp_t*>(loopTarget), temp, ExpUsage::Closure);
8094 _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nlr(loopTarget); 8684 _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nl(loopTarget);
8095 out.push_back(clearBuf()); 8685 out.push_back(clearBuf());
8096 break; 8686 break;
8097 case id<ExpList_t>(): 8687 case id<ExpList_t>():
8098 transformExpList(static_cast<ExpList_t*>(loopTarget), temp); 8688 transformExpList(static_cast<ExpList_t*>(loopTarget), temp);
8099 _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nlr(loopTarget); 8689 _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nl(loopTarget);
8100 out.push_back(clearBuf()); 8690 out.push_back(clearBuf());
8101 break; 8691 break;
8102 default: YUEE("AST node mismatch", loopTarget); break; 8692 default: YUEE("AST node mismatch", loopTarget); break;
@@ -8109,11 +8699,18 @@ private:
8109 if (!destructPairs.empty()) { 8699 if (!destructPairs.empty()) {
8110 temp.clear(); 8700 temp.clear();
8111 for (auto& pair : destructPairs) { 8701 for (auto& pair : destructPairs) {
8112 auto sValue = x->new_ptr<SimpleValue_t>();
8113 sValue->value.set(pair.first);
8114 auto exp = newExp(sValue, x);
8115 auto expList = x->new_ptr<ExpList_t>(); 8702 auto expList = x->new_ptr<ExpList_t>();
8116 expList->exprs.push_back(exp); 8703 if (ast_is<SimpleTable_t>(pair.first)) {
8704 auto value = x->new_ptr<Value_t>();
8705 value->item.set(pair.first);
8706 auto exp = newExp(value, x);
8707 expList->exprs.push_back(exp);
8708 } else {
8709 auto sValue = x->new_ptr<SimpleValue_t>();
8710 sValue->value.set(pair.first);
8711 auto exp = newExp(sValue, x);
8712 expList->exprs.push_back(exp);
8713 }
8117 auto assign = x->new_ptr<Assign_t>(); 8714 auto assign = x->new_ptr<Assign_t>();
8118 assign->values.push_back(pair.second); 8715 assign->values.push_back(pair.second);
8119 auto assignment = x->new_ptr<ExpListAssign_t>(); 8716 auto assignment = x->new_ptr<ExpListAssign_t>();
@@ -8173,7 +8770,7 @@ private:
8173 out.push_back('(' + join(temp, ", "sv) + ')'); 8770 out.push_back('(' + join(temp, ", "sv) + ')');
8174 } 8771 }
8175 8772
8176 void transformForHead(Variable_t* var, Exp_t* startVal, Exp_t* stopVal, ForStepValue_t* stepVal, str_list& out) { 8773 void transformForNumHead(Variable_t* var, Exp_t* startVal, Exp_t* stopVal, ForStepValue_t* stepVal, str_list& out) {
8177 str_list temp; 8774 str_list temp;
8178 std::string varName = variableToString(var); 8775 std::string varName = variableToString(var);
8179 transformExp(startVal, temp, ExpUsage::Closure); 8776 transformExp(startVal, temp, ExpUsage::Closure);
@@ -8187,15 +8784,15 @@ private:
8187 const auto& start = *it; 8784 const auto& start = *it;
8188 const auto& stop = *(++it); 8785 const auto& stop = *(++it);
8189 const auto& step = *(++it); 8786 const auto& step = *(++it);
8190 _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : ", "s + step) << " do"sv << nll(var); 8787 _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : ", "s + step) << " do"sv << nl(var);
8191 pushScope(); 8788 pushScope();
8192 forceAddToScope(varName); 8789 forceAddToScope(varName);
8193 markVarLocalConst(varName); 8790 markVarLocalConst(varName);
8194 out.push_back(clearBuf()); 8791 out.push_back(clearBuf());
8195 } 8792 }
8196 8793
8197 void transformForHead(For_t* forNode, str_list& out) { 8794 void transformForNumHead(ForNum_t* forNum, str_list& out) {
8198 transformForHead(forNode->varName, forNode->startValue, forNode->stopValue, forNode->stepValue, out); 8795 transformForNumHead(forNum->varName, forNum->startValue, forNum->stopValue, forNum->stepValue, out);
8199 } 8796 }
8200 8797
8201 void transform_plain_body(ast_node* bodyOrStmt, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { 8798 void transform_plain_body(ast_node* bodyOrStmt, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
@@ -8205,7 +8802,7 @@ private:
8205 break; 8802 break;
8206 case id<Statement_t>(): { 8803 case id<Statement_t>(): {
8207 auto newBlock = bodyOrStmt->new_ptr<Block_t>(); 8804 auto newBlock = bodyOrStmt->new_ptr<Block_t>();
8208 newBlock->statements.push_back(bodyOrStmt); 8805 newBlock->statementOrComments.push_back(bodyOrStmt);
8209 transformBlock(newBlock, out, usage, assignList); 8806 transformBlock(newBlock, out, usage, assignList);
8210 break; 8807 break;
8211 } 8808 }
@@ -8302,9 +8899,9 @@ private:
8302 } 8899 }
8303 8900
8304 void addDoToLastLineReturn(ast_node* body) { 8901 void addDoToLastLineReturn(ast_node* body) {
8305 if (auto block = ast_cast<Block_t>(body); block && !block->statements.empty()) { 8902 if (auto block = ast_cast<Block_t>(body); block && !block->statementOrComments.empty()) {
8306 auto last = static_cast<Statement_t*>(block->statements.back()); 8903 auto last = lastStatementFrom(block);
8307 if (last->content.is<Return_t>()) { 8904 if (last && last->content.is<Return_t>()) {
8308 auto doNode = last->new_ptr<Do_t>(); 8905 auto doNode = last->new_ptr<Do_t>();
8309 auto newBody = last->new_ptr<Body_t>(); 8906 auto newBody = last->new_ptr<Body_t>();
8310 auto newStmt = last->new_ptr<Statement_t>(); 8907 auto newStmt = last->new_ptr<Statement_t>();
@@ -8331,8 +8928,8 @@ private:
8331 if (withContinue) { 8928 if (withContinue) {
8332 if (target < 502) { 8929 if (target < 502) {
8333 if (auto block = ast_cast<Block_t>(body)) { 8930 if (auto block = ast_cast<Block_t>(body)) {
8334 if (!block->statements.empty()) { 8931 if (!block->statementOrComments.empty()) {
8335 auto stmt = static_cast<Statement_t*>(block->statements.back()); 8932 auto stmt = lastStatementFrom(block);
8336 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { 8933 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) {
8337 extraDo = breakLoop->type.is<Break_t>(); 8934 extraDo = breakLoop->type.is<Break_t>();
8338 } 8935 }
@@ -8341,11 +8938,11 @@ private:
8341 auto continueVar = getUnusedName("_continue_"sv); 8938 auto continueVar = getUnusedName("_continue_"sv);
8342 addToScope(continueVar); 8939 addToScope(continueVar);
8343 _continueVars.push({continueVar, nullptr}); 8940 _continueVars.push({continueVar, nullptr});
8344 _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body); 8941 _buf << indent() << "local "sv << continueVar << " = false"sv << nl(body);
8345 _buf << indent() << "repeat"sv << nll(body); 8942 _buf << indent() << "repeat"sv << nl(body);
8346 pushScope(); 8943 pushScope();
8347 if (extraDo) { 8944 if (extraDo) {
8348 _buf << indent() << "do"sv << nll(body); 8945 _buf << indent() << "do"sv << nl(body);
8349 pushScope(); 8946 pushScope();
8350 } 8947 }
8351 temp.push_back(clearBuf()); 8948 temp.push_back(clearBuf());
@@ -8365,14 +8962,14 @@ private:
8365 if (target < 502) { 8962 if (target < 502) {
8366 if (extraDo) { 8963 if (extraDo) {
8367 popScope(); 8964 popScope();
8368 _buf << indent() << "end"sv << nll(body); 8965 _buf << indent() << "end"sv << nl(body);
8369 } 8966 }
8370 _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); 8967 _buf << indent() << _continueVars.top().var << " = true"sv << nl(body);
8371 popScope(); 8968 popScope();
8372 _buf << indent() << "until true"sv << nlr(body); 8969 _buf << indent() << "until true"sv << nl(body);
8373 _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nlr(body); 8970 _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nl(body);
8374 _buf << indent(1) << "break"sv << nlr(body); 8971 _buf << indent(1) << "break"sv << nl(body);
8375 _buf << indent() << "end"sv << nlr(body); 8972 _buf << indent() << "end"sv << nl(body);
8376 temp.push_back(clearBuf()); 8973 temp.push_back(clearBuf());
8377 _continueVars.pop(); 8974 _continueVars.pop();
8378 } else { 8975 } else {
@@ -8386,7 +8983,7 @@ private:
8386 std::string transformRepeatBody(Repeat_t* repeatNode, str_list& out) { 8983 std::string transformRepeatBody(Repeat_t* repeatNode, str_list& out) {
8387 str_list temp; 8984 str_list temp;
8388 bool extraDo = false; 8985 bool extraDo = false;
8389 auto body = repeatNode->body->content.get(); 8986 auto body = repeatNode->body.get();
8390 auto breakLoopType = getBreakLoopType(body, Empty); 8987 auto breakLoopType = getBreakLoopType(body, Empty);
8391 bool withContinue = hasContinue(breakLoopType); 8988 bool withContinue = hasContinue(breakLoopType);
8392 std::string conditionVar; 8989 std::string conditionVar;
@@ -8396,8 +8993,8 @@ private:
8396 if (withContinue) { 8993 if (withContinue) {
8397 if (target < 502) { 8994 if (target < 502) {
8398 if (auto block = ast_cast<Block_t>(body)) { 8995 if (auto block = ast_cast<Block_t>(body)) {
8399 if (!block->statements.empty()) { 8996 if (!block->statementOrComments.empty()) {
8400 auto stmt = static_cast<Statement_t*>(block->statements.back()); 8997 auto stmt = lastStatementFrom(block);
8401 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { 8998 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) {
8402 extraDo = breakLoop->type.is<Break_t>(); 8999 extraDo = breakLoop->type.is<Break_t>();
8403 } 9000 }
@@ -8414,12 +9011,12 @@ private:
8414 assign->values.push_back(repeatNode->condition); 9011 assign->values.push_back(repeatNode->condition);
8415 _continueVars.push({continueVar, assignment.get()}); 9012 _continueVars.push({continueVar, assignment.get()});
8416 } 9013 }
8417 _buf << indent() << "local "sv << conditionVar << " = false"sv << nll(body); 9014 _buf << indent() << "local "sv << conditionVar << " = false"sv << nl(body);
8418 _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body); 9015 _buf << indent() << "local "sv << continueVar << " = false"sv << nl(body);
8419 _buf << indent() << "repeat"sv << nll(body); 9016 _buf << indent() << "repeat"sv << nl(body);
8420 pushScope(); 9017 pushScope();
8421 if (extraDo) { 9018 if (extraDo) {
8422 _buf << indent() << "do"sv << nll(body); 9019 _buf << indent() << "do"sv << nl(body);
8423 pushScope(); 9020 pushScope();
8424 } 9021 }
8425 temp.push_back(clearBuf()); 9022 temp.push_back(clearBuf());
@@ -8440,14 +9037,14 @@ private:
8440 transformAssignment(_continueVars.top().condAssign, temp); 9037 transformAssignment(_continueVars.top().condAssign, temp);
8441 if (extraDo) { 9038 if (extraDo) {
8442 popScope(); 9039 popScope();
8443 _buf << indent() << "end"sv << nll(body); 9040 _buf << indent() << "end"sv << nl(body);
8444 } 9041 }
8445 _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); 9042 _buf << indent() << _continueVars.top().var << " = true"sv << nl(body);
8446 popScope(); 9043 popScope();
8447 _buf << indent() << "until true"sv << nlr(body); 9044 _buf << indent() << "until true"sv << nl(body);
8448 _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nlr(body); 9045 _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nl(body);
8449 _buf << indent(1) << "break"sv << nlr(body); 9046 _buf << indent(1) << "break"sv << nl(body);
8450 _buf << indent() << "end"sv << nlr(body); 9047 _buf << indent() << "end"sv << nl(body);
8451 temp.push_back(clearBuf()); 9048 temp.push_back(clearBuf());
8452 _continueVars.pop(); 9049 _continueVars.pop();
8453 } else { 9050 } else {
@@ -8459,46 +9056,48 @@ private:
8459 return conditionVar; 9056 return conditionVar;
8460 } 9057 }
8461 9058
8462 void transformFor(For_t* forNode, str_list& out) { 9059 void transformForNum(ForNum_t* forNum, str_list& out) {
8463 str_list temp; 9060 str_list temp;
8464 transformForHead(forNode, temp); 9061 transformForNumHead(forNum, temp);
8465 auto breakLoopType = getBreakLoopType(forNode->body, Empty); 9062 auto breakLoopType = getBreakLoopType(forNum->body, Empty);
8466 transformLoopBody(forNode->body, temp, breakLoopType, ExpUsage::Common); 9063 transformLoopBody(forNum->body, temp, breakLoopType, ExpUsage::Common);
8467 popScope(); 9064 popScope();
8468 out.push_back(join(temp) + indent() + "end"s + nlr(forNode)); 9065 out.push_back(join(temp) + indent() + "end"s + nl(forNum));
8469 } 9066 }
8470 9067
8471 std::string transformForInner(For_t* forNode, str_list& out) { 9068 std::string transformForNumInner(ForNum_t* forNum, str_list& out) {
8472 auto x = forNode; 9069 auto x = forNum;
8473 std::string accum = getUnusedName("_accum_"sv); 9070 std::string accum = getUnusedName("_accum_"sv);
8474 addToScope(accum); 9071 addToScope(accum);
8475 std::string len = getUnusedName("_len_"sv); 9072 std::string len = getUnusedName("_len_"sv);
8476 addToScope(len); 9073 addToScope(len);
8477 auto breakLoopType = getBreakLoopType(forNode->body, accum); 9074 auto breakLoopType = getBreakLoopType(forNum->body, accum);
8478 _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(forNode); 9075 _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(forNum);
8479 out.emplace_back(clearBuf()); 9076 out.emplace_back(clearBuf());
8480 _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode); 9077 _buf << indent() << "local "sv << len << " = 1"sv << nl(forNum);
8481 auto& lenAssign = out.emplace_back(clearBuf()); 9078 auto& lenAssign = out.emplace_back(clearBuf());
8482 transformForHead(forNode, out); 9079 transformForNumHead(forNum, out);
8483 if (hasBreakWithValue(breakLoopType)) { 9080 if (hasBreakWithValue(breakLoopType)) {
8484 lenAssign.clear(); 9081 lenAssign.clear();
8485 transformLoopBody(forNode->body, out, breakLoopType, ExpUsage::Common); 9082 transformLoopBody(forNum->body, out, breakLoopType, ExpUsage::Common);
8486 } else { 9083 } else {
8487 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); 9084 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x);
8488 auto followStmt = toAst<Statement_t>(len + "+=1"s, forNode->body); 9085 auto followStmt = toAst<Statement_t>(len + "+=1"s, forNum->body);
8489 expList->followStmt = followStmt.get(); 9086 expList->followStmt = followStmt.get();
8490 transformLoopBody(forNode->body, out, breakLoopType, ExpUsage::Assignment, expList); 9087 transformLoopBody(forNum->body, out, breakLoopType, ExpUsage::Assignment, expList);
8491 if (!expList->followStmtProcessed) { 9088 if (!expList->followStmtProcessed) {
8492 lenAssign.clear(); 9089 lenAssign.clear();
8493 } 9090 }
8494 } 9091 }
8495 popScope(); 9092 popScope();
8496 out.push_back(indent() + "end"s + nlr(forNode)); 9093 out.push_back(indent() + "end"s + nl(forNum));
8497 return accum; 9094 return accum;
8498 } 9095 }
8499 9096
8500 void transformForClosure(For_t* forNode, str_list& out) { 9097 void transformForNumClosure(ForNum_t* forNum, str_list& out) {
8501 auto simpleValue = forNode->new_ptr<SimpleValue_t>(); 9098 auto forNode = forNum->new_ptr<For_t>();
9099 forNode->forLoop.set(forNum);
9100 auto simpleValue = forNum->new_ptr<SimpleValue_t>();
8502 simpleValue->value.set(forNode); 9101 simpleValue->value.set(forNode);
8503 if (transformAsUpValueFunc(newExp(simpleValue, forNode), out)) { 9102 if (transformAsUpValueFunc(newExp(simpleValue, forNode), out)) {
8504 return; 9103 return;
@@ -8508,26 +9107,26 @@ private:
8508 pushAnonVarArg(); 9107 pushAnonVarArg();
8509 std::string& funcStart = temp.emplace_back(); 9108 std::string& funcStart = temp.emplace_back();
8510 pushScope(); 9109 pushScope();
8511 auto accum = transformForInner(forNode, temp); 9110 auto accum = transformForNumInner(forNum, temp);
8512 temp.push_back(indent() + "return "s + accum + nlr(forNode)); 9111 temp.push_back(indent() + "return "s + accum + nl(forNum));
8513 popScope(); 9112 popScope();
8514 funcStart = anonFuncStart() + nll(forNode); 9113 funcStart = anonFuncStart() + nl(forNum);
8515 temp.push_back(indent() + anonFuncEnd()); 9114 temp.push_back(indent() + anonFuncEnd());
8516 popAnonVarArg(); 9115 popAnonVarArg();
8517 popFunctionScope(); 9116 popFunctionScope();
8518 out.push_back(join(temp)); 9117 out.push_back(join(temp));
8519 } 9118 }
8520 9119
8521 void transformForInPlace(For_t* forNode, str_list& out, ExpList_t* assignExpList = nullptr) { 9120 void transformForNumInPlace(ForNum_t* forNum, str_list& out, ExpList_t* assignExpList) {
8522 auto x = forNode; 9121 auto x = forNum;
8523 str_list temp; 9122 str_list temp;
8524 bool isScoped = !currentScope().lastStatement; 9123 bool isScoped = !currentScope().lastStatement;
8525 if (assignExpList) { 9124 if (assignExpList) {
8526 if (isScoped) { 9125 if (isScoped) {
8527 _buf << indent() << "do"sv << nll(forNode); 9126 _buf << indent() << "do"sv << nl(forNum);
8528 pushScope(); 9127 pushScope();
8529 } 9128 }
8530 auto accum = transformForInner(forNode, temp); 9129 auto accum = transformForNumInner(forNum, temp);
8531 auto assign = x->new_ptr<Assign_t>(); 9130 auto assign = x->new_ptr<Assign_t>();
8532 assign->values.push_back(toAst<Exp_t>(accum, x)); 9131 assign->values.push_back(toAst<Exp_t>(accum, x));
8533 auto assignment = x->new_ptr<ExpListAssign_t>(); 9132 auto assignment = x->new_ptr<ExpListAssign_t>();
@@ -8536,10 +9135,10 @@ private:
8536 transformAssignment(assignment, temp); 9135 transformAssignment(assignment, temp);
8537 if (isScoped) { 9136 if (isScoped) {
8538 popScope(); 9137 popScope();
8539 temp.push_back(indent() + "end"s + nlr(forNode)); 9138 temp.push_back(indent() + "end"s + nl(forNum));
8540 } 9139 }
8541 } else { 9140 } else {
8542 auto accum = transformForInner(forNode, temp); 9141 auto accum = transformForNumInner(forNum, temp);
8543 auto returnNode = x->new_ptr<Return_t>(); 9142 auto returnNode = x->new_ptr<Return_t>();
8544 returnNode->explicitReturn = false; 9143 returnNode->explicitReturn = false;
8545 auto expListLow = toAst<ExpListLow_t>(accum, x); 9144 auto expListLow = toAst<ExpListLow_t>(accum, x);
@@ -8573,10 +9172,10 @@ private:
8573 auto breakLoopType = getBreakLoopType(forEach->body, Empty); 9172 auto breakLoopType = getBreakLoopType(forEach->body, Empty);
8574 transformLoopBody(forEach->body, temp, breakLoopType, ExpUsage::Common); 9173 transformLoopBody(forEach->body, temp, breakLoopType, ExpUsage::Common);
8575 popScope(); 9174 popScope();
8576 out.push_back(temp.front() + temp.back() + indent() + "end"s + nlr(forEach)); 9175 out.push_back(temp.front() + temp.back() + indent() + "end"s + nl(forEach));
8577 if (extraScoped) { 9176 if (extraScoped) {
8578 popScope(); 9177 popScope();
8579 out.back().append(indent() + "end"s + nlr(forEach)); 9178 out.back().append(indent() + "end"s + nl(forEach));
8580 } 9179 }
8581 } 9180 }
8582 9181
@@ -8587,9 +9186,9 @@ private:
8587 std::string len = getUnusedName("_len_"sv); 9186 std::string len = getUnusedName("_len_"sv);
8588 addToScope(len); 9187 addToScope(len);
8589 auto breakLoopType = getBreakLoopType(forEach->body, accum); 9188 auto breakLoopType = getBreakLoopType(forEach->body, accum);
8590 _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(forEach); 9189 _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(forEach);
8591 out.emplace_back(clearBuf()); 9190 out.emplace_back(clearBuf());
8592 _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach); 9191 _buf << indent() << "local "sv << len << " = 1"sv << nl(forEach);
8593 auto& lenAssign = out.emplace_back(clearBuf()); 9192 auto& lenAssign = out.emplace_back(clearBuf());
8594 transformForEachHead(forEach->nameList, forEach->loopValue, out, true); 9193 transformForEachHead(forEach->nameList, forEach->loopValue, out, true);
8595 if (hasBreakWithValue(breakLoopType)) { 9194 if (hasBreakWithValue(breakLoopType)) {
@@ -8605,14 +9204,16 @@ private:
8605 } 9204 }
8606 } 9205 }
8607 popScope(); 9206 popScope();
8608 out.push_back(indent() + "end"s + nlr(forEach)); 9207 out.push_back(indent() + "end"s + nl(forEach));
8609 return accum; 9208 return accum;
8610 } 9209 }
8611 9210
8612 void transformForEachClosure(ForEach_t* forEach, str_list& out) { 9211 void transformForEachClosure(ForEach_t* forEach, str_list& out) {
9212 auto forNode = forEach->new_ptr<For_t>();
9213 forNode->forLoop.set(forEach);
8613 auto simpleValue = forEach->new_ptr<SimpleValue_t>(); 9214 auto simpleValue = forEach->new_ptr<SimpleValue_t>();
8614 simpleValue->value.set(forEach); 9215 simpleValue->value.set(forNode);
8615 if (transformAsUpValueFunc(newExp(simpleValue, forEach), out)) { 9216 if (transformAsUpValueFunc(newExp(simpleValue, forNode), out)) {
8616 return; 9217 return;
8617 } 9218 }
8618 str_list temp; 9219 str_list temp;
@@ -8621,22 +9222,22 @@ private:
8621 std::string& funcStart = temp.emplace_back(); 9222 std::string& funcStart = temp.emplace_back();
8622 pushScope(); 9223 pushScope();
8623 auto accum = transformForEachInner(forEach, temp); 9224 auto accum = transformForEachInner(forEach, temp);
8624 temp.push_back(indent() + "return "s + accum + nlr(forEach)); 9225 temp.push_back(indent() + "return "s + accum + nl(forEach));
8625 popScope(); 9226 popScope();
8626 funcStart = anonFuncStart() + nll(forEach); 9227 funcStart = anonFuncStart() + nl(forEach);
8627 temp.push_back(indent() + anonFuncEnd()); 9228 temp.push_back(indent() + anonFuncEnd());
8628 popAnonVarArg(); 9229 popAnonVarArg();
8629 popFunctionScope(); 9230 popFunctionScope();
8630 out.push_back(join(temp)); 9231 out.push_back(join(temp));
8631 } 9232 }
8632 9233
8633 void transformForEachInPlace(ForEach_t* forEach, str_list& out, ExpList_t* assignExpList = nullptr) { 9234 void transformForEachInPlace(ForEach_t* forEach, str_list& out, ExpList_t* assignExpList) {
8634 auto x = forEach; 9235 auto x = forEach;
8635 str_list temp; 9236 str_list temp;
8636 bool isScoped = !currentScope().lastStatement; 9237 bool isScoped = !currentScope().lastStatement;
8637 if (assignExpList) { 9238 if (assignExpList) {
8638 if (isScoped) { 9239 if (isScoped) {
8639 _buf << indent() << "do"sv << nll(forEach); 9240 _buf << indent() << "do"sv << nl(forEach);
8640 pushScope(); 9241 pushScope();
8641 } 9242 }
8642 auto accum = transformForEachInner(forEach, temp); 9243 auto accum = transformForEachInner(forEach, temp);
@@ -8648,7 +9249,7 @@ private:
8648 transformAssignment(assignment, temp); 9249 transformAssignment(assignment, temp);
8649 if (isScoped) { 9250 if (isScoped) {
8650 popScope(); 9251 popScope();
8651 temp.push_back(indent() + "end"s + nlr(forEach)); 9252 temp.push_back(indent() + "end"s + nl(forEach));
8652 } 9253 }
8653 } else { 9254 } else {
8654 auto accum = transformForEachInner(forEach, temp); 9255 auto accum = transformForEachInner(forEach, temp);
@@ -8661,6 +9262,48 @@ private:
8661 out.push_back(join(temp)); 9262 out.push_back(join(temp));
8662 } 9263 }
8663 9264
9265 void transformFor(For_t* forNode, str_list& out) {
9266 switch (forNode->forLoop->get_id()) {
9267 case id<ForNum_t>():
9268 transformForNum(static_cast<ForNum_t*>(forNode->forLoop.get()), out);
9269 break;
9270 case id<ForEach_t>():
9271 transformForEach(static_cast<ForEach_t*>(forNode->forLoop.get()), out);
9272 break;
9273 default:
9274 YUEE("AST node mismatch", forNode->forLoop.get());
9275 break;
9276 }
9277 }
9278
9279 void transformForClosure(For_t* forNode, str_list& out) {
9280 switch (forNode->forLoop->get_id()) {
9281 case id<ForNum_t>():
9282 transformForNumClosure(static_cast<ForNum_t*>(forNode->forLoop.get()), out);
9283 break;
9284 case id<ForEach_t>():
9285 transformForEachClosure(static_cast<ForEach_t*>(forNode->forLoop.get()), out);
9286 break;
9287 default:
9288 YUEE("AST node mismatch", forNode->forLoop.get());
9289 break;
9290 }
9291 }
9292
9293 void transformForInPlace(For_t* forNode, str_list& out, ExpList_t* assignExpList) {
9294 switch (forNode->forLoop->get_id()) {
9295 case id<ForNum_t>():
9296 transformForNumInPlace(static_cast<ForNum_t*>(forNode->forLoop.get()), out, assignExpList);
9297 break;
9298 case id<ForEach_t>():
9299 transformForEachInPlace(static_cast<ForEach_t*>(forNode->forLoop.get()), out, assignExpList);
9300 break;
9301 default:
9302 YUEE("AST node mismatch", forNode->forLoop.get());
9303 break;
9304 }
9305 }
9306
8664 void transform_variable_pair(VariablePair_t* pair, str_list& out) { 9307 void transform_variable_pair(VariablePair_t* pair, str_list& out) {
8665 auto name = _parser.toString(pair->name); 9308 auto name = _parser.toString(pair->name);
8666 if (pair->name->name.is<UnicodeName_t>()) { 9309 if (pair->name->name.is<UnicodeName_t>()) {
@@ -8672,8 +9315,8 @@ private:
8672 } 9315 }
8673 if (_config.lintGlobalVariable && !isLocal(name)) { 9316 if (_config.lintGlobalVariable && !isLocal(name)) {
8674 auto key = name + ':' + std::to_string(pair->name->m_begin.m_line) + ':' + std::to_string(pair->name->m_begin.m_col); 9317 auto key = name + ':' + std::to_string(pair->name->m_begin.m_line) + ':' + std::to_string(pair->name->m_begin.m_col);
8675 if (_globals.find(key) != _globals.end()) { 9318 if (_globals.find(key) == _globals.end()) {
8676 _globals[key] = {name, pair->name->m_begin.m_line, pair->name->m_begin.m_col, _funcLevel > 1 ? AccessType::Capture : AccessType::Read}; 9319 _globals[key] = {name, pair->name->m_begin.m_line, pair->name->m_begin.m_col, _funcLevel > 1 ? AccessType::Capture : AccessType::Read, isSolidDefined(name)};
8677 } 9320 }
8678 } 9321 }
8679 } 9322 }
@@ -8787,12 +9430,64 @@ private:
8787 out.push_back(temp.empty() ? "\"\""s : join(temp, " .. "sv)); 9430 out.push_back(temp.empty() ? "\"\""s : join(temp, " .. "sv));
8788 } 9431 }
8789 9432
9433 void transformYAMLMultiline(YAMLMultiline_t* multiline, str_list& out) {
9434 std::optional<std::string> indent;
9435 str_list temp;
9436 for (auto line_ : multiline->lines.objects()) {
9437 auto line = static_cast<YAMLLine_t*>(line_);
9438 auto indentStr = _parser.toString(line->indent);
9439 if (!indent) {
9440 indent = indentStr;
9441 }
9442 if (std::string_view{indentStr.c_str(), indent.value().size()} != indent.value()) {
9443 throw CompileError("inconsistent indent"sv, line);
9444 }
9445 indentStr = indentStr.substr(indent.value().size());
9446 str_list segs;
9447 bool firstSeg = true;
9448 for (auto seg_ : line->segments.objects()) {
9449 auto content = static_cast<YAMLLineContent_t*>(seg_)->content.get();
9450 switch (content->get_id()) {
9451 case id<YAMLLineInner_t>(): {
9452 auto seqStr = _parser.toString(content);
9453 Utils::replace(seqStr, "\\#"sv, "#"sv);
9454 if (firstSeg) {
9455 firstSeg = false;
9456 seqStr.insert(0, indentStr);
9457 }
9458 segs.push_back(Utils::toLuaDoubleString(seqStr));
9459 break;
9460 }
9461 case id<Exp_t>(): {
9462 if (firstSeg) {
9463 firstSeg = false;
9464 if (!indentStr.empty()) {
9465 segs.push_back(Utils::toLuaDoubleString(indentStr));
9466 }
9467 }
9468 transformExp(static_cast<Exp_t*>(content), segs, ExpUsage::Closure);
9469 segs.back() = globalVar("tostring"sv, content, AccessType::Read) + '(' + segs.back() + ')';
9470 break;
9471 }
9472 default: YUEE("AST node mismatch", content); break;
9473 }
9474 }
9475 temp.push_back(join(segs, " .. "sv));
9476 }
9477 auto str = join(temp, " .. '\\n' .. "sv);
9478 Utils::replace(str, "\" .. '\\n' .. \""sv, "\\n"sv);
9479 Utils::replace(str, "\" .. '\\n'"sv, "\\n\""sv);
9480 Utils::replace(str, "'\\n' .. \""sv, "\"\\n"sv);
9481 out.push_back(str);
9482 }
9483
8790 void transformString(String_t* string, str_list& out) { 9484 void transformString(String_t* string, str_list& out) {
8791 auto str = string->str.get(); 9485 auto str = string->str.get();
8792 switch (str->get_id()) { 9486 switch (str->get_id()) {
8793 case id<SingleString_t>(): transformSingleString(static_cast<SingleString_t*>(str), out); break; 9487 case id<SingleString_t>(): transformSingleString(static_cast<SingleString_t*>(str), out); break;
8794 case id<DoubleString_t>(): transformDoubleString(static_cast<DoubleString_t*>(str), out); break; 9488 case id<DoubleString_t>(): transformDoubleString(static_cast<DoubleString_t*>(str), out); break;
8795 case id<LuaString_t>(): transformLuaString(static_cast<LuaString_t*>(str), out); break; 9489 case id<LuaString_t>(): transformLuaString(static_cast<LuaString_t*>(str), out); break;
9490 case id<YAMLMultiline_t>(): transformYAMLMultiline(static_cast<YAMLMultiline_t*>(str), out); break;
8796 default: YUEE("AST node mismatch", str); break; 9491 default: YUEE("AST node mismatch", str); break;
8797 } 9492 }
8798 } 9493 }
@@ -8823,7 +9518,7 @@ private:
8823 pushScope(); 9518 pushScope();
8824 transformClassDecl(classDecl, temp, ExpUsage::Return); 9519 transformClassDecl(classDecl, temp, ExpUsage::Return);
8825 popScope(); 9520 popScope();
8826 funcStart = anonFuncStart() + nll(classDecl); 9521 funcStart = anonFuncStart() + nl(classDecl);
8827 temp.push_back(indent() + anonFuncEnd()); 9522 temp.push_back(indent() + anonFuncEnd());
8828 popAnonVarArg(); 9523 popAnonVarArg();
8829 popFunctionScope(); 9524 popFunctionScope();
@@ -8847,7 +9542,7 @@ private:
8847 bool newDefined = false; 9542 bool newDefined = false;
8848 std::tie(className, newDefined, classTextName) = defineClassVariable(assignable); 9543 std::tie(className, newDefined, classTextName) = defineClassVariable(assignable);
8849 if (newDefined) { 9544 if (newDefined) {
8850 temp.push_back(indent() + "local "s + className + nll(classDecl)); 9545 temp.push_back(indent() + "local "s + className + nl(classDecl));
8851 } 9546 }
8852 if (classTextName.empty()) { 9547 if (classTextName.empty()) {
8853 if (auto chain = ast_cast<AssignableChain_t>(assignable->item)) { 9548 if (auto chain = ast_cast<AssignableChain_t>(assignable->item)) {
@@ -8884,12 +9579,12 @@ private:
8884 } 9579 }
8885 } 9580 }
8886 if (isScoped) { 9581 if (isScoped) {
8887 temp.push_back(indent() + "do"s + nll(classDecl)); 9582 temp.push_back(indent() + "do"s + nl(classDecl));
8888 pushScope(); 9583 pushScope();
8889 } 9584 }
8890 auto classVar = getUnusedName("_class_"sv); 9585 auto classVar = getUnusedName("_class_"sv);
8891 addToScope(classVar); 9586 addToScope(classVar);
8892 temp.push_back(indent() + "local "s + classVar + nll(classDecl)); 9587 temp.push_back(indent() + "local "s + classVar + nl(classDecl));
8893 auto block = classDecl->new_ptr<Block_t>(); 9588 auto block = classDecl->new_ptr<Block_t>();
8894 str_list classConstVars; 9589 str_list classConstVars;
8895 if (body) { 9590 if (body) {
@@ -8898,7 +9593,7 @@ private:
8898 if (auto statement = ast_cast<Statement_t>(item)) { 9593 if (auto statement = ast_cast<Statement_t>(item)) {
8899 ClassDecl_t* clsDecl = nullptr; 9594 ClassDecl_t* clsDecl = nullptr;
8900 if (auto assignment = assignmentFrom(statement)) { 9595 if (auto assignment = assignmentFrom(statement)) {
8901 block->statements.push_back(statement); 9596 block->statementOrComments.push_back(statement);
8902 auto names = transformAssignDefs(assignment->expList.get(), DefOp::Mark); 9597 auto names = transformAssignDefs(assignment->expList.get(), DefOp::Mark);
8903 for (const auto& name : names) { 9598 for (const auto& name : names) {
8904 varDefs.push_back(name.first); 9599 varDefs.push_back(name.first);
@@ -8928,12 +9623,12 @@ private:
8928 clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>(); 9623 clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>();
8929 BLOCK_END 9624 BLOCK_END
8930 } else if (auto expList = expListFrom(statement)) { 9625 } else if (auto expList = expListFrom(statement)) {
8931 block->statements.push_back(statement); 9626 block->statementOrComments.push_back(statement);
8932 if (auto value = singleValueFrom(expList)) { 9627 if (auto value = singleValueFrom(expList)) {
8933 clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>(); 9628 clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>();
8934 } 9629 }
8935 } else if (auto local = statement->content.as<Local_t>()) { 9630 } else if (auto local = statement->content.as<Local_t>()) {
8936 block->statements.push_back(statement); 9631 block->statementOrComments.push_back(statement);
8937 if (auto values = local->item.as<LocalValues_t>()) { 9632 if (auto values = local->item.as<LocalValues_t>()) {
8938 for (auto name : values->nameList->names.objects()) { 9633 for (auto name : values->nameList->names.objects()) {
8939 auto varName = variableToString(static_cast<Variable_t*>(name)); 9634 auto varName = variableToString(static_cast<Variable_t*>(name));
@@ -8996,7 +9691,6 @@ private:
8996 } 9691 }
8997 } 9692 }
8998 auto stmt = statement->new_ptr<Statement_t>(); 9693 auto stmt = statement->new_ptr<Statement_t>();
8999 stmt->comments.dup(statement->comments);
9000 auto newAttrib = localAttrib->new_ptr<LocalAttrib_t>(); 9694 auto newAttrib = localAttrib->new_ptr<LocalAttrib_t>();
9001 newAttrib->attrib.set(localAttrib->attrib); 9695 newAttrib->attrib.set(localAttrib->attrib);
9002 newAttrib->leftList.dup(localAttrib->leftList); 9696 newAttrib->leftList.dup(localAttrib->leftList);
@@ -9004,7 +9698,7 @@ private:
9004 newAttrib->forceLocal = false; 9698 newAttrib->forceLocal = false;
9005 stmt->content.set(newAttrib); 9699 stmt->content.set(newAttrib);
9006 stmt->appendix.set(statement->appendix); 9700 stmt->appendix.set(statement->appendix);
9007 block->statements.push_back(stmt); 9701 block->statementOrComments.push_back(stmt);
9008 } else if (statement->content.is<Global_t>()) { 9702 } else if (statement->content.is<Global_t>()) {
9009 throw CompileError("global statement is not allowed here"sv, statement->content); 9703 throw CompileError("global statement is not allowed here"sv, statement->content);
9010 } 9704 }
@@ -9018,7 +9712,7 @@ private:
9018 } 9712 }
9019 } 9713 }
9020 if (!varDefs.empty()) { 9714 if (!varDefs.empty()) {
9021 temp.push_back(indent() + "local "s + join(varDefs, ", "sv) + nll(body)); 9715 temp.push_back(indent() + "local "s + join(varDefs, ", "sv) + nl(body));
9022 } 9716 }
9023 } 9717 }
9024 std::string parent, parentVar; 9718 std::string parent, parentVar;
@@ -9028,7 +9722,7 @@ private:
9028 transformExp(extend, temp, ExpUsage::Closure); 9722 transformExp(extend, temp, ExpUsage::Closure);
9029 parent = std::move(temp.back()); 9723 parent = std::move(temp.back());
9030 temp.pop_back(); 9724 temp.pop_back();
9031 temp.push_back(indent() + "local "s + parentVar + " = "s + parent + nll(classDecl)); 9725 temp.push_back(indent() + "local "s + parentVar + " = "s + parent + nl(classDecl));
9032 } 9726 }
9033 auto baseVar = getUnusedName("_base_"sv); 9727 auto baseVar = getUnusedName("_base_"sv);
9034 addToScope(baseVar); 9728 addToScope(baseVar);
@@ -9047,7 +9741,7 @@ private:
9047 for (; it != members.end(); ++it) { 9741 for (; it != members.end(); ++it) {
9048 auto& member = *it; 9742 auto& member = *it;
9049 if (member.type == MemType::Property) { 9743 if (member.type == MemType::Property) {
9050 statements.push_back(indent() + member.item + nll(content)); 9744 statements.push_back(indent() + member.item + nl(content));
9051 } else { 9745 } else {
9052 member.item = indent(1) + member.item; 9746 member.item = indent(1) + member.item;
9053 } 9747 }
@@ -9059,32 +9753,34 @@ private:
9059 } 9753 }
9060 } 9754 }
9061 for (const auto& classVar : classConstVars) { 9755 for (const auto& classVar : classConstVars) {
9062 auto& scope = _scopes.back(); 9756 forceAddToScope(classVar);
9063 scope.vars->insert_or_assign(classVar, VarType::Local);
9064 } 9757 }
9065 for (auto stmt_ : block->statements.objects()) { 9758 forceAddToScope("self"s);
9066 transformStatement(static_cast<Statement_t*>(stmt_), statements); 9759 for (auto stmt_ : block->statementOrComments.objects()) {
9760 if (auto stmt = ast_cast<Statement_t>(stmt_)) {
9761 transformStatement(stmt, statements);
9762 }
9067 } 9763 }
9068 for (auto& member : members) { 9764 for (auto& member : members) {
9069 switch (member.type) { 9765 switch (member.type) {
9070 case MemType::Common: 9766 case MemType::Common:
9071 commons.push_back((commons.empty() ? Empty : ',' + nll(member.node)) + member.item); 9767 commons.push_back((commons.empty() ? Empty : ',' + nl(member.node)) + member.item);
9072 break; 9768 break;
9073 case MemType::Builtin: 9769 case MemType::Builtin:
9074 builtins.push_back((builtins.empty() ? Empty : ',' + nll(member.node)) + member.item); 9770 builtins.push_back((builtins.empty() ? Empty : ',' + nl(member.node)) + member.item);
9075 break; 9771 break;
9076 default: break; 9772 default: break;
9077 } 9773 }
9078 } 9774 }
9079 if (!commons.empty()) { 9775 if (!commons.empty()) {
9080 temp.back() += '{' + nll(body); 9776 temp.back() += '{' + nl(body);
9081 temp.push_back(join(commons) + nll(body)); 9777 temp.push_back(join(commons) + nl(body));
9082 temp.push_back(indent() + '}' + nll(body)); 9778 temp.push_back(indent() + '}' + nl(body));
9083 } else { 9779 } else {
9084 temp.back() += "{ }"s + nll(body); 9780 temp.back() += "{ }"s + nl(body);
9085 } 9781 }
9086 } else { 9782 } else {
9087 temp.back() += "{ }"s + nll(classDecl); 9783 temp.back() += "{ }"s + nl(classDecl);
9088 } 9784 }
9089 if (classDecl->mixes) { 9785 if (classDecl->mixes) {
9090 auto item = getUnusedName("_item_"sv); 9786 auto item = getUnusedName("_item_"sv);
@@ -9117,72 +9813,72 @@ private:
9117 transformAssignment(assignment, tmp); 9813 transformAssignment(assignment, tmp);
9118 } 9814 }
9119 if (extend) { 9815 if (extend) {
9120 _buf << indent() << "setmetatable("sv << baseVar << ", "sv << parentVar << ".__base)"sv << nll(classDecl); 9816 _buf << indent() << "setmetatable("sv << baseVar << ", "sv << parentVar << ".__base)"sv << nl(classDecl);
9121 } 9817 }
9122 _buf << indent() << classVar << " = "sv << globalVar("setmetatable"sv, classDecl, AccessType::Read) << "({"sv << nll(classDecl); 9818 _buf << indent() << classVar << " = "sv << globalVar("setmetatable"sv, classDecl, AccessType::Read) << "({"sv << nl(classDecl);
9123 if (!builtins.empty()) { 9819 if (!builtins.empty()) {
9124 _buf << join(builtins) << ',' << nll(classDecl); 9820 _buf << join(builtins) << ',' << nl(classDecl);
9125 } else { 9821 } else {
9126 if (extend) { 9822 if (extend) {
9127 _buf << indent(1) << "__init = function(self, ...)"sv << nll(classDecl); 9823 _buf << indent(1) << "__init = function(self, ...)"sv << nl(classDecl);
9128 _buf << indent(2) << "return "sv << classVar << ".__parent.__init(self, ...)"sv << nll(classDecl); 9824 _buf << indent(2) << "return "sv << classVar << ".__parent.__init(self, ...)"sv << nl(classDecl);
9129 _buf << indent(1) << "end,"sv << nll(classDecl); 9825 _buf << indent(1) << "end,"sv << nl(classDecl);
9130 } else { 9826 } else {
9131 _buf << indent(1) << "__init = function() end,"sv << nll(classDecl); 9827 _buf << indent(1) << "__init = function() end,"sv << nl(classDecl);
9132 } 9828 }
9133 } 9829 }
9134 _buf << indent(1) << "__base = "sv << baseVar; 9830 _buf << indent(1) << "__base = "sv << baseVar;
9135 if (!classTextName.empty()) { 9831 if (!classTextName.empty()) {
9136 _buf << ","sv << nll(classDecl); 9832 _buf << ","sv << nl(classDecl);
9137 _buf << indent(1) << "__name = "sv << classTextName; 9833 _buf << indent(1) << "__name = "sv << classTextName;
9138 } 9834 }
9139 if (extend) { 9835 if (extend) {
9140 _buf << ","sv << nll(classDecl); 9836 _buf << ","sv << nl(classDecl);
9141 _buf << indent(1) << "__parent = "sv << parentVar; 9837 _buf << indent(1) << "__parent = "sv << parentVar;
9142 } 9838 }
9143 _buf << nll(classDecl); 9839 _buf << nl(classDecl);
9144 _buf << indent() << "}, {"sv << nll(classDecl); 9840 _buf << indent() << "}, {"sv << nl(classDecl);
9145 if (extend) { 9841 if (extend) {
9146 _buf << indent(1) << "__index = function(cls, name)"sv << nll(classDecl); 9842 _buf << indent(1) << "__index = function(cls, name)"sv << nl(classDecl);
9147 _buf << indent(2) << "local val = rawget("sv << baseVar << ", name)"sv << nll(classDecl); 9843 _buf << indent(2) << "local val = rawget("sv << baseVar << ", name)"sv << nl(classDecl);
9148 _buf << indent(2) << "if val == nil then"sv << nll(classDecl); 9844 _buf << indent(2) << "if val == nil then"sv << nl(classDecl);
9149 _buf << indent(3) << "local parent = rawget(cls, \"__parent\")"sv << nll(classDecl); 9845 _buf << indent(3) << "local parent = rawget(cls, \"__parent\")"sv << nl(classDecl);
9150 _buf << indent(3) << "if parent then"sv << nll(classDecl); 9846 _buf << indent(3) << "if parent then"sv << nl(classDecl);
9151 _buf << indent(4) << "return parent[name]"sv << nll(classDecl); 9847 _buf << indent(4) << "return parent[name]"sv << nl(classDecl);
9152 _buf << indent(3) << "end"sv << nll(classDecl); 9848 _buf << indent(3) << "end"sv << nl(classDecl);
9153 _buf << indent(2) << "else"sv << nll(classDecl); 9849 _buf << indent(2) << "else"sv << nl(classDecl);
9154 _buf << indent(3) << "return val"sv << nll(classDecl); 9850 _buf << indent(3) << "return val"sv << nl(classDecl);
9155 _buf << indent(2) << "end"sv << nll(classDecl); 9851 _buf << indent(2) << "end"sv << nl(classDecl);
9156 _buf << indent(1) << "end,"sv << nll(classDecl); 9852 _buf << indent(1) << "end,"sv << nl(classDecl);
9157 } else { 9853 } else {
9158 _buf << indent(1) << "__index = "sv << baseVar << ","sv << nll(classDecl); 9854 _buf << indent(1) << "__index = "sv << baseVar << ","sv << nl(classDecl);
9159 } 9855 }
9160 _buf << indent(1) << "__call = function(cls, ...)"sv << nll(classDecl); 9856 _buf << indent(1) << "__call = function(cls, ...)"sv << nl(classDecl);
9161 pushScope(); 9857 pushScope();
9162 auto selfVar = getUnusedName("_self_"sv); 9858 auto selfVar = getUnusedName("_self_"sv);
9163 addToScope(selfVar); 9859 addToScope(selfVar);
9164 _buf << indent(1) << "local "sv << selfVar << " = setmetatable({ }, "sv << baseVar << ")"sv << nll(classDecl); 9860 _buf << indent(1) << "local "sv << selfVar << " = setmetatable({ }, "sv << baseVar << ")"sv << nl(classDecl);
9165 _buf << indent(1) << "cls.__init("sv << selfVar << ", ...)"sv << nll(classDecl); 9861 _buf << indent(1) << "cls.__init("sv << selfVar << ", ...)"sv << nl(classDecl);
9166 _buf << indent(1) << "return "sv << selfVar << nll(classDecl); 9862 _buf << indent(1) << "return "sv << selfVar << nl(classDecl);
9167 popScope(); 9863 popScope();
9168 _buf << indent(1) << "end"sv << nll(classDecl); 9864 _buf << indent(1) << "end"sv << nl(classDecl);
9169 _buf << indent() << "})"sv << nll(classDecl); 9865 _buf << indent() << "})"sv << nl(classDecl);
9170 _buf << indent() << baseVar << ".__class = "sv << classVar << nll(classDecl); 9866 _buf << indent() << baseVar << ".__class = "sv << classVar << nl(classDecl);
9171 if (!statements.empty()) { 9867 if (!statements.empty()) {
9172 _buf << indent() << "local self = "sv << classVar << ';' << nll(classDecl); 9868 _buf << indent() << "local self = "sv << classVar << ';' << nl(classDecl);
9173 } 9869 }
9174 _buf << join(statements); 9870 _buf << join(statements);
9175 if (extend) { 9871 if (extend) {
9176 _buf << indent() << "if "sv << parentVar << ".__inherited then"sv << nll(classDecl); 9872 _buf << indent() << "if "sv << parentVar << ".__inherited then"sv << nl(classDecl);
9177 _buf << indent(1) << parentVar << ".__inherited("sv << parentVar << ", "sv << classVar << ")"sv << nll(classDecl); 9873 _buf << indent(1) << parentVar << ".__inherited("sv << parentVar << ", "sv << classVar << ")"sv << nl(classDecl);
9178 _buf << indent() << "end"sv << nll(classDecl); 9874 _buf << indent() << "end"sv << nl(classDecl);
9179 } 9875 }
9180 if (!assignItem.empty()) { 9876 if (!assignItem.empty()) {
9181 _buf << indent() << assignItem << " = "sv << classVar << nll(classDecl); 9877 _buf << indent() << assignItem << " = "sv << classVar << nl(classDecl);
9182 } 9878 }
9183 switch (usage) { 9879 switch (usage) {
9184 case ExpUsage::Return: { 9880 case ExpUsage::Return: {
9185 _buf << indent() << "return "sv << classVar << nlr(classDecl); 9881 _buf << indent() << "return "sv << classVar << nl(classDecl);
9186 break; 9882 break;
9187 } 9883 }
9188 case ExpUsage::Assignment: { 9884 case ExpUsage::Assignment: {
@@ -9194,7 +9890,7 @@ private:
9194 temp.push_back(clearBuf()); 9890 temp.push_back(clearBuf());
9195 if (isScoped) { 9891 if (isScoped) {
9196 popScope(); 9892 popScope();
9197 temp.push_back(indent() + "end"s + nlr(classDecl)); 9893 temp.push_back(indent() + "end"s + nl(classDecl));
9198 } 9894 }
9199 out.push_back(join(temp)); 9895 out.push_back(join(temp));
9200 } 9896 }
@@ -9357,7 +10053,7 @@ private:
9357 pushScope(); 10053 pushScope();
9358 transformWith(with, temp, nullptr, true); 10054 transformWith(with, temp, nullptr, true);
9359 popScope(); 10055 popScope();
9360 funcStart = anonFuncStart() + nll(with); 10056 funcStart = anonFuncStart() + nl(with);
9361 temp.push_back(indent() + anonFuncEnd()); 10057 temp.push_back(indent() + anonFuncEnd());
9362 popAnonVarArg(); 10058 popAnonVarArg();
9363 popFunctionScope(); 10059 popFunctionScope();
@@ -9370,11 +10066,11 @@ private:
9370 std::string withVar; 10066 std::string withVar;
9371 bool needScope = !currentScope().lastStatement && !returnValue; 10067 bool needScope = !currentScope().lastStatement && !returnValue;
9372 bool extraScope = false; 10068 bool extraScope = false;
9373 if (with->assigns) { 10069 if (with->assign) {
9374 auto vars = getAssignVars(with); 10070 auto vars = getAssignVars(with);
9375 if (vars.front().empty() || isDeclaredAsGlobal(vars.front())) { 10071 if (vars.front().empty() || isDeclaredAsGlobal(vars.front())) {
9376 if (with->assigns->values.objects().size() == 1) { 10072 if (with->assign->values.objects().size() == 1) {
9377 auto var = singleVariableFrom(with->assigns->values.objects().front(), AccessType::Read); 10073 auto var = singleVariableFrom(with->assign->values.objects().front(), AccessType::Read);
9378 if (!var.empty() && isLocal(var)) { 10074 if (!var.empty() && isLocal(var)) {
9379 withVar = var; 10075 withVar = var;
9380 } 10076 }
@@ -9384,11 +10080,11 @@ private:
9384 auto assignment = x->new_ptr<ExpListAssign_t>(); 10080 auto assignment = x->new_ptr<ExpListAssign_t>();
9385 assignment->expList.set(toAst<ExpList_t>(withVar, x)); 10081 assignment->expList.set(toAst<ExpList_t>(withVar, x));
9386 auto assign = x->new_ptr<Assign_t>(); 10082 auto assign = x->new_ptr<Assign_t>();
9387 assign->values.push_back(with->assigns->values.objects().front()); 10083 assign->values.push_back(with->assign->values.objects().front());
9388 assignment->action.set(assign); 10084 assignment->action.set(assign);
9389 if (needScope) { 10085 if (needScope) {
9390 extraScope = true; 10086 extraScope = true;
9391 temp.push_back(indent() + "do"s + nll(with)); 10087 temp.push_back(indent() + "do"s + nl(with));
9392 pushScope(); 10088 pushScope();
9393 } 10089 }
9394 transformAssignment(assignment, temp); 10090 transformAssignment(assignment, temp);
@@ -9398,7 +10094,7 @@ private:
9398 auto assign = x->new_ptr<Assign_t>(); 10094 auto assign = x->new_ptr<Assign_t>();
9399 assign->values.push_back(toAst<Exp_t>(withVar, x)); 10095 assign->values.push_back(toAst<Exp_t>(withVar, x));
9400 bool skipFirst = true; 10096 bool skipFirst = true;
9401 for (auto value : with->assigns->values.objects()) { 10097 for (auto value : with->assign->values.objects()) {
9402 if (skipFirst) { 10098 if (skipFirst) {
9403 skipFirst = false; 10099 skipFirst = false;
9404 continue; 10100 continue;
@@ -9411,10 +10107,10 @@ private:
9411 withVar = vars.front(); 10107 withVar = vars.front();
9412 auto assignment = x->new_ptr<ExpListAssign_t>(); 10108 auto assignment = x->new_ptr<ExpListAssign_t>();
9413 assignment->expList.set(with->valueList); 10109 assignment->expList.set(with->valueList);
9414 assignment->action.set(with->assigns); 10110 assignment->action.set(with->assign);
9415 if (needScope) { 10111 if (needScope) {
9416 extraScope = true; 10112 extraScope = true;
9417 temp.push_back(indent() + "do"s + nll(with)); 10113 temp.push_back(indent() + "do"s + nl(with));
9418 pushScope(); 10114 pushScope();
9419 } 10115 }
9420 transformAssignment(assignment, temp); 10116 transformAssignment(assignment, temp);
@@ -9430,7 +10126,7 @@ private:
9430 assignment->action.set(assign); 10126 assignment->action.set(assign);
9431 if (needScope) { 10127 if (needScope) {
9432 extraScope = true; 10128 extraScope = true;
9433 temp.push_back(indent() + "do"s + nll(with)); 10129 temp.push_back(indent() + "do"s + nl(with));
9434 pushScope(); 10130 pushScope();
9435 } 10131 }
9436 transformAssignment(assignment, temp); 10132 transformAssignment(assignment, temp);
@@ -9484,7 +10180,7 @@ private:
9484 }); 10180 });
9485 popScope(); 10181 popScope();
9486 if (extraScope) { 10182 if (extraScope) {
9487 temp.push_back(indent() + "do"s + nll(with)); 10183 temp.push_back(indent() + "do"s + nl(with));
9488 pushScope(); 10184 pushScope();
9489 } 10185 }
9490 } 10186 }
@@ -9513,49 +10209,40 @@ private:
9513 expListAssign->expList.set(expList); 10209 expListAssign->expList.set(expList);
9514 auto stmt = x->new_ptr<Statement_t>(); 10210 auto stmt = x->new_ptr<Statement_t>();
9515 stmt->content.set(expListAssign); 10211 stmt->content.set(expListAssign);
9516 auto whileNode = toAst<While_t>("while true do break"s, x); 10212 auto repeatNode = toAst<Repeat_t>("repeat\n\t--\nuntil true"s, x);
9517 auto block = x->new_ptr<Block_t>(); 10213 auto block = x->new_ptr<Block_t>();
9518 block->statements.push_back(stmt); 10214 block->statementOrComments.push_back(stmt);
9519 block->statements.push_back(whileNode->body); 10215 repeatNode->body.set(block);
9520 auto body = x->new_ptr<Body_t>();
9521 body->content.set(block);
9522 whileNode->body.set(block);
9523 auto sVal = x->new_ptr<SimpleValue_t>(); 10216 auto sVal = x->new_ptr<SimpleValue_t>();
9524 sVal->value.set(whileNode); 10217 sVal->value.set(repeatNode);
9525 auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x); 10218 auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x);
9526 transformAssignment(asmt, temp); 10219 transformAssignment(asmt, temp);
9527 } 10220 }
9528 } else { 10221 } else {
9529 bool transformed = false; 10222 bool transformed = false;
9530 if (!breakWithVar.empty()) { 10223 if (!breakWithVar.empty()) {
9531 auto whileNode = toAst<While_t>("while true do break"s, x); 10224 auto repeatNode = toAst<Repeat_t>("repeat\n\t--\nuntil true"s, x);
9532 auto block = x->new_ptr<Block_t>(); 10225 auto block = x->new_ptr<Block_t>();
9533 if (auto blk = with->body.as<Block_t>()) { 10226 if (auto blk = with->body.as<Block_t>()) {
9534 block->statements.dup(blk->statements); 10227 block->statementOrComments.dup(blk->statementOrComments);
9535 } else { 10228 } else {
9536 auto stmt = with->body.to<Statement_t>(); 10229 auto stmt = with->body.to<Statement_t>();
9537 block->statements.push_back(stmt); 10230 block->statementOrComments.push_back(stmt);
9538 }
9539 auto breakLoop = whileNode->body.to<Statement_t>()->content.as<BreakLoop_t>();
9540 if (!(breakLoop && breakLoop->type.is<Break_t>())) {
9541 block->statements.push_back(whileNode->body);
9542 } 10231 }
9543 auto body = x->new_ptr<Body_t>(); 10232 repeatNode->body.set(block);
9544 body->content.set(block);
9545 whileNode->body.set(block);
9546 auto sVal = x->new_ptr<SimpleValue_t>(); 10233 auto sVal = x->new_ptr<SimpleValue_t>();
9547 sVal->value.set(whileNode); 10234 sVal->value.set(repeatNode);
9548 auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x); 10235 auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x);
9549 transformAssignment(asmt, temp); 10236 transformAssignment(asmt, temp);
9550 transformed = true; 10237 transformed = true;
9551 } else if (!extraScope && assignList) { 10238 } else if (!extraScope && assignList) {
9552 if (auto block = with->body.as<Block_t>()) { 10239 if (auto block = with->body.as<Block_t>()) {
9553 if (!block->statements.empty()) { 10240 if (!block->statementOrComments.empty()) {
9554 Statement_t* stmt = static_cast<Statement_t*>(block->statements.back()); 10241 Statement_t* stmt = lastStatementFrom(block);
9555 if (stmt->content.is<Return_t>()) { 10242 if (stmt && stmt->content.is<Return_t>()) {
9556 auto newBlock = with->body->new_ptr<Block_t>(); 10243 auto newBlock = with->body->new_ptr<Block_t>();
9557 newBlock->statements.dup(block->statements); 10244 newBlock->statementOrComments.dup(block->statementOrComments);
9558 newBlock->statements.pop_back(); 10245 newBlock->statementOrComments.pop_back();
9559 transform_plain_body(newBlock, temp, ExpUsage::Common); 10246 transform_plain_body(newBlock, temp, ExpUsage::Common);
9560 auto newBody = stmt->new_ptr<Body_t>(); 10247 auto newBody = stmt->new_ptr<Body_t>();
9561 newBody->content.set(stmt); 10248 newBody->content.set(stmt);
@@ -9593,12 +10280,12 @@ private:
9593 if (returnValue) { 10280 if (returnValue) {
9594 auto last = lastStatementFrom(with->body); 10281 auto last = lastStatementFrom(with->body);
9595 if (last && !last->content.is<Return_t>()) { 10282 if (last && !last->content.is<Return_t>()) {
9596 temp.push_back(indent() + "return "s + withVar + nll(with)); 10283 temp.push_back(indent() + "return "s + withVar + nl(with));
9597 } 10284 }
9598 } 10285 }
9599 if (extraScope) { 10286 if (extraScope) {
9600 popScope(); 10287 popScope();
9601 temp.push_back(indent() + "end"s + nll(with)); 10288 temp.push_back(indent() + "end"s + nl(with));
9602 } 10289 }
9603 out.push_back(join(temp)); 10290 out.push_back(join(temp));
9604 } 10291 }
@@ -9808,7 +10495,7 @@ private:
9808 } 10495 }
9809 } 10496 }
9810 if (_info.exportDefault) { 10497 if (_info.exportDefault) {
9811 out.back().append(indent() + _info.moduleName + " = "s + names.back().first + nlr(exportNode)); 10498 out.back().append(indent() + _info.moduleName + " = "s + names.back().first + nl(exportNode));
9812 } else { 10499 } else {
9813 str_list lefts, rights; 10500 str_list lefts, rights;
9814 for (const auto& name : names) { 10501 for (const auto& name : names) {
@@ -9821,7 +10508,7 @@ private:
9821 lefts.push_back(_info.moduleName + "[\""s + realName + "\"]"s); 10508 lefts.push_back(_info.moduleName + "[\""s + realName + "\"]"s);
9822 rights.push_back(name.first); 10509 rights.push_back(name.first);
9823 } 10510 }
9824 out.back().append(indent() + join(lefts, ", "sv) + " = "s + join(rights, ", "sv) + nlr(exportNode)); 10511 out.back().append(indent() + join(lefts, ", "sv) + " = "s + join(rights, ", "sv) + nl(exportNode));
9825 } 10512 }
9826 } 10513 }
9827 } else { 10514 } else {
@@ -9905,12 +10592,12 @@ private:
9905 case id<CompForEach_t>(): 10592 case id<CompForEach_t>():
9906 transformCompForEach(static_cast<CompForEach_t*>(item), temp); 10593 transformCompForEach(static_cast<CompForEach_t*>(item), temp);
9907 break; 10594 break;
9908 case id<CompFor_t>(): 10595 case id<CompForNum_t>():
9909 transformCompFor(static_cast<CompFor_t*>(item), temp); 10596 transformCompForNum(static_cast<CompForNum_t*>(item), temp);
9910 break; 10597 break;
9911 case id<Exp_t>(): 10598 case id<Exp_t>():
9912 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure); 10599 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure);
9913 temp.back() = indent() + "if "s + temp.back() + " then"s + nll(item); 10600 temp.back() = indent() + "if "s + temp.back() + " then"s + nl(item);
9914 pushScope(); 10601 pushScope();
9915 break; 10602 break;
9916 default: YUEE("AST node mismatch", item); break; 10603 default: YUEE("AST node mismatch", item); break;
@@ -9923,27 +10610,27 @@ private:
9923 for (size_t i = 0; i < compInner->items.objects().size(); ++i) { 10610 for (size_t i = 0; i < compInner->items.objects().size(); ++i) {
9924 popScope(); 10611 popScope();
9925 } 10612 }
9926 _buf << indent() << "local "sv << tbl << " = { }"sv << nll(comp); 10613 _buf << indent() << "local "sv << tbl << " = { }"sv << nl(comp);
9927 _buf << join(temp); 10614 _buf << join(temp);
9928 pushScope(); 10615 pushScope();
9929 if (!comp->value) { 10616 if (!comp->value) {
9930 auto keyVar = getUnusedName("_key_"sv); 10617 auto keyVar = getUnusedName("_key_"sv);
9931 auto valVar = getUnusedName("_val_"sv); 10618 auto valVar = getUnusedName("_val_"sv);
9932 _buf << indent(int(temp.size()) - 1) << "local "sv << keyVar << ", "sv << valVar << " = "sv << kv.front() << nll(comp); 10619 _buf << indent(int(temp.size()) - 1) << "local "sv << keyVar << ", "sv << valVar << " = "sv << kv.front() << nl(comp);
9933 kv.front() = keyVar; 10620 kv.front() = keyVar;
9934 kv.push_back(valVar); 10621 kv.push_back(valVar);
9935 } 10622 }
9936 _buf << indent(int(temp.size()) - 1) << tbl << "["sv << kv.front() << "] = "sv << kv.back() << nll(comp); 10623 _buf << indent(int(temp.size()) - 1) << tbl << "["sv << kv.front() << "] = "sv << kv.back() << nl(comp);
9937 for (int ind = int(temp.size()) - 2; ind > -1; --ind) { 10624 for (int ind = int(temp.size()) - 2; ind > -1; --ind) {
9938 _buf << indent(ind) << "end"sv << nll(comp); 10625 _buf << indent(ind) << "end"sv << nl(comp);
9939 } 10626 }
9940 popScope(); 10627 popScope();
9941 _buf << indent() << "end"sv << nll(comp); 10628 _buf << indent() << "end"sv << nl(comp);
9942 switch (usage) { 10629 switch (usage) {
9943 case ExpUsage::Closure: 10630 case ExpUsage::Closure:
9944 out.push_back(clearBuf() + indent() + "return "s + tbl + nlr(comp)); 10631 out.push_back(clearBuf() + indent() + "return "s + tbl + nl(comp));
9945 popScope(); 10632 popScope();
9946 out.back().insert(0, anonFuncStart() + nll(comp)); 10633 out.back().insert(0, anonFuncStart() + nl(comp));
9947 out.back().append(indent() + anonFuncEnd()); 10634 out.back().append(indent() + anonFuncEnd());
9948 popAnonVarArg(); 10635 popAnonVarArg();
9949 popFunctionScope(); 10636 popFunctionScope();
@@ -9959,21 +10646,21 @@ private:
9959 out.back().append(temp.back()); 10646 out.back().append(temp.back());
9960 if (extraScope) { 10647 if (extraScope) {
9961 popScope(); 10648 popScope();
9962 out.back().insert(0, indent() + "do"s + nll(comp)); 10649 out.back().insert(0, indent() + "do"s + nl(comp));
9963 out.back().append(indent() + "end"s + nlr(comp)); 10650 out.back().append(indent() + "end"s + nl(comp));
9964 } 10651 }
9965 break; 10652 break;
9966 } 10653 }
9967 case ExpUsage::Return: 10654 case ExpUsage::Return:
9968 out.push_back(clearBuf() + indent() + "return "s + tbl + nlr(comp)); 10655 out.push_back(clearBuf() + indent() + "return "s + tbl + nl(comp));
9969 break; 10656 break;
9970 default: 10657 default:
9971 break; 10658 break;
9972 } 10659 }
9973 } 10660 }
9974 10661
9975 void transformCompFor(CompFor_t* comp, str_list& out) { 10662 void transformCompForNum(CompForNum_t* comp, str_list& out) {
9976 transformForHead(comp->varName, comp->startValue, comp->stopValue, comp->stepValue, out); 10663 transformForNumHead(comp->varName, comp->startValue, comp->stopValue, comp->stepValue, out);
9977 } 10664 }
9978 10665
9979 void transformTableBlockIndent(TableBlockIndent_t* table, str_list& out) { 10666 void transformTableBlockIndent(TableBlockIndent_t* table, str_list& out) {
@@ -10003,25 +10690,64 @@ private:
10003 funcStart = &temp.emplace_back(); 10690 funcStart = &temp.emplace_back();
10004 pushScope(); 10691 pushScope();
10005 } else { 10692 } else {
10006 temp.push_back(indent() + "do"s + nll(doNode)); 10693 temp.push_back(indent() + "do"s + nl(doNode));
10007 pushScope(); 10694 pushScope();
10008 } 10695 }
10009 transformBody(doNode->body, temp, usage, assignList); 10696 transformBody(doNode->body, temp, usage, assignList);
10010 if (usage == ExpUsage::Closure) { 10697 if (usage == ExpUsage::Closure) {
10011 popScope(); 10698 popScope();
10012 *funcStart = anonFuncStart() + nll(doNode); 10699 *funcStart = anonFuncStart() + nl(doNode);
10013 temp.push_back(indent() + anonFuncEnd()); 10700 temp.push_back(indent() + anonFuncEnd());
10014 popAnonVarArg(); 10701 popAnonVarArg();
10015 popFunctionScope(); 10702 popFunctionScope();
10016 } else { 10703 } else {
10017 popScope(); 10704 popScope();
10018 temp.push_back(indent() + "end"s + nlr(doNode)); 10705 temp.push_back(indent() + "end"s + nl(doNode));
10019 } 10706 }
10020 out.push_back(join(temp)); 10707 out.push_back(join(temp));
10021 } 10708 }
10022 10709
10023 void transformTry(Try_t* tryNode, str_list& out, ExpUsage usage) { 10710 void transformTry(Try_t* tryNode, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
10024 auto x = tryNode; 10711 auto x = tryNode;
10712 if (tryNode->eop && usage == ExpUsage::Assignment) {
10713 str_list rets;
10714 pushScope();
10715 auto okVar = getUnusedName("_ok_"sv);
10716 for (size_t i = 0; i < assignList->exprs.size(); i++) {
10717 auto retVar = getUnusedName("_ret_"sv);
10718 rets.emplace_back(retVar);
10719 addToScope(retVar);
10720 }
10721 popScope();
10722 auto varList = join(rets, ","sv);
10723 auto ifNode = toAst<If_t>("if "s + okVar + ',' + varList + ":=try nil then "s + varList, x);
10724 auto exp = ast_to<IfCond_t>(ifNode->nodes.front())->assignment->assign->values.front();
10725 auto sVal = simpleSingleValueFrom(exp);
10726 auto newTry = sVal->value.to<Try_t>();
10727 newTry->func.set(tryNode->func);
10728 newTry->catchBlock.set(tryNode->catchBlock);
10729 auto assignment = x->new_ptr<ExpListAssign_t>();
10730 assignment->expList.set(assignList);
10731 auto assign = x->new_ptr<Assign_t>();
10732 assign->values.push_back(ifNode);
10733 assignment->action.set(assign);
10734 transformAssignment(assignment, out);
10735 return;
10736 }
10737 if (tryNode->eop && usage != ExpUsage::Common) {
10738 auto okVar = getUnusedName("_ok_"sv);
10739 auto code = "do\n\t"s + okVar + ", ... = try nil\n\t... if "s + okVar;
10740 auto doNode = toAst<Do_t>(code, x);
10741 auto block = doNode->body->content.to<Block_t>();
10742 auto asmt = static_cast<Statement_t*>(block->statementOrComments.front())->content.to<ExpListAssign_t>();
10743 auto assign = asmt->action.to<Assign_t>();
10744 auto sVal = simpleSingleValueFrom(assign->values.back());
10745 auto newTry = sVal->value.to<Try_t>();
10746 newTry->func.set(tryNode->func);
10747 newTry->catchBlock.set(tryNode->catchBlock);
10748 transformDo(doNode, out, usage);
10749 return;
10750 }
10025 ast_ptr<true, Exp_t> errHandler; 10751 ast_ptr<true, Exp_t> errHandler;
10026 if (tryNode->catchBlock) { 10752 if (tryNode->catchBlock) {
10027 auto catchBlock = tryNode->catchBlock.get(); 10753 auto catchBlock = tryNode->catchBlock.get();
@@ -10037,8 +10763,8 @@ private:
10037 tryFunc.set(tryNode->func); 10763 tryFunc.set(tryNode->func);
10038 if (auto tryBlock = tryFunc.as<Block_t>()) { 10764 if (auto tryBlock = tryFunc.as<Block_t>()) {
10039 BLOCK_START 10765 BLOCK_START
10040 BREAK_IF(tryBlock->statements.size() != 1); 10766 BREAK_IF(countStatementFrom(tryBlock) != 1);
10041 auto stmt = static_cast<Statement_t*>(tryBlock->statements.front()); 10767 auto stmt = firstStatementFrom(tryBlock);
10042 auto expListAssign = stmt->content.as<ExpListAssign_t>(); 10768 auto expListAssign = stmt->content.as<ExpListAssign_t>();
10043 BREAK_IF(!expListAssign); 10769 BREAK_IF(!expListAssign);
10044 BREAK_IF(expListAssign->action); 10770 BREAK_IF(expListAssign->action);
@@ -10102,7 +10828,7 @@ private:
10102 auto stmt = x->new_ptr<Statement_t>(); 10828 auto stmt = x->new_ptr<Statement_t>();
10103 stmt->content.set(expListAssign); 10829 stmt->content.set(expListAssign);
10104 auto block = x->new_ptr<Block_t>(); 10830 auto block = x->new_ptr<Block_t>();
10105 block->statements.push_back(stmt); 10831 block->statementOrComments.push_back(stmt);
10106 tryFunc.set(block); 10832 tryFunc.set(block);
10107 } 10833 }
10108 } 10834 }
@@ -10130,7 +10856,7 @@ private:
10130 } 10856 }
10131 if (usage == ExpUsage::Common) { 10857 if (usage == ExpUsage::Common) {
10132 out.back().insert(0, indent()); 10858 out.back().insert(0, indent());
10133 out.back().append(nlr(x)); 10859 out.back().append(nl(x));
10134 } 10860 }
10135 return; 10861 return;
10136 } 10862 }
@@ -10155,7 +10881,7 @@ private:
10155 } 10881 }
10156 if (usage == ExpUsage::Common) { 10882 if (usage == ExpUsage::Common) {
10157 out.back().insert(0, indent()); 10883 out.back().insert(0, indent());
10158 out.back().append(nlr(x)); 10884 out.back().append(nl(x));
10159 } 10885 }
10160 return; 10886 return;
10161 } else if (auto value = singleValueFrom(tryFunc)) { 10887 } else if (auto value = singleValueFrom(tryFunc)) {
@@ -10216,7 +10942,7 @@ private:
10216 } 10942 }
10217 if (usage == ExpUsage::Common) { 10943 if (usage == ExpUsage::Common) {
10218 out.back().insert(0, indent()); 10944 out.back().insert(0, indent());
10219 out.back().append(nlr(x)); 10945 out.back().append(nl(x));
10220 } 10946 }
10221 return; 10947 return;
10222 BLOCK_END 10948 BLOCK_END
@@ -10235,13 +10961,13 @@ private:
10235 } 10961 }
10236 if (usage == ExpUsage::Common) { 10962 if (usage == ExpUsage::Common) {
10237 out.back().insert(0, indent()); 10963 out.back().insert(0, indent());
10238 out.back().append(nlr(x)); 10964 out.back().append(nl(x));
10239 } 10965 }
10240 } 10966 }
10241 10967
10242 void transformImportFrom(ImportFrom_t* importNode, str_list& out) { 10968 void transformImportFrom(ImportFrom_t* importNode, str_list& out) {
10243 str_list temp; 10969 str_list temp;
10244 auto x = importNode; 10970 auto x = importNode->item.get();
10245 auto objVar = singleVariableFrom(importNode->item, AccessType::Read); 10971 auto objVar = singleVariableFrom(importNode->item, AccessType::Read);
10246 ast_ptr<false, ExpListAssign_t> objAssign; 10972 ast_ptr<false, ExpListAssign_t> objAssign;
10247 if (objVar.empty()) { 10973 if (objVar.empty()) {
@@ -10311,11 +11037,11 @@ private:
10311 if (objAssign) { 11037 if (objAssign) {
10312 auto preDef = toLocalDecl(transformAssignDefs(expList, DefOp::Mark)); 11038 auto preDef = toLocalDecl(transformAssignDefs(expList, DefOp::Mark));
10313 if (!preDef.empty()) { 11039 if (!preDef.empty()) {
10314 temp.push_back(preDef + nll(importNode)); 11040 temp.push_back(preDef + nl(importNode));
10315 } 11041 }
10316 if (!currentScope().lastStatement) { 11042 if (!currentScope().lastStatement) {
10317 extraScope = true; 11043 extraScope = true;
10318 temp.push_back(indent() + "do"s + nll(importNode)); 11044 temp.push_back(indent() + "do"s + nl(importNode));
10319 pushScope(); 11045 pushScope();
10320 } 11046 }
10321 transformAssignment(objAssign, temp); 11047 transformAssignment(objAssign, temp);
@@ -10327,7 +11053,7 @@ private:
10327 if (objAssign) { 11053 if (objAssign) {
10328 if (extraScope) { 11054 if (extraScope) {
10329 popScope(); 11055 popScope();
10330 temp.push_back(indent() + "end"s + nlr(importNode)); 11056 temp.push_back(indent() + "end"s + nl(importNode));
10331 } 11057 }
10332 } 11058 }
10333 out.push_back(join(temp)); 11059 out.push_back(join(temp));
@@ -10567,6 +11293,30 @@ private:
10567 } 11293 }
10568 } 11294 }
10569 11295
11296 void transformImportGlobal(ImportGlobal_t* importNode, str_list& out) {
11297 auto uname = static_cast<UnicodeName_t*>(importNode->segs.front());
11298 auto var = _parser.toString(uname);
11299 auto isNormal = _parser.match<Name_t>(var) && _parser.match<Variable_t>(var);
11300 auto varName = unicodeVariableFrom(uname);
11301 str_list temp;
11302 auto it = ++importNode->segs.objects().begin();
11303 for (; it != importNode->segs.objects().end(); ++it) {
11304 temp.emplace_back(_parser.toString(*it));
11305 }
11306 temp.emplace_front(var);
11307 if (isLocal(varName) || !isNormal) {
11308 temp.emplace_front("_G"s);
11309 }
11310 std::string stmt;
11311 if (importNode->target) {
11312 stmt = "const "s + _parser.toString(importNode->target) + '=' + join(temp, "."sv);
11313 } else {
11314 stmt = "const "s + temp.back() + '=' + join(temp, "."sv);
11315 }
11316 auto localAttrib = toAst<LocalAttrib_t>(stmt, importNode);
11317 transformLocalAttrib(localAttrib, out);
11318 }
11319
10570 void transformImport(Import_t* import, str_list& out) { 11320 void transformImport(Import_t* import, str_list& out) {
10571 auto content = import->content.get(); 11321 auto content = import->content.get();
10572 switch (content->get_id()) { 11322 switch (content->get_id()) {
@@ -10579,6 +11329,9 @@ private:
10579 case id<FromImport_t>(): 11329 case id<FromImport_t>():
10580 transformFromImport(static_cast<FromImport_t*>(content), out); 11330 transformFromImport(static_cast<FromImport_t*>(content), out);
10581 break; 11331 break;
11332 case id<ImportGlobal_t>():
11333 transformImportGlobal(static_cast<ImportGlobal_t*>(content), out);
11334 break;
10582 default: YUEE("AST node mismatch", content); break; 11335 default: YUEE("AST node mismatch", content); break;
10583 } 11336 }
10584 } 11337 }
@@ -10590,7 +11343,7 @@ private:
10590 if (expList) { 11343 if (expList) {
10591 if (!currentScope().lastStatement) { 11344 if (!currentScope().lastStatement) {
10592 extraScope = true; 11345 extraScope = true;
10593 temp.push_back(indent() + "do"s + nll(whileNode)); 11346 temp.push_back(indent() + "do"s + nl(whileNode));
10594 pushScope(); 11347 pushScope();
10595 } 11348 }
10596 } 11349 }
@@ -10599,13 +11352,13 @@ private:
10599 auto lenVar = getUnusedName("_len_"sv); 11352 auto lenVar = getUnusedName("_len_"sv);
10600 addToScope(lenVar); 11353 addToScope(lenVar);
10601 auto breakLoopType = getBreakLoopType(whileNode->body, accumVar); 11354 auto breakLoopType = getBreakLoopType(whileNode->body, accumVar);
10602 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(whileNode); 11355 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(whileNode);
10603 temp.emplace_back(clearBuf()); 11356 temp.emplace_back(clearBuf());
10604 _buf << indent() << "local "s << lenVar << " = 1"s << nll(whileNode); 11357 _buf << indent() << "local "s << lenVar << " = 1"s << nl(whileNode);
10605 auto& lenAssign = temp.emplace_back(clearBuf()); 11358 auto& lenAssign = temp.emplace_back(clearBuf());
10606 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 11359 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
10607 auto condStr = transformCondExp(whileNode->condition, isUntil); 11360 auto condStr = transformCondExp(whileNode->condition, isUntil);
10608 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); 11361 temp.push_back(indent() + "while "s + condStr + " do"s + nl(whileNode));
10609 pushScope(); 11362 pushScope();
10610 if (hasBreakWithValue(breakLoopType)) { 11363 if (hasBreakWithValue(breakLoopType)) {
10611 lenAssign.clear(); 11364 lenAssign.clear();
@@ -10620,7 +11373,7 @@ private:
10620 } 11373 }
10621 } 11374 }
10622 popScope(); 11375 popScope();
10623 temp.push_back(indent() + "end"s + nlr(whileNode)); 11376 temp.push_back(indent() + "end"s + nl(whileNode));
10624 if (expList) { 11377 if (expList) {
10625 auto assign = x->new_ptr<Assign_t>(); 11378 auto assign = x->new_ptr<Assign_t>();
10626 assign->values.push_back(toAst<Exp_t>(accumVar, x)); 11379 assign->values.push_back(toAst<Exp_t>(accumVar, x));
@@ -10630,10 +11383,10 @@ private:
10630 transformAssignment(assignment, temp); 11383 transformAssignment(assignment, temp);
10631 if (extraScope) popScope(); 11384 if (extraScope) popScope();
10632 } else { 11385 } else {
10633 temp.push_back(indent() + "return "s + accumVar + nlr(whileNode)); 11386 temp.push_back(indent() + "return "s + accumVar + nl(whileNode));
10634 } 11387 }
10635 if (expList && extraScope) { 11388 if (expList && extraScope) {
10636 temp.push_back(indent() + "end"s + nlr(whileNode)); 11389 temp.push_back(indent() + "end"s + nl(whileNode));
10637 } 11390 }
10638 out.push_back(join(temp)); 11391 out.push_back(join(temp));
10639 } 11392 }
@@ -10655,12 +11408,12 @@ private:
10655 auto lenVar = getUnusedName("_len_"sv); 11408 auto lenVar = getUnusedName("_len_"sv);
10656 addToScope(lenVar); 11409 addToScope(lenVar);
10657 auto breakLoopType = getBreakLoopType(whileNode->body, accumVar); 11410 auto breakLoopType = getBreakLoopType(whileNode->body, accumVar);
10658 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(whileNode); 11411 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(whileNode);
10659 temp.emplace_back(clearBuf()); 11412 temp.emplace_back(clearBuf());
10660 auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nll(whileNode)); 11413 auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nl(whileNode));
10661 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 11414 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
10662 auto condStr = transformCondExp(whileNode->condition, isUntil); 11415 auto condStr = transformCondExp(whileNode->condition, isUntil);
10663 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); 11416 temp.push_back(indent() + "while "s + condStr + " do"s + nl(whileNode));
10664 pushScope(); 11417 pushScope();
10665 if (hasBreakWithValue(breakLoopType)) { 11418 if (hasBreakWithValue(breakLoopType)) {
10666 lenAssign.clear(); 11419 lenAssign.clear();
@@ -10675,10 +11428,10 @@ private:
10675 } 11428 }
10676 } 11429 }
10677 popScope(); 11430 popScope();
10678 temp.push_back(indent() + "end"s + nlr(whileNode)); 11431 temp.push_back(indent() + "end"s + nl(whileNode));
10679 temp.push_back(indent() + "return "s + accumVar + nlr(whileNode)); 11432 temp.push_back(indent() + "return "s + accumVar + nl(whileNode));
10680 popScope(); 11433 popScope();
10681 funcStart = anonFuncStart() + nll(whileNode); 11434 funcStart = anonFuncStart() + nl(whileNode);
10682 temp.push_back(indent() + anonFuncEnd()); 11435 temp.push_back(indent() + anonFuncEnd());
10683 popAnonVarArg(); 11436 popAnonVarArg();
10684 popFunctionScope(); 11437 popFunctionScope();
@@ -10708,9 +11461,7 @@ private:
10708 expListAssign->expList.set(expList); 11461 expListAssign->expList.set(expList);
10709 auto stmt = x->new_ptr<Statement_t>(); 11462 auto stmt = x->new_ptr<Statement_t>();
10710 stmt->content.set(expListAssign); 11463 stmt->content.set(expListAssign);
10711 auto body = x->new_ptr<Body_t>(); 11464 repeat->body.set(stmt);
10712 body->content.set(stmt);
10713 repeat->body.set(body);
10714 transformRepeat(repeat, out); 11465 transformRepeat(repeat, out);
10715 return; 11466 return;
10716 } 11467 }
@@ -10721,12 +11472,112 @@ private:
10721 auto breakLoopType = getBreakLoopType(whileNode->body, Empty); 11472 auto breakLoopType = getBreakLoopType(whileNode->body, Empty);
10722 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common); 11473 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common);
10723 popScope(); 11474 popScope();
10724 _buf << indent() << "while "sv << condStr << " do"sv << nll(whileNode); 11475 _buf << indent() << "while "sv << condStr << " do"sv << nl(whileNode);
10725 _buf << temp.back(); 11476 _buf << temp.back();
10726 _buf << indent() << "end"sv << nlr(whileNode); 11477 _buf << indent() << "end"sv << nl(whileNode);
10727 out.push_back(clearBuf()); 11478 out.push_back(clearBuf());
10728 } 11479 }
10729 11480
11481 void transformRepeatInPlace(Repeat_t* repeatNode, str_list& out, ExpList_t* expList = nullptr) {
11482 auto x = repeatNode;
11483 str_list temp;
11484 bool extraScope = false;
11485 if (expList) {
11486 if (!currentScope().lastStatement) {
11487 extraScope = true;
11488 temp.push_back(indent() + "do"s + nl(repeatNode));
11489 pushScope();
11490 }
11491 }
11492 auto accumVar = getUnusedName("_accum_"sv);
11493 addToScope(accumVar);
11494 auto lenVar = getUnusedName("_len_"sv);
11495 addToScope(lenVar);
11496 auto breakLoopType = getBreakLoopType(repeatNode->body, accumVar);
11497 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(repeatNode);
11498 temp.emplace_back(clearBuf());
11499 _buf << indent() << "local "s << lenVar << " = 1"s << nl(repeatNode);
11500 auto& lenAssign = temp.emplace_back(clearBuf());
11501 auto condStr = transformCondExp(repeatNode->condition, false);
11502 temp.push_back(indent() + "repeat"s + nl(repeatNode));
11503 pushScope();
11504 if (hasBreakWithValue(breakLoopType)) {
11505 lenAssign.clear();
11506 transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Common);
11507 } else {
11508 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x);
11509 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, repeatNode);
11510 assignLeft->followStmt = followStmt.get();
11511 transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
11512 if (!assignLeft->followStmtProcessed) {
11513 lenAssign.clear();
11514 }
11515 }
11516 popScope();
11517 temp.push_back(indent() + "until "s + condStr + nl(repeatNode));
11518 if (expList) {
11519 auto assign = x->new_ptr<Assign_t>();
11520 assign->values.push_back(toAst<Exp_t>(accumVar, x));
11521 auto assignment = x->new_ptr<ExpListAssign_t>();
11522 assignment->expList.set(expList);
11523 assignment->action.set(assign);
11524 transformAssignment(assignment, temp);
11525 if (extraScope) popScope();
11526 } else {
11527 temp.push_back(indent() + "return "s + accumVar + nl(repeatNode));
11528 }
11529 if (expList && extraScope) {
11530 temp.push_back(indent() + "end"s + nl(repeatNode));
11531 }
11532 out.push_back(join(temp));
11533 }
11534
11535 void transformRepeatClosure(Repeat_t* repeatNode, str_list& out) {
11536 auto x = repeatNode;
11537 auto simpleValue = x->new_ptr<SimpleValue_t>();
11538 simpleValue->value.set(repeatNode);
11539 if (transformAsUpValueFunc(newExp(simpleValue, x), out)) {
11540 return;
11541 }
11542 str_list temp;
11543 pushAnonFunctionScope();
11544 pushAnonVarArg();
11545 std::string& funcStart = temp.emplace_back();
11546 pushScope();
11547 auto accumVar = getUnusedName("_accum_"sv);
11548 addToScope(accumVar);
11549 auto lenVar = getUnusedName("_len_"sv);
11550 addToScope(lenVar);
11551 auto breakLoopType = getBreakLoopType(repeatNode->body, accumVar);
11552 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(repeatNode);
11553 temp.emplace_back(clearBuf());
11554 auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nl(repeatNode));
11555 auto condStr = transformCondExp(repeatNode->condition, false);
11556 temp.push_back(indent() + "repeat"s + nl(repeatNode));
11557 pushScope();
11558 if (hasBreakWithValue(breakLoopType)) {
11559 lenAssign.clear();
11560 transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Common);
11561 } else {
11562 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x);
11563 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, repeatNode);
11564 assignLeft->followStmt = followStmt.get();
11565 transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
11566 if (!assignLeft->followStmtProcessed) {
11567 lenAssign.clear();
11568 }
11569 }
11570 popScope();
11571 temp.push_back(indent() + "until "s + condStr + nl(repeatNode));
11572 temp.push_back(indent() + "return "s + accumVar + nl(repeatNode));
11573 popScope();
11574 funcStart = anonFuncStart() + nl(repeatNode);
11575 temp.push_back(indent() + anonFuncEnd());
11576 popAnonVarArg();
11577 popFunctionScope();
11578 out.push_back(join(temp));
11579 }
11580
10730 void transformRepeat(Repeat_t* repeat, str_list& out) { 11581 void transformRepeat(Repeat_t* repeat, str_list& out) {
10731 str_list temp; 11582 str_list temp;
10732 pushScope(); 11583 pushScope();
@@ -10737,9 +11588,9 @@ private:
10737 temp.push_back(condVar); 11588 temp.push_back(condVar);
10738 } 11589 }
10739 popScope(); 11590 popScope();
10740 _buf << indent() << "repeat"sv << nll(repeat); 11591 _buf << indent() << "repeat"sv << nl(repeat);
10741 _buf << temp.front(); 11592 _buf << temp.front();
10742 _buf << indent() << "until "sv << temp.back() << nlr(repeat); 11593 _buf << indent() << "until "sv << temp.back() << nl(repeat);
10743 out.push_back(clearBuf()); 11594 out.push_back(clearBuf());
10744 } 11595 }
10745 11596
@@ -10760,12 +11611,28 @@ private:
10760 pushScope(); 11611 pushScope();
10761 } 11612 }
10762 bool extraScope = false; 11613 bool extraScope = false;
11614 if (switchNode->assignment) {
11615 if (needScope) {
11616 extraScope = true;
11617 temp.push_back(indent() + "do"s + nl(x));
11618 pushScope();
11619 }
11620 auto asmt = x->new_ptr<ExpListAssign_t>();
11621 auto expList = x->new_ptr<ExpList_t>();
11622 expList->exprs.push_back(switchNode->target);
11623 if (switchNode->assignment->expList) {
11624 expList->exprs.dup(switchNode->assignment->expList->exprs);
11625 }
11626 asmt->expList.set(expList);
11627 asmt->action.set(switchNode->assignment->assign);
11628 transformAssignment(asmt, temp);
11629 }
10763 auto objVar = singleVariableFrom(switchNode->target, AccessType::Read); 11630 auto objVar = singleVariableFrom(switchNode->target, AccessType::Read);
10764 if (objVar.empty() || !isLocal(objVar)) { 11631 if (objVar.empty() || !isLocal(objVar)) {
10765 if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) { 11632 if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) {
10766 if (needScope) { 11633 if (needScope && !extraScope) {
10767 extraScope = true; 11634 extraScope = true;
10768 temp.push_back(indent() + "do"s + nll(x)); 11635 temp.push_back(indent() + "do"s + nl(x));
10769 pushScope(); 11636 pushScope();
10770 } 11637 }
10771 } 11638 }
@@ -10795,13 +11662,13 @@ private:
10795 } 11662 }
10796 if (tableMatching) { 11663 if (tableMatching) {
10797 if (!firstBranch) { 11664 if (!firstBranch) {
10798 temp.push_back(indent() + "else"s + nll(branch)); 11665 temp.push_back(indent() + "else"s + nl(branch));
10799 pushScope(); 11666 pushScope();
10800 addScope++; 11667 addScope++;
10801 } 11668 }
10802 if (tabCheckVar.empty()) { 11669 if (tabCheckVar.empty()) {
10803 if (!extraScope && needScope) { 11670 if (!extraScope && needScope) {
10804 temp.push_back(indent() + "do"s + nll(branch)); 11671 temp.push_back(indent() + "do"s + nl(branch));
10805 pushScope(); 11672 pushScope();
10806 extraScope = true; 11673 extraScope = true;
10807 } 11674 }
@@ -10809,17 +11676,17 @@ private:
10809 forceAddToScope(typeVar); 11676 forceAddToScope(typeVar);
10810 tabCheckVar = getUnusedName("_tab_"sv); 11677 tabCheckVar = getUnusedName("_tab_"sv);
10811 forceAddToScope(tabCheckVar); 11678 forceAddToScope(tabCheckVar);
10812 temp.push_back(indent() + "local "s + typeVar + " = "s + globalVar("type"sv, branch, AccessType::Read) + '(' + objVar + ')' + nll(branch)); 11679 temp.push_back(indent() + "local "s + typeVar + " = "s + globalVar("type"sv, branch, AccessType::Read) + '(' + objVar + ')' + nl(branch));
10813 temp.push_back(indent() + "local "s + tabCheckVar + " = \"table\" == "s + typeVar + " or \"userdata\" == "s + typeVar + nll(branch)); 11680 temp.push_back(indent() + "local "s + tabCheckVar + " = \"table\" == "s + typeVar + " or \"userdata\" == "s + typeVar + nl(branch));
10814 } 11681 }
10815 std::string matchVar; 11682 std::string matchVar;
10816 bool lastBranch = branches.back() == branch_ && !switchNode->lastBranch; 11683 bool lastBranch = branches.back() == branch_ && !switchNode->lastBranch;
10817 if (!lastBranch) { 11684 if (!lastBranch) {
10818 matchVar = getUnusedName("_match_"sv); 11685 matchVar = getUnusedName("_match_"sv);
10819 forceAddToScope(matchVar); 11686 forceAddToScope(matchVar);
10820 temp.push_back(indent() + "local "s + matchVar + " = false"s + nll(branch)); 11687 temp.push_back(indent() + "local "s + matchVar + " = false"s + nl(branch));
10821 } 11688 }
10822 temp.back().append(indent() + "if "s + tabCheckVar + " then"s + nll(branch)); 11689 temp.back().append(indent() + "if "s + tabCheckVar + " then"s + nl(branch));
10823 pushScope(); 11690 pushScope();
10824 auto chainValue = toAst<ChainValue_t>(objVar, branch); 11691 auto chainValue = toAst<ChainValue_t>(objVar, branch);
10825 auto assignment = assignmentFrom(static_cast<Exp_t*>(valueList->exprs.front()), newExp(chainValue, branch), branch); 11692 auto assignment = assignmentFrom(static_cast<Exp_t*>(valueList->exprs.front()), newExp(chainValue, branch), branch);
@@ -10862,21 +11729,21 @@ private:
10862 } 11729 }
10863 } 11730 }
10864 if (!conds.empty()) { 11731 if (!conds.empty()) {
10865 temp.push_back(indent() + "if "s + join(conds, " and "sv) + " then"s + nll(branch)); 11732 temp.push_back(indent() + "if "s + join(conds, " and "sv) + " then"s + nl(branch));
10866 pushScope(); 11733 pushScope();
10867 } 11734 }
10868 if (!lastBranch) { 11735 if (!lastBranch) {
10869 temp.push_back(indent() + matchVar + " = true"s + nll(branch)); 11736 temp.push_back(indent() + matchVar + " = true"s + nl(branch));
10870 } 11737 }
10871 transform_plain_body(branch->body, temp, usage, assignList); 11738 transform_plain_body(branch->body, temp, usage, assignList);
10872 if (!conds.empty()) { 11739 if (!conds.empty()) {
10873 popScope(); 11740 popScope();
10874 temp.push_back(indent() + "end"s + nll(branch)); 11741 temp.push_back(indent() + "end"s + nl(branch));
10875 } 11742 }
10876 if (!lastBranch) { 11743 if (!lastBranch) {
10877 popScope(); 11744 popScope();
10878 temp.push_back(indent() + "end"s + nll(branch)); 11745 temp.push_back(indent() + "end"s + nl(branch));
10879 temp.push_back(indent() + "if not "s + matchVar + " then"s + nll(branch)); 11746 temp.push_back(indent() + "if not "s + matchVar + " then"s + nl(branch));
10880 pushScope(); 11747 pushScope();
10881 addScope++; 11748 addScope++;
10882 } else { 11749 } else {
@@ -10896,7 +11763,7 @@ private:
10896 } 11763 }
10897 temp.back().append(' ' + tmp.back() + " == "s + (exp == exprs.back() ? objVar : objVar + " or"s)); 11764 temp.back().append(' ' + tmp.back() + " == "s + (exp == exprs.back() ? objVar : objVar + " or"s));
10898 } 11765 }
10899 temp.back().append(" then"s + nll(branch)); 11766 temp.back().append(" then"s + nl(branch));
10900 pushScope(); 11767 pushScope();
10901 transform_plain_body(branch->body, temp, usage, assignList); 11768 transform_plain_body(branch->body, temp, usage, assignList);
10902 popScope(); 11769 popScope();
@@ -10904,7 +11771,7 @@ private:
10904 } 11771 }
10905 if (switchNode->lastBranch) { 11772 if (switchNode->lastBranch) {
10906 if (!firstBranch) { 11773 if (!firstBranch) {
10907 temp.push_back(indent() + "else"s + nll(switchNode->lastBranch)); 11774 temp.push_back(indent() + "else"s + nl(switchNode->lastBranch));
10908 pushScope(); 11775 pushScope();
10909 } else { 11776 } else {
10910 addScope--; 11777 addScope--;
@@ -10914,20 +11781,20 @@ private:
10914 } 11781 }
10915 while (addScope > 0) { 11782 while (addScope > 0) {
10916 addScope--; 11783 addScope--;
10917 temp.push_back(indent() + "end"s + nlr(switchNode)); 11784 temp.push_back(indent() + "end"s + nl(switchNode));
10918 popScope(); 11785 popScope();
10919 } 11786 }
10920 temp.push_back(indent() + "end"s + nlr(switchNode)); 11787 temp.push_back(indent() + "end"s + nl(switchNode));
10921 if (usage == ExpUsage::Closure) { 11788 if (usage == ExpUsage::Closure) {
10922 popFunctionScope(); 11789 popFunctionScope();
10923 popScope(); 11790 popScope();
10924 *funcStart = anonFuncStart() + nll(switchNode); 11791 *funcStart = anonFuncStart() + nl(switchNode);
10925 temp.push_back(indent() + anonFuncEnd()); 11792 temp.push_back(indent() + anonFuncEnd());
10926 popAnonVarArg(); 11793 popAnonVarArg();
10927 } 11794 }
10928 if (extraScope) { 11795 if (extraScope) {
10929 popScope(); 11796 popScope();
10930 temp.push_back(indent() + "end"s + nlr(switchNode)); 11797 temp.push_back(indent() + "end"s + nl(switchNode));
10931 } 11798 }
10932 out.push_back(join(temp)); 11799 out.push_back(join(temp));
10933 } 11800 }
@@ -10946,7 +11813,7 @@ private:
10946 } 11813 }
10947 auto preDefine = toLocalDecl(defs); 11814 auto preDefine = toLocalDecl(defs);
10948 if (!preDefine.empty()) { 11815 if (!preDefine.empty()) {
10949 out.push_back(preDefine + nll(local)); 11816 out.push_back(preDefine + nl(local));
10950 } 11817 }
10951 } 11818 }
10952 } 11819 }
@@ -11151,7 +12018,7 @@ private:
11151 } 12018 }
11152 str_list temp; 12019 str_list temp;
11153 if (localAttrib->forceLocal) { 12020 if (localAttrib->forceLocal) {
11154 temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x)); 12021 temp.push_back(indent() + "local "s + join(vars, ", "sv) + nl(x));
11155 } 12022 }
11156 transformAssignment(assignment, temp); 12023 transformAssignment(assignment, temp);
11157 for (const auto& name : vars) { 12024 for (const auto& name : vars) {
@@ -11197,13 +12064,13 @@ private:
11197 auto rit = items.begin(); 12064 auto rit = items.begin();
11198 str_list tmp; 12065 str_list tmp;
11199 while (lit != vars.end()) { 12066 while (lit != vars.end()) {
11200 tmp.push_back(indent() + "local "s + *lit + (target >= 504 ? " <close> = "s : " = "s) + *rit + nll(x)); 12067 tmp.push_back(indent() + "local "s + *lit + (target >= 504 ? " <close> = "s : " = "s) + *rit + nl(x));
11201 lit++; 12068 lit++;
11202 rit++; 12069 rit++;
11203 } 12070 }
11204 temp.push_back(join(tmp)); 12071 temp.push_back(join(tmp));
11205 } else { 12072 } else {
11206 temp.push_back(indent() + "local "s + join(vars, ", "sv) + " = "s + join(items, ", "sv) + nll(x)); 12073 temp.push_back(indent() + "local "s + join(vars, ", "sv) + " = "s + join(items, ", "sv) + nl(x));
11207 str_list leftVars; 12074 str_list leftVars;
11208 pushScope(); 12075 pushScope();
11209 for (size_t i = 0; i < vars.size(); i++) { 12076 for (size_t i = 0; i < vars.size(); i++) {
@@ -11224,7 +12091,7 @@ private:
11224 for (auto item : assignA->values.objects()) { 12091 for (auto item : assignA->values.objects()) {
11225 transformAssignItem(item, items); 12092 transformAssignItem(item, items);
11226 } 12093 }
11227 temp.push_back(indent() + "local "s + join(leftVars, ", "sv) + " = "s + join(items, ", "sv) + nll(x)); 12094 temp.push_back(indent() + "local "s + join(leftVars, ", "sv) + " = "s + join(items, ", "sv) + nl(x));
11228 } 12095 }
11229 for (const auto& var : vars) { 12096 for (const auto& var : vars) {
11230 markVarLocalConst(var); 12097 markVarLocalConst(var);
@@ -11249,7 +12116,7 @@ private:
11249 vars.push_back(item.targetVar); 12116 vars.push_back(item.targetVar);
11250 } 12117 }
11251 } 12118 }
11252 temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x)); 12119 temp.push_back(indent() + "local "s + join(vars, ", "sv) + nl(x));
11253 transformAssignment(assignment, temp); 12120 transformAssignment(assignment, temp);
11254 for (const auto& name : vars) { 12121 for (const auto& name : vars) {
11255 markVarLocalConst(name); 12122 markVarLocalConst(name);
@@ -11270,7 +12137,7 @@ private:
11270 auto assignment = assignmentFrom(exp, breakLoop->value, breakLoop); 12137 auto assignment = assignmentFrom(exp, breakLoop->value, breakLoop);
11271 transformAssignment(assignment, out); 12138 transformAssignment(assignment, out);
11272 } 12139 }
11273 out.push_back(indent() + keyword + nll(breakLoop)); 12140 out.push_back(indent() + keyword + nl(breakLoop));
11274 return; 12141 return;
11275 } 12142 }
11276 if (_continueVars.empty()) throw CompileError("continue is not inside a loop"sv, breakLoop); 12143 if (_continueVars.empty()) throw CompileError("continue is not inside a loop"sv, breakLoop);
@@ -11283,8 +12150,8 @@ private:
11283 if (!temp.empty()) { 12150 if (!temp.empty()) {
11284 _buf << temp.back(); 12151 _buf << temp.back();
11285 } 12152 }
11286 _buf << indent() << item.var << " = true"sv << nll(breakLoop); 12153 _buf << indent() << item.var << " = true"sv << nl(breakLoop);
11287 _buf << indent() << "break"sv << nll(breakLoop); 12154 _buf << indent() << "break"sv << nl(breakLoop);
11288 out.push_back(clearBuf()); 12155 out.push_back(clearBuf());
11289 } else { 12156 } else {
11290 transformGoto(toAst<Goto_t>("goto "s + item.var, breakLoop), temp); 12157 transformGoto(toAst<Goto_t>("goto "s + item.var, breakLoop), temp);
@@ -11296,7 +12163,7 @@ private:
11296 if (getLuaTarget(label) < 502) { 12163 if (getLuaTarget(label) < 502) {
11297 throw CompileError("label statement is not available when not targeting Lua version 5.2 or higher"sv, label); 12164 throw CompileError("label statement is not available when not targeting Lua version 5.2 or higher"sv, label);
11298 } 12165 }
11299 auto labelStr = unicodeVariableFrom(label->label->name); 12166 auto labelStr = unicodeVariableFrom(label->label);
11300 int currentScope = _gotoScopes.top(); 12167 int currentScope = _gotoScopes.top();
11301 if (static_cast<int>(_labels.size()) <= currentScope) { 12168 if (static_cast<int>(_labels.size()) <= currentScope) {
11302 _labels.resize(currentScope + 1, std::nullopt); 12169 _labels.resize(currentScope + 1, std::nullopt);
@@ -11310,16 +12177,16 @@ private:
11310 throw CompileError("label '"s + labelStr + "' already defined at line "s + std::to_string(it->second.line), label); 12177 throw CompileError("label '"s + labelStr + "' already defined at line "s + std::to_string(it->second.line), label);
11311 } 12178 }
11312 scope[labelStr] = {label->m_begin.m_line, static_cast<int>(_scopes.size())}; 12179 scope[labelStr] = {label->m_begin.m_line, static_cast<int>(_scopes.size())};
11313 out.push_back(indent() + "::"s + labelStr + "::"s + nll(label)); 12180 out.push_back(indent() + "::"s + labelStr + "::"s + nl(label));
11314 } 12181 }
11315 12182
11316 void transformGoto(Goto_t* gotoNode, str_list& out) { 12183 void transformGoto(Goto_t* gotoNode, str_list& out) {
11317 if (getLuaTarget(gotoNode) < 502) { 12184 if (getLuaTarget(gotoNode) < 502) {
11318 throw CompileError("goto statement is not available when not targeting Lua version 5.2 or higher"sv, gotoNode); 12185 throw CompileError("goto statement is not available when not targeting Lua version 5.2 or higher"sv, gotoNode);
11319 } 12186 }
11320 auto labelStr = unicodeVariableFrom(gotoNode->label->name); 12187 auto labelStr = unicodeVariableFrom(gotoNode->label);
11321 gotos.push_back({gotoNode, labelStr, _gotoScopes.top(), static_cast<int>(_scopes.size())}); 12188 gotos.push_back({gotoNode, labelStr, _gotoScopes.top(), static_cast<int>(_scopes.size())});
11322 out.push_back(indent() + "goto "s + labelStr + nll(gotoNode)); 12189 out.push_back(indent() + "goto "s + labelStr + nl(gotoNode));
11323 } 12190 }
11324 12191
11325 void transformShortTabAppending(ShortTabAppending_t* tab, str_list& out) { 12192 void transformShortTabAppending(ShortTabAppending_t* tab, str_list& out) {
@@ -11383,13 +12250,13 @@ private:
11383 temp.push_back(getPreDefineLine(assignment)); 12250 temp.push_back(getPreDefineLine(assignment));
11384 } 12251 }
11385 assignments.push_front(assignmentFrom(newValue, value, value)); 12252 assignments.push_front(assignmentFrom(newValue, value, value));
11386 temp.push_back(indent() + "do"s + nll(x)); 12253 temp.push_back(indent() + "do"s + nl(x));
11387 pushScope(); 12254 pushScope();
11388 for (auto item : assignments.objects()) { 12255 for (auto item : assignments.objects()) {
11389 transformAssignment(static_cast<ExpListAssign_t*>(item), temp); 12256 transformAssignment(static_cast<ExpListAssign_t*>(item), temp);
11390 } 12257 }
11391 popScope(); 12258 popScope();
11392 temp.push_back(indent() + "end"s + nll(x)); 12259 temp.push_back(indent() + "end"s + nl(x));
11393 out.push_back(join(temp)); 12260 out.push_back(join(temp));
11394 } 12261 }
11395}; 12262};
diff --git a/src/yuescript/yue_compiler.h b/src/yuescript/yue_compiler.h
index d352636..eb5fb16 100644
--- a/src/yuescript/yue_compiler.h
+++ b/src/yuescript/yue_compiler.h
@@ -1,4 +1,4 @@
1/* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> 1/* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com>
2 2
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 cd1fd48..1dfe978 100644
--- a/src/yuescript/yue_parser.cpp
+++ b/src/yuescript/yue_parser.cpp
@@ -1,4 +1,4 @@
1/* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> 1/* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com>
2 2
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 123
106 invalid_interpolation_error = pl::user(true_(), [](const item_t& item) { 124 empty_block_error = expect_error(
107 throw ParserError("invalid string interpolation"sv, item.begin); 125 "expected a valid statement or indented block"sv
108 return false; 126 );
109 }); 127 export_expression_error = expect_error(
110 128 "invalid export expression"sv
111 confusing_unary_not_error = pl::user(true_(), [](const item_t& item) { 129 );
112 throw ParserError("deprecated use for unary operator 'not' to be here"sv, item.begin); 130 invalid_interpolation_error = expect_error(
113 return false; 131 "invalid string interpolation"sv
114 }); 132 );
115 133 confusing_unary_not_error = expect_error(
116 table_key_pair_error = pl::user(true_(), [](const item_t& item) { 134 "deprecated use for unary operator 'not' to be here"sv
117 throw ParserError("can not put hash pair in a list"sv, item.begin); 135 );
118 return false; 136 table_key_pair_error = expect_error(
119 }); 137 "can not put hash pair in a list"sv
120 138 );
121 if_assignment_syntax_error = pl::user(true_(), [](const item_t& item) { 139 assignment_expression_syntax_error = expect_error(
122 throw ParserError("use := for if-assignment expression"sv, item.begin); 140 "use := for assignment expression"sv
123 return false; 141 );
124 }); 142 braces_expression_error = expect_error(
143 "syntax error in brace expression"sv
144 );
145 brackets_expression_error = expect_error(
146 "unclosed bracket expression"sv
147 );
148 slice_expression_error = expect_error(
149 "syntax error in slice expression"sv
150 );
151 unclosed_single_string_error = expect_error(
152 "unclosed single-quoted string"sv
153 );
154 unclosed_double_string_error = expect_error(
155 "unclosed double-quoted string"sv
156 );
157 unclosed_lua_string_error = expect_error(
158 "unclosed Lua string"sv
159 );
160 unexpected_comma_error = expect_error(
161 "got unexpected comma"sv
162 );
163 parenthesis_error = expect_error(
164 "expected only one expression in parenthesis"sv
165 );
166 dangling_clause_error = expect_error(
167 "dangling control clause"sv
168 );
169 keyword_as_label_error = expect_error(
170 "keyword cannot be used as a label name"sv
171 );
172 vararg_position_error = expect_error(
173 "vararg '...' must be the last parameter in function argument list"sv
174 );
175 invalid_import_syntax_error = expect_error(
176 "invalid import syntax, expected `import \"X.mod\"`, `import \"X.mod\" as {:name}`, `from mod import name` or `import mod.name`"sv
177 );
178 invalid_import_as_syntax_error = expect_error(
179 "invalid import syntax, expected `import \"X.mod\" as modname` or `import \"X.mod\" as {:name}`"sv
180 );
181 expected_expression_error = expect_error(
182 "expected valid expression"sv
183 );
184 invalid_from_import_error = expect_error(
185 "invalid import syntax, expected `from \"X.mod\" import name` or `from mod import name`"sv
186 );
187 invalid_export_syntax_error = expect_error(
188 "invalid export syntax, expected `export item`, `export item = x`, `export.item = x` or `export default item`"sv
189 );
190 invalid_macro_definition_error = expect_error(
191 "invalid macro definition, expected `macro Name = -> body` or `macro Name = $Name(...)`"sv
192 );
193 invalid_global_declaration_error = expect_error(
194 "invalid global declaration, expected `global name`, `global name = ...`, `global *`, `global ^` or `global class ...`"sv
195 );
196 invalid_local_declaration_error = expect_error(
197 "invalid local declaration, expected `local name`, `local name = ...`, `local *` or `local ^`"sv
198 );
199 invalid_with_syntax_error = expect_error(
200 "invalid 'with' statement"sv
201 );
202 invalid_try_syntax_error = expect_error(
203 "invalid 'try' expression, expected `try expr` or `try block` optionally followed by `catch err` with a handling block"sv
204 );
205 keyword_as_identifier_syntax_error = expect_error(
206 "can not use keyword as identifier"sv
207 );
208 invalid_number_literal_error = expect_error(
209 "invalid numeric literal"sv
210 );
211 invalid_import_literal_error = expect_error(
212 "invalid import path literal, expected a dotted path like X.Y.Z"sv
213 );
214 expected_indentifier_error = expect_error(
215 "expected valid identifer"sv
216 );
125 217
126 #define ensure(patt, finally) ((patt) >> (finally) | (finally) >> cut) 218 #define ensure(patt, finally) ((patt) >> (finally) | (finally) >> cut)
127 219
@@ -162,6 +254,13 @@ YueParser::YueParser() {
162 ) \ 254 ) \
163 ) 255 )
164 256
257 #define disable_until_rule(patt) ( \
258 disable_until >> ( \
259 (patt) >> enable_until | \
260 enable_until >> cut \
261 ) \
262 )
263
165 #define body_with(str) ( \ 264 #define body_with(str) ( \
166 key(str) >> space >> (in_block | Statement) | \ 265 key(str) >> space >> (in_block | Statement) | \
167 in_block | \ 266 in_block | \
@@ -194,20 +293,6 @@ YueParser::YueParser() {
194 return isValid; 293 return isValid;
195 }); 294 });
196 295
197 LabelName = pl::user(UnicodeName, [](const item_t& item) {
198 State* st = reinterpret_cast<State*>(item.user_data);
199 for (auto it = item.begin->m_it; it != item.end->m_it; ++it) {
200 if (*it > 255) {
201 st->buffer.clear();
202 return true;
203 }
204 st->buffer += static_cast<char>(*it);
205 }
206 auto isValid = LuaKeywords.find(st->buffer) == LuaKeywords.end();
207 st->buffer.clear();
208 return isValid;
209 });
210
211 LuaKeyword = pl::user(Name, [](const item_t& item) { 296 LuaKeyword = pl::user(Name, [](const item_t& item) {
212 State* st = reinterpret_cast<State*>(item.user_data); 297 State* st = reinterpret_cast<State*>(item.user_data);
213 for (auto it = item.begin->m_it; it != item.end->m_it; ++it) st->buffer += static_cast<char>(*it); 298 for (auto it = item.begin->m_it; it != item.end->m_it; ++it) st->buffer += static_cast<char>(*it);
@@ -223,29 +308,46 @@ YueParser::YueParser() {
223 308
224 SelfItem = SelfClassName | SelfClass | SelfName | Self; 309 SelfItem = SelfClassName | SelfClass | SelfName | Self;
225 KeyName = SelfItem | Name | UnicodeName; 310 KeyName = SelfItem | Name | UnicodeName;
311 VarArgDef = "..." >> -(space >> Variable);
226 VarArg = "..."; 312 VarArg = "...";
227 313
228 check_indent = pl::user(plain_space, [](const item_t& item) { 314 auto getIndent = [](const item_t& item) -> int {
315 if (item.begin->m_it == item.end->m_it) return 0;
316 State* st = reinterpret_cast<State*>(item.user_data);
317 bool useTab = false;
318 if (st->useTab) {
319 useTab = st->useTab.value();
320 } else {
321 useTab = *item.begin->m_it == '\t';
322 st->useTab = useTab;
323 }
229 int indent = 0; 324 int indent = 0;
230 for (input_it i = item.begin->m_it; i != item.end->m_it; ++i) { 325 if (useTab) {
231 switch (*i) { 326 for (input_it i = item.begin->m_it; i != item.end->m_it; ++i) {
232 case ' ': indent++; break; 327 switch (*i) {
233 case '\t': indent += 4; break; 328 case '\t': indent += 4; break;
329 default: RaiseErrorI("can not mix the use of tabs and spaces as indents"sv, item); break;
330 }
331 }
332 } else {
333 for (input_it i = item.begin->m_it; i != item.end->m_it; ++i) {
334 switch (*i) {
335 case ' ': indent++; break;
336 default: RaiseErrorI("can not mix the use of tabs and spaces as indents"sv, item); break;
337 }
234 } 338 }
235 } 339 }
340 return indent;
341 };
342
343 check_indent = pl::user(plain_space, [getIndent](const item_t& item) {
236 State* st = reinterpret_cast<State*>(item.user_data); 344 State* st = reinterpret_cast<State*>(item.user_data);
237 return st->indents.top() == indent; 345 return st->indents.top() == getIndent(item);
238 }); 346 });
239 check_indent_match = and_(check_indent); 347 check_indent_match = and_(check_indent);
240 348
241 advance = pl::user(plain_space, [](const item_t& item) { 349 advance = pl::user(plain_space, [getIndent](const item_t& item) {
242 int indent = 0; 350 int indent = getIndent(item);
243 for (input_it i = item.begin->m_it; i != item.end->m_it; ++i) {
244 switch (*i) {
245 case ' ': indent++; break;
246 case '\t': indent += 4; break;
247 }
248 }
249 State* st = reinterpret_cast<State*>(item.user_data); 351 State* st = reinterpret_cast<State*>(item.user_data);
250 int top = st->indents.top(); 352 int top = st->indents.top();
251 if (top != -1 && indent > top) { 353 if (top != -1 && indent > top) {
@@ -265,6 +367,12 @@ YueParser::YueParser() {
265 } 367 }
266 } 368 }
267 State* st = reinterpret_cast<State*>(item.user_data); 369 State* st = reinterpret_cast<State*>(item.user_data);
370 if (st->indents.empty()) {
371 RaiseError("unknown indent level"sv, item);
372 }
373 if (st->indents.top() > indent) {
374 RaiseError("unexpected dedent"sv, item);
375 }
268 st->indents.push(indent); 376 st->indents.push(indent);
269 return true; 377 return true;
270 }); 378 });
@@ -285,31 +393,41 @@ YueParser::YueParser() {
285 in_block = space_break >> *(*set(" \t") >> line_break) >> advance_match >> ensure(Block, pop_indent); 393 in_block = space_break >> *(*set(" \t") >> line_break) >> advance_match >> ensure(Block, pop_indent);
286 394
287 LocalFlag = expr('*') | '^'; 395 LocalFlag = expr('*') | '^';
288 LocalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpListLow)); 396 LocalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpListLow | expected_expression_error));
289 Local = key("local") >> space >> (LocalFlag | LocalValues); 397 Local = key("local") >> space >> (LocalFlag | LocalValues | invalid_local_declaration_error);
290 398
291 ConstAttrib = key("const"); 399 ConstAttrib = key("const");
292 CloseAttrib = key("close"); 400 CloseAttrib = key("close");
293 local_const_item = Variable | SimpleTable | TableLit | Comprehension; 401 local_const_item = Variable | SimpleTable | TableLit | Comprehension;
294 LocalAttrib = ( 402 LocalAttrib = (
295 ConstAttrib >> Seperator >> space >> local_const_item >> *(space >> ',' >> space >> local_const_item) | 403 ConstAttrib >> Seperator >> space >> local_const_item >> *(space >> ',' >> space >> local_const_item) |
296 CloseAttrib >> Seperator >> space >> Variable >> *(space >> ',' >> space >> Variable) 404 CloseAttrib >> Seperator >> space >> must_variable >> *(space >> ',' >> space >> must_variable)
297 ) >> space >> Assign; 405 ) >> space >> Assign;
298 406
299 ColonImportName = '\\' >> space >> Variable; 407 ColonImportName = '\\' >> must_variable;
300 import_name = ColonImportName | Variable; 408 import_name = not_(key("from")) >> (ColonImportName | must_variable);
301 import_name_list = Seperator >> *space_break >> space >> import_name >> *((+space_break | space >> ',' >> *space_break) >> space >> import_name); 409 import_name_list = Seperator >> *space_break >> space >> import_name >> *(
302 ImportFrom = import_name_list >> *space_break >> space >> key("from") >> space >> (ImportLiteral | not_(String) >> Exp); 410 (+space_break | space >> ',' >> *space_break) >> space >> import_name
303 from_import_name_list_line = import_name >> *(space >> ',' >> space >> import_name); 411 );
412 ImportFrom = import_name_list >> *space_break >> space >> key("from") >> space >> (ImportLiteral | not_(String) >> must_exp);
413 from_import_name_list_line = import_name >> *(space >> ',' >> space >> not_(line_break) >> import_name);
304 from_import_name_in_block = +space_break >> advance_match >> ensure(space >> from_import_name_list_line >> *(-(space >> ',') >> +space_break >> check_indent_match >> space >> from_import_name_list_line), pop_indent); 414 from_import_name_in_block = +space_break >> advance_match >> ensure(space >> from_import_name_list_line >> *(-(space >> ',') >> +space_break >> check_indent_match >> space >> from_import_name_list_line), pop_indent);
305 FromImport = key("from") >> space >> (ImportLiteral | not_(String) >> Exp) >> *space_break >> space >> key("import") >> space >> Seperator >> (from_import_name_list_line >> -(space >> ',') >> -from_import_name_in_block | from_import_name_in_block); 415 FromImport = key("from") >> space >> (
416 ImportLiteral | not_(String) >> Exp | invalid_from_import_error
417 ) >> *space_break >> space >> (
418 key("import") | invalid_from_import_error
419 ) >> space >> Seperator >> (
420 from_import_name_in_block |
421 from_import_name_list_line >> -(space >> ',') >> -from_import_name_in_block |
422 invalid_from_import_error
423 );
306 424
307 ImportLiteralInner = (range('a', 'z') | range('A', 'Z') | set("_-") | larger(255)) >> *(alpha_num | '-' | larger(255)); 425 ImportLiteralInner = (range('a', 'z') | range('A', 'Z') | set("_-") | larger(255)) >> *(alpha_num | '-' | larger(255));
308 import_literal_chain = Seperator >> ImportLiteralInner >> *('.' >> ImportLiteralInner); 426 import_literal_chain = Seperator >> ImportLiteralInner >> *('.' >> ImportLiteralInner);
309 ImportLiteral = ( 427 ImportLiteral = (
310 '\'' >> import_literal_chain >> '\'' 428 '\'' >> import_literal_chain >> -(not_('\'') >> invalid_import_literal_error) >> '\''
311 ) | ( 429 ) | (
312 '"' >> import_literal_chain >> '"' 430 '"' >> import_literal_chain >> -(not_('"') >> invalid_import_literal_error) >> '"'
313 ); 431 );
314 432
315 MacroNamePair = MacroName >> ':' >> space >> MacroName; 433 MacroNamePair = MacroName >> ':' >> space >> MacroName;
@@ -325,7 +443,7 @@ YueParser::YueParser() {
325 Exp; 443 Exp;
326 import_tab_list = import_tab_item >> *(space >> ',' >> space >> import_tab_item); 444 import_tab_list = import_tab_item >> *(space >> ',' >> space >> import_tab_item);
327 import_tab_line = ( 445 import_tab_line = (
328 push_indent_match >> (space >> import_tab_list >> pop_indent | pop_indent) 446 push_indent_match >> ensure(space >> import_tab_list, pop_indent)
329 ) | space; 447 ) | space;
330 import_tab_lines = space_break >> import_tab_line >> *(-(space >> ',') >> space_break >> import_tab_line) >> -(space >> ','); 448 import_tab_lines = space_break >> import_tab_line >> *(-(space >> ',') >> space_break >> import_tab_line) >> -(space >> ',');
331 import_tab_key_value = key_value | ':' >> MacroName | MacroNamePair | ImportAllMacro; 449 import_tab_key_value = key_value | ':' >> MacroName | MacroNamePair | ImportAllMacro;
@@ -335,18 +453,22 @@ YueParser::YueParser() {
335 -(space >> ',') >> 453 -(space >> ',') >>
336 -import_tab_lines >> 454 -import_tab_lines >>
337 white >> 455 white >>
338 '}' 456 end_braces_expression
339 ) | ( 457 ) | (
340 Seperator >> import_tab_key_value >> *(space >> ',' >> space >> import_tab_key_value) 458 Seperator >> import_tab_key_value >> *(space >> ',' >> space >> import_tab_key_value)
341 ); 459 );
342 460
343 ImportAs = ImportLiteral >> -(space >> key("as") >> space >> (ImportTabLit | Variable | ImportAllMacro)); 461 ImportAs = ImportLiteral >> -(space >> key("as") >> space >> (
462 ImportTabLit | Variable | ImportAllMacro | invalid_import_as_syntax_error
463 ));
464
465 ImportGlobal = Seperator >> UnicodeName >> *('.' >> UnicodeName) >> space >> not_(',' | key("from")) >> -(key("as") >> space >> must_variable);
344 466
345 Import = key("import") >> space >> (ImportAs | ImportFrom) | FromImport; 467 Import = key("import") >> space >> (ImportGlobal | ImportAs | ImportFrom | invalid_import_syntax_error) | FromImport;
346 468
347 Label = "::" >> LabelName >> "::"; 469 Label = "::" >> (and_(LuaKeyword >> "::") >> keyword_as_label_error | UnicodeName >> "::");
348 470
349 Goto = key("goto") >> space >> LabelName; 471 Goto = key("goto") >> space >> (and_(LuaKeyword >> not_alpha_num) >> keyword_as_label_error | UnicodeName);
350 472
351 ShortTabAppending = "[]" >> space >> Assign; 473 ShortTabAppending = "[]" >> space >> Assign;
352 474
@@ -356,9 +478,14 @@ YueParser::YueParser() {
356 478
357 Return = key("return") >> -(space >> (TableBlock | ExpListLow)); 479 Return = key("return") >> -(space >> (TableBlock | ExpListLow));
358 480
359 with_exp = ExpList >> -(space >> Assign); 481 must_exp = Exp | expected_expression_error;
360 482
361 With = key("with") >> -ExistentialOp >> space >> disable_do_chain_arg_table_block_rule(with_exp) >> space >> body_with("do"); 483 with_exp = ExpList >> -(space >> (':' >> Assign | and_('=') >> assignment_expression_syntax_error)) | expected_expression_error;
484
485 With = key("with") >> -ExistentialOp >> space >> (
486 disable_do_chain_arg_table_block_rule(with_exp) >> space >> body_with("do") |
487 invalid_with_syntax_error
488 );
362 SwitchCase = key("when") >> space >> disable_chain_rule(disable_arg_table_block_rule(SwitchList)) >> space >> body_with("then"); 489 SwitchCase = key("when") >> space >> disable_chain_rule(disable_arg_table_block_rule(SwitchList)) >> space >> body_with("then");
363 switch_else = key("else") >> space >> body; 490 switch_else = key("else") >> space >> body;
364 491
@@ -370,9 +497,11 @@ YueParser::YueParser() {
370 497
371 SwitchList = Seperator >> ( 498 SwitchList = Seperator >> (
372 and_(SimpleTable | TableLit) >> Exp | 499 and_(SimpleTable | TableLit) >> Exp |
373 exp_not_tab >> *(space >> ',' >> space >> exp_not_tab) 500 exp_not_tab >> *(space >> ',' >> space >> exp_not_tab) |
501 expected_expression_error
374 ); 502 );
375 Switch = key("switch") >> space >> Exp >> 503 Switch = key("switch") >> space >>
504 must_exp >> -(space >> Assignment) >>
376 space >> Seperator >> ( 505 space >> Seperator >> (
377 SwitchCase >> space >> ( 506 SwitchCase >> space >> (
378 switch_block | 507 switch_block |
@@ -381,45 +510,53 @@ YueParser::YueParser() {
381 +space_break >> advance_match >> space >> SwitchCase >> switch_block >> pop_indent 510 +space_break >> advance_match >> space >> SwitchCase >> switch_block >> pop_indent
382 ); 511 );
383 512
384 Assignment = -(',' >> space >> ExpList >> space) >> (':' >> Assign | and_('=') >> if_assignment_syntax_error); 513 Assignment = -(',' >> space >> ExpList >> space) >> (':' >> Assign | and_('=') >> assignment_expression_syntax_error);
385 IfCond = disable_chain_rule(disable_arg_table_block_rule(Exp >> -(space >> Assignment))); 514 IfCond = disable_chain_rule(disable_arg_table_block_rule(Exp >> -(space >> Assignment))) | expected_expression_error;
386 if_else_if = -(line_break >> *space_break >> check_indent_match) >> space >> key("elseif") >> space >> IfCond >> space >> body_with("then"); 515 if_else_if = -(line_break >> *space_break >> check_indent_match) >> space >> key("elseif") >> space >> IfCond >> space >> body_with("then");
387 if_else = -(line_break >> *space_break >> check_indent_match) >> space >> key("else") >> space >> body; 516 if_else = -(line_break >> *space_break >> check_indent_match) >> space >> key("else") >> space >> body;
388 IfType = (expr("if") | "unless") >> not_alpha_num; 517 IfType = (expr("if") | "unless") >> not_alpha_num;
389 If = IfType >> space >> IfCond >> space >> opt_body_with("then") >> *if_else_if >> -if_else; 518 If = IfType >> space >> IfCond >> space >> opt_body_with("then") >> *if_else_if >> -if_else;
390 519
391 WhileType = (expr("while") | "until") >> not_alpha_num; 520 WhileType = (expr("while") | pl::user("until", [](const item_t& item) {
392 While = WhileType >> space >> disable_do_chain_arg_table_block_rule(Exp >> -(space >> Assignment)) >> space >> opt_body_with("do"); 521 State* st = reinterpret_cast<State*>(item.user_data);
393 Repeat = key("repeat") >> space >> Body >> line_break >> *space_break >> check_indent_match >> space >> key("until") >> space >> Exp; 522 return st->noUntilStack.empty() || !st->noUntilStack.back();
523 })) >> not_alpha_num;
524 While = key(WhileType) >> space >> (disable_do_chain_arg_table_block_rule(Exp >> -(space >> Assignment)) | expected_expression_error) >> space >> opt_body_with("do");
525 Repeat = key("repeat") >> space >> (
526 in_block >> line_break >> *space_break >> check_indent_match |
527 disable_until_rule(Statement)
528 ) >> space >> key("until") >> space >> must_exp;
394 529
395 for_key = pl::user(key("for"), [](const item_t& item) { 530 for_key = pl::user(key("for"), [](const item_t& item) {
396 State* st = reinterpret_cast<State*>(item.user_data); 531 State* st = reinterpret_cast<State*>(item.user_data);
397 return st->noForStack.empty() || !st->noForStack.top(); 532 return st->noForStack.empty() || !st->noForStack.back();
398 }); 533 });
399 ForStepValue = ',' >> space >> Exp; 534 ForStepValue = ',' >> space >> must_exp;
400 for_args = Variable >> space >> '=' >> space >> Exp >> space >> ',' >> space >> Exp >> space >> -ForStepValue; 535 for_args = Variable >> space >> '=' >> space >> must_exp >> space >> ',' >> space >> must_exp >> space >> -ForStepValue;
401 536
402 For = for_key >> space >> disable_do_chain_arg_table_block_rule(for_args) >> space >> opt_body_with("do"); 537 ForNum = disable_do_chain_arg_table_block_rule(for_args) >> space >> opt_body_with("do");
403 538
404 for_in = StarExp | ExpList; 539 for_in = StarExp | ExpList | expected_expression_error;
405 540
406 ForEach = for_key >> space >> AssignableNameList >> space >> key("in") >> space >> 541 ForEach = AssignableNameList >> space >> key("in") >> space >>
407 disable_do_chain_arg_table_block_rule(for_in) >> space >> opt_body_with("do"); 542 disable_do_chain_arg_table_block_rule(for_in) >> space >> opt_body_with("do");
408 543
544 For = for_key >> space >> (ForNum | ForEach);
545
409 Do = pl::user(key("do"), [](const item_t& item) { 546 Do = pl::user(key("do"), [](const item_t& item) {
410 State* st = reinterpret_cast<State*>(item.user_data); 547 State* st = reinterpret_cast<State*>(item.user_data);
411 return st->noDoStack.empty() || !st->noDoStack.top(); 548 return st->noDoStack.empty() || !st->noDoStack.back();
412 }) >> space >> Body; 549 }) >> space >> Body;
413 550
414 disable_do = pl::user(true_(), [](const item_t& item) { 551 disable_do = pl::user(true_(), [](const item_t& item) {
415 State* st = reinterpret_cast<State*>(item.user_data); 552 State* st = reinterpret_cast<State*>(item.user_data);
416 st->noDoStack.push(true); 553 st->noDoStack.push_back(true);
417 return true; 554 return true;
418 }); 555 });
419 556
420 enable_do = pl::user(true_(), [](const item_t& item) { 557 enable_do = pl::user(true_(), [](const item_t& item) {
421 State* st = reinterpret_cast<State*>(item.user_data); 558 State* st = reinterpret_cast<State*>(item.user_data);
422 st->noDoStack.pop(); 559 st->noDoStack.pop_back();
423 return true; 560 return true;
424 }); 561 });
425 562
@@ -437,46 +574,58 @@ YueParser::YueParser() {
437 574
438 disable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) { 575 disable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) {
439 State* st = reinterpret_cast<State*>(item.user_data); 576 State* st = reinterpret_cast<State*>(item.user_data);
440 st->noDoStack.push(true); 577 st->noDoStack.push_back(true);
441 st->noChainBlockStack.push(true); 578 st->noChainBlockStack.push_back(true);
442 st->noTableBlockStack.push(true); 579 st->noTableBlockStack.push_back(true);
443 return true; 580 return true;
444 }); 581 });
445 582
446 enable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) { 583 enable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) {
447 State* st = reinterpret_cast<State*>(item.user_data); 584 State* st = reinterpret_cast<State*>(item.user_data);
448 st->noDoStack.pop(); 585 st->noDoStack.pop_back();
449 st->noChainBlockStack.pop(); 586 st->noChainBlockStack.pop_back();
450 st->noTableBlockStack.pop(); 587 st->noTableBlockStack.pop_back();
451 return true; 588 return true;
452 }); 589 });
453 590
454 disable_arg_table_block = pl::user(true_(), [](const item_t& item) { 591 disable_arg_table_block = pl::user(true_(), [](const item_t& item) {
455 State* st = reinterpret_cast<State*>(item.user_data); 592 State* st = reinterpret_cast<State*>(item.user_data);
456 st->noTableBlockStack.push(true); 593 st->noTableBlockStack.push_back(true);
457 return true; 594 return true;
458 }); 595 });
459 596
460 enable_arg_table_block = pl::user(true_(), [](const item_t& item) { 597 enable_arg_table_block = pl::user(true_(), [](const item_t& item) {
461 State* st = reinterpret_cast<State*>(item.user_data); 598 State* st = reinterpret_cast<State*>(item.user_data);
462 st->noTableBlockStack.pop(); 599 st->noTableBlockStack.pop_back();
463 return true; 600 return true;
464 }); 601 });
465 602
466 disable_for = pl::user(true_(), [](const item_t& item) { 603 disable_for = pl::user(true_(), [](const item_t& item) {
467 State* st = reinterpret_cast<State*>(item.user_data); 604 State* st = reinterpret_cast<State*>(item.user_data);
468 st->noForStack.push(true); 605 st->noForStack.push_back(true);
469 return true; 606 return true;
470 }); 607 });
471 608
472 enable_for = pl::user(true_(), [](const item_t& item) { 609 enable_for = pl::user(true_(), [](const item_t& item) {
473 State* st = reinterpret_cast<State*>(item.user_data); 610 State* st = reinterpret_cast<State*>(item.user_data);
474 st->noForStack.pop(); 611 st->noForStack.pop_back();
475 return true; 612 return true;
476 }); 613 });
477 614
478 CatchBlock = line_break >> *space_break >> check_indent_match >> space >> key("catch") >> space >> Variable >> space >> in_block; 615 disable_until = pl::user(true_(), [](const item_t& item) {
479 Try = key("try") >> space >> (in_block | Exp) >> -CatchBlock; 616 State* st = reinterpret_cast<State*>(item.user_data);
617 st->noUntilStack.push_back(true);
618 return true;
619 });
620
621 enable_until = pl::user(true_(), [](const item_t& item) {
622 State* st = reinterpret_cast<State*>(item.user_data);
623 st->noUntilStack.pop_back();
624 return true;
625 });
626
627 CatchBlock = line_break >> *space_break >> check_indent_match >> space >> key("catch") >> space >> must_variable >> space >> (in_block | invalid_try_syntax_error);
628 Try = key("try") >> -ExistentialOp >> space >> (in_block | Exp | invalid_try_syntax_error) >> -CatchBlock;
480 629
481 list_value = 630 list_value =
482 and_( 631 and_(
@@ -498,28 +647,33 @@ YueParser::YueParser() {
498 647
499 list_lit_lines = +space_break >> list_lit_line >> *(-(space >> ',') >> space_break >> list_lit_line) >> -(space >> ','); 648 list_lit_lines = +space_break >> list_lit_line >> *(-(space >> ',') >> space_break >> list_lit_line) >> -(space >> ',');
500 649
650 end_brackets_expression = ']' | brackets_expression_error;
651
501 Comprehension = '[' >> not_('[') >> 652 Comprehension = '[' >> not_('[') >>
502 Seperator >> space >> ( 653 Seperator >> space >> (
503 disable_for_rule(list_value) >> space >> ( 654 disable_for_rule(list_value) >> space >> (
504 CompInner >> space >> ']' | 655 CompFor >> space >> end_brackets_expression |
505 (list_value_list >> -(space >> ',') | space >> ',') >> -list_lit_lines >> white >> ']' 656 (list_value_list >> -(space >> ',') | space >> ',') >> -list_lit_lines >> white >> end_brackets_expression
506 ) | 657 ) |
507 list_lit_lines >> white >> ']' | 658 list_lit_lines >> white >> end_brackets_expression |
508 white >> ']' >> not_(space >> '=') 659 white >> ']' >> not_(space >> '=')
509 ); 660 );
510 661
511 CompValue = ',' >> space >> Exp; 662 end_braces_expression = '}' | braces_expression_error;
512 TblComprehension = and_('{') >> ('{' >> space >> disable_for_rule(Exp >> space >> -(CompValue >> space)) >> CompInner >> space >> '}' | braces_expression_error);
513 663
514 CompInner = Seperator >> (CompForEach | CompFor) >> *(space >> comp_clause); 664 CompValue = ',' >> space >> must_exp;
515 StarExp = '*' >> space >> Exp; 665 TblComprehension = '{' >> space >> disable_for_rule(Exp >> space >> -(CompValue >> space)) >> (CompFor | braces_expression_error) >> space >> end_braces_expression;
516 CompForEach = key("for") >> space >> AssignableNameList >> space >> key("in") >> space >> (StarExp | Exp); 666
517 CompFor = key("for") >> space >> Variable >> space >> '=' >> space >> Exp >> space >> ',' >> space >> Exp >> -ForStepValue; 667 CompFor = key("for") >> space >> Seperator >> (CompForNum | CompForEach) >> *(space >> comp_clause);
518 comp_clause = CompFor | CompForEach | key("when") >> space >> Exp; 668 StarExp = '*' >> space >> must_exp;
669 CompForEach = AssignableNameList >> space >> key("in") >> space >> (StarExp | must_exp);
670 CompForNum = Variable >> space >> '=' >> space >> must_exp >> space >> ',' >> space >> must_exp >> -ForStepValue;
671 comp_clause = key("when") >> space >> must_exp | key("for") >> space >> (CompForNum | CompForEach);
519 672
520 Assign = '=' >> space >> Seperator >> ( 673 Assign = '=' >> space >> Seperator >> (
521 With | If | Switch | TableBlock | 674 With | If | Switch | TableBlock |
522 Exp >> *(space >> set(",;") >> space >> Exp) 675 (SpreadListExp | Exp) >> *(space >> set(",;") >> space >> (SpreadListExp | Exp)) |
676 expected_expression_error
523 ); 677 );
524 678
525 UpdateOp = 679 UpdateOp =
@@ -527,7 +681,7 @@ YueParser::YueParser() {
527 ">>" | "<<" | "??" | 681 ">>" | "<<" | "??" |
528 set("+-*/%&|^"); 682 set("+-*/%&|^");
529 683
530 Update = UpdateOp >> '=' >> space >> Exp; 684 Update = UpdateOp >> '=' >> space >> must_exp;
531 685
532 Assignable = AssignableChain | Variable | SelfItem; 686 Assignable = AssignableChain | Variable | SelfItem;
533 687
@@ -548,35 +702,38 @@ YueParser::YueParser() {
548 UnaryExp = *(UnaryOperator >> space) >> expo_exp >> -(space >> In); 702 UnaryExp = *(UnaryOperator >> space) >> expo_exp >> -(space >> In);
549 703
550 pipe_operator = "|>"; 704 pipe_operator = "|>";
551 pipe_value = pipe_operator >> *space_break >> space >> UnaryExp; 705 pipe_value = pipe_operator >> *space_break >> space >> must_unary_exp;
552 pipe_exp = UnaryExp >> *(space >> pipe_value); 706 pipe_exp = UnaryExp >> *(space >> pipe_value);
553 707
554 BinaryOperator = 708 BinaryOperator = (
555 key("or") | 709 key("or") |
556 key("and") | 710 key("and") |
557 "<=" | ">=" | "~=" | "!=" | "==" | 711 "<=" | ">=" | "~=" | "!=" | "==" |
558 ".." | "<<" | ">>" | "//" | 712 ".." | "<<" | ">>" | "//" |
559 set("+-*/%><|&~"); 713 set("+*/%>|&~") |
714 '-' >> not_('>') |
715 '<' >> not_('-')
716 ) >> not_('=');
560 717
561 ExpOpValue = BinaryOperator >> *space_break >> space >> pipe_exp; 718 ExpOpValue = BinaryOperator >> *space_break >> space >> (pipe_exp | expected_expression_error);
562 Exp = Seperator >> pipe_exp >> *(space >> ExpOpValue) >> -(space >> "??" >> space >> Exp); 719 Exp = Seperator >> pipe_exp >> *(space >> ExpOpValue) >> -(space >> "??" >> not_('=') >> *space_break >> space >> must_exp);
563 720
564 disable_chain = pl::user(true_(), [](const item_t& item) { 721 disable_chain = pl::user(true_(), [](const item_t& item) {
565 State* st = reinterpret_cast<State*>(item.user_data); 722 State* st = reinterpret_cast<State*>(item.user_data);
566 st->noChainBlockStack.push(true); 723 st->noChainBlockStack.push_back(true);
567 return true; 724 return true;
568 }); 725 });
569 726
570 enable_chain = pl::user(true_(), [](const item_t& item) { 727 enable_chain = pl::user(true_(), [](const item_t& item) {
571 State* st = reinterpret_cast<State*>(item.user_data); 728 State* st = reinterpret_cast<State*>(item.user_data);
572 st->noChainBlockStack.pop(); 729 st->noChainBlockStack.pop_back();
573 return true; 730 return true;
574 }); 731 });
575 732
576 chain_line = check_indent_match >> space >> (chain_dot_chain | colon_chain) >> -InvokeArgs; 733 chain_line = check_indent_match >> space >> (chain_dot_chain | colon_chain) >> -InvokeArgs;
577 chain_block = pl::user(true_(), [](const item_t& item) { 734 chain_block = pl::user(true_(), [](const item_t& item) {
578 State* st = reinterpret_cast<State*>(item.user_data); 735 State* st = reinterpret_cast<State*>(item.user_data);
579 return st->noChainBlockStack.empty() || !st->noChainBlockStack.top(); 736 return st->noChainBlockStack.empty() || !st->noChainBlockStack.back();
580 }) >> +space_break >> advance_match >> ensure( 737 }) >> +space_break >> advance_match >> ensure(
581 chain_line >> *(+space_break >> chain_line), pop_indent); 738 chain_line >> *(+space_break >> chain_line), pop_indent);
582 ChainValue = 739 ChainValue =
@@ -591,7 +748,7 @@ YueParser::YueParser() {
591 st->expLevel++; 748 st->expLevel++;
592 const int max_exp_level = 100; 749 const int max_exp_level = 100;
593 if (st->expLevel > max_exp_level) { 750 if (st->expLevel > max_exp_level) {
594 throw ParserError("nesting expressions exceeds 100 levels"sv, item.begin); 751 RaiseError("nesting expressions exceeds 100 levels"sv, item);
595 } 752 }
596 return true; 753 return true;
597 }); 754 });
@@ -606,14 +763,22 @@ YueParser::YueParser() {
606 Value = inc_exp_level >> ensure(SimpleValue | SimpleTable | ChainValue | String, dec_exp_level); 763 Value = inc_exp_level >> ensure(SimpleValue | SimpleTable | ChainValue | String, dec_exp_level);
607 764
608 single_string_inner = '\\' >> set("'\\") | not_('\'') >> any_char; 765 single_string_inner = '\\' >> set("'\\") | not_('\'') >> any_char;
609 SingleString = '\'' >> *single_string_inner >> '\''; 766 SingleString = '\'' >> *single_string_inner >> ('\'' | unclosed_single_string_error);
610 767
611 interp = "#{" >> space >> (Exp >> space >> '}' | invalid_interpolation_error); 768 interp = "#{" >> space >> (Exp >> space >> '}' | invalid_interpolation_error);
612 double_string_plain = '\\' >> set("\"\\#") | not_('"') >> any_char; 769 double_string_plain = '\\' >> set("\"\\#") | not_('"') >> any_char;
613 DoubleStringInner = +(not_("#{") >> double_string_plain); 770 DoubleStringInner = +(not_("#{") >> double_string_plain);
614 DoubleStringContent = DoubleStringInner | interp; 771 DoubleStringContent = DoubleStringInner | interp;
615 DoubleString = '"' >> Seperator >> *DoubleStringContent >> '"'; 772 DoubleString = '"' >> Seperator >> *DoubleStringContent >> ('"' | unclosed_double_string_error);
616 String = DoubleString | SingleString | LuaString; 773
774 YAMLIndent = +set(" \t");
775 YAMLLineInner = +('\\' >> set("\"\\#") | not_("#{" | stop) >> any_char);
776 YAMLLineContent = YAMLLineInner | interp;
777 YAMLLine = check_indent_match >> YAMLIndent >> +(YAMLLineContent) |
778 advance_match >> YAMLIndent >> ensure(+YAMLLineContent, pop_indent);
779 YAMLMultiline = '|' >> space >> Seperator >> +(*set(" \t") >> line_break) >> advance_match >> ensure(YAMLLine >> *(+(*set(" \t") >> line_break) >> YAMLLine), pop_indent);
780
781 String = DoubleString | SingleString | LuaString | YAMLMultiline;
617 782
618 lua_string_open = '[' >> *expr('=') >> '['; 783 lua_string_open = '[' >> *expr('=') >> '[';
619 lua_string_close = ']' >> *expr('=') >> ']'; 784 lua_string_close = ']' >> *expr('=') >> ']';
@@ -633,15 +798,15 @@ YueParser::YueParser() {
633 798
634 LuaStringContent = *(not_(LuaStringClose) >> any_char); 799 LuaStringContent = *(not_(LuaStringClose) >> any_char);
635 800
636 LuaString = LuaStringOpen >> -line_break >> LuaStringContent >> LuaStringClose; 801 LuaString = LuaStringOpen >> -line_break >> LuaStringContent >> (LuaStringClose | unclosed_lua_string_error);
637 802
638 Parens = '(' >> *space_break >> space >> Exp >> *space_break >> space >> ')'; 803 Parens = '(' >> (*space_break >> space >> Exp >> *space_break >> space >> ')' | parenthesis_error);
639 Callable = Variable | SelfItem | MacroName | Parens; 804 Callable = Variable | SelfItem | MacroName | Parens;
640 805
641 fn_args_value_list = Exp >> *(space >> ',' >> space >> Exp); 806 fn_args_value_list = Exp >> *(space >> ',' >> space >> Exp);
642 807
643 fn_args_lit_line = ( 808 fn_args_lit_line = (
644 push_indent_match >> (space >> fn_args_value_list >> pop_indent | pop_indent) 809 push_indent_match >> ensure(space >> fn_args_value_list, pop_indent)
645 ) | ( 810 ) | (
646 space 811 space
647 ); 812 );
@@ -651,14 +816,14 @@ YueParser::YueParser() {
651 fn_args = 816 fn_args =
652 '(' >> -(space >> fn_args_value_list >> -(space >> ',')) >> 817 '(' >> -(space >> fn_args_value_list >> -(space >> ',')) >>
653 -fn_args_lit_lines >> 818 -fn_args_lit_lines >>
654 white >> ')' | space >> '!' >> not_('='); 819 white >> -(and_(',') >> unexpected_comma_error) >>')' | space >> '!' >> not_('=');
655 820
656 meta_index = Name | index | String; 821 meta_index = Name | index | String;
657 Metatable = '<' >> space >> '>'; 822 Metatable = '<' >> space >> '>';
658 Metamethod = '<' >> space >> meta_index >> space >> '>'; 823 Metamethod = '<' >> space >> meta_index >> space >> '>';
659 824
660 ExistentialOp = '?' >> not_('?'); 825 ExistentialOp = '?' >> not_('?');
661 TableAppendingOp = and_('[') >> ("[]" | brackets_expression_error); 826 TableAppendingOp = and_('[') >> "[]";
662 PlainItem = +any_char; 827 PlainItem = +any_char;
663 828
664 chain_call = ( 829 chain_call = (
@@ -683,7 +848,8 @@ YueParser::YueParser() {
683 chain_with_colon = +chain_item >> -colon_chain; 848 chain_with_colon = +chain_item >> -colon_chain;
684 chain_items = chain_with_colon | colon_chain; 849 chain_items = chain_with_colon | colon_chain;
685 850
686 index = '[' >> not_('[') >> space >> Exp >> space >> ']'; 851 index = '[' >> not_('[') >> space >> (ReversedIndex >> and_(space >> ']') | Exp) >> space >> ']';
852 ReversedIndex = '#' >> space >> -('-' >> space >> Exp);
687 chain_item = 853 chain_item =
688 Invoke >> -ExistentialOp | 854 Invoke >> -ExistentialOp |
689 DotChainItem >> -ExistentialOp | 855 DotChainItem >> -ExistentialOp |
@@ -722,10 +888,8 @@ YueParser::YueParser() {
722 SpreadExp | 888 SpreadExp |
723 NormalDef; 889 NormalDef;
724 890
725 table_value_list = table_value >> *(space >> ',' >> space >> table_value);
726
727 table_lit_line = ( 891 table_lit_line = (
728 push_indent_match >> (space >> table_value_list >> pop_indent | pop_indent) 892 push_indent_match >> (space >> not_(line_break | '}') >> (table_value | expected_expression_error) >> *(space >> ',' >> space >> table_value) >> pop_indent | pop_indent)
729 ) | ( 893 ) | (
730 space 894 space
731 ); 895 );
@@ -734,13 +898,15 @@ YueParser::YueParser() {
734 898
735 TableLit = 899 TableLit =
736 '{' >> Seperator >> 900 '{' >> Seperator >>
737 -(space >> table_value_list >> -(space >> ',')) >> 901 -(space >> table_value >> *(space >> ',' >> space >> table_value) >> -(space >> ',')) >>
738 -table_lit_lines >> 902 (
739 white >> '}'; 903 table_lit_lines >> white >> end_braces_expression |
904 white >> '}'
905 );
740 906
741 table_block_inner = Seperator >> key_value_line >> *(+space_break >> key_value_line); 907 table_block_inner = Seperator >> key_value_line >> *(+space_break >> key_value_line);
742 TableBlock = +space_break >> advance_match >> ensure(table_block_inner, pop_indent); 908 TableBlock = +space_break >> advance_match >> ensure(table_block_inner, pop_indent);
743 TableBlockIndent = '*' >> Seperator >> disable_arg_table_block_rule( 909 TableBlockIndent = ('*' | '-' >> space_one) >> Seperator >> disable_arg_table_block_rule(
744 space >> key_value_list >> -(space >> ',') >> 910 space >> key_value_list >> -(space >> ',') >>
745 -(+space_break >> advance_match >> space >> ensure(key_value_list >> -(space >> ',') >> *(+space_break >> key_value_line), pop_indent))); 911 -(+space_break >> advance_match >> space >> ensure(key_value_list >> -(space >> ',') >> *(+space_break >> key_value_line), pop_indent)));
746 912
@@ -755,13 +921,18 @@ YueParser::YueParser() {
755 ClassDecl = 921 ClassDecl =
756 key("class") >> not_(':') >> disable_arg_table_block_rule( 922 key("class") >> not_(':') >> disable_arg_table_block_rule(
757 -(space >> Assignable) >> 923 -(space >> Assignable) >>
758 -(space >> key("extends") >> prevent_indent >> space >> ensure(Exp, pop_indent)) >> 924 -(space >> key("extends") >> prevent_indent >> space >> ensure(must_exp, pop_indent)) >>
759 -(space >> key("using") >> prevent_indent >> space >> ensure(ExpList, pop_indent)) 925 -(space >> key("using") >> prevent_indent >> space >> ensure(ExpList | expected_expression_error, pop_indent))
760 ) >> -ClassBlock; 926 ) >> -ClassBlock;
761 927
762 GlobalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpListLow)); 928 GlobalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpListLow | expected_expression_error));
763 GlobalOp = expr('*') | '^'; 929 GlobalOp = expr('*') | '^';
764 Global = key("global") >> space >> (-(ConstAttrib >> space) >> ClassDecl | GlobalOp | -(ConstAttrib >> space) >> GlobalValues); 930 Global = key("global") >> space >> (
931 -(ConstAttrib >> space) >> ClassDecl |
932 GlobalOp |
933 -(ConstAttrib >> space) >> GlobalValues |
934 invalid_global_declaration_error
935 );
765 936
766 ExportDefault = key("default"); 937 ExportDefault = key("default");
767 938
@@ -773,10 +944,10 @@ YueParser::YueParser() {
773 pl::user(space >> ExportDefault >> space >> Exp, [](const item_t& item) { 944 pl::user(space >> ExportDefault >> space >> Exp, [](const item_t& item) {
774 State* st = reinterpret_cast<State*>(item.user_data); 945 State* st = reinterpret_cast<State*>(item.user_data);
775 if (st->exportDefault) { 946 if (st->exportDefault) {
776 throw ParserError("export default has already been declared"sv, item.begin); 947 RaiseError("export default has already been declared"sv, item);
777 } 948 }
778 if (st->exportCount > 1) { 949 if (st->exportCount > 1) {
779 throw ParserError("there are items already being exported"sv, item.begin); 950 RaiseError("there are items already being exported"sv, item);
780 } 951 }
781 st->exportDefault = true; 952 st->exportDefault = true;
782 return true; 953 return true;
@@ -784,17 +955,17 @@ YueParser::YueParser() {
784 not_(space >> ExportDefault) >> pl::user(true_(), [](const item_t& item) { 955 not_(space >> ExportDefault) >> pl::user(true_(), [](const item_t& item) {
785 State* st = reinterpret_cast<State*>(item.user_data); 956 State* st = reinterpret_cast<State*>(item.user_data);
786 if (st->exportDefault && st->exportCount > 1) { 957 if (st->exportDefault && st->exportCount > 1) {
787 throw ParserError("can not export any more items when 'export default' is declared"sv, item.begin); 958 RaiseError("can not export any more items when 'export default' is declared"sv, item);
788 } 959 }
789 return true; 960 return true;
790 }) >> ( 961 }) >> (
791 and_(set(".[")) >> ((pl::user(and_('.' >> Metatable), [](const item_t& item) { 962 and_(set(".[")) >> ((pl::user(and_('.' >> Metatable), [](const item_t& item) {
792 State* st = reinterpret_cast<State*>(item.user_data); 963 State* st = reinterpret_cast<State*>(item.user_data);
793 if (st->exportMetatable) { 964 if (st->exportMetatable) {
794 throw ParserError("module metatable duplicated"sv, item.begin); 965 RaiseError("module metatable duplicated"sv, item);
795 } 966 }
796 if (st->exportMetamethod) { 967 if (st->exportMetamethod) {
797 throw ParserError("metatable should be exported before metamethod"sv, item.begin); 968 RaiseError("metatable should be exported before metamethod"sv, item);
798 } 969 }
799 st->exportMetatable = true; 970 st->exportMetatable = true;
800 return true; 971 return true;
@@ -809,7 +980,8 @@ YueParser::YueParser() {
809 State* st = reinterpret_cast<State*>(item.user_data); 980 State* st = reinterpret_cast<State*>(item.user_data);
810 st->exportMacro = true; 981 st->exportMacro = true;
811 return true; 982 return true;
812 }) 983 }) |
984 invalid_export_syntax_error
813 ) >> not_(space >> StatementAppendix); 985 ) >> not_(space >> StatementAppendix);
814 986
815 VariablePair = ':' >> Variable; 987 VariablePair = ':' >> Variable;
@@ -819,13 +991,13 @@ YueParser::YueParser() {
819 KeyName | 991 KeyName |
820 '[' >> not_('[') >> space >> Exp >> space >> ']' | 992 '[' >> not_('[') >> space >> Exp >> space >> ']' |
821 String 993 String
822 ) >> ':' >> not_(':') >> space >> 994 ) >> ':' >> not_(':' | '=' >> not_('>')) >> space >>
823 (Exp | TableBlock | +space_break >> space >> Exp); 995 (Exp | TableBlock | +space_break >> space >> Exp | expected_expression_error);
824 996
825 MetaVariablePair = ":<" >> space >> Variable >> space >> '>'; 997 MetaVariablePair = ":<" >> space >> must_variable >> space >> '>';
826 998
827 MetaNormalPair = '<' >> space >> -meta_index >> space >> ">:" >> space >> 999 MetaNormalPair = '<' >> space >> -meta_index >> space >> ">:" >> space >>
828 (Exp | TableBlock | +space_break >> space >> Exp); 1000 (Exp | TableBlock | +space_break >> space >> Exp | expected_expression_error);
829 1001
830 destruct_def = -(space >> '=' >> space >> Exp); 1002 destruct_def = -(space >> '=' >> space >> Exp);
831 VariablePairDef = VariablePair >> destruct_def; 1003 VariablePairDef = VariablePair >> destruct_def;
@@ -843,29 +1015,39 @@ YueParser::YueParser() {
843 key_value_line = check_indent_match >> space >> ( 1015 key_value_line = check_indent_match >> space >> (
844 key_value_list >> -(space >> ',') | 1016 key_value_list >> -(space >> ',') |
845 TableBlockIndent | 1017 TableBlockIndent |
846 '*' >> space >> (SpreadExp | Exp | TableBlock) 1018 ('*' | '-' >> space_one) >> space >> (SpreadExp | Exp | TableBlock)
847 ); 1019 );
848 1020
849 fn_arg_def_list = FnArgDef >> *(space >> ',' >> space >> FnArgDef); 1021 fn_arg_def_list = FnArgDef >> *(space >> ',' >> space >> FnArgDef);
850 1022
851 fn_arg_def_lit_line = ( 1023 fn_arg_def_lit_line = (
852 push_indent_match >> (space >> fn_arg_def_list >> pop_indent | pop_indent) 1024 push_indent_match >> ensure(space >> fn_arg_def_list, pop_indent)
853 ) | ( 1025 ) | (
854 space 1026 space
855 ); 1027 );
856 1028
857 fn_arg_def_lit_lines = fn_arg_def_lit_line >> *(-(space >> ',') >> space_break >> fn_arg_def_lit_line); 1029 fn_arg_def_lit_lines = fn_arg_def_lit_line >> *(-(space >> ',') >> space_break >> fn_arg_def_lit_line);
858 1030
859 FnArgDef = (Variable | SelfItem >> -ExistentialOp) >> -(space >> '=' >> space >> Exp); 1031 FnArgDef = (Variable | SelfItem >> -ExistentialOp) >> -(space >> '`' >> space >> Name) >> -(space >> '=' >> space >> Exp) | TableLit | SimpleTable;
860 1032
861 FnArgDefList = Seperator >> ( 1033 check_vararg_position = and_(white >> (')' | key("using"))) | white >> -(',' >> white) >> vararg_position_error;
862 fn_arg_def_lit_lines >> -(-(space >> ',') >> white >> VarArg) |
863 white >> VarArg
864 );
865 1034
866 OuterVarShadow = key("using") >> space >> (NameList | key("nil")); 1035 var_arg_def = (
1036 VarArgDef |
1037 +space_break >> push_indent_match >> ensure(space >> VarArgDef >> -(space >> '`' >> space >> Name), pop_indent)
1038 ) >> check_vararg_position;
867 1039
868 FnArgsDef = '(' >> *space_break >> -FnArgDefList >> -(white >> OuterVarShadow) >> white >> ')'; 1040 FnArgDefList = Seperator >>
1041 -fn_arg_def_list >>
1042 -(-(space >> ',') >> +space_break >> fn_arg_def_lit_lines) >>
1043 -(-(space >> ',') >> space >> var_arg_def);
1044
1045 OuterVarShadow = key("using") >> space >> (key("nil") | NameList);
1046
1047 outer_var_shadow_def = OuterVarShadow |
1048 +space_break >> push_indent_match >> ensure(space >> OuterVarShadow, pop_indent);
1049
1050 FnArgsDef = '(' >> space >> -FnArgDefList >> -(space >> outer_var_shadow_def) >> white >> -(and_(',') >> unexpected_comma_error) >> ')';
869 FnArrow = expr("->") | "=>"; 1051 FnArrow = expr("->") | "=>";
870 FunLit = pl::user(true_(), [](const item_t& item) { 1052 FunLit = pl::user(true_(), [](const item_t& item) {
871 State* st = reinterpret_cast<State*>(item.user_data); 1053 State* st = reinterpret_cast<State*>(item.user_data);
@@ -877,23 +1059,30 @@ YueParser::YueParser() {
877 ) >> space >> FnArrow >> -(space >> Body); 1059 ) >> space >> FnArrow >> -(space >> Body);
878 1060
879 MacroName = '$' >> UnicodeName; 1061 MacroName = '$' >> UnicodeName;
880 macro_args_def = '(' >> white >> -FnArgDefList >> white >> ')'; 1062 macro_args_def = '(' >> space >> -FnArgDefList >> white >> -(and_(',') >> unexpected_comma_error) >> ')';
881 MacroLit = -(macro_args_def >> space) >> "->" >> space >> Body; 1063 MacroLit = -(macro_args_def >> space) >> "->" >> space >> Body;
882 MacroFunc = MacroName >> (Invoke | InvokeArgs); 1064 MacroFunc = MacroName >> (Invoke | InvokeArgs);
883 Macro = key("macro") >> space >> UnicodeName >> space >> '=' >> space >> (MacroLit | MacroFunc); 1065 Macro = key("macro") >> space >> (
1066 UnicodeName >> space >> '=' >> space >> (MacroLit | MacroFunc | invalid_macro_definition_error) |
1067 invalid_macro_definition_error
1068 );
884 MacroInPlace = '$' >> space >> "->" >> space >> Body; 1069 MacroInPlace = '$' >> space >> "->" >> space >> Body;
885 1070
886 NameList = Seperator >> Variable >> *(space >> ',' >> space >> Variable); 1071 must_variable = Variable | and_(LuaKeyword >> not_alpha_num) >> keyword_as_identifier_syntax_error | expected_indentifier_error;
887 NameOrDestructure = Variable | TableLit | Comprehension; 1072
1073 NameList = Seperator >> must_variable >> *(space >> ',' >> space >> must_variable);
1074 NameOrDestructure = Variable | TableLit | Comprehension | SimpleTable | expected_expression_error;
888 AssignableNameList = Seperator >> NameOrDestructure >> *(space >> ',' >> space >> NameOrDestructure); 1075 AssignableNameList = Seperator >> NameOrDestructure >> *(space >> ',' >> space >> NameOrDestructure);
889 1076
890 FnArrowBack = '<' >> set("-="); 1077 FnArrowBack = '<' >> set("-=");
891 Backcall = -(FnArgsDef >> space) >> FnArrowBack >> space >> ChainValue; 1078 Backcall = -(FnArgsDef >> space) >> FnArrowBack >> space >> ChainValue;
892 SubBackcall = FnArrowBack >> space >> ChainValue; 1079 SubBackcall = FnArrowBack >> space >> ChainValue;
893 1080
1081 must_unary_exp = UnaryExp | expected_expression_error;
1082
894 PipeBody = Seperator >> 1083 PipeBody = Seperator >>
895 pipe_operator >> space >> UnaryExp >> 1084 pipe_operator >> space >> must_unary_exp >>
896 *(+space_break >> check_indent_match >> space >> pipe_operator >> space >> UnaryExp); 1085 *(+space_break >> check_indent_match >> space >> pipe_operator >> space >> must_unary_exp);
897 1086
898 ExpList = Seperator >> Exp >> *(space >> ',' >> space >> Exp); 1087 ExpList = Seperator >> Exp >> *(space >> ',' >> space >> Exp);
899 ExpListLow = Seperator >> Exp >> *(space >> set(",;") >> space >> Exp); 1088 ExpListLow = Seperator >> Exp >> *(space >> set(",;") >> space >> Exp);
@@ -903,7 +1092,7 @@ YueParser::YueParser() {
903 1092
904 arg_table_block = pl::user(true_(), [](const item_t& item) { 1093 arg_table_block = pl::user(true_(), [](const item_t& item) {
905 State* st = reinterpret_cast<State*>(item.user_data); 1094 State* st = reinterpret_cast<State*>(item.user_data);
906 return st->noTableBlockStack.empty() || !st->noTableBlockStack.top(); 1095 return st->noTableBlockStack.empty() || !st->noTableBlockStack.back();
907 }) >> TableBlock; 1096 }) >> TableBlock;
908 1097
909 invoke_args_with_table = 1098 invoke_args_with_table =
@@ -912,38 +1101,17 @@ YueParser::YueParser() {
912 space_break >> advance_match >> arg_block >> -(-(space >> ',') >> arg_table_block) 1101 space_break >> advance_match >> arg_block >> -(-(space >> ',') >> arg_table_block)
913 ) | arg_table_block; 1102 ) | arg_table_block;
914 1103
915 leading_spaces_error = pl::user(+space_one >> '(' >> space >> Exp >> +(space >> ',' >> space >> Exp) >> space >> ')', [](const item_t& item) {
916 throw ParserError("write invoke arguments in parentheses without leading spaces or just leading spaces without parentheses"sv, item.begin);
917 return false;
918 });
919
920 InvokeArgs = 1104 InvokeArgs =
921 not_(set("-~") | "[]") >> space >> Seperator >> ( 1105 not_(set("-~") | "[]") >> space >> Seperator >> (
922 Exp >> *(space >> ',' >> space >> Exp) >> -(space >> invoke_args_with_table) | 1106 Exp >> *(space >> ',' >> space >> Exp) >> -(space >> invoke_args_with_table) |
923 arg_table_block | 1107 arg_table_block
924 leading_spaces_error
925 ); 1108 );
926 1109
927 ConstValue = (expr("nil") | "true" | "false") >> not_alpha_num; 1110 ConstValue = (expr("nil") | "true" | "false") >> not_alpha_num;
928 1111
929 braces_expression_error = pl::user(true_(), [](const item_t& item) {
930 throw ParserError("syntax error in brace expression"sv, item.begin);
931 return false;
932 });
933
934 brackets_expression_error = pl::user(true_(), [](const item_t& item) {
935 throw ParserError("syntax error in bracket expression"sv, item.begin);
936 return false;
937 });
938
939 slice_expression_error = pl::user(true_(), [](const item_t& item) {
940 throw ParserError("syntax error in slice expression"sv, item.begin);
941 return false;
942 });
943
944 SimpleValue = 1112 SimpleValue =
945 TableLit | ConstValue | If | Switch | Try | With | 1113 TableLit | ConstValue | If | Switch | Try | With |
946 ClassDecl | ForEach | For | While | Do | 1114 ClassDecl | For | While | Repeat | Do |
947 UnaryValue | TblComprehension | Comprehension | 1115 UnaryValue | TblComprehension | Comprehension |
948 FunLit | Num | VarArg; 1116 FunLit | Num | VarArg;
949 1117
@@ -952,63 +1120,59 @@ YueParser::YueParser() {
952 IfLine = IfType >> space >> IfCond; 1120 IfLine = IfType >> space >> IfCond;
953 WhileLine = WhileType >> space >> Exp; 1121 WhileLine = WhileType >> space >> Exp;
954 1122
955 YueLineComment = *(not_(set("\r\n")) >> any_char);
956 yue_line_comment = "--" >> YueLineComment >> and_(stop);
957 MultilineCommentInner = multi_line_content;
958 YueMultilineComment = multi_line_open >> MultilineCommentInner >> multi_line_close;
959 yue_comment = check_indent >> (
960 (
961 YueMultilineComment >>
962 *(set(" \t") | YueMultilineComment) >>
963 -yue_line_comment
964 ) | yue_line_comment
965 ) >> and_(line_break);
966
967 ChainAssign = Seperator >> Exp >> +(space >> '=' >> space >> Exp >> space >> and_('=')) >> space >> Assign; 1123 ChainAssign = Seperator >> Exp >> +(space >> '=' >> space >> Exp >> space >> and_('=')) >> space >> Assign;
968 1124
969 StatementAppendix = (IfLine | WhileLine | CompInner) >> space; 1125 StatementAppendix = (IfLine | WhileLine | CompFor) >> space;
970 Statement = 1126 Statement =
971 Seperator >> 1127 (
972 -( 1128 Import | While | Repeat | For |
973 yue_comment >>
974 *(line_break >> yue_comment) >>
975 line_break >>
976 check_indent_match
977 ) >>
978 space >> (
979 Import | While | Repeat | For | ForEach |
980 Return | Local | Global | Export | Macro | 1129 Return | Local | Global | Export | Macro |
981 MacroInPlace | BreakLoop | Label | Goto | ShortTabAppending | 1130 MacroInPlace | BreakLoop | Label | Goto | ShortTabAppending |
982 LocalAttrib | Backcall | PipeBody | ExpListAssign | ChainAssign | 1131 LocalAttrib | Backcall | PipeBody | ExpListAssign | ChainAssign |
983 StatementAppendix >> empty_block_error 1132 StatementAppendix >> empty_block_error |
984 ) >> 1133 and_(key("else") | key("elseif") | key("when")) >> dangling_clause_error
985 space >> 1134 ) >> space >>
986 -StatementAppendix; 1135 -StatementAppendix;
987 1136
988 StatementSep = white >> (set("('\"") | "[[" | "[="); 1137 StatementSep = white >> (set("('\"") | "[[" | "[=");
989 1138
990 Body = in_block | Statement; 1139 Body = in_block | Statement;
991 1140
992 empty_line_break = 1141 YueLineComment = *(not_(set("\r\n")) >> any_char);
993 check_indent >> (multi_line_comment >> space | comment) >> and_(stop) | 1142 yue_line_comment = "--" >> YueLineComment >> and_(stop);
994 advance >> ensure(multi_line_comment >> space | comment, pop_indent) >> and_(stop) | 1143 YueMultilineComment = multi_line_content;
995 plain_space >> and_(line_break); 1144 yue_multiline_comment = multi_line_open >> YueMultilineComment >> multi_line_close;
1145 comment_line =
1146 yue_multiline_comment >> *(set(" \t") | yue_multiline_comment) >> plain_space >> -yue_line_comment |
1147 yue_line_comment;
1148 YueComment =
1149 check_indent >> comment_line >> and_(stop) |
1150 advance >> ensure(comment_line, pop_indent) >> and_(stop);
1151
1152 EmptyLine = plain_space >> and_(stop);
996 1153
997 indentation_error = pl::user(not_(pipe_operator | eof()), [](const item_t& item) { 1154 indentation_error = pl::user(not_(pipe_operator | eof()), [](const item_t& item) {
998 throw ParserError("unexpected indent"sv, item.begin); 1155 RaiseError("unexpected indent"sv, item);
999 return false; 1156 return false;
1000 }); 1157 });
1001 1158
1002 line = ( 1159 line = *(EmptyLine >> line_break) >> (
1003 check_indent_match >> Statement | 1160 check_indent_match >> space >> Statement |
1004 empty_line_break | 1161 YueComment |
1005 advance_match >> ensure(space >> (indentation_error | Statement), pop_indent) 1162 advance_match >> ensure(space >> (indentation_error | Statement), pop_indent)
1006 ); 1163 );
1007 Block = Seperator >> line >> *(+line_break >> line); 1164 Block = Seperator >> (pl::user(true_(), [](const item_t& item) {
1165 State* st = reinterpret_cast<State*>(item.user_data);
1166 return st->lax;
1167 }) >> lax_line >> *(line_break >> lax_line) | line >> *(line_break >> line));
1008 1168
1009 shebang = "#!" >> *(not_(stop) >> any_char); 1169 shebang = "#!" >> *(not_(stop) >> any_char);
1010 BlockEnd = Block >> white >> stop; 1170 BlockEnd = Block >> plain_white >> stop;
1011 File = -shebang >> -Block >> white >> stop; 1171 File = -shebang >> -Block >> plain_white >> stop;
1172
1173 lax_line = advance_match >> ensure(*(not_(stop) >> any()), pop_indent) |
1174 line >> and_(stop) |
1175 check_indent_match >> *(not_(stop) >> any());
1012} 1176}
1013// clang-format on 1177// clang-format on
1014 1178
@@ -1019,7 +1183,7 @@ bool YueParser::startWith(std::string_view codes, rule& r) {
1019 } 1183 }
1020 try { 1184 try {
1021 if (!codes.empty()) { 1185 if (!codes.empty()) {
1022 converted = std::make_unique<input>(_converter.from_bytes(&codes.front(), &codes.back() + 1)); 1186 converted = std::make_unique<input>(utf8_decode({&codes.front(), &codes.back() + 1}));
1023 } else { 1187 } else {
1024 converted = std::make_unique<input>(); 1188 converted = std::make_unique<input>();
1025 } 1189 }
@@ -1038,24 +1202,25 @@ bool YueParser::startWith(std::string_view codes, rule& r) {
1038 return true; 1202 return true;
1039} 1203}
1040 1204
1041ParseInfo YueParser::parse(std::string_view codes, rule& r) { 1205ParseInfo YueParser::parse(std::string_view codes, rule& r, bool lax) {
1042 ParseInfo res; 1206 ParseInfo res;
1043 if (codes.substr(0, 3) == "\xEF\xBB\xBF"sv) { 1207 if (codes.substr(0, 3) == "\xEF\xBB\xBF"sv) {
1044 codes = codes.substr(3); 1208 codes = codes.substr(3);
1045 } 1209 }
1046 try { 1210 try {
1047 if (!codes.empty()) { 1211 if (!codes.empty()) {
1048 res.codes = std::make_unique<input>(_converter.from_bytes(&codes.front(), &codes.back() + 1)); 1212 res.codes = std::make_unique<input>(utf8_decode({&codes.front(), &codes.back() + 1}));
1049 } else { 1213 } else {
1050 res.codes = std::make_unique<input>(); 1214 res.codes = std::make_unique<input>();
1051 } 1215 }
1052 } catch (const std::range_error&) { 1216 } catch (const std::exception&) {
1053 res.error = {"invalid text encoding"s, 1, 1}; 1217 res.error = {"invalid text encoding"s, 1, 1};
1054 return res; 1218 return res;
1055 } 1219 }
1056 error_list errors; 1220 error_list errors;
1057 try { 1221 try {
1058 State state; 1222 State state;
1223 state.lax = lax;
1059 res.node.set(::yue::parse(*(res.codes), r, errors, &state)); 1224 res.node.set(::yue::parse(*(res.codes), r, errors, &state));
1060 if (state.exportCount > 0) { 1225 if (state.exportCount > 0) {
1061 int index = 0; 1226 int index = 0;
@@ -1093,29 +1258,31 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) {
1093 return res; 1258 return res;
1094} 1259}
1095 1260
1096ParseInfo YueParser::parse(std::string_view astName, std::string_view codes) { 1261ParseInfo YueParser::parse(std::string_view astName, std::string_view codes, bool lax) {
1097 auto it = _rules.find(astName); 1262 auto it = _rules.find(astName);
1098 if (it != _rules.end()) { 1263 if (it != _rules.end()) {
1099 return parse(codes, *it->second); 1264 return parse(codes, *it->second, lax);
1100 } 1265 }
1101 return {}; 1266 ParseInfo info{};
1267 info.error = ParseInfo::Error{"invalid rule: "s + std::string{astName}, 1, 1};
1268 return info;
1102} 1269}
1103 1270
1104bool YueParser::match(std::string_view astName, std::string_view codes) { 1271bool YueParser::match(std::string_view astName, std::string_view codes) {
1105 auto it = _rules.find(astName); 1272 auto it = _rules.find(astName);
1106 if (it != _rules.end()) { 1273 if (it != _rules.end()) {
1107 auto rEnd = rule(*it->second >> eof()); 1274 auto rEnd = rule(*it->second >> eof());
1108 return parse(codes, rEnd).node; 1275 return parse(codes, rEnd, false).node;
1109 } 1276 }
1110 return false; 1277 return false;
1111} 1278}
1112 1279
1113std::string YueParser::toString(ast_node* node) { 1280std::string YueParser::toString(ast_node* node) {
1114 return _converter.to_bytes(std::wstring(node->m_begin.m_it, node->m_end.m_it)); 1281 return utf8_encode({node->m_begin.m_it, node->m_end.m_it});
1115} 1282}
1116 1283
1117std::string YueParser::toString(input::iterator begin, input::iterator end) { 1284std::string YueParser::toString(input::iterator begin, input::iterator end) {
1118 return _converter.to_bytes(std::wstring(begin, end)); 1285 return utf8_encode({begin, end});
1119} 1286}
1120 1287
1121bool YueParser::hasAST(std::string_view name) const { 1288bool YueParser::hasAST(std::string_view name) const {
@@ -1141,6 +1308,24 @@ void trim(std::string& str) {
1141 str.erase(0, str.find_first_not_of(" \t\r\n")); 1308 str.erase(0, str.find_first_not_of(" \t\r\n"));
1142 str.erase(str.find_last_not_of(" \t\r\n") + 1); 1309 str.erase(str.find_last_not_of(" \t\r\n") + 1);
1143} 1310}
1311
1312std::string toLuaDoubleString(const std::string& input) {
1313 std::string luaStr = "\"";
1314 for (char c : input) {
1315 switch (c) {
1316 case '\"': luaStr += "\\\""; break;
1317 case '\\': luaStr += "\\\\"; break;
1318 case '\n': luaStr += "\\n"; break;
1319 case '\r': luaStr += "\\r"; break;
1320 case '\t': luaStr += "\\t"; break;
1321 default:
1322 luaStr += c;
1323 break;
1324 }
1325 }
1326 luaStr += "\"";
1327 return luaStr;
1328}
1144} // namespace Utils 1329} // namespace Utils
1145 1330
1146std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCol, int lineOffset) const { 1331std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCol, int lineOffset) const {
@@ -1174,7 +1359,7 @@ std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCo
1174 } 1359 }
1175 ++it; 1360 ++it;
1176 } 1361 }
1177 auto line = Converter{}.to_bytes(std::wstring(begin, end)); 1362 auto line = utf8_encode({begin, end});
1178 while (col < static_cast<int>(line.size()) 1363 while (col < static_cast<int>(line.size())
1179 && (line[col] == ' ' || line[col] == '\t')) { 1364 && (line[col] == ' ' || line[col] == '\t')) {
1180 col++; 1365 col++;
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h
index 4488685..acb56d0 100644
--- a/src/yuescript/yue_parser.h
+++ b/src/yuescript/yue_parser.h
@@ -1,4 +1,4 @@
1/* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> 1/* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com>
2 2
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,17 @@ private:
279 NONE_AST_RULE(expo_exp); 314 NONE_AST_RULE(expo_exp);
280 NONE_AST_RULE(exp_not_tab); 315 NONE_AST_RULE(exp_not_tab);
281 NONE_AST_RULE(local_const_item); 316 NONE_AST_RULE(local_const_item);
282 NONE_AST_RULE(empty_line_break); 317 NONE_AST_RULE(comment_line);
283 NONE_AST_RULE(yue_comment);
284 NONE_AST_RULE(yue_line_comment); 318 NONE_AST_RULE(yue_line_comment);
319 NONE_AST_RULE(yue_multiline_comment);
285 NONE_AST_RULE(line); 320 NONE_AST_RULE(line);
286 NONE_AST_RULE(shebang); 321 NONE_AST_RULE(shebang);
322 NONE_AST_RULE(lax_line);
287 323
288 AST_RULE(Num); 324 AST_RULE(Num);
289 AST_RULE(Name); 325 AST_RULE(Name);
290 AST_RULE(UnicodeName); 326 AST_RULE(UnicodeName);
291 AST_RULE(Variable); 327 AST_RULE(Variable);
292 AST_RULE(LabelName);
293 AST_RULE(LuaKeyword); 328 AST_RULE(LuaKeyword);
294 AST_RULE(Self); 329 AST_RULE(Self);
295 AST_RULE(SelfName); 330 AST_RULE(SelfName);
@@ -298,6 +333,7 @@ private:
298 AST_RULE(SelfItem); 333 AST_RULE(SelfItem);
299 AST_RULE(KeyName); 334 AST_RULE(KeyName);
300 AST_RULE(VarArg); 335 AST_RULE(VarArg);
336 AST_RULE(VarArgDef);
301 AST_RULE(Seperator); 337 AST_RULE(Seperator);
302 AST_RULE(NameList); 338 AST_RULE(NameList);
303 AST_RULE(LocalFlag); 339 AST_RULE(LocalFlag);
@@ -315,6 +351,7 @@ private:
315 AST_RULE(ImportAllMacro); 351 AST_RULE(ImportAllMacro);
316 AST_RULE(ImportTabLit); 352 AST_RULE(ImportTabLit);
317 AST_RULE(ImportAs); 353 AST_RULE(ImportAs);
354 AST_RULE(ImportGlobal);
318 AST_RULE(Import); 355 AST_RULE(Import);
319 AST_RULE(Label); 356 AST_RULE(Label);
320 AST_RULE(Goto); 357 AST_RULE(Goto);
@@ -339,6 +376,7 @@ private:
339 AST_RULE(Repeat); 376 AST_RULE(Repeat);
340 AST_RULE(ForStepValue); 377 AST_RULE(ForStepValue);
341 AST_RULE(For); 378 AST_RULE(For);
379 AST_RULE(ForNum);
342 AST_RULE(ForEach); 380 AST_RULE(ForEach);
343 AST_RULE(Do); 381 AST_RULE(Do);
344 AST_RULE(CatchBlock); 382 AST_RULE(CatchBlock);
@@ -348,8 +386,8 @@ private:
348 AST_RULE(TblComprehension); 386 AST_RULE(TblComprehension);
349 AST_RULE(StarExp); 387 AST_RULE(StarExp);
350 AST_RULE(CompForEach); 388 AST_RULE(CompForEach);
389 AST_RULE(CompForNum);
351 AST_RULE(CompFor); 390 AST_RULE(CompFor);
352 AST_RULE(CompInner);
353 AST_RULE(Assign); 391 AST_RULE(Assign);
354 AST_RULE(UpdateOp); 392 AST_RULE(UpdateOp);
355 AST_RULE(Update); 393 AST_RULE(Update);
@@ -360,6 +398,7 @@ private:
360 AST_RULE(ExpOpValue); 398 AST_RULE(ExpOpValue);
361 AST_RULE(Exp); 399 AST_RULE(Exp);
362 AST_RULE(Callable); 400 AST_RULE(Callable);
401 AST_RULE(ReversedIndex);
363 AST_RULE(ChainValue); 402 AST_RULE(ChainValue);
364 AST_RULE(SimpleTable); 403 AST_RULE(SimpleTable);
365 AST_RULE(SimpleValue); 404 AST_RULE(SimpleValue);
@@ -372,6 +411,11 @@ private:
372 AST_RULE(DoubleStringInner); 411 AST_RULE(DoubleStringInner);
373 AST_RULE(DoubleStringContent); 412 AST_RULE(DoubleStringContent);
374 AST_RULE(DoubleString); 413 AST_RULE(DoubleString);
414 AST_RULE(YAMLIndent);
415 AST_RULE(YAMLLineInner);
416 AST_RULE(YAMLLineContent);
417 AST_RULE(YAMLLine);
418 AST_RULE(YAMLMultiline);
375 AST_RULE(String); 419 AST_RULE(String);
376 AST_RULE(Parens); 420 AST_RULE(Parens);
377 AST_RULE(DotChainItem); 421 AST_RULE(DotChainItem);
@@ -435,8 +479,9 @@ private:
435 AST_RULE(Statement); 479 AST_RULE(Statement);
436 AST_RULE(StatementSep); 480 AST_RULE(StatementSep);
437 AST_RULE(YueLineComment); 481 AST_RULE(YueLineComment);
438 AST_RULE(MultilineCommentInner);
439 AST_RULE(YueMultilineComment); 482 AST_RULE(YueMultilineComment);
483 AST_RULE(YueComment);
484 AST_RULE(EmptyLine);
440 AST_RULE(ChainAssign); 485 AST_RULE(ChainAssign);
441 AST_RULE(Body); 486 AST_RULE(Body);
442 AST_RULE(Block); 487 AST_RULE(Block);
@@ -447,6 +492,7 @@ private:
447namespace Utils { 492namespace Utils {
448void replace(std::string& str, std::string_view from, std::string_view to); 493void replace(std::string& str, std::string_view from, std::string_view to);
449void trim(std::string& str); 494void trim(std::string& str);
495std::string toLuaDoubleString(const std::string& input);
450} // namespace Utils 496} // namespace Utils
451 497
452} // namespace yue 498} // namespace yue
diff --git a/src/yuescript/yuescript.cpp b/src/yuescript/yuescript.cpp
index 7e8e8b7..fd2bf62 100644
--- a/src/yuescript/yuescript.cpp
+++ b/src/yuescript/yuescript.cpp
@@ -1,4 +1,4 @@
1/* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> 1/* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com>
2 2
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 }