aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/3rdParty/efsw/FileWatcherGeneric.cpp2
-rw-r--r--src/yuescript/yue_ast.cpp201
-rw-r--r--src/yuescript/yue_ast.h100
-rw-r--r--src/yuescript/yue_compiler.cpp1208
-rw-r--r--src/yuescript/yue_compiler.h1
-rw-r--r--src/yuescript/yue_parser.cpp162
-rw-r--r--src/yuescript/yue_parser.h36
-rw-r--r--src/yuescript/yuescript.cpp16
8 files changed, 1436 insertions, 290 deletions
diff --git a/src/3rdParty/efsw/FileWatcherGeneric.cpp b/src/3rdParty/efsw/FileWatcherGeneric.cpp
index 3f3c52e..468d27c 100644
--- a/src/3rdParty/efsw/FileWatcherGeneric.cpp
+++ b/src/3rdParty/efsw/FileWatcherGeneric.cpp
@@ -25,7 +25,7 @@ FileWatcherGeneric::~FileWatcherGeneric() {
25} 25}
26 26
27WatchID FileWatcherGeneric::addWatch( const std::string& directory, FileWatchListener* watcher, 27WatchID FileWatcherGeneric::addWatch( const std::string& directory, FileWatchListener* watcher,
28 bool recursive, const std::vector<WatcherOption>& options ) { 28 bool recursive, const std::vector<WatcherOption>& /*options*/ ) {
29 std::string dir( directory ); 29 std::string dir( directory );
30 30
31 FileSystem::dirAddSlashAtEnd( dir ); 31 FileSystem::dirAddSlashAtEnd( dir );
diff --git a/src/yuescript/yue_ast.cpp b/src/yuescript/yue_ast.cpp
index fe6e726..945e1d7 100644
--- a/src/yuescript/yue_ast.cpp
+++ b/src/yuescript/yue_ast.cpp
@@ -167,12 +167,11 @@ std::string ExistentialOp_t::to_string(void*) const {
167std::string TableAppendingOp_t::to_string(void*) const { 167std::string TableAppendingOp_t::to_string(void*) const {
168 return "[]"s; 168 return "[]"s;
169} 169}
170std::string PlainItem_t::to_string(void *) const { 170std::string PlainItem_t::to_string(void*) const {
171 return {}; 171 return {};
172} 172}
173std::string GlobalOp_t::to_string(void* ud) const { 173std::string GlobalOp_t::to_string(void*) const {
174 auto info = reinterpret_cast<YueFormat*>(ud); 174 return "*"s;
175 return info->convert(this);
176} 175}
177std::string ExportDefault_t::to_string(void*) const { 176std::string ExportDefault_t::to_string(void*) const {
178 return "default"s; 177 return "default"s;
@@ -188,9 +187,17 @@ std::string ConstValue_t::to_string(void* ud) const {
188std::string NotIn_t::to_string(void*) const { 187std::string NotIn_t::to_string(void*) const {
189 return {}; 188 return {};
190} 189}
190std::string Break_t::to_string(void*) const {
191 return "break"s;
192}
193std::string Continue_t::to_string(void*) const {
194 return "continue"s;
195}
191std::string BreakLoop_t::to_string(void* ud) const { 196std::string BreakLoop_t::to_string(void* ud) const {
192 auto info = reinterpret_cast<YueFormat*>(ud); 197 if (value) {
193 return info->convert(this); 198 return type->to_string(ud) + ' ' + value->to_string(ud);
199 }
200 return type->to_string(ud);
194} 201}
195std::string YueLineComment_t::to_string(void* ud) const { 202std::string YueLineComment_t::to_string(void* ud) const {
196 auto info = reinterpret_cast<YueFormat*>(ud); 203 auto info = reinterpret_cast<YueFormat*>(ud);
@@ -297,6 +304,17 @@ std::string ImportAs_t::to_string(void* ud) const {
297 } 304 }
298 return join(temp, " "s); 305 return join(temp, " "s);
299} 306}
307std::string ImportGlobal_t::to_string(void* ud) const {
308 str_list temp;
309 for (auto seg : segs.objects()) {
310 temp.emplace_back(seg->to_string(ud));
311 }
312 auto item = join(temp, "."s);
313 if (target) {
314 return item + " as "s + target->to_string(ud);
315 }
316 return item;
317}
300std::string Import_t::to_string(void* ud) const { 318std::string Import_t::to_string(void* ud) const {
301 if (ast_is<FromImport_t>(content)) { 319 if (ast_is<FromImport_t>(content)) {
302 return content->to_string(ud); 320 return content->to_string(ud);
@@ -324,6 +342,12 @@ std::string Backcall_t::to_string(void* ud) const {
324 temp.emplace_back(value->to_string(ud)); 342 temp.emplace_back(value->to_string(ud));
325 return join(temp, " "sv); 343 return join(temp, " "sv);
326} 344}
345std::string SubBackcall_t::to_string(void* ud) const {
346 str_list temp;
347 temp.emplace_back(arrow->to_string(ud));
348 temp.emplace_back(value->to_string(ud));
349 return join(temp, " "sv);
350}
327std::string PipeBody_t::to_string(void* ud) const { 351std::string PipeBody_t::to_string(void* ud) const {
328 auto info = reinterpret_cast<YueFormat*>(ud); 352 auto info = reinterpret_cast<YueFormat*>(ud);
329 str_list temp; 353 str_list temp;
@@ -359,8 +383,8 @@ std::string With_t::to_string(void* ud) const {
359 str_list temp{ 383 str_list temp{
360 eop ? "with?"s : "with"s, 384 eop ? "with?"s : "with"s,
361 valueList->to_string(ud)}; 385 valueList->to_string(ud)};
362 if (assigns) { 386 if (assign) {
363 temp.push_back(assigns->to_string(ud)); 387 temp.push_back(':' + assign->to_string(ud));
364 } 388 }
365 if (body.is<Statement_t>()) { 389 if (body.is<Statement_t>()) {
366 return join(temp, " "sv) + " do "s + body->to_string(ud); 390 return join(temp, " "sv) + " do "s + body->to_string(ud);
@@ -406,6 +430,9 @@ std::string SwitchCase_t::to_string(void* ud) const {
406std::string Switch_t::to_string(void* ud) const { 430std::string Switch_t::to_string(void* ud) const {
407 auto info = reinterpret_cast<YueFormat*>(ud); 431 auto info = reinterpret_cast<YueFormat*>(ud);
408 str_list temp{"switch "s + target->to_string(ud)}; 432 str_list temp{"switch "s + target->to_string(ud)};
433 if (assignment) {
434 temp.back().append(assignment->to_string(ud));
435 }
409 info->pushScope(); 436 info->pushScope();
410 for (auto branch : branches.objects()) { 437 for (auto branch : branches.objects()) {
411 temp.emplace_back(info->ind() + branch->to_string(ud)); 438 temp.emplace_back(info->ind() + branch->to_string(ud));
@@ -449,41 +476,75 @@ std::string If_t::to_string(void* ud) const {
449 temp.back() += " then"s; 476 temp.back() += " then"s;
450 } 477 }
451 ++it; 478 ++it;
452 bool condition = true; 479 enum class NType {
480 Cond,
481 Stat,
482 Block
483 };
484 NType lastType = NType::Cond;
453 for (; it != nodes.objects().end(); ++it) { 485 for (; it != nodes.objects().end(); ++it) {
454 auto node = *it; 486 auto node = *it;
455 switch (node->get_id()) { 487 switch (node->get_id()) {
456 case id<IfCond_t>(): 488 case id<IfCond_t>():
457 temp.emplace_back(info->ind() + "elseif "s + node->to_string(ud)); 489 temp.emplace_back(info->ind() + "elseif "s + node->to_string(ud));
458 condition = true; 490 lastType = NType::Cond;
459 break; 491 break;
460 case id<Statement_t>(): { 492 case id<Statement_t>(): {
461 if (condition) { 493 switch (lastType) {
462 temp.back() += " then "s + node->to_string(ud); 494 case NType::Cond:
463 } else { 495 temp.back() += " then "s + node->to_string(ud);
464 temp.emplace_back(info->ind() + "else "s + node->to_string(ud)); 496 break;
497 case NType::Stat:
498 if (temp.back().back() == '\n') {
499 temp.emplace_back(info->ind() + "else "s + node->to_string(ud));
500 } else {
501 temp.back() += " else "s + node->to_string(ud);
502 }
503 break;
504 case NType::Block:
505 temp.emplace_back(info->ind() + "else "s + node->to_string(ud));
506 break;
465 } 507 }
466 condition = false; 508 lastType = NType::Stat;
467 break; 509 break;
468 } 510 }
469 case id<Block_t>(): { 511 case id<Block_t>(): {
470 if (condition) { 512 switch (lastType) {
471 info->pushScope(); 513 case NType::Cond: {
472 temp.emplace_back(node->to_string(ud)); 514 info->pushScope();
473 if (temp.back().empty()) { 515 temp.emplace_back(node->to_string(ud));
474 temp.back() = info->ind() + "--"s; 516 if (temp.back().empty()) {
517 temp.back() = info->ind() + "--"s;
518 }
519 info->popScope();
520 break;
521 }
522 case NType::Stat: {
523 if (temp.back().back() == '\n') {
524 temp.emplace_back(info->ind() + "else"s);
525 } else {
526 temp.back() += " else"s;
527 }
528 info->pushScope();
529 temp.emplace_back(node->to_string(ud));
530 if (temp.back().empty()) {
531 temp.back() = info->ind() + "--"s;
532 }
533 info->popScope();
534 break;
475 } 535 }
476 info->popScope(); 536 case NType::Block: {
477 } else { 537 temp.emplace_back(info->ind() + "else"s);
478 temp.emplace_back(info->ind() + "else"s); 538 info->pushScope();
479 info->pushScope(); 539 temp.emplace_back(node->to_string(ud));
480 temp.emplace_back(node->to_string(ud)); 540 if (temp.back().empty()) {
481 if (temp.back().empty()) { 541 temp.back() = info->ind() + "--"s;
482 temp.back() = info->ind() + "--"s; 542 }
543 info->popScope();
544 break;
483 } 545 }
484 info->popScope();
485 } 546 }
486 condition = false; 547 lastType = NType::Block;
487 break; 548 break;
488 } 549 }
489 } 550 }
@@ -511,10 +572,10 @@ std::string While_t::to_string(void* ud) const {
511} 572}
512std::string Repeat_t::to_string(void* ud) const { 573std::string Repeat_t::to_string(void* ud) const {
513 auto info = reinterpret_cast<YueFormat*>(ud); 574 auto info = reinterpret_cast<YueFormat*>(ud);
514 str_list temp; 575 if (body.is<Statement_t>()) {
515 if (body->content.is<Statement_t>()) { 576 return "repeat "s + body->to_string(ud) + " until "s + condition->to_string(ud);
516 temp.emplace_back("repeat "s + body->to_string(ud));
517 } else { 577 } else {
578 str_list temp;
518 temp.emplace_back("repeat"s); 579 temp.emplace_back("repeat"s);
519 info->pushScope(); 580 info->pushScope();
520 temp.emplace_back(body->to_string(ud)); 581 temp.emplace_back(body->to_string(ud));
@@ -522,9 +583,9 @@ std::string Repeat_t::to_string(void* ud) const {
522 temp.back() = info->ind() + "--"s; 583 temp.back() = info->ind() + "--"s;
523 } 584 }
524 info->popScope(); 585 info->popScope();
586 temp.emplace_back(info->ind() + "until "s + condition->to_string(ud));
587 return join(temp, "\n"sv);
525 } 588 }
526 temp.emplace_back(info->ind() + "until "s + condition->to_string(ud));
527 return join(temp, "\n"sv);
528} 589}
529std::string ForStepValue_t::to_string(void* ud) const { 590std::string ForStepValue_t::to_string(void* ud) const {
530 return value->to_string(ud); 591 return value->to_string(ud);
@@ -596,10 +657,13 @@ std::string CatchBlock_t::to_string(void* ud) const {
596std::string Try_t::to_string(void* ud) const { 657std::string Try_t::to_string(void* ud) const {
597 auto info = reinterpret_cast<YueFormat*>(ud); 658 auto info = reinterpret_cast<YueFormat*>(ud);
598 str_list temp; 659 str_list temp;
660 temp.emplace_back("try"s);
661 if (eop) {
662 temp.back() += eop->to_string(ud);
663 }
599 if (func.is<Exp_t>()) { 664 if (func.is<Exp_t>()) {
600 temp.emplace_back("try "s + func->to_string(ud)); 665 temp.back() += (" "s + func->to_string(ud));
601 } else { 666 } else {
602 temp.emplace_back("try"s);
603 info->pushScope(); 667 info->pushScope();
604 temp.emplace_back(func->to_string(ud)); 668 temp.emplace_back(func->to_string(ud));
605 if (temp.back().empty()) { 669 if (temp.back().empty()) {
@@ -851,6 +915,12 @@ std::string Exp_t::to_string(void* ud) const {
851 } 915 }
852 return join(temp, " "sv); 916 return join(temp, " "sv);
853} 917}
918std::string ReversedIndex_t::to_string(void* ud) const {
919 if (modifier) {
920 return "[# - "s + modifier->to_string(ud) + ']';
921 }
922 return "[#]"s;
923}
854std::string Callable_t::to_string(void* ud) const { 924std::string Callable_t::to_string(void* ud) const {
855 return item->to_string(ud); 925 return item->to_string(ud);
856} 926}
@@ -937,6 +1007,51 @@ std::string DoubleString_t::to_string(void* ud) const {
937 } 1007 }
938 return '"' + join(temp) + '"'; 1008 return '"' + join(temp) + '"';
939} 1009}
1010std::string YAMLIndent_t::to_string(void* ud) const {
1011 auto info = reinterpret_cast<YueFormat*>(ud);
1012 return info->convert(this);
1013}
1014std::string YAMLLineInner_t::to_string(void* ud) const {
1015 auto info = reinterpret_cast<YueFormat*>(ud);
1016 return info->convert(this);
1017}
1018std::string YAMLLineContent_t::to_string(void* ud) const {
1019 if (content.is<Exp_t>()) {
1020 return "#{"s + content->to_string(ud) + '}';
1021 }
1022 return content->to_string(ud);
1023}
1024std::string YAMLLine_t::to_string(void* ud) const {
1025 str_list temp;
1026 for (auto seg : segments.objects()) {
1027 temp.emplace_back(seg->to_string(ud));
1028 }
1029 return join(temp);
1030}
1031std::string YAMLMultiline_t::to_string(void* ud) const {
1032 auto info = reinterpret_cast<YueFormat*>(ud);
1033 int currentIndent = info->indent;
1034 str_list temp;
1035 int lastIndent = -1;
1036 for (auto line_ : lines.objects()) {
1037 auto line = static_cast<YAMLLine_t*>(line_);
1038 auto indent = line->indent->to_string(ud);
1039 int ind = 0;
1040 for (auto c : indent) {
1041 if (c == ' ') ind++;
1042 if (c == '\t') ind += 4;
1043 }
1044 if (lastIndent < ind) {
1045 info->pushScope();
1046 } else if (lastIndent > ind) {
1047 info->popScope();
1048 }
1049 lastIndent = ind;
1050 temp.emplace_back(indent + line->to_string(ud));
1051 }
1052 info->indent = currentIndent;
1053 return "|\n" + join(temp, "\n"sv) + '\n';
1054}
940std::string String_t::to_string(void* ud) const { 1055std::string String_t::to_string(void* ud) const {
941 return str->to_string(ud); 1056 return str->to_string(ud);
942} 1057}
@@ -1125,7 +1240,7 @@ std::string ClassDecl_t::to_string(void* ud) const {
1125 return line; 1240 return line;
1126} 1241}
1127std::string GlobalValues_t::to_string(void* ud) const { 1242std::string GlobalValues_t::to_string(void* ud) const {
1128 auto line = nameList->to_string(ud); 1243 std::string line = nameList->to_string(ud);
1129 if (valueList) { 1244 if (valueList) {
1130 if (valueList.is<TableBlock_t>()) { 1245 if (valueList.is<TableBlock_t>()) {
1131 line += " =\n"s + valueList->to_string(ud); 1246 line += " =\n"s + valueList->to_string(ud);
@@ -1136,7 +1251,7 @@ std::string GlobalValues_t::to_string(void* ud) const {
1136 return line; 1251 return line;
1137} 1252}
1138std::string Global_t::to_string(void* ud) const { 1253std::string Global_t::to_string(void* ud) const {
1139 return "global "s + item->to_string(ud); 1254 return "global "s + (constAttrib ? "const "s : ""s) + item->to_string(ud);
1140} 1255}
1141std::string Export_t::to_string(void* ud) const { 1256std::string Export_t::to_string(void* ud) const {
1142 auto line = "export"s; 1257 auto line = "export"s;
@@ -1235,6 +1350,9 @@ std::string FnArgDef_t::to_string(void* ud) const {
1235 if (op) { 1350 if (op) {
1236 line += op->to_string(ud); 1351 line += op->to_string(ud);
1237 } 1352 }
1353 if (label) {
1354 line += '`' + label->to_string(ud);
1355 }
1238 if (defaultValue) { 1356 if (defaultValue) {
1239 line += " = "s + defaultValue->to_string(ud); 1357 line += " = "s + defaultValue->to_string(ud);
1240 } 1358 }
@@ -1257,6 +1375,9 @@ std::string FnArgDefList_t::to_string(void* ud) const {
1257 } 1375 }
1258 if (varArg) { 1376 if (varArg) {
1259 temp.emplace_back(info->ind() + varArg->to_string(ud)); 1377 temp.emplace_back(info->ind() + varArg->to_string(ud));
1378 if (label) {
1379 temp.back().append('`' + label->to_string(ud));
1380 }
1260 } 1381 }
1261 return join(temp, "\n"sv); 1382 return join(temp, "\n"sv);
1262 } else { 1383 } else {
@@ -1265,6 +1386,9 @@ std::string FnArgDefList_t::to_string(void* ud) const {
1265 } 1386 }
1266 if (varArg) { 1387 if (varArg) {
1267 temp.emplace_back(varArg->to_string(ud)); 1388 temp.emplace_back(varArg->to_string(ud));
1389 if (label) {
1390 temp.back().append('`' + label->to_string(ud));
1391 }
1268 } 1392 }
1269 return join(temp, ", "sv); 1393 return join(temp, ", "sv);
1270 } 1394 }
@@ -1546,3 +1670,4 @@ std::string File_t::to_string(void* ud) const {
1546} // namespace yue 1670} // namespace yue
1547 1671
1548} // namespace parserlib 1672} // namespace parserlib
1673
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h
index 5e70645..1937eb8 100644
--- a/src/yuescript/yue_ast.h
+++ b/src/yuescript/yue_ast.h
@@ -233,8 +233,15 @@ 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
@@ -273,6 +280,8 @@ AST_NODE(ExpList)
273 ast_ptr<true, Seperator_t> sep; 280 ast_ptr<true, Seperator_t> sep;
274 ast_list<true, Exp_t> exprs; 281 ast_list<true, Exp_t> exprs;
275 AST_MEMBER(ExpList, &sep, &exprs) 282 AST_MEMBER(ExpList, &sep, &exprs)
283 bool followStmtProcessed = false;
284 Statement_t* followStmt = nullptr;
276AST_END(ExpList) 285AST_END(ExpList)
277 286
278AST_NODE(Return) 287AST_NODE(Return)
@@ -285,9 +294,9 @@ AST_END(Return)
285AST_NODE(With) 294AST_NODE(With)
286 ast_ptr<false, ExistentialOp_t> eop; 295 ast_ptr<false, ExistentialOp_t> eop;
287 ast_ptr<true, ExpList_t> valueList; 296 ast_ptr<true, ExpList_t> valueList;
288 ast_ptr<false, Assign_t> assigns; 297 ast_ptr<false, Assign_t> assign;
289 ast_sel<true, Block_t, Statement_t> body; 298 ast_sel<true, Block_t, Statement_t> body;
290 AST_MEMBER(With, &eop, &valueList, &assigns, &body) 299 AST_MEMBER(With, &eop, &valueList, &assign, &body)
291AST_END(With) 300AST_END(With)
292 301
293AST_NODE(SwitchList) 302AST_NODE(SwitchList)
@@ -302,20 +311,21 @@ AST_NODE(SwitchCase)
302 AST_MEMBER(SwitchCase, &condition, &body) 311 AST_MEMBER(SwitchCase, &condition, &body)
303AST_END(SwitchCase) 312AST_END(SwitchCase)
304 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
305AST_NODE(Switch) 320AST_NODE(Switch)
306 ast_ptr<true, Exp_t> target; 321 ast_ptr<true, Exp_t> target;
322 ast_ptr<false, Assignment_t> assignment;
307 ast_ptr<true, Seperator_t> sep; 323 ast_ptr<true, Seperator_t> sep;
308 ast_list<true, SwitchCase_t> branches; 324 ast_list<true, SwitchCase_t> branches;
309 ast_sel<false, Block_t, Statement_t> lastBranch; 325 ast_sel<false, Block_t, Statement_t> lastBranch;
310 AST_MEMBER(Switch, &target, &sep, &branches, &lastBranch) 326 AST_MEMBER(Switch, &target, &assignment, &sep, &branches, &lastBranch)
311AST_END(Switch) 327AST_END(Switch)
312 328
313AST_NODE(Assignment)
314 ast_ptr<false, ExpList_t> expList;
315 ast_ptr<true, Assign_t> assign;
316 AST_MEMBER(Assignment, &expList, &assign)
317AST_END(Assignment)
318
319AST_NODE(IfCond) 329AST_NODE(IfCond)
320 ast_ptr<true, Exp_t> condition; 330 ast_ptr<true, Exp_t> condition;
321 ast_ptr<false, Assignment_t> assignment; 331 ast_ptr<false, Assignment_t> assignment;
@@ -343,7 +353,7 @@ AST_NODE(While)
343AST_END(While) 353AST_END(While)
344 354
345AST_NODE(Repeat) 355AST_NODE(Repeat)
346 ast_ptr<true, Body_t> body; 356 ast_sel<true, Block_t, Statement_t> body;
347 ast_ptr<true, Exp_t> condition; 357 ast_ptr<true, Exp_t> condition;
348 AST_MEMBER(Repeat, &body, &condition) 358 AST_MEMBER(Repeat, &body, &condition)
349AST_END(Repeat) 359AST_END(Repeat)
@@ -381,9 +391,10 @@ AST_NODE(CatchBlock)
381AST_END(CatchBlock) 391AST_END(CatchBlock)
382 392
383AST_NODE(Try) 393AST_NODE(Try)
394 ast_ptr<false, ExistentialOp_t> eop;
384 ast_sel<true, Block_t, Exp_t> func; 395 ast_sel<true, Block_t, Exp_t> func;
385 ast_ptr<false, CatchBlock_t> catchBlock; 396 ast_ptr<false, CatchBlock_t> catchBlock;
386 AST_MEMBER(Try, &func, &catchBlock) 397 AST_MEMBER(Try, &eop, &func, &catchBlock)
387AST_END(Try) 398AST_END(Try)
388 399
389AST_NODE(Comprehension) 400AST_NODE(Comprehension)
@@ -547,8 +558,8 @@ AST_NODE(SimpleValue)
547 ast_sel<true, 558 ast_sel<true,
548 TableLit_t, ConstValue_t, 559 TableLit_t, ConstValue_t,
549 If_t, Switch_t, With_t, ClassDecl_t, 560 If_t, Switch_t, With_t, ClassDecl_t,
550 ForEach_t, For_t, While_t, Do_t, Try_t, 561 ForEach_t, For_t, While_t, Repeat_t,
551 UnaryValue_t, 562 Do_t, Try_t, UnaryValue_t,
552 TblComprehension_t, Comprehension_t, 563 TblComprehension_t, Comprehension_t,
553 FunLit_t, Num_t, VarArg_t> value; 564 FunLit_t, Num_t, VarArg_t> value;
554 AST_MEMBER(SimpleValue, &value) 565 AST_MEMBER(SimpleValue, &value)
@@ -587,8 +598,31 @@ AST_NODE(DoubleString)
587 AST_MEMBER(DoubleString, &sep, &segments) 598 AST_MEMBER(DoubleString, &sep, &segments)
588AST_END(DoubleString) 599AST_END(DoubleString)
589 600
601AST_LEAF(YAMLIndent)
602AST_END(YAMLIndent)
603
604AST_LEAF(YAMLLineInner)
605AST_END(YAMLLineInner)
606
607AST_NODE(YAMLLineContent)
608 ast_sel<true, YAMLLineInner_t, Exp_t> content;
609 AST_MEMBER(YAMLLineContent, &content)
610AST_END(YAMLLineContent)
611
612AST_NODE(YAMLLine)
613 ast_ptr<true, YAMLIndent_t> indent;
614 ast_list<true, YAMLLineContent_t> segments;
615 AST_MEMBER(YAMLLine, &indent, &segments)
616AST_END(YAMLLine)
617
618AST_NODE(YAMLMultiline)
619 ast_ptr<true, Seperator_t> sep;
620 ast_list<true, YAMLLine_t> lines;
621 AST_MEMBER(YAMLMultiline, &sep, &lines)
622AST_END(YAMLMultiline)
623
590AST_NODE(String) 624AST_NODE(String)
591 ast_sel<true, DoubleString_t, SingleString_t, LuaString_t> str; 625 ast_sel<true, DoubleString_t, SingleString_t, LuaString_t, YAMLMultiline_t> str;
592 AST_MEMBER(String, &str) 626 AST_MEMBER(String, &str)
593AST_END(String) 627AST_END(String)
594 628
@@ -639,9 +673,14 @@ AST_END(TableAppendingOp)
639AST_LEAF(PlainItem) 673AST_LEAF(PlainItem)
640AST_END(PlainItem) 674AST_END(PlainItem)
641 675
676AST_NODE(ReversedIndex)
677 ast_ptr<false, Exp_t> modifier;
678 AST_MEMBER(ReversedIndex, &modifier)
679AST_END(ReversedIndex)
680
642AST_NODE(ChainValue) 681AST_NODE(ChainValue)
643 ast_ptr<true, Seperator_t> sep; 682 ast_ptr<true, Seperator_t> sep;
644 ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Slice_t, Exp_t, String_t, InvokeArgs_t, ExistentialOp_t, TableAppendingOp_t, 683 ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Slice_t, Exp_t, String_t, InvokeArgs_t, ExistentialOp_t, TableAppendingOp_t, ReversedIndex_t,
645 /*non-syntax-rule*/ PlainItem_t> items; 684 /*non-syntax-rule*/ PlainItem_t> items;
646 AST_MEMBER(ChainValue, &sep, &items) 685 AST_MEMBER(ChainValue, &sep, &items)
647AST_END(ChainValue) 686AST_END(ChainValue)
@@ -725,8 +764,9 @@ AST_LEAF(GlobalOp)
725AST_END(GlobalOp) 764AST_END(GlobalOp)
726 765
727AST_NODE(Global) 766AST_NODE(Global)
767 ast_ptr<false, ConstAttrib_t> constAttrib;
728 ast_sel<true, ClassDecl_t, GlobalOp_t, GlobalValues_t> item; 768 ast_sel<true, ClassDecl_t, GlobalOp_t, GlobalValues_t> item;
729 AST_MEMBER(Global, &item) 769 AST_MEMBER(Global, &constAttrib, &item)
730AST_END(Global) 770AST_END(Global)
731 771
732AST_LEAF(ExportDefault) 772AST_LEAF(ExportDefault)
@@ -742,15 +782,17 @@ AST_END(Export)
742AST_NODE(FnArgDef) 782AST_NODE(FnArgDef)
743 ast_sel<true, Variable_t, SelfItem_t> name; 783 ast_sel<true, Variable_t, SelfItem_t> name;
744 ast_ptr<false, ExistentialOp_t> op; 784 ast_ptr<false, ExistentialOp_t> op;
785 ast_ptr<false, Name_t> label;
745 ast_ptr<false, Exp_t> defaultValue; 786 ast_ptr<false, Exp_t> defaultValue;
746 AST_MEMBER(FnArgDef, &name, &op, &defaultValue) 787 AST_MEMBER(FnArgDef, &name, &op, &label, &defaultValue)
747AST_END(FnArgDef) 788AST_END(FnArgDef)
748 789
749AST_NODE(FnArgDefList) 790AST_NODE(FnArgDefList)
750 ast_ptr<true, Seperator_t> sep; 791 ast_ptr<true, Seperator_t> sep;
751 ast_list<false, FnArgDef_t> definitions; 792 ast_list<false, FnArgDef_t> definitions;
752 ast_ptr<false, VarArg_t> varArg; 793 ast_ptr<false, VarArg_t> varArg;
753 AST_MEMBER(FnArgDefList, &sep, &definitions, &varArg) 794 ast_ptr<false, Name_t> label;
795 AST_MEMBER(FnArgDefList, &sep, &definitions, &varArg, &label)
754AST_END(FnArgDefList) 796AST_END(FnArgDefList)
755 797
756AST_NODE(OuterVarShadow) 798AST_NODE(OuterVarShadow)
@@ -838,9 +880,15 @@ AST_NODE(UnaryExp)
838 AST_MEMBER(UnaryExp, &ops, &expos, &inExp) 880 AST_MEMBER(UnaryExp, &ops, &expos, &inExp)
839AST_END(UnaryExp) 881AST_END(UnaryExp)
840 882
883AST_NODE(SubBackcall)
884 ast_ptr<true, FnArrowBack_t> arrow;
885 ast_ptr<true, ChainValue_t> value;
886 AST_MEMBER(SubBackcall, &arrow, &value)
887AST_END(SubBackcall)
888
841AST_NODE(ExpListAssign) 889AST_NODE(ExpListAssign)
842 ast_ptr<true, ExpList_t> expList; 890 ast_ptr<true, ExpList_t> expList;
843 ast_sel<false, Update_t, Assign_t> action; 891 ast_sel<false, Update_t, Assign_t, SubBackcall_t> action;
844 AST_MEMBER(ExpListAssign, &expList, &action) 892 AST_MEMBER(ExpListAssign, &expList, &action)
845AST_END(ExpListAssign) 893AST_END(ExpListAssign)
846 894
@@ -856,7 +904,17 @@ AST_NODE(WhileLine)
856 AST_MEMBER(WhileLine, &type, &condition) 904 AST_MEMBER(WhileLine, &type, &condition)
857AST_END(WhileLine) 905AST_END(WhileLine)
858 906
859AST_LEAF(BreakLoop) 907AST_LEAF(Break)
908AST_END(Break)
909
910AST_LEAF(Continue)
911AST_END(Continue)
912
913AST_NODE(BreakLoop)
914 ast_sel<true, Break_t, Continue_t> type;
915 ast_ptr<false, Exp_t> value;
916 AST_MEMBER(BreakLoop, &type, &value)
917 std::string varBWV;
860AST_END(BreakLoop) 918AST_END(BreakLoop)
861 919
862AST_NODE(PipeBody) 920AST_NODE(PipeBody)
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index 590c502..d676750 100644
--- a/src/yuescript/yue_compiler.cpp
+++ b/src/yuescript/yue_compiler.cpp
@@ -78,7 +78,7 @@ static std::unordered_set<std::string> Metamethods = {
78 "close"s // Lua 5.4 78 "close"s // Lua 5.4
79}; 79};
80 80
81const std::string_view version = "0.27.5"sv; 81const std::string_view version = "0.29.3"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;
@@ -429,8 +429,9 @@ private:
429 }; 429 };
430 enum class VarType { 430 enum class VarType {
431 Local = 0, 431 Local = 0,
432 Const = 1, 432 LocalConst = 1,
433 Global = 2 433 Global = 2,
434 GlobalConst = 3
434 }; 435 };
435 struct Scope { 436 struct Scope {
436 GlobalMode mode = GlobalMode::None; 437 GlobalMode mode = GlobalMode::None;
@@ -558,7 +559,7 @@ private:
558 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) { 559 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) {
559 auto vars = it->vars.get(); 560 auto vars = it->vars.get();
560 auto vit = vars->find(name); 561 auto vit = vars->find(name);
561 if (vit != vars->end() && vit->second != VarType::Global) { 562 if (vit != vars->end() && (vit->second == VarType::Local || vit->second == VarType::LocalConst)) {
562 local = true; 563 local = true;
563 break; 564 break;
564 } 565 }
@@ -571,7 +572,7 @@ private:
571 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) { 572 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) {
572 auto vars = it->vars.get(); 573 auto vars = it->vars.get();
573 auto vit = vars->find(name); 574 auto vit = vars->find(name);
574 if (vit != vars->end() && vit->second == VarType::Global) { 575 if (vit != vars->end() && (vit->second == VarType::Global || vit->second == VarType::GlobalConst)) {
575 global = true; 576 global = true;
576 break; 577 break;
577 } 578 }
@@ -593,7 +594,7 @@ private:
593 auto vars = it->vars.get(); 594 auto vars = it->vars.get();
594 auto vit = vars->find(name); 595 auto vit = vars->find(name);
595 if (vit != vars->end()) { 596 if (vit != vars->end()) {
596 isConst = (vit->second == VarType::Const); 597 isConst = (vit->second == VarType::LocalConst || vit->second == VarType::GlobalConst);
597 break; 598 break;
598 } 599 }
599 if (checkShadowScopeOnly && it->allows) break; 600 if (checkShadowScopeOnly && it->allows) break;
@@ -874,9 +875,9 @@ private:
874 return false; 875 return false;
875 } 876 }
876 877
877 void markVarConst(const std::string& name) { 878 void markVarLocalConst(const std::string& name) {
878 auto& scope = _scopes.back(); 879 auto& scope = _scopes.back();
879 scope.vars->insert_or_assign(name, VarType::Const); 880 scope.vars->insert_or_assign(name, VarType::LocalConst);
880 } 881 }
881 882
882 void markVarShadowed() { 883 void markVarShadowed() {
@@ -895,6 +896,11 @@ private:
895 scope.vars->insert_or_assign(name, VarType::Global); 896 scope.vars->insert_or_assign(name, VarType::Global);
896 } 897 }
897 898
899 void markVarGlobalConst(const std::string& name) {
900 auto& scope = _scopes.back();
901 scope.vars->insert_or_assign(name, VarType::GlobalConst);
902 }
903
898 void addToAllowList(const std::string& name) { 904 void addToAllowList(const std::string& name) {
899 auto& scope = _scopes.back(); 905 auto& scope = _scopes.back();
900 scope.allows->insert(name); 906 scope.allows->insert(name);
@@ -1252,7 +1258,7 @@ private:
1252 1258
1253 template <class T> 1259 template <class T>
1254 ast_ptr<false, T> toAst(std::string_view codes, ast_node* parent) { 1260 ast_ptr<false, T> toAst(std::string_view codes, ast_node* parent) {
1255 auto res = _parser.parse<T>(std::string(codes)); 1261 auto res = _parser.parse<T>(std::string(codes), false);
1256 if (res.error) { 1262 if (res.error) {
1257 throw CompileError(res.error.value().msg, parent); 1263 throw CompileError(res.error.value().msg, parent);
1258 } 1264 }
@@ -1275,6 +1281,8 @@ private:
1275 Common, 1281 Common,
1276 EndWithColon, 1282 EndWithColon,
1277 EndWithEOP, 1283 EndWithEOP,
1284 EndWithSlice,
1285 HasRIndex,
1278 HasEOP, 1286 HasEOP,
1279 HasKeyword, 1287 HasKeyword,
1280 HasUnicode, 1288 HasUnicode,
@@ -1293,6 +1301,9 @@ private:
1293 if (ast_is<ExistentialOp_t>(chainValue->items.back())) { 1301 if (ast_is<ExistentialOp_t>(chainValue->items.back())) {
1294 return ChainType::EndWithEOP; 1302 return ChainType::EndWithEOP;
1295 } 1303 }
1304 if (ast_is<Slice_t>(chainValue->items.back())) {
1305 return ChainType::EndWithSlice;
1306 }
1296 if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) { 1307 if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) {
1297 if (dot->name.is<Metatable_t>()) { 1308 if (dot->name.is<Metatable_t>()) {
1298 return ChainType::Metatable; 1309 return ChainType::Metatable;
@@ -1318,6 +1329,8 @@ private:
1318 } 1329 }
1319 } else if (ast_is<ExistentialOp_t>(item)) { 1330 } else if (ast_is<ExistentialOp_t>(item)) {
1320 return ChainType::HasEOP; 1331 return ChainType::HasEOP;
1332 } else if (ast_is<ReversedIndex_t>(item)) {
1333 return ChainType::HasRIndex;
1321 } 1334 }
1322 } 1335 }
1323 return type; 1336 return type;
@@ -1840,6 +1853,7 @@ private:
1840 case id<ForEach_t>(): transformForEach(static_cast<ForEach_t*>(value), out); break; 1853 case id<ForEach_t>(): transformForEach(static_cast<ForEach_t*>(value), out); break;
1841 case id<For_t>(): transformFor(static_cast<For_t*>(value), out); break; 1854 case id<For_t>(): transformFor(static_cast<For_t*>(value), out); break;
1842 case id<While_t>(): transformWhile(static_cast<While_t*>(value), out); break; 1855 case id<While_t>(): transformWhile(static_cast<While_t*>(value), out); break;
1856 case id<Repeat_t>(): transformRepeat(static_cast<Repeat_t*>(value), out); break;
1843 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Common); break; 1857 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Common); break;
1844 case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Common); break; 1858 case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Common); break;
1845 case id<Comprehension_t>(): { 1859 case id<Comprehension_t>(): {
@@ -2051,13 +2065,16 @@ private:
2051 if (item.targetVar.empty()) { 2065 if (item.targetVar.empty()) {
2052 throw CompileError("can only declare variable as const"sv, item.target); 2066 throw CompileError("can only declare variable as const"sv, item.target);
2053 } 2067 }
2054 markVarConst(item.targetVar); 2068 markVarLocalConst(item.targetVar);
2055 } 2069 }
2056 } 2070 }
2057 } 2071 }
2058 } 2072 }
2059 2073
2060 bool transformAssignment(ExpListAssign_t* assignment, str_list& out, bool optionalDestruct = false) { 2074 bool transformAssignment(ExpListAssign_t* assignment, str_list& out, bool optionalDestruct = false) {
2075 if (assignment->action.is<SubBackcall_t>()) {
2076 YUEE("AST node mismatch", assignment->action);
2077 }
2061 checkAssignable(assignment->expList); 2078 checkAssignable(assignment->expList);
2062 BLOCK_START 2079 BLOCK_START
2063 auto assign = ast_cast<Assign_t>(assignment->action); 2080 auto assign = ast_cast<Assign_t>(assignment->action);
@@ -2320,6 +2337,17 @@ private:
2320 out.back().insert(0, preDefine); 2337 out.back().insert(0, preDefine);
2321 return false; 2338 return false;
2322 } 2339 }
2340 case id<Try_t>(): {
2341 auto tryNode = static_cast<Try_t*>(value);
2342 if (tryNode->eop) {
2343 auto assignList = assignment->expList.get();
2344 std::string preDefine = getPreDefineLine(assignment);
2345 transformTry(tryNode, out, ExpUsage::Assignment, assignList);
2346 out.back().insert(0, preDefine);
2347 return false;
2348 }
2349 break;
2350 }
2323 case id<Switch_t>(): { 2351 case id<Switch_t>(): {
2324 auto switchNode = static_cast<Switch_t*>(value); 2352 auto switchNode = static_cast<Switch_t*>(value);
2325 auto assignList = assignment->expList.get(); 2353 auto assignList = assignment->expList.get();
@@ -2391,6 +2419,13 @@ private:
2391 out.back().insert(0, preDefine); 2419 out.back().insert(0, preDefine);
2392 return false; 2420 return false;
2393 } 2421 }
2422 case id<Repeat_t>(): {
2423 auto expList = assignment->expList.get();
2424 std::string preDefine = getPreDefineLine(assignment);
2425 transformRepeatInPlace(static_cast<Repeat_t*>(value), out, expList);
2426 out.back().insert(0, preDefine);
2427 return false;
2428 }
2394 case id<TableLit_t>(): { 2429 case id<TableLit_t>(): {
2395 auto tableLit = static_cast<TableLit_t*>(value); 2430 auto tableLit = static_cast<TableLit_t*>(value);
2396 if (hasSpreadExp(tableLit->values.objects())) { 2431 if (hasSpreadExp(tableLit->values.objects())) {
@@ -2443,12 +2478,14 @@ private:
2443 switch (type) { 2478 switch (type) {
2444 case ChainType::HasEOP: 2479 case ChainType::HasEOP:
2445 case ChainType::EndWithColon: 2480 case ChainType::EndWithColon:
2481 case ChainType::EndWithSlice:
2446 case ChainType::MetaFieldInvocation: { 2482 case ChainType::MetaFieldInvocation: {
2447 std::string preDefine = getPreDefineLine(assignment); 2483 std::string preDefine = getPreDefineLine(assignment);
2448 transformChainValue(chainValue, out, ExpUsage::Assignment, expList, false, optionalDestruct); 2484 transformChainValue(chainValue, out, ExpUsage::Assignment, expList, false, optionalDestruct);
2449 out.back().insert(0, preDefine); 2485 out.back().insert(0, preDefine);
2450 return false; 2486 return false;
2451 } 2487 }
2488 case ChainType::HasRIndex:
2452 case ChainType::HasKeyword: 2489 case ChainType::HasKeyword:
2453 case ChainType::HasUnicode: 2490 case ChainType::HasUnicode:
2454 case ChainType::Macro: 2491 case ChainType::Macro:
@@ -2464,6 +2501,10 @@ private:
2464 auto info = extractDestructureInfo(assignment, false, optionalDestruct); 2501 auto info = extractDestructureInfo(assignment, false, optionalDestruct);
2465 if (info.destructures.empty()) { 2502 if (info.destructures.empty()) {
2466 transformAssignmentCommon(assignment, out); 2503 transformAssignmentCommon(assignment, out);
2504 if (assignment->expList->followStmt) {
2505 transformStatement(assignment->expList->followStmt, out);
2506 assignment->expList->followStmtProcessed = true;
2507 }
2467 return true; 2508 return true;
2468 } else { 2509 } else {
2469 auto x = assignment; 2510 auto x = assignment;
@@ -2729,8 +2770,12 @@ private:
2729 temp.push_back(indent() + "end"s + nlr(x)); 2770 temp.push_back(indent() + "end"s + nlr(x));
2730 } 2771 }
2731 out.push_back(join(temp)); 2772 out.push_back(join(temp));
2773 if (assignment->expList->followStmt) {
2774 transformStatement(assignment->expList->followStmt, out);
2775 assignment->expList->followStmtProcessed = true;
2776 }
2777 return false;
2732 } 2778 }
2733 return false;
2734 } 2779 }
2735 2780
2736 void transformAssignItem(ast_node* value, str_list& out) { 2781 void transformAssignItem(ast_node* value, str_list& out) {
@@ -2796,20 +2841,46 @@ private:
2796 if (!tableItems) throw CompileError("invalid destructure value"sv, node); 2841 if (!tableItems) throw CompileError("invalid destructure value"sv, node);
2797 std::list<DestructItem> pairs; 2842 std::list<DestructItem> pairs;
2798 int index = 0; 2843 int index = 0;
2844 int count = 0;
2845 bool hasSpread = false;
2799 auto subMetaDestruct = node->new_ptr<TableLit_t>(); 2846 auto subMetaDestruct = node->new_ptr<TableLit_t>();
2800 for (auto pair : *tableItems) { 2847 for (auto pair : *tableItems) {
2801 switch (pair->get_id()) { 2848 switch (pair->get_id()) {
2802 case id<Exp_t>(): 2849 case id<Exp_t>():
2803 case id<NormalDef_t>(): { 2850 case id<NormalDef_t>(): {
2851 ++index;
2804 Exp_t* defVal = nullptr; 2852 Exp_t* defVal = nullptr;
2805 if (auto nd = ast_cast<NormalDef_t>(pair)) { 2853 if (auto nd = ast_cast<NormalDef_t>(pair)) {
2806 pair = nd->item.get(); 2854 pair = nd->item.get();
2807 defVal = nd->defVal.get(); 2855 defVal = nd->defVal.get();
2808 } 2856 }
2809 ++index; 2857 bool assignable = false;
2810 if (!varDefOnly && !isAssignable(static_cast<Exp_t*>(pair))) { 2858 try {
2859 assignable = isAssignable(static_cast<Exp_t*>(pair));
2860 } catch (const CompileError& e) {
2861 if (!varDefOnly) throw e;
2862 }
2863 if (!assignable && !varDefOnly) {
2864 if (optional) break;
2811 throw CompileError("can't destructure value"sv, pair); 2865 throw CompileError("can't destructure value"sv, pair);
2812 } 2866 }
2867 ast_ptr<true, ast_node> indexItem;
2868 if (hasSpread) {
2869 int rIndex = count - index;
2870 indexItem.set(toAst<ReversedIndex_t>('#' + (rIndex == 0 ? Empty : "-"s + std::to_string(rIndex)), pair));
2871 } else {
2872 indexItem.set(toAst<Exp_t>(std::to_string(index), pair));
2873 }
2874 if (optional && varDefOnly && !assignable) {
2875 if (defVal) {
2876 throw CompileError("default value is not supported here"sv, defVal);
2877 }
2878 auto exp = static_cast<Exp_t*>(pair);
2879 auto chain = exp->new_ptr<ChainValue_t>();
2880 chain->items.push_back(indexItem);
2881 pairs.push_back({exp, Empty, chain, nullptr});
2882 break;
2883 }
2813 auto value = singleValueFrom(pair); 2884 auto value = singleValueFrom(pair);
2814 auto item = value->item.get(); 2885 auto item = value->item.get();
2815 ast_node* subExp = ast_cast<SimpleTable_t>(item); 2886 ast_node* subExp = ast_cast<SimpleTable_t>(item);
@@ -2820,7 +2891,6 @@ private:
2820 throw CompileError("default value is not supported here"sv, defVal); 2891 throw CompileError("default value is not supported here"sv, defVal);
2821 } 2892 }
2822 } 2893 }
2823 auto indexItem = toAst<Exp_t>(std::to_string(index), value);
2824 for (auto& p : subPairs) { 2894 for (auto& p : subPairs) {
2825 if (sep) p.structure->items.push_front(sep); 2895 if (sep) p.structure->items.push_front(sep);
2826 p.structure->items.push_front(indexItem); 2896 p.structure->items.push_front(indexItem);
@@ -2831,7 +2901,6 @@ private:
2831 auto varName = singleVariableFrom(exp, AccessType::None); 2901 auto varName = singleVariableFrom(exp, AccessType::None);
2832 if (varName == "_"sv) break; 2902 if (varName == "_"sv) break;
2833 auto chain = exp->new_ptr<ChainValue_t>(); 2903 auto chain = exp->new_ptr<ChainValue_t>();
2834 auto indexItem = toAst<Exp_t>(std::to_string(index), exp);
2835 chain->items.push_back(indexItem); 2904 chain->items.push_back(indexItem);
2836 pairs.push_back({exp, 2905 pairs.push_back({exp,
2837 varName, 2906 varName,
@@ -2889,7 +2958,25 @@ private:
2889 } 2958 }
2890 } 2959 }
2891 if (auto exp = np->value.as<Exp_t>()) { 2960 if (auto exp = np->value.as<Exp_t>()) {
2892 if (!varDefOnly && !isAssignable(exp)) throw CompileError("can't do destructure value"sv, exp); 2961 bool assignable = false;
2962 try {
2963 assignable = isAssignable(exp);
2964 } catch (const CompileError& e) {
2965 if (!varDefOnly) throw e;
2966 }
2967 if (!assignable && !varDefOnly) {
2968 if (optional) break;
2969 throw CompileError("can't destructure value"sv, pair);
2970 }
2971 if (optional && varDefOnly && !assignable) {
2972 if (defVal) {
2973 throw CompileError("default value is not supported here"sv, defVal);
2974 }
2975 auto chain = exp->new_ptr<ChainValue_t>();
2976 if (keyIndex) chain->items.push_back(keyIndex);
2977 pairs.push_back({exp, Empty, chain, nullptr});
2978 break;
2979 }
2893 auto item = singleValueFrom(exp)->item.get(); 2980 auto item = singleValueFrom(exp)->item.get();
2894 ast_node* subExp = ast_cast<SimpleTable_t>(item); 2981 ast_node* subExp = ast_cast<SimpleTable_t>(item);
2895 if (subExp || (subExp = item->get_by_path<TableLit_t>()) || (subExp = item->get_by_path<Comprehension_t>())) { 2982 if (subExp || (subExp = item->get_by_path<TableLit_t>()) || (subExp = item->get_by_path<Comprehension_t>())) {
@@ -2938,7 +3025,13 @@ private:
2938 auto tb = static_cast<TableBlockIndent_t*>(pair); 3025 auto tb = static_cast<TableBlockIndent_t*>(pair);
2939 ++index; 3026 ++index;
2940 auto subPairs = destructFromExp(tb, varDefOnly, optional); 3027 auto subPairs = destructFromExp(tb, varDefOnly, optional);
2941 auto indexItem = toAst<Exp_t>(std::to_string(index), tb); 3028 ast_ptr<true, ast_node> indexItem;
3029 if (hasSpread) {
3030 int rIndex = count - index;
3031 indexItem.set(toAst<ReversedIndex_t>('#' + (rIndex == 0 ? Empty : "-"s + std::to_string(rIndex)), tb));
3032 } else {
3033 indexItem.set(toAst<Exp_t>(std::to_string(index), tb));
3034 }
2942 for (auto& p : subPairs) { 3035 for (auto& p : subPairs) {
2943 if (sep) p.structure->items.push_front(sep); 3036 if (sep) p.structure->items.push_front(sep);
2944 p.structure->items.push_front(indexItem); 3037 p.structure->items.push_front(indexItem);
@@ -2995,6 +3088,42 @@ private:
2995 subMetaDestruct->values.push_back(newPairDef); 3088 subMetaDestruct->values.push_back(newPairDef);
2996 break; 3089 break;
2997 } 3090 }
3091 case id<SpreadListExp_t>():
3092 case id<SpreadExp_t>(): {
3093 ++index;
3094 if (hasSpread) {
3095 throw CompileError("duplicated spread expression"sv, pair);
3096 }
3097 hasSpread = true;
3098 for (auto item : *tableItems) {
3099 if (ast_is<
3100 SpreadListExp_t, SpreadExp_t,
3101 TableBlockIndent_t,
3102 Exp_t, NormalDef_t>(item)) {
3103 count++;
3104 }
3105 }
3106 Exp_t* exp = nullptr;
3107 if (auto se = ast_cast<SpreadExp_t>(pair)) {
3108 exp = se->exp.get();
3109 } else {
3110 exp = ast_to<SpreadListExp_t>(pair)->exp.get();
3111 }
3112 auto varName = singleVariableFrom(exp, AccessType::None);
3113 if (varName == "_"sv) break;
3114 int start = index;
3115 int stop = index - count - 1;
3116 auto chain = exp->new_ptr<ChainValue_t>();
3117 auto slice = toAst<Slice_t>(
3118 '[' + (start == 1 ? Empty : std::to_string(start)) + ',' + (stop == -1 ? Empty : std::to_string(stop)) + ']', exp);
3119 chain->items.push_back(slice);
3120 auto nil = toAst<Exp_t>("nil"sv, slice);
3121 pairs.push_back({exp,
3122 varName,
3123 chain,
3124 nil.get()});
3125 break;
3126 }
2998 default: YUEE("AST node mismatch", pair); break; 3127 default: YUEE("AST node mismatch", pair); break;
2999 } 3128 }
3000 } 3129 }
@@ -3111,7 +3240,11 @@ private:
3111 break; 3240 break;
3112 default: YUEE("AST node mismatch", destructNode); break; 3241 default: YUEE("AST node mismatch", destructNode); break;
3113 } 3242 }
3114 if (dlist->empty()) throw CompileError("expect items to be destructured"sv, destructNode); 3243 if (dlist->empty()) {
3244 if (!optional) {
3245 throw CompileError("expect items to be destructured"sv, destructNode);
3246 }
3247 }
3115 for (auto item : *dlist) { 3248 for (auto item : *dlist) {
3116 switch (item->get_id()) { 3249 switch (item->get_id()) {
3117 case id<MetaVariablePairDef_t>(): { 3250 case id<MetaVariablePairDef_t>(): {
@@ -3247,7 +3380,9 @@ private:
3247 simpleValue->value.set(tab); 3380 simpleValue->value.set(tab);
3248 auto pairs = destructFromExp(newExp(simpleValue, expr), varDefOnly, optional); 3381 auto pairs = destructFromExp(newExp(simpleValue, expr), varDefOnly, optional);
3249 if (pairs.empty()) { 3382 if (pairs.empty()) {
3250 throw CompileError("expect items to be destructured"sv, tab); 3383 if (!optional) {
3384 throw CompileError("expect items to be destructured"sv, tab);
3385 }
3251 } 3386 }
3252 destruct.items = std::move(pairs); 3387 destruct.items = std::move(pairs);
3253 if (!varDefOnly) { 3388 if (!varDefOnly) {
@@ -3286,7 +3421,7 @@ private:
3286 destruct.valueVar.clear(); 3421 destruct.valueVar.clear();
3287 } 3422 }
3288 } 3423 }
3289 destructs.push_back(destruct); 3424 destructs.push_back(std::move(destruct));
3290 } 3425 }
3291 } 3426 }
3292 } else { 3427 } else {
@@ -4205,12 +4340,22 @@ private:
4205 4340
4206 std::optional<std::pair<std::string, str_list>> upValueFuncFromExp(Exp_t* exp, str_list* ensureArgListInTheEnd, bool blockRewrite) { 4341 std::optional<std::pair<std::string, str_list>> upValueFuncFromExp(Exp_t* exp, str_list* ensureArgListInTheEnd, bool blockRewrite) {
4207 if (checkUpValueFuncAvailable(exp)) { 4342 if (checkUpValueFuncAvailable(exp)) {
4343 auto block = exp->new_ptr<Block_t>();
4344 if (auto sVal = simpleSingleValueFrom(exp)) {
4345 if (auto doNode = sVal->value.as<Do_t>()) {
4346 if (auto blk = doNode->body->content.as<Block_t>()) {
4347 block->statements.dup(blk->statements);
4348 } else {
4349 block->statements.push_back(doNode->body->content.to<Statement_t>());
4350 }
4351 return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false, blockRewrite);
4352 }
4353 }
4208 auto returnNode = exp->new_ptr<Return_t>(); 4354 auto returnNode = exp->new_ptr<Return_t>();
4209 returnNode->explicitReturn = false; 4355 returnNode->explicitReturn = false;
4210 auto returnList = exp->new_ptr<ExpListLow_t>(); 4356 auto returnList = exp->new_ptr<ExpListLow_t>();
4211 returnList->exprs.push_back(exp); 4357 returnList->exprs.push_back(exp);
4212 returnNode->valueList.set(returnList); 4358 returnNode->valueList.set(returnList);
4213 auto block = exp->new_ptr<Block_t>();
4214 auto stmt = exp->new_ptr<Statement_t>(); 4359 auto stmt = exp->new_ptr<Statement_t>();
4215 stmt->content.set(returnNode); 4360 stmt->content.set(returnNode);
4216 block->statements.push_back(stmt); 4361 block->statements.push_back(stmt);
@@ -4287,7 +4432,9 @@ private:
4287 return false; 4432 return false;
4288 }; 4433 };
4289 switch (usage) { 4434 switch (usage) {
4290 case ExpUsage::Common: YUEE("AST node mismatch", x); return; 4435 case ExpUsage::Common:
4436 YUEE("AST node mismatch", x);
4437 return;
4291 case ExpUsage::Return: 4438 case ExpUsage::Return:
4292 case ExpUsage::Closure: { 4439 case ExpUsage::Closure: {
4293 prepareValue(); 4440 prepareValue();
@@ -4410,6 +4557,7 @@ private:
4410 case id<ForEach_t>(): transformForEachClosure(static_cast<ForEach_t*>(value), out); break; 4557 case id<ForEach_t>(): transformForEachClosure(static_cast<ForEach_t*>(value), out); break;
4411 case id<For_t>(): transformForClosure(static_cast<For_t*>(value), out); break; 4558 case id<For_t>(): transformForClosure(static_cast<For_t*>(value), out); break;
4412 case id<While_t>(): transformWhileClosure(static_cast<While_t*>(value), out); break; 4559 case id<While_t>(): transformWhileClosure(static_cast<While_t*>(value), out); break;
4560 case id<Repeat_t>(): transformRepeatClosure(static_cast<Repeat_t*>(value), out); break;
4413 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Closure); break; 4561 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Closure); break;
4414 case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Closure); break; 4562 case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Closure); break;
4415 case id<UnaryValue_t>(): transformUnaryValue(static_cast<UnaryValue_t*>(value), out); break; 4563 case id<UnaryValue_t>(): transformUnaryValue(static_cast<UnaryValue_t*>(value), out); break;
@@ -4729,11 +4877,7 @@ private:
4729 auto newBody = x->new_ptr<Body_t>(); 4877 auto newBody = x->new_ptr<Body_t>();
4730 newBody->content.set(followingBlock); 4878 newBody->content.set(followingBlock);
4731 { 4879 {
4732 auto doNode = x->new_ptr<Do_t>(); 4880 if (auto result = upValueFuncFromBlock(followingBlock.get(), &argNames, false, true)) {
4733 doNode->body.set(newBody);
4734 auto simpleValue = x->new_ptr<SimpleValue_t>();
4735 simpleValue->value.set(doNode);
4736 if (auto result = upValueFuncFromExp(newExp(simpleValue, x), &argNames, true)) {
4737 auto [funcName, args] = std::move(*result); 4881 auto [funcName, args] = std::move(*result);
4738 str_list finalArgs; 4882 str_list finalArgs;
4739 for (const auto& arg : args) { 4883 for (const auto& arg : args) {
@@ -4741,9 +4885,13 @@ private:
4741 finalArgs.push_back(arg); 4885 finalArgs.push_back(arg);
4742 } 4886 }
4743 } 4887 }
4744 newBlock->statements.push_back(toAst<Statement_t>(funcName + ' ' + join(finalArgs, ","sv), x)); 4888 newBlock->statements.push_back(toAst<Statement_t>(funcName + ' ' + (finalArgs.empty() ? "nil"s : join(finalArgs, ","sv)), x));
4745 auto sVal = singleValueFrom(static_cast<Statement_t*>(newBlock->statements.back())->content.to<ExpListAssign_t>()->expList); 4889 auto sVal = singleValueFrom(static_cast<Statement_t*>(newBlock->statements.back())->content.to<ExpListAssign_t>()->expList);
4746 ast_to<InvokeArgs_t>(sVal->item.to<ChainValue_t>()->items.back())->args.dup(newInvoke->args); 4890 auto invokArgs = ast_to<InvokeArgs_t>(sVal->item.to<ChainValue_t>()->items.back());
4891 if (finalArgs.empty()) {
4892 invokArgs->args.clear();
4893 }
4894 invokArgs->args.dup(newInvoke->args);
4747 transformBlock(newBlock, out, usage, assignList, isRoot); 4895 transformBlock(newBlock, out, usage, assignList, isRoot);
4748 return; 4896 return;
4749 } 4897 }
@@ -4820,6 +4968,38 @@ private:
4820 newBlock->statements.push_back(toAst<Statement_t>("if "s + okVar + " then return ... else error ..."s, x)); 4968 newBlock->statements.push_back(toAst<Statement_t>("if "s + okVar + " then return ... else error ..."s, x));
4821 transformBlock(newBlock, out, usage, assignList, isRoot); 4969 transformBlock(newBlock, out, usage, assignList, isRoot);
4822 return; 4970 return;
4971 } else if (auto expListAssign = stmt->content.as<ExpListAssign_t>();
4972 expListAssign && expListAssign->action && expListAssign->action.is<SubBackcall_t>()) {
4973 auto x = *nodes.begin();
4974 auto newBlock = x->new_ptr<Block_t>();
4975 if (it != nodes.begin()) {
4976 for (auto i = nodes.begin(); i != it; ++i) {
4977 newBlock->statements.push_back(*i);
4978 }
4979 }
4980 auto doBackcall = static_cast<SubBackcall_t*>(expListAssign->action.get());
4981 auto backcall = expListAssign->new_ptr<Backcall_t>();
4982 auto argsDef = backcall->new_ptr<FnArgsDef_t>();
4983 try {
4984 auto defList = toAst<FnArgDefList_t>(YueFormat{}.toString(expListAssign->expList), expListAssign->expList);
4985 argsDef->defList.set(defList);
4986 } catch (const std::exception&) {
4987 throw CompileError("backcall syntax error", backcall);
4988 }
4989 backcall->argsDef.set(argsDef);
4990 backcall->arrow.set(doBackcall->arrow);
4991 backcall->value.set(doBackcall->value);
4992 auto newStmt = backcall->new_ptr<Statement_t>();
4993 newStmt->content.set(backcall);
4994 newStmt->comments.dup(stmt->comments);
4995 newStmt->appendix.set(stmt->appendix);
4996 newBlock->statements.push_back(newStmt);
4997 auto ait = it;
4998 for (auto i = ++ait; i != nodes.end(); ++i) {
4999 newBlock->statements.push_back(*i);
5000 }
5001 transformBlock(newBlock, out, usage, assignList, isRoot);
5002 return;
4823 } 5003 }
4824 if (auto local = stmt->content.as<Local_t>()) { 5004 if (auto local = stmt->content.as<Local_t>()) {
4825 if (!local->collected) { 5005 if (!local->collected) {
@@ -4991,36 +5171,45 @@ private:
4991 if (!nodes.empty()) { 5171 if (!nodes.empty()) {
4992 str_list temp; 5172 str_list temp;
4993 for (auto node : nodes) { 5173 for (auto node : nodes) {
4994 currentScope().lastStatement = (node == nodes.back()) && currentScope().mode == GlobalMode::None; 5174 auto transformNode = [&]() {
4995 transformStatement(static_cast<Statement_t*>(node), temp); 5175 currentScope().lastStatement = (node == nodes.back()) && currentScope().mode == GlobalMode::None;
4996 if (isRoot && !_rootDefs.empty()) { 5176 transformStatement(static_cast<Statement_t*>(node), temp);
4997 auto last = std::move(temp.back()); 5177 if (isRoot && !_rootDefs.empty()) {
4998 temp.pop_back(); 5178 auto last = std::move(temp.back());
4999 temp.insert(temp.end(), _rootDefs.begin(), _rootDefs.end()); 5179 temp.pop_back();
5000 _rootDefs.clear(); 5180 temp.insert(temp.end(), _rootDefs.begin(), _rootDefs.end());
5001 temp.push_back(std::move(last)); 5181 _rootDefs.clear();
5002 } 5182 temp.push_back(std::move(last));
5003 if (!temp.empty() && _parser.startWith<StatementSep_t>(temp.back())) { 5183 }
5004 auto rit = ++temp.rbegin(); 5184 if (!temp.empty() && _parser.startWith<StatementSep_t>(temp.back())) {
5005 if (rit != temp.rend() && !rit->empty()) { 5185 auto rit = ++temp.rbegin();
5006 auto index = std::string::npos; 5186 if (rit != temp.rend() && !rit->empty()) {
5007 if (_config.reserveLineNumber) { 5187 auto index = std::string::npos;
5008 index = rit->rfind(" -- "sv); 5188 if (_config.reserveLineNumber) {
5009 } else { 5189 index = rit->rfind(" -- "sv);
5010 index = rit->find_last_not_of('\n'); 5190 } else {
5011 if (index != std::string::npos) index++; 5191 index = rit->find_last_not_of('\n');
5012 } 5192 if (index != std::string::npos) index++;
5013 if (index != std::string::npos) {
5014 auto ending = rit->substr(0, index);
5015 auto ind = ending.find_last_of(" \t\n"sv);
5016 if (ind != std::string::npos) {
5017 ending = ending.substr(ind + 1);
5018 } 5193 }
5019 if (LuaKeywords.find(ending) == LuaKeywords.end()) { 5194 if (index != std::string::npos) {
5020 rit->insert(index, ";"sv); 5195 auto ending = rit->substr(0, index);
5196 auto ind = ending.find_last_of(" \t\n"sv);
5197 if (ind != std::string::npos) {
5198 ending = ending.substr(ind + 1);
5199 }
5200 if (LuaKeywords.find(ending) == LuaKeywords.end()) {
5201 rit->insert(index, ";"sv);
5202 }
5021 } 5203 }
5022 } 5204 }
5023 } 5205 }
5206 };
5207 if (_config.lax) {
5208 try {
5209 transformNode();
5210 } catch (const CompileError&) { }
5211 } else {
5212 transformNode();
5024 } 5213 }
5025 } 5214 }
5026 out.push_back(join(temp)); 5215 out.push_back(join(temp));
@@ -5229,18 +5418,29 @@ private:
5229 auto macroLit = macro->decl.to<MacroLit_t>(); 5418 auto macroLit = macro->decl.to<MacroLit_t>();
5230 auto argsDef = macroLit->argsDef.get(); 5419 auto argsDef = macroLit->argsDef.get();
5231 str_list newArgs; 5420 str_list newArgs;
5421 str_list argChecks;
5422 bool hasCheck = false;
5232 if (argsDef) { 5423 if (argsDef) {
5233 for (auto def_ : argsDef->definitions.objects()) { 5424 for (auto def_ : argsDef->definitions.objects()) {
5234 auto def = static_cast<FnArgDef_t*>(def_); 5425 auto def = static_cast<FnArgDef_t*>(def_);
5235 if (def->name.is<SelfItem_t>()) { 5426 if (def->name.is<SelfItem_t>()) {
5236 throw CompileError("self name is not supported for macro function argument"sv, def->name); 5427 throw CompileError("self name is not supported for macro function argument"sv, def->name);
5237 } else { 5428 } else {
5429 if (def->op) throw CompileError("invalid existence checking"sv, def->op);
5430 if (def->label) {
5431 hasCheck = true;
5432 const auto& astName = argChecks.emplace_back(_parser.toString(def->label));
5433 if (!_parser.hasAST(astName)) {
5434 throw CompileError("invalid AST name"sv, def->label);
5435 }
5436 } else {
5437 argChecks.emplace_back();
5438 }
5238 std::string defVal; 5439 std::string defVal;
5239 if (def->defaultValue) { 5440 if (def->defaultValue) {
5240 defVal = _parser.toString(def->defaultValue); 5441 defVal = _parser.toString(def->defaultValue);
5241 Utils::trim(defVal); 5442 Utils::trim(defVal);
5242 defVal.insert(0, "=[==========["sv); 5443 defVal = '=' + Utils::toLuaDoubleString(defVal);
5243 defVal.append("]==========]"sv);
5244 } 5444 }
5245 newArgs.emplace_back(_parser.toString(def->name) + defVal); 5445 newArgs.emplace_back(_parser.toString(def->name) + defVal);
5246 } 5446 }
@@ -5248,6 +5448,14 @@ private:
5248 if (argsDef->varArg) { 5448 if (argsDef->varArg) {
5249 newArgs.emplace_back(_parser.toString(argsDef->varArg)); 5449 newArgs.emplace_back(_parser.toString(argsDef->varArg));
5250 } 5450 }
5451 if (argsDef->label) {
5452 hasCheck = true;
5453 const auto& astName = _parser.toString(argsDef->label);
5454 if (!_parser.hasAST(astName)) {
5455 throw CompileError("invalid AST name"sv, argsDef->label);
5456 }
5457 argChecks.emplace_back("..."s + astName);
5458 }
5251 } 5459 }
5252 std::string macroCodes = "_ENV=require('yue').macro_env\n("s + join(newArgs, ","sv) + ")->"s + _parser.toString(macroLit->body); 5460 std::string macroCodes = "_ENV=require('yue').macro_env\n("s + join(newArgs, ","sv) + ")->"s + _parser.toString(macroLit->body);
5253 auto chunkName = "=(macro "s + macroName + ')'; 5461 auto chunkName = "=(macro "s + macroName + ')';
@@ -5278,6 +5486,24 @@ private:
5278 throw CompileError("failed to generate macro function\n"s + err, macroLit); 5486 throw CompileError("failed to generate macro function\n"s + err, macroLit);
5279 } // cur true macro 5487 } // cur true macro
5280 lua_remove(L, -2); // cur macro 5488 lua_remove(L, -2); // cur macro
5489 if (hasCheck) {
5490 lua_createtable(L, 0, 0); // cur macro checks
5491 int i = 1;
5492 for (const auto& check : argChecks) {
5493 if (check.empty()) {
5494 lua_pushboolean(L, 0);
5495 lua_rawseti(L, -2, i);
5496 } else {
5497 lua_pushlstring(L, check.c_str(), check.size());
5498 lua_rawseti(L, -2, i);
5499 }
5500 i++;
5501 }
5502 lua_createtable(L, 2, 0); // cur macro checks macrotab
5503 lua_insert(L, -3); // cur macrotab macro checks
5504 lua_rawseti(L, -3, 1); // macrotab[1] = checks, cur macrotab macro
5505 lua_rawseti(L, -2, 2); // macrotab[2] = macro, cur macrotab
5506 } // cur macro
5281 if (exporting && _config.exporting && !_config.module.empty()) { 5507 if (exporting && _config.exporting && !_config.module.empty()) {
5282 pushModuleTable(_config.module); // cur macro module 5508 pushModuleTable(_config.module); // cur macro module
5283 lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro module name 5509 lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro module name
@@ -5352,6 +5578,9 @@ private:
5352 case id<While_t>(): 5578 case id<While_t>():
5353 transformWhileInPlace(static_cast<While_t*>(value), out); 5579 transformWhileInPlace(static_cast<While_t*>(value), out);
5354 return; 5580 return;
5581 case id<Repeat_t>():
5582 transformRepeatInPlace(static_cast<Repeat_t*>(value), out);
5583 return;
5355 case id<For_t>(): 5584 case id<For_t>():
5356 transformForInPlace(static_cast<For_t*>(value), out); 5585 transformForInPlace(static_cast<For_t*>(value), out);
5357 return; 5586 return;
@@ -5432,7 +5661,11 @@ private:
5432 auto def = static_cast<FnArgDef_t*>(_def); 5661 auto def = static_cast<FnArgDef_t*>(_def);
5433 auto& arg = argItems.emplace_back(); 5662 auto& arg = argItems.emplace_back();
5434 switch (def->name->get_id()) { 5663 switch (def->name->get_id()) {
5435 case id<Variable_t>(): arg.name = variableToString(static_cast<Variable_t*>(def->name.get())); break; 5664 case id<Variable_t>(): {
5665 if (def->op) throw CompileError("invalid existence checking"sv, def->op);
5666 arg.name = variableToString(static_cast<Variable_t*>(def->name.get()));
5667 break;
5668 }
5436 case id<SelfItem_t>(): { 5669 case id<SelfItem_t>(): {
5437 assignSelf = true; 5670 assignSelf = true;
5438 if (def->op) { 5671 if (def->op) {
@@ -5571,6 +5804,45 @@ private:
5571 } 5804 }
5572 } 5805 }
5573 5806
5807 bool transformChainEndWithSlice(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) {
5808 auto x = chainList.front();
5809 if (ast_is<Slice_t>(chainList.back())) {
5810 auto comp = x->new_ptr<Comprehension_t>();
5811 {
5812 auto chainValue = x->new_ptr<ChainValue_t>();
5813 for (auto item : chainList) {
5814 chainValue->items.push_back(item);
5815 }
5816 auto itemVar = getUnusedName("_item_"sv);
5817 auto expCode = YueFormat{}.toString(chainValue);
5818 auto compCode = '[' + itemVar + " for "s + itemVar + " in *"s + expCode + ']';
5819 comp.set(toAst<Comprehension_t>(compCode, x));
5820 }
5821 switch (usage) {
5822 case ExpUsage::Assignment: {
5823 auto simpleValue = x->new_ptr<SimpleValue_t>();
5824 simpleValue->value.set(comp);
5825 auto exp = newExp(simpleValue, x);
5826 auto assignment = x->new_ptr<ExpListAssign_t>();
5827 assignment->expList.set(assignList);
5828 auto assign = x->new_ptr<Assign_t>();
5829 assign->values.push_back(exp);
5830 assignment->action.set(assign);
5831 transformAssignment(assignment, out);
5832 break;
5833 }
5834 case ExpUsage::Return:
5835 transformComprehension(comp, out, ExpUsage::Return);
5836 break;
5837 default:
5838 transformComprehension(comp, out, ExpUsage::Closure);
5839 break;
5840 }
5841 return true;
5842 }
5843 return false;
5844 }
5845
5574 bool transformChainEndWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) { 5846 bool transformChainEndWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) {
5575 auto x = chainList.front(); 5847 auto x = chainList.front();
5576 if (ast_is<ExistentialOp_t>(chainList.back())) { 5848 if (ast_is<ExistentialOp_t>(chainList.back())) {
@@ -6088,7 +6360,7 @@ private:
6088 case id<ColonChainItem_t>(): 6360 case id<ColonChainItem_t>():
6089 case id<Exp_t>(): 6361 case id<Exp_t>():
6090 if (_withVars.empty()) { 6362 if (_withVars.empty()) {
6091 throw CompileError("short dot/colon and indexing syntax must be called within a with block"sv, x); 6363 throw CompileError("short dot/colon/indexing syntax must be called within a with block"sv, x);
6092 } else { 6364 } else {
6093 temp.push_back(_withVars.top()); 6365 temp.push_back(_withVars.top());
6094 } 6366 }
@@ -6234,6 +6506,93 @@ private:
6234 } 6506 }
6235 return; 6507 return;
6236 } 6508 }
6509 break;
6510 }
6511 case id<ReversedIndex_t>(): {
6512 auto rIndex = static_cast<ReversedIndex_t*>(*it);
6513 auto current = it;
6514 auto prevChain = x->new_ptr<ChainValue_t>();
6515 for (auto i = chainList.begin(); i != current; ++i) {
6516 prevChain->items.push_back(*i);
6517 }
6518 auto var = singleVariableFrom(prevChain, AccessType::None);
6519 if (!var.empty() && isLocal(var)) {
6520 auto indexNode = toAst<Exp_t>('#' + var, rIndex);
6521 if (rIndex->modifier) {
6522 auto opValue = rIndex->new_ptr<ExpOpValue_t>();
6523 opValue->op.set(toAst<BinaryOperator_t>("-"sv, rIndex));
6524 opValue->pipeExprs.dup(rIndex->modifier->pipeExprs);
6525 indexNode->opValues.push_back(opValue);
6526 indexNode->opValues.dup(rIndex->modifier->opValues);
6527 indexNode->nilCoalesed.set(rIndex->modifier->nilCoalesed);
6528 }
6529 prevChain->items.push_back(indexNode);
6530 auto next = current;
6531 ++next;
6532 for (auto i = next; i != chainList.end(); ++i) {
6533 prevChain->items.push_back(*i);
6534 }
6535 if (usage == ExpUsage::Assignment) {
6536 auto assignment = x->new_ptr<ExpListAssign_t>();
6537 assignment->expList.set(assignList);
6538 auto assign = x->new_ptr<Assign_t>();
6539 assign->values.push_back(newExp(prevChain, x));
6540 assignment->action.set(assign);
6541 transformAssignment(assignment, out);
6542 return;
6543 }
6544 transformChainValue(prevChain, out, usage, assignList);
6545 return;
6546 } else {
6547 auto itemVar = getUnusedName("_item_"sv);
6548 auto asmt = assignmentFrom(toAst<Exp_t>(itemVar, x), newExp(prevChain, x), x);
6549 auto stmt1 = x->new_ptr<Statement_t>();
6550 stmt1->content.set(asmt);
6551 auto newChain = x->new_ptr<ChainValue_t>();
6552 newChain->items.push_back(toAst<Callable_t>(itemVar, x));
6553 auto indexNode = toAst<Exp_t>('#' + itemVar, rIndex);
6554 if (rIndex->modifier) {
6555 auto opValue = rIndex->new_ptr<ExpOpValue_t>();
6556 opValue->op.set(toAst<BinaryOperator_t>("-"sv, rIndex));
6557 opValue->pipeExprs.dup(rIndex->modifier->pipeExprs);
6558 indexNode->opValues.push_back(opValue);
6559 indexNode->opValues.dup(rIndex->modifier->opValues);
6560 indexNode->nilCoalesed.set(rIndex->modifier->nilCoalesed);
6561 }
6562 newChain->items.push_back(indexNode);
6563 auto next = current;
6564 ++next;
6565 for (auto i = next; i != chainList.end(); ++i) {
6566 newChain->items.push_back(*i);
6567 }
6568 auto expList = x->new_ptr<ExpList_t>();
6569 expList->exprs.push_back(newExp(newChain, x));
6570 auto expListAssign = x->new_ptr<ExpListAssign_t>();
6571 expListAssign->expList.set(expList);
6572 auto stmt2 = x->new_ptr<Statement_t>();
6573 stmt2->content.set(expListAssign);
6574 auto block = x->new_ptr<Block_t>();
6575 block->statements.push_back(stmt1);
6576 block->statements.push_back(stmt2);
6577 auto body = x->new_ptr<Body_t>();
6578 body->content.set(block);
6579 auto doNode = x->new_ptr<Do_t>();
6580 doNode->body.set(body);
6581 if (usage == ExpUsage::Assignment) {
6582 auto assignment = x->new_ptr<ExpListAssign_t>();
6583 assignment->expList.set(assignList);
6584 auto assign = x->new_ptr<Assign_t>();
6585 auto sVal = x->new_ptr<SimpleValue_t>();
6586 sVal->value.set(doNode);
6587 assign->values.push_back(newExp(sVal, x));
6588 assignment->action.set(assign);
6589 transformAssignment(assignment, out);
6590 return;
6591 }
6592 transformDo(doNode, out, usage);
6593 return;
6594 }
6595 break;
6237 } 6596 }
6238 } 6597 }
6239 } 6598 }
@@ -6418,7 +6777,7 @@ private:
6418 } 6777 }
6419 } 6778 }
6420 } 6779 }
6421 int len = lua_objlen(L, -1); 6780 int len = static_cast<int>(lua_objlen(L, -1));
6422 lua_pushnil(L); // cur nil 6781 lua_pushnil(L); // cur nil
6423 for (int i = len; i >= 1; i--) { 6782 for (int i = len; i >= 1; i--) {
6424 lua_pop(L, 1); // cur 6783 lua_pop(L, 1); // cur
@@ -6430,7 +6789,25 @@ private:
6430 break; 6789 break;
6431 } 6790 }
6432 } 6791 }
6433 if (!lua_isfunction(L, -1)) { 6792 str_list checks;
6793 if (lua_istable(L, -1)) {
6794 lua_rawgeti(L, -1, 1); // cur macrotab checks
6795 int len = static_cast<int>(lua_objlen(L, -1));
6796 for (int i = 1; i <= len; i++) {
6797 lua_rawgeti(L, -1, i);
6798 if (lua_toboolean(L, -1) == 0) {
6799 checks.emplace_back();
6800 } else {
6801 size_t str_len = 0;
6802 auto str = lua_tolstring(L, -1, &str_len);
6803 checks.emplace_back(std::string{str, str_len});
6804 }
6805 lua_pop(L, 1);
6806 }
6807 lua_pop(L, 1);
6808 lua_rawgeti(L, -1, 2); // cur macrotab macroFunc
6809 lua_remove(L, -2); // cur macroFunc
6810 } else if (!lua_isfunction(L, -1)) {
6434 auto code = expandBuiltinMacro(macroName, x); 6811 auto code = expandBuiltinMacro(macroName, x);
6435 if (!code.empty()) return code; 6812 if (!code.empty()) return code;
6436 if (macroName == "is_ast"sv) { 6813 if (macroName == "is_ast"sv) {
@@ -6475,11 +6852,34 @@ private:
6475 } // cur macroFunc 6852 } // cur macroFunc
6476 pushYue("pcall"sv); // cur macroFunc pcall 6853 pushYue("pcall"sv); // cur macroFunc pcall
6477 lua_insert(L, -2); // cur pcall macroFunc 6854 lua_insert(L, -2); // cur pcall macroFunc
6478 if (!lua_checkstack(L, argStrs.size())) { 6855 if (!lua_checkstack(L, static_cast<int>(argStrs.size()))) {
6479 throw CompileError("too much macro params"s, x); 6856 throw CompileError("too much macro params"s, x);
6480 } 6857 }
6858 auto checkIt = checks.begin();
6859 node_container::const_iterator argIt;
6860 if (args) {
6861 argIt = args->begin();
6862 }
6481 for (const auto& arg : argStrs) { 6863 for (const auto& arg : argStrs) {
6864 if (checkIt != checks.end()) {
6865 if (checkIt->empty()) {
6866 ++checkIt;
6867 } else {
6868 if ((*checkIt)[0] == '.') {
6869 auto astName = checkIt->substr(3);
6870 if (!_parser.match(astName, arg)) {
6871 throw CompileError("expecting \""s + astName + "\", AST mismatch"s, *argIt);
6872 }
6873 } else {
6874 if (!_parser.match(*checkIt, arg)) {
6875 throw CompileError("expecting \""s + *checkIt + "\", AST mismatch"s, *argIt);
6876 }
6877 ++checkIt;
6878 }
6879 }
6880 }
6482 lua_pushlstring(L, arg.c_str(), arg.size()); 6881 lua_pushlstring(L, arg.c_str(), arg.size());
6882 ++argIt;
6483 } // cur pcall macroFunc args... 6883 } // cur pcall macroFunc args...
6484 bool success = lua_pcall(L, static_cast<int>(argStrs.size()), 1, 0) == 0; 6884 bool success = lua_pcall(L, static_cast<int>(argStrs.size()), 1, 0) == 0;
6485 if (!success) { // cur err 6885 if (!success) { // cur err
@@ -6609,14 +7009,14 @@ private:
6609 } else { 7009 } else {
6610 if (!codes.empty()) { 7010 if (!codes.empty()) {
6611 if (isBlock) { 7011 if (isBlock) {
6612 info = _parser.parse<BlockEnd_t>(codes); 7012 info = _parser.parse<BlockEnd_t>(codes, false);
6613 if (info.error) { 7013 if (info.error) {
6614 throw CompileError("failed to expand macro as block: "s + info.error.value().msg, x); 7014 throw CompileError("failed to expand macro as block: "s + info.error.value().msg, x);
6615 } 7015 }
6616 } else { 7016 } else {
6617 info = _parser.parse<Exp_t>(codes); 7017 info = _parser.parse<Exp_t>(codes, false);
6618 if (!info.node && allowBlockMacroReturn) { 7018 if (!info.node && allowBlockMacroReturn) {
6619 info = _parser.parse<BlockEnd_t>(codes); 7019 info = _parser.parse<BlockEnd_t>(codes, false);
6620 if (info.error) { 7020 if (info.error) {
6621 throw CompileError("failed to expand macro as expr or block: "s + info.error.value().msg, x); 7021 throw CompileError("failed to expand macro as expr or block: "s + info.error.value().msg, x);
6622 } 7022 }
@@ -6752,6 +7152,9 @@ private:
6752 if (transformChainEndWithColonItem(chainList, out, usage, assignList)) { 7152 if (transformChainEndWithColonItem(chainList, out, usage, assignList)) {
6753 return; 7153 return;
6754 } 7154 }
7155 if (transformChainEndWithSlice(chainList, out, usage, assignList)) {
7156 return;
7157 }
6755 transformChainList(chainList, out, usage, assignList); 7158 transformChainList(chainList, out, usage, assignList);
6756 } 7159 }
6757 7160
@@ -7153,7 +7556,7 @@ private:
7153 try { 7556 try {
7154 unsigned long long value = std::stoull(binaryPart, nullptr, 2); 7557 unsigned long long value = std::stoull(binaryPart, nullptr, 2);
7155 numStr = std::to_string(value); 7558 numStr = std::to_string(value);
7156 } catch (const std::exception& e) { 7559 } catch (const std::exception&) {
7157 throw CompileError("invalid binary literal"sv, num); 7560 throw CompileError("invalid binary literal"sv, num);
7158 } 7561 }
7159 } else if (getLuaTarget(num) < 502) { 7562 } else if (getLuaTarget(num) < 502) {
@@ -7859,6 +8262,11 @@ private:
7859 } 8262 }
7860 8263
7861 bool transformForEachHead(AssignableNameList_t* nameList, ast_node* loopTarget, str_list& out, bool inClosure) { 8264 bool transformForEachHead(AssignableNameList_t* nameList, ast_node* loopTarget, str_list& out, bool inClosure) {
8265 enum class NumState {
8266 Unknown,
8267 Positive,
8268 Negtive
8269 };
7862 auto x = nameList; 8270 auto x = nameList;
7863 str_list temp; 8271 str_list temp;
7864 str_list vars; 8272 str_list vars;
@@ -7925,15 +8333,35 @@ private:
7925 for (auto item : chainList) { 8333 for (auto item : chainList) {
7926 chain->items.push_back(item); 8334 chain->items.push_back(item);
7927 } 8335 }
7928 std::string startValue("1"sv); 8336 std::string startValue;
8337 NumState startStatus = NumState::Unknown;
7929 if (auto exp = slice->startValue.as<Exp_t>()) { 8338 if (auto exp = slice->startValue.as<Exp_t>()) {
7930 transformExp(exp, temp, ExpUsage::Closure); 8339 transformExp(exp, temp, ExpUsage::Closure);
8340 if (temp.back().at(0) == '-') {
8341 if (_parser.match<Num_t>(temp.back().substr(1))) {
8342 startStatus = NumState::Negtive;
8343 }
8344 } else {
8345 if (_parser.match<Num_t>(temp.back())) {
8346 startStatus = NumState::Positive;
8347 }
8348 }
7931 startValue = std::move(temp.back()); 8349 startValue = std::move(temp.back());
7932 temp.pop_back(); 8350 temp.pop_back();
7933 } 8351 }
7934 std::string stopValue; 8352 std::string stopValue;
8353 NumState stopStatus = NumState::Unknown;
7935 if (auto exp = slice->stopValue.as<Exp_t>()) { 8354 if (auto exp = slice->stopValue.as<Exp_t>()) {
7936 transformExp(exp, temp, ExpUsage::Closure); 8355 transformExp(exp, temp, ExpUsage::Closure);
8356 if (temp.back().at(0) == '-') {
8357 if (_parser.match<Num_t>(temp.back().substr(1))) {
8358 stopStatus = NumState::Negtive;
8359 }
8360 } else {
8361 if (_parser.match<Num_t>(temp.back())) {
8362 stopStatus = NumState::Positive;
8363 }
8364 }
7937 stopValue = std::move(temp.back()); 8365 stopValue = std::move(temp.back());
7938 temp.pop_back(); 8366 temp.pop_back();
7939 } 8367 }
@@ -7955,8 +8383,33 @@ private:
7955 transformChainValue(chain, temp, ExpUsage::Closure); 8383 transformChainValue(chain, temp, ExpUsage::Closure);
7956 _buf << prefix << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList); 8384 _buf << prefix << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList);
7957 } 8385 }
8386 if (startValue.empty()) {
8387 startValue = "1"s;
8388 startStatus = NumState::Positive;
8389 }
8390 std::string minVar;
8391 if (startStatus != NumState::Positive) {
8392 std::string prefix;
8393 if (!extraScope && !inClosure && needScope) {
8394 extraScope = true;
8395 prefix = indent() + "do"s + nll(x);
8396 pushScope();
8397 }
8398 minVar = getUnusedName("_min_"sv);
8399 varBefore.push_back(minVar);
8400 if (startStatus == NumState::Negtive) {
8401 _buf << prefix << indent() << "local "sv << minVar << " = "sv << "#"sv << listVar << " + "sv << startValue << " + 1"sv << nll(nameList);
8402 } else {
8403 _buf << prefix << indent() << "local "sv << minVar << " = "sv << startValue << nll(nameList);
8404 }
8405 }
8406 bool defaultStop = false;
8407 if (stopValue.empty()) {
8408 stopValue = "#"s + listVar;
8409 defaultStop = true;
8410 }
7958 std::string maxVar; 8411 std::string maxVar;
7959 if (!stopValue.empty()) { 8412 if (stopStatus != NumState::Positive) {
7960 std::string prefix; 8413 std::string prefix;
7961 if (!extraScope && !inClosure && needScope) { 8414 if (!extraScope && !inClosure && needScope) {
7962 extraScope = true; 8415 extraScope = true;
@@ -7965,14 +8418,45 @@ private:
7965 } 8418 }
7966 maxVar = getUnusedName("_max_"sv); 8419 maxVar = getUnusedName("_max_"sv);
7967 varBefore.push_back(maxVar); 8420 varBefore.push_back(maxVar);
7968 _buf << prefix << indent() << "local "sv << maxVar << " = "sv << stopValue << nll(nameList); 8421 if (stopStatus == NumState::Negtive) {
8422 _buf << indent() << "local "sv << maxVar << " = "sv << "#"sv << listVar << " + "sv << stopValue << " + 1"sv << nll(nameList);
8423 } else {
8424 _buf << prefix << indent() << "local "sv << maxVar << " = "sv << stopValue << nll(nameList);
8425 }
8426 }
8427 if (startStatus == NumState::Unknown) {
8428 _buf << indent() << minVar << " = "sv << minVar << " < 0 and #"sv << listVar << " + "sv << minVar << " + 1 or "sv << minVar << nll(nameList);
8429 }
8430 if (!defaultStop && stopStatus == NumState::Unknown) {
8431 _buf << indent() << maxVar << " = "sv << maxVar << " < 0 and #"sv << listVar << " + "sv << maxVar << " + 1 or "sv << maxVar << nll(nameList);
7969 } 8432 }
7970 _buf << indent() << "for "sv << indexVar << " = "sv; 8433 _buf << indent() << "for "sv << indexVar << " = "sv;
7971 _buf << startValue << ", "sv; 8434 if (startValue.empty()) {
8435 _buf << "1"sv;
8436 } else {
8437 switch (startStatus) {
8438 case NumState::Unknown:
8439 case NumState::Negtive:
8440 _buf << minVar;
8441 break;
8442 case NumState::Positive:
8443 _buf << startValue;
8444 break;
8445 }
8446 }
8447 _buf << ", "sv;
7972 if (stopValue.empty()) { 8448 if (stopValue.empty()) {
7973 _buf << "#"sv << listVar; 8449 _buf << "#"sv << listVar;
7974 } else { 8450 } else {
7975 _buf << maxVar << " < 0 and #"sv << listVar << " + "sv << maxVar << " or "sv << maxVar; 8451 switch (stopStatus) {
8452 case NumState::Unknown:
8453 case NumState::Negtive:
8454 _buf << maxVar;
8455 break;
8456 case NumState::Positive:
8457 _buf << stopValue;
8458 break;
8459 }
7976 } 8460 }
7977 if (!stepValue.empty()) { 8461 if (!stepValue.empty()) {
7978 _buf << ", "sv << stepValue; 8462 _buf << ", "sv << stepValue;
@@ -8012,7 +8496,7 @@ private:
8012 pushScope(); 8496 pushScope();
8013 for (const auto& var : vars) forceAddToScope(var); 8497 for (const auto& var : vars) forceAddToScope(var);
8014 for (const auto& var : varAfter) addToScope(var); 8498 for (const auto& var : varAfter) addToScope(var);
8015 if (!varConstAfter.empty()) markVarConst(varConstAfter); 8499 if (!varConstAfter.empty()) markVarLocalConst(varConstAfter);
8016 if (!destructPairs.empty()) { 8500 if (!destructPairs.empty()) {
8017 temp.clear(); 8501 temp.clear();
8018 for (auto& pair : destructPairs) { 8502 for (auto& pair : destructPairs) {
@@ -8097,7 +8581,7 @@ private:
8097 _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : ", "s + step) << " do"sv << nll(var); 8581 _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : ", "s + step) << " do"sv << nll(var);
8098 pushScope(); 8582 pushScope();
8099 forceAddToScope(varName); 8583 forceAddToScope(varName);
8100 markVarConst(varName); 8584 markVarLocalConst(varName);
8101 out.push_back(clearBuf()); 8585 out.push_back(clearBuf());
8102 } 8586 }
8103 8587
@@ -8105,26 +8589,59 @@ private:
8105 transformForHead(forNode->varName, forNode->startValue, forNode->stopValue, forNode->stepValue, out); 8589 transformForHead(forNode->varName, forNode->startValue, forNode->stopValue, forNode->stepValue, out);
8106 } 8590 }
8107 8591
8108 void transform_plain_body(ast_node* body, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { 8592 void transform_plain_body(ast_node* bodyOrStmt, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
8109 switch (body->get_id()) { 8593 switch (bodyOrStmt->get_id()) {
8110 case id<Block_t>(): 8594 case id<Block_t>():
8111 transformBlock(static_cast<Block_t*>(body), out, usage, assignList); 8595 transformBlock(static_cast<Block_t*>(bodyOrStmt), out, usage, assignList);
8112 break; 8596 break;
8113 case id<Statement_t>(): { 8597 case id<Statement_t>(): {
8114 auto newBlock = body->new_ptr<Block_t>(); 8598 auto newBlock = bodyOrStmt->new_ptr<Block_t>();
8115 newBlock->statements.push_back(body); 8599 newBlock->statements.push_back(bodyOrStmt);
8116 transformBlock(newBlock, out, usage, assignList); 8600 transformBlock(newBlock, out, usage, assignList);
8117 break; 8601 break;
8118 } 8602 }
8119 default: YUEE("AST node mismatch", body); break; 8603 default: YUEE("AST node mismatch", bodyOrStmt); break;
8120 } 8604 }
8121 } 8605 }
8122 8606
8123 bool hasContinueStatement(ast_node* body) { 8607 enum class BreakLoopType {
8124 return traversal::Stop == body->traverse([&](ast_node* node) { 8608 None = 0,
8609 Break = 1,
8610 BreakWithValue = 1 << 1,
8611 Continue = 1 << 2
8612 };
8613
8614 bool hasBreak(uint32_t breakLoopType) const {
8615 return (breakLoopType & int(BreakLoopType::Break)) != 0;
8616 }
8617
8618 bool hasBreakWithValue(uint32_t breakLoopType) const {
8619 return (breakLoopType & int(BreakLoopType::BreakWithValue)) != 0;
8620 }
8621
8622 bool hasContinue(uint32_t breakLoopType) const {
8623 return (breakLoopType & int(BreakLoopType::Continue)) != 0;
8624 }
8625
8626 uint32_t getBreakLoopType(ast_node* body, const std::string& varBWV) {
8627 uint32_t type = 0;
8628 body->traverse([&](ast_node* node) {
8125 if (auto stmt = ast_cast<Statement_t>(node)) { 8629 if (auto stmt = ast_cast<Statement_t>(node)) {
8126 if (stmt->content.is<BreakLoop_t>()) { 8630 if (auto breakLoop = stmt->content.as<BreakLoop_t>()) {
8127 return _parser.toString(stmt->content) == "continue"sv ? traversal::Stop : traversal::Return; 8631 if (breakLoop->type.is<Continue_t>()) {
8632 type |= int(BreakLoopType::Continue);
8633 return traversal::Return;
8634 } else {
8635 if (breakLoop->value) {
8636 if (varBWV.empty()) {
8637 throw CompileError("break with a value is not allowed here"sv, breakLoop->value);
8638 }
8639 type |= int(BreakLoopType::BreakWithValue);
8640 breakLoop->varBWV = varBWV;
8641 } else {
8642 type |= int(BreakLoopType::Break);
8643 }
8644 }
8128 } else if (auto expList = expListFrom(stmt)) { 8645 } else if (auto expList = expListFrom(stmt)) {
8129 BLOCK_START 8646 BLOCK_START
8130 auto value = singleValueFrom(expList); 8647 auto value = singleValueFrom(expList);
@@ -8135,40 +8652,30 @@ private:
8135 switch (sVal->get_id()) { 8652 switch (sVal->get_id()) {
8136 case id<With_t>(): { 8653 case id<With_t>(): {
8137 auto withNode = static_cast<With_t*>(sVal); 8654 auto withNode = static_cast<With_t*>(sVal);
8138 if (hasContinueStatement(withNode->body)) { 8655 type |= getBreakLoopType(withNode->body, varBWV);
8139 return traversal::Stop; 8656 return traversal::Return;
8140 }
8141 break;
8142 } 8657 }
8143 case id<Do_t>(): { 8658 case id<Do_t>(): {
8144 auto doNode = static_cast<Do_t*>(sVal); 8659 auto doNode = static_cast<Do_t*>(sVal);
8145 if (hasContinueStatement(doNode->body)) { 8660 type |= getBreakLoopType(doNode->body, varBWV);
8146 return traversal::Stop; 8661 return traversal::Return;
8147 }
8148 break;
8149 } 8662 }
8150 case id<If_t>(): { 8663 case id<If_t>(): {
8151 auto ifNode = static_cast<If_t*>(sVal); 8664 auto ifNode = static_cast<If_t*>(sVal);
8152 for (auto n : ifNode->nodes.objects()) { 8665 for (auto n : ifNode->nodes.objects()) {
8153 if (hasContinueStatement(n)) { 8666 type |= getBreakLoopType(n, varBWV);
8154 return traversal::Stop;
8155 }
8156 } 8667 }
8157 break; 8668 return traversal::Return;
8158 } 8669 }
8159 case id<Switch_t>(): { 8670 case id<Switch_t>(): {
8160 auto switchNode = static_cast<Switch_t*>(sVal); 8671 auto switchNode = static_cast<Switch_t*>(sVal);
8161 for (auto branch : switchNode->branches.objects()) { 8672 for (auto branch : switchNode->branches.objects()) {
8162 if (hasContinueStatement(static_cast<SwitchCase_t*>(branch)->body)) { 8673 type |= getBreakLoopType(static_cast<SwitchCase_t*>(branch)->body, varBWV);
8163 return traversal::Stop;
8164 }
8165 } 8674 }
8166 if (switchNode->lastBranch) { 8675 if (switchNode->lastBranch) {
8167 if (hasContinueStatement(switchNode->lastBranch)) { 8676 type |= getBreakLoopType(switchNode->lastBranch, varBWV);
8168 return traversal::Stop;
8169 }
8170 } 8677 }
8171 break; 8678 return traversal::Return;
8172 } 8679 }
8173 } 8680 }
8174 BLOCK_END 8681 BLOCK_END
@@ -8182,6 +8689,7 @@ private:
8182 } 8689 }
8183 return traversal::Return; 8690 return traversal::Return;
8184 }); 8691 });
8692 return type;
8185 } 8693 }
8186 8694
8187 void addDoToLastLineReturn(ast_node* body) { 8695 void addDoToLastLineReturn(ast_node* body) {
@@ -8205,10 +8713,10 @@ private:
8205 } 8713 }
8206 } 8714 }
8207 8715
8208 void transformLoopBody(ast_node* body, str_list& out, const std::string& appendContent, ExpUsage usage, ExpList_t* assignList = nullptr) { 8716 void transformLoopBody(ast_node* body, str_list& out, uint32_t breakLoopType, ExpUsage usage, ExpList_t* assignList = nullptr) {
8209 str_list temp; 8717 str_list temp;
8210 bool extraDo = false; 8718 bool extraDo = false;
8211 bool withContinue = hasContinueStatement(body); 8719 bool withContinue = hasContinue(breakLoopType);
8212 int target = getLuaTarget(body); 8720 int target = getLuaTarget(body);
8213 std::string extraLabel; 8721 std::string extraLabel;
8214 if (withContinue) { 8722 if (withContinue) {
@@ -8217,7 +8725,7 @@ private:
8217 if (!block->statements.empty()) { 8725 if (!block->statements.empty()) {
8218 auto stmt = static_cast<Statement_t*>(block->statements.back()); 8726 auto stmt = static_cast<Statement_t*>(block->statements.back());
8219 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { 8727 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) {
8220 extraDo = _parser.toString(breakLoop) == "break"sv; 8728 extraDo = breakLoop->type.is<Break_t>();
8221 } 8729 }
8222 } 8730 }
8223 } 8731 }
@@ -8250,9 +8758,6 @@ private:
8250 popScope(); 8758 popScope();
8251 _buf << indent() << "end"sv << nll(body); 8759 _buf << indent() << "end"sv << nll(body);
8252 } 8760 }
8253 if (!appendContent.empty()) {
8254 _buf << indent() << appendContent;
8255 }
8256 _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); 8761 _buf << indent() << _continueVars.top().var << " = true"sv << nll(body);
8257 popScope(); 8762 popScope();
8258 _buf << indent() << "until true"sv << nlr(body); 8763 _buf << indent() << "until true"sv << nlr(body);
@@ -8262,14 +8767,9 @@ private:
8262 temp.push_back(clearBuf()); 8767 temp.push_back(clearBuf());
8263 _continueVars.pop(); 8768 _continueVars.pop();
8264 } else { 8769 } else {
8265 if (!appendContent.empty()) {
8266 temp.push_back(indent() + appendContent);
8267 }
8268 temp.push_back(extraLabel); 8770 temp.push_back(extraLabel);
8269 _continueVars.pop(); 8771 _continueVars.pop();
8270 } 8772 }
8271 } else if (!appendContent.empty()) {
8272 temp.back().append(indent() + appendContent);
8273 } 8773 }
8274 out.push_back(join(temp)); 8774 out.push_back(join(temp));
8275 } 8775 }
@@ -8277,8 +8777,9 @@ private:
8277 std::string transformRepeatBody(Repeat_t* repeatNode, str_list& out) { 8777 std::string transformRepeatBody(Repeat_t* repeatNode, str_list& out) {
8278 str_list temp; 8778 str_list temp;
8279 bool extraDo = false; 8779 bool extraDo = false;
8280 auto body = repeatNode->body->content.get(); 8780 auto body = repeatNode->body.get();
8281 bool withContinue = hasContinueStatement(body); 8781 auto breakLoopType = getBreakLoopType(body, Empty);
8782 bool withContinue = hasContinue(breakLoopType);
8282 std::string conditionVar; 8783 std::string conditionVar;
8283 std::string extraLabel; 8784 std::string extraLabel;
8284 ast_ptr<false, ExpListAssign_t> condAssign; 8785 ast_ptr<false, ExpListAssign_t> condAssign;
@@ -8289,7 +8790,7 @@ private:
8289 if (!block->statements.empty()) { 8790 if (!block->statements.empty()) {
8290 auto stmt = static_cast<Statement_t*>(block->statements.back()); 8791 auto stmt = static_cast<Statement_t*>(block->statements.back());
8291 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { 8792 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) {
8292 extraDo = _parser.toString(breakLoop) == "break"sv; 8793 extraDo = breakLoop->type.is<Break_t>();
8293 } 8794 }
8294 } 8795 }
8295 } 8796 }
@@ -8352,7 +8853,8 @@ private:
8352 void transformFor(For_t* forNode, str_list& out) { 8853 void transformFor(For_t* forNode, str_list& out) {
8353 str_list temp; 8854 str_list temp;
8354 transformForHead(forNode, temp); 8855 transformForHead(forNode, temp);
8355 transformLoopBody(forNode->body, temp, Empty, ExpUsage::Common); 8856 auto breakLoopType = getBreakLoopType(forNode->body, Empty);
8857 transformLoopBody(forNode->body, temp, breakLoopType, ExpUsage::Common);
8356 popScope(); 8858 popScope();
8357 out.push_back(join(temp) + indent() + "end"s + nlr(forNode)); 8859 out.push_back(join(temp) + indent() + "end"s + nlr(forNode));
8358 } 8860 }
@@ -8363,13 +8865,24 @@ private:
8363 addToScope(accum); 8865 addToScope(accum);
8364 std::string len = getUnusedName("_len_"sv); 8866 std::string len = getUnusedName("_len_"sv);
8365 addToScope(len); 8867 addToScope(len);
8366 _buf << indent() << "local "sv << accum << " = { }"sv << nll(forNode); 8868 auto breakLoopType = getBreakLoopType(forNode->body, accum);
8869 _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(forNode);
8870 out.emplace_back(clearBuf());
8367 _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode); 8871 _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode);
8368 out.push_back(clearBuf()); 8872 auto& lenAssign = out.emplace_back(clearBuf());
8369 transformForHead(forNode, out); 8873 transformForHead(forNode, out);
8370 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); 8874 if (hasBreakWithValue(breakLoopType)) {
8371 auto lenLine = len + " = "s + len + " + 1"s + nlr(forNode->body); 8875 lenAssign.clear();
8372 transformLoopBody(forNode->body, out, lenLine, ExpUsage::Assignment, expList); 8876 transformLoopBody(forNode->body, out, breakLoopType, ExpUsage::Common);
8877 } else {
8878 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x);
8879 auto followStmt = toAst<Statement_t>(len + "+=1"s, forNode->body);
8880 expList->followStmt = followStmt.get();
8881 transformLoopBody(forNode->body, out, breakLoopType, ExpUsage::Assignment, expList);
8882 if (!expList->followStmtProcessed) {
8883 lenAssign.clear();
8884 }
8885 }
8373 popScope(); 8886 popScope();
8374 out.push_back(indent() + "end"s + nlr(forNode)); 8887 out.push_back(indent() + "end"s + nlr(forNode));
8375 return accum; 8888 return accum;
@@ -8448,7 +8961,8 @@ private:
8448 void transformForEach(ForEach_t* forEach, str_list& out) { 8961 void transformForEach(ForEach_t* forEach, str_list& out) {
8449 str_list temp; 8962 str_list temp;
8450 bool extraScoped = transformForEachHead(forEach->nameList, forEach->loopValue, temp, false); 8963 bool extraScoped = transformForEachHead(forEach->nameList, forEach->loopValue, temp, false);
8451 transformLoopBody(forEach->body, temp, Empty, ExpUsage::Common); 8964 auto breakLoopType = getBreakLoopType(forEach->body, Empty);
8965 transformLoopBody(forEach->body, temp, breakLoopType, ExpUsage::Common);
8452 popScope(); 8966 popScope();
8453 out.push_back(temp.front() + temp.back() + indent() + "end"s + nlr(forEach)); 8967 out.push_back(temp.front() + temp.back() + indent() + "end"s + nlr(forEach));
8454 if (extraScoped) { 8968 if (extraScoped) {
@@ -8463,13 +8977,24 @@ private:
8463 addToScope(accum); 8977 addToScope(accum);
8464 std::string len = getUnusedName("_len_"sv); 8978 std::string len = getUnusedName("_len_"sv);
8465 addToScope(len); 8979 addToScope(len);
8466 _buf << indent() << "local "sv << accum << " = { }"sv << nll(forEach); 8980 auto breakLoopType = getBreakLoopType(forEach->body, accum);
8981 _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(forEach);
8982 out.emplace_back(clearBuf());
8467 _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach); 8983 _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach);
8468 out.push_back(clearBuf()); 8984 auto& lenAssign = out.emplace_back(clearBuf());
8469 transformForEachHead(forEach->nameList, forEach->loopValue, out, true); 8985 transformForEachHead(forEach->nameList, forEach->loopValue, out, true);
8470 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); 8986 if (hasBreakWithValue(breakLoopType)) {
8471 auto lenLine = len + " = "s + len + " + 1"s + nlr(forEach->body); 8987 lenAssign.clear();
8472 transformLoopBody(forEach->body, out, lenLine, ExpUsage::Assignment, expList); 8988 transformLoopBody(forEach->body, out, breakLoopType, ExpUsage::Common);
8989 } else {
8990 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x);
8991 auto followStmt = toAst<Statement_t>(len + "+=1"s, forEach->body);
8992 expList->followStmt = followStmt.get();
8993 transformLoopBody(forEach->body, out, breakLoopType, ExpUsage::Assignment, expList);
8994 if (!expList->followStmtProcessed) {
8995 lenAssign.clear();
8996 }
8997 }
8473 popScope(); 8998 popScope();
8474 out.push_back(indent() + "end"s + nlr(forEach)); 8999 out.push_back(indent() + "end"s + nlr(forEach));
8475 return accum; 9000 return accum;
@@ -8653,12 +9178,64 @@ private:
8653 out.push_back(temp.empty() ? "\"\""s : join(temp, " .. "sv)); 9178 out.push_back(temp.empty() ? "\"\""s : join(temp, " .. "sv));
8654 } 9179 }
8655 9180
9181 void transformYAMLMultiline(YAMLMultiline_t* multiline, str_list& out) {
9182 std::optional<std::string> indent;
9183 str_list temp;
9184 for (auto line_ : multiline->lines.objects()) {
9185 auto line = static_cast<YAMLLine_t*>(line_);
9186 auto indentStr = _parser.toString(line->indent);
9187 if (!indent) {
9188 indent = indentStr;
9189 }
9190 if (std::string_view{indentStr.c_str(), indent.value().size()} != indent.value()) {
9191 throw CompileError("inconsistent indent"sv, line);
9192 }
9193 indentStr = indentStr.substr(indent.value().size());
9194 str_list segs;
9195 bool firstSeg = true;
9196 for (auto seg_ : line->segments.objects()) {
9197 auto content = static_cast<YAMLLineContent_t*>(seg_)->content.get();
9198 switch (content->get_id()) {
9199 case id<YAMLLineInner_t>(): {
9200 auto seqStr = _parser.toString(content);
9201 Utils::replace(seqStr, "\\#"sv, "#"sv);
9202 if (firstSeg) {
9203 firstSeg = false;
9204 seqStr.insert(0, indentStr);
9205 }
9206 segs.push_back(Utils::toLuaDoubleString(seqStr));
9207 break;
9208 }
9209 case id<Exp_t>(): {
9210 if (firstSeg) {
9211 firstSeg = false;
9212 if (!indentStr.empty()) {
9213 segs.push_back(Utils::toLuaDoubleString(indentStr));
9214 }
9215 }
9216 transformExp(static_cast<Exp_t*>(content), segs, ExpUsage::Closure);
9217 segs.back() = globalVar("tostring"sv, content, AccessType::Read) + '(' + segs.back() + ')';
9218 break;
9219 }
9220 default: YUEE("AST node mismatch", content); break;
9221 }
9222 }
9223 temp.push_back(join(segs, " .. "sv));
9224 }
9225 auto str = join(temp, " .. '\\n' .. "sv);
9226 Utils::replace(str, "\" .. '\\n' .. \""sv, "\\n"sv);
9227 Utils::replace(str, "\" .. '\\n'"sv, "\\n\""sv);
9228 Utils::replace(str, "'\\n' .. \""sv, "\"\\n"sv);
9229 out.push_back(str);
9230 }
9231
8656 void transformString(String_t* string, str_list& out) { 9232 void transformString(String_t* string, str_list& out) {
8657 auto str = string->str.get(); 9233 auto str = string->str.get();
8658 switch (str->get_id()) { 9234 switch (str->get_id()) {
8659 case id<SingleString_t>(): transformSingleString(static_cast<SingleString_t*>(str), out); break; 9235 case id<SingleString_t>(): transformSingleString(static_cast<SingleString_t*>(str), out); break;
8660 case id<DoubleString_t>(): transformDoubleString(static_cast<DoubleString_t*>(str), out); break; 9236 case id<DoubleString_t>(): transformDoubleString(static_cast<DoubleString_t*>(str), out); break;
8661 case id<LuaString_t>(): transformLuaString(static_cast<LuaString_t*>(str), out); break; 9237 case id<LuaString_t>(): transformLuaString(static_cast<LuaString_t*>(str), out); break;
9238 case id<YAMLMultiline_t>(): transformYAMLMultiline(static_cast<YAMLMultiline_t*>(str), out); break;
8662 default: YUEE("AST node mismatch", str); break; 9239 default: YUEE("AST node mismatch", str); break;
8663 } 9240 }
8664 } 9241 }
@@ -8840,7 +9417,7 @@ private:
8840 auto names = transformAssignDefs(assignment->expList.get(), DefOp::Get); 9417 auto names = transformAssignDefs(assignment->expList.get(), DefOp::Get);
8841 for (const auto& name : names) { 9418 for (const auto& name : names) {
8842 forceAddToScope(name.first); 9419 forceAddToScope(name.first);
8843 markVarConst(name.first); 9420 markVarLocalConst(name.first);
8844 varDefs.push_back(name.first); 9421 varDefs.push_back(name.first);
8845 classConstVars.push_back(name.first); 9422 classConstVars.push_back(name.first);
8846 } 9423 }
@@ -8854,7 +9431,7 @@ private:
8854 for (const auto& item : destruct.items) { 9431 for (const auto& item : destruct.items) {
8855 if (!item.targetVar.empty()) { 9432 if (!item.targetVar.empty()) {
8856 forceAddToScope(item.targetVar); 9433 forceAddToScope(item.targetVar);
8857 markVarConst(item.targetVar); 9434 markVarLocalConst(item.targetVar);
8858 varDefs.push_back(item.targetVar); 9435 varDefs.push_back(item.targetVar);
8859 classConstVars.push_back(item.targetVar); 9436 classConstVars.push_back(item.targetVar);
8860 } 9437 }
@@ -9236,11 +9813,11 @@ private:
9236 std::string withVar; 9813 std::string withVar;
9237 bool needScope = !currentScope().lastStatement && !returnValue; 9814 bool needScope = !currentScope().lastStatement && !returnValue;
9238 bool extraScope = false; 9815 bool extraScope = false;
9239 if (with->assigns) { 9816 if (with->assign) {
9240 auto vars = getAssignVars(with); 9817 auto vars = getAssignVars(with);
9241 if (vars.front().empty() || isDeclaredAsGlobal(vars.front())) { 9818 if (vars.front().empty() || isDeclaredAsGlobal(vars.front())) {
9242 if (with->assigns->values.objects().size() == 1) { 9819 if (with->assign->values.objects().size() == 1) {
9243 auto var = singleVariableFrom(with->assigns->values.objects().front(), AccessType::Read); 9820 auto var = singleVariableFrom(with->assign->values.objects().front(), AccessType::Read);
9244 if (!var.empty() && isLocal(var)) { 9821 if (!var.empty() && isLocal(var)) {
9245 withVar = var; 9822 withVar = var;
9246 } 9823 }
@@ -9250,7 +9827,7 @@ private:
9250 auto assignment = x->new_ptr<ExpListAssign_t>(); 9827 auto assignment = x->new_ptr<ExpListAssign_t>();
9251 assignment->expList.set(toAst<ExpList_t>(withVar, x)); 9828 assignment->expList.set(toAst<ExpList_t>(withVar, x));
9252 auto assign = x->new_ptr<Assign_t>(); 9829 auto assign = x->new_ptr<Assign_t>();
9253 assign->values.push_back(with->assigns->values.objects().front()); 9830 assign->values.push_back(with->assign->values.objects().front());
9254 assignment->action.set(assign); 9831 assignment->action.set(assign);
9255 if (needScope) { 9832 if (needScope) {
9256 extraScope = true; 9833 extraScope = true;
@@ -9264,7 +9841,7 @@ private:
9264 auto assign = x->new_ptr<Assign_t>(); 9841 auto assign = x->new_ptr<Assign_t>();
9265 assign->values.push_back(toAst<Exp_t>(withVar, x)); 9842 assign->values.push_back(toAst<Exp_t>(withVar, x));
9266 bool skipFirst = true; 9843 bool skipFirst = true;
9267 for (auto value : with->assigns->values.objects()) { 9844 for (auto value : with->assign->values.objects()) {
9268 if (skipFirst) { 9845 if (skipFirst) {
9269 skipFirst = false; 9846 skipFirst = false;
9270 continue; 9847 continue;
@@ -9277,7 +9854,7 @@ private:
9277 withVar = vars.front(); 9854 withVar = vars.front();
9278 auto assignment = x->new_ptr<ExpListAssign_t>(); 9855 auto assignment = x->new_ptr<ExpListAssign_t>();
9279 assignment->expList.set(with->valueList); 9856 assignment->expList.set(with->valueList);
9280 assignment->action.set(with->assigns); 9857 assignment->action.set(with->assign);
9281 if (needScope) { 9858 if (needScope) {
9282 extraScope = true; 9859 extraScope = true;
9283 temp.push_back(indent() + "do"s + nll(with)); 9860 temp.push_back(indent() + "do"s + nll(with));
@@ -9355,15 +9932,57 @@ private:
9355 } 9932 }
9356 } 9933 }
9357 _withVars.push(withVar); 9934 _withVars.push(withVar);
9935 std::string breakWithVar;
9936 if (assignList || returnValue) {
9937 auto breakLoopType = getBreakLoopType(with->body, withVar);
9938 if (hasBreakWithValue(breakLoopType)) {
9939 breakWithVar = withVar;
9940 }
9941 }
9358 if (with->eop) { 9942 if (with->eop) {
9359 auto ifNode = x->new_ptr<If_t>(); 9943 auto ifNode = x->new_ptr<If_t>();
9360 ifNode->type.set(toAst<IfType_t>("if"sv, x)); 9944 ifNode->type.set(toAst<IfType_t>("if"sv, x));
9361 ifNode->nodes.push_back(toAst<IfCond_t>(withVar + "~=nil"s, x)); 9945 ifNode->nodes.push_back(toAst<IfCond_t>(withVar + "~=nil"s, x));
9362 ifNode->nodes.push_back(with->body); 9946 ifNode->nodes.push_back(with->body);
9363 transformIf(ifNode, temp, ExpUsage::Common); 9947 if (breakWithVar.empty()) {
9948 transformIf(ifNode, temp, ExpUsage::Common);
9949 } else {
9950 auto simpleValue = x->new_ptr<SimpleValue_t>();
9951 simpleValue->value.set(ifNode);
9952 auto exp = newExp(simpleValue, x);
9953 auto expList = x->new_ptr<ExpList_t>();
9954 expList->exprs.push_back(exp);
9955 auto expListAssign = x->new_ptr<ExpListAssign_t>();
9956 expListAssign->expList.set(expList);
9957 auto stmt = x->new_ptr<Statement_t>();
9958 stmt->content.set(expListAssign);
9959 auto repeatNode = toAst<Repeat_t>("repeat\n\t--\nuntil true"s, x);
9960 auto block = x->new_ptr<Block_t>();
9961 block->statements.push_back(stmt);
9962 repeatNode->body.set(block);
9963 auto sVal = x->new_ptr<SimpleValue_t>();
9964 sVal->value.set(repeatNode);
9965 auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x);
9966 transformAssignment(asmt, temp);
9967 }
9364 } else { 9968 } else {
9365 bool transformed = false; 9969 bool transformed = false;
9366 if (!extraScope && assignList) { 9970 if (!breakWithVar.empty()) {
9971 auto repeatNode = toAst<Repeat_t>("repeat\n\t--\nuntil true"s, x);
9972 auto block = x->new_ptr<Block_t>();
9973 if (auto blk = with->body.as<Block_t>()) {
9974 block->statements.dup(blk->statements);
9975 } else {
9976 auto stmt = with->body.to<Statement_t>();
9977 block->statements.push_back(stmt);
9978 }
9979 repeatNode->body.set(block);
9980 auto sVal = x->new_ptr<SimpleValue_t>();
9981 sVal->value.set(repeatNode);
9982 auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x);
9983 transformAssignment(asmt, temp);
9984 transformed = true;
9985 } else if (!extraScope && assignList) {
9367 if (auto block = with->body.as<Block_t>()) { 9986 if (auto block = with->body.as<Block_t>()) {
9368 if (!block->statements.empty()) { 9987 if (!block->statements.empty()) {
9369 Statement_t* stmt = static_cast<Statement_t*>(block->statements.back()); 9988 Statement_t* stmt = static_cast<Statement_t*>(block->statements.back());
@@ -9428,12 +10047,18 @@ private:
9428 switch (item->get_id()) { 10047 switch (item->get_id()) {
9429 case id<ClassDecl_t>(): { 10048 case id<ClassDecl_t>(): {
9430 auto classDecl = static_cast<ClassDecl_t*>(item); 10049 auto classDecl = static_cast<ClassDecl_t*>(item);
10050 std::string varName;
9431 if (classDecl->name) { 10051 if (classDecl->name) {
9432 if (auto var = classDecl->name->item.as<Variable_t>()) { 10052 if (auto var = classDecl->name->item.as<Variable_t>()) {
9433 addGlobalVar(variableToString(var), classDecl->name->item); 10053 varName = variableToString(var);
10054 addGlobalVar(varName, var);
9434 } 10055 }
9435 } 10056 }
10057 if (varName.empty()) {
10058 throw CompileError("missing name for class", classDecl);
10059 }
9436 transformClassDecl(classDecl, out, ExpUsage::Common); 10060 transformClassDecl(classDecl, out, ExpUsage::Common);
10061 markVarGlobalConst(varName);
9437 break; 10062 break;
9438 } 10063 }
9439 case id<GlobalOp_t>(): 10064 case id<GlobalOp_t>():
@@ -9447,9 +10072,11 @@ private:
9447 auto values = global->item.to<GlobalValues_t>(); 10072 auto values = global->item.to<GlobalValues_t>();
9448 if (values->valueList) { 10073 if (values->valueList) {
9449 auto expList = x->new_ptr<ExpList_t>(); 10074 auto expList = x->new_ptr<ExpList_t>();
10075 str_list varNames;
9450 for (auto name : values->nameList->names.objects()) { 10076 for (auto name : values->nameList->names.objects()) {
9451 auto var = static_cast<Variable_t*>(name); 10077 auto var = static_cast<Variable_t*>(name);
9452 addGlobalVar(variableToString(var), var); 10078 varNames.emplace_back(variableToString(var));
10079 addGlobalVar(varNames.back(), var);
9453 auto callable = x->new_ptr<Callable_t>(); 10080 auto callable = x->new_ptr<Callable_t>();
9454 callable->item.set(name); 10081 callable->item.set(name);
9455 auto chainValue = x->new_ptr<ChainValue_t>(); 10082 auto chainValue = x->new_ptr<ChainValue_t>();
@@ -9468,10 +10095,17 @@ private:
9468 } 10095 }
9469 assignment->action.set(assign); 10096 assignment->action.set(assign);
9470 transformAssignment(assignment, out); 10097 transformAssignment(assignment, out);
10098 for (const auto& name : varNames) {
10099 markVarGlobalConst(name);
10100 }
9471 } else { 10101 } else {
9472 for (auto name : values->nameList->names.objects()) { 10102 for (auto name : values->nameList->names.objects()) {
9473 auto var = static_cast<Variable_t*>(name); 10103 auto var = static_cast<Variable_t*>(name);
9474 addGlobalVar(variableToString(var), var); 10104 auto varName = variableToString(var);
10105 addGlobalVar(varName, var);
10106 if (global->constAttrib) {
10107 markVarGlobalConst(varName);
10108 }
9475 } 10109 }
9476 } 10110 }
9477 break; 10111 break;
@@ -9820,8 +10454,47 @@ private:
9820 out.push_back(join(temp)); 10454 out.push_back(join(temp));
9821 } 10455 }
9822 10456
9823 void transformTry(Try_t* tryNode, str_list& out, ExpUsage usage) { 10457 void transformTry(Try_t* tryNode, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
9824 auto x = tryNode; 10458 auto x = tryNode;
10459 if (tryNode->eop && usage == ExpUsage::Assignment) {
10460 str_list rets;
10461 pushScope();
10462 auto okVar = getUnusedName("_ok_"sv);
10463 for (size_t i = 0; i < assignList->exprs.size(); i++) {
10464 auto retVar = getUnusedName("_ret_"sv);
10465 rets.emplace_back(retVar);
10466 addToScope(retVar);
10467 }
10468 popScope();
10469 auto varList = join(rets, ","sv);
10470 auto ifNode = toAst<If_t>("if "s + okVar + ',' + varList + ":=try nil then "s + varList, x);
10471 auto exp = ast_to<IfCond_t>(ifNode->nodes.front())->assignment->assign->values.front();
10472 auto sVal = simpleSingleValueFrom(exp);
10473 auto newTry = sVal->value.to<Try_t>();
10474 newTry->func.set(tryNode->func);
10475 newTry->catchBlock.set(tryNode->catchBlock);
10476 auto assignment = x->new_ptr<ExpListAssign_t>();
10477 assignment->expList.set(assignList);
10478 auto assign = x->new_ptr<Assign_t>();
10479 assign->values.push_back(ifNode);
10480 assignment->action.set(assign);
10481 transformAssignment(assignment, out);
10482 return;
10483 }
10484 if (tryNode->eop && usage != ExpUsage::Common) {
10485 auto okVar = getUnusedName("_ok_"sv);
10486 auto code = "do\n\t"s + okVar + ", ... = try nil\n\t... if "s + okVar;
10487 auto doNode = toAst<Do_t>(code, x);
10488 auto block = doNode->body->content.to<Block_t>();
10489 auto asmt = static_cast<Statement_t*>(block->statements.front())->content.to<ExpListAssign_t>();
10490 auto assign = asmt->action.to<Assign_t>();
10491 auto sVal = simpleSingleValueFrom(assign->values.back());
10492 auto newTry = sVal->value.to<Try_t>();
10493 newTry->func.set(tryNode->func);
10494 newTry->catchBlock.set(tryNode->catchBlock);
10495 transformDo(doNode, out, usage);
10496 return;
10497 }
9825 ast_ptr<true, Exp_t> errHandler; 10498 ast_ptr<true, Exp_t> errHandler;
9826 if (tryNode->catchBlock) { 10499 if (tryNode->catchBlock) {
9827 auto catchBlock = tryNode->catchBlock.get(); 10500 auto catchBlock = tryNode->catchBlock.get();
@@ -10133,7 +10806,7 @@ private:
10133 out.push_back(join(temp)); 10806 out.push_back(join(temp));
10134 auto vars = getAssignVars(assignment); 10807 auto vars = getAssignVars(assignment);
10135 for (const auto& var : vars) { 10808 for (const auto& var : vars) {
10136 markVarConst(var); 10809 markVarLocalConst(var);
10137 } 10810 }
10138 } 10811 }
10139 10812
@@ -10361,12 +11034,36 @@ private:
10361 transformAssignment(assignment, out); 11034 transformAssignment(assignment, out);
10362 if (auto var = ast_cast<Variable_t>(target)) { 11035 if (auto var = ast_cast<Variable_t>(target)) {
10363 auto moduleName = variableToString(var); 11036 auto moduleName = variableToString(var);
10364 markVarConst(moduleName); 11037 markVarLocalConst(moduleName);
10365 } else { 11038 } else {
10366 markDestructureConst(assignment); 11039 markDestructureConst(assignment);
10367 } 11040 }
10368 } 11041 }
10369 11042
11043 void transformImportGlobal(ImportGlobal_t* importNode, str_list& out) {
11044 auto uname = static_cast<UnicodeName_t*>(importNode->segs.front());
11045 auto var = _parser.toString(uname);
11046 auto isNormal = _parser.match<Name_t>(var) && _parser.match<Variable_t>(var);
11047 auto varName = unicodeVariableFrom(uname);
11048 str_list temp;
11049 auto it = ++importNode->segs.objects().begin();
11050 for (; it != importNode->segs.objects().end(); ++it) {
11051 temp.emplace_back(_parser.toString(*it));
11052 }
11053 temp.emplace_front(var);
11054 if (isLocal(varName) || !isNormal) {
11055 temp.emplace_front("_G"s);
11056 }
11057 std::string stmt;
11058 if (importNode->target) {
11059 stmt = "const "s + _parser.toString(importNode->target) + '=' + join(temp, "."sv);
11060 } else {
11061 stmt = "const "s + temp.back() + '=' + join(temp, "."sv);
11062 }
11063 auto localAttrib = toAst<LocalAttrib_t>(stmt, importNode);
11064 transformLocalAttrib(localAttrib, out);
11065 }
11066
10370 void transformImport(Import_t* import, str_list& out) { 11067 void transformImport(Import_t* import, str_list& out) {
10371 auto content = import->content.get(); 11068 auto content = import->content.get();
10372 switch (content->get_id()) { 11069 switch (content->get_id()) {
@@ -10379,6 +11076,9 @@ private:
10379 case id<FromImport_t>(): 11076 case id<FromImport_t>():
10380 transformFromImport(static_cast<FromImport_t*>(content), out); 11077 transformFromImport(static_cast<FromImport_t*>(content), out);
10381 break; 11078 break;
11079 case id<ImportGlobal_t>():
11080 transformImportGlobal(static_cast<ImportGlobal_t*>(content), out);
11081 break;
10382 default: YUEE("AST node mismatch", content); break; 11082 default: YUEE("AST node mismatch", content); break;
10383 } 11083 }
10384 } 11084 }
@@ -10398,15 +11098,27 @@ private:
10398 addToScope(accumVar); 11098 addToScope(accumVar);
10399 auto lenVar = getUnusedName("_len_"sv); 11099 auto lenVar = getUnusedName("_len_"sv);
10400 addToScope(lenVar); 11100 addToScope(lenVar);
10401 temp.push_back(indent() + "local "s + accumVar + " = { }"s + nll(whileNode)); 11101 auto breakLoopType = getBreakLoopType(whileNode->body, accumVar);
10402 temp.push_back(indent() + "local "s + lenVar + " = 1"s + nll(whileNode)); 11102 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(whileNode);
11103 temp.emplace_back(clearBuf());
11104 _buf << indent() << "local "s << lenVar << " = 1"s << nll(whileNode);
11105 auto& lenAssign = temp.emplace_back(clearBuf());
10403 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 11106 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
10404 auto condStr = transformCondExp(whileNode->condition, isUntil); 11107 auto condStr = transformCondExp(whileNode->condition, isUntil);
10405 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); 11108 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode));
10406 pushScope(); 11109 pushScope();
10407 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); 11110 if (hasBreakWithValue(breakLoopType)) {
10408 auto lenLine = lenVar + " = "s + lenVar + " + 1"s + nlr(whileNode); 11111 lenAssign.clear();
10409 transformLoopBody(whileNode->body, temp, lenLine, ExpUsage::Assignment, assignLeft); 11112 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common);
11113 } else {
11114 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x);
11115 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, whileNode);
11116 assignLeft->followStmt = followStmt.get();
11117 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
11118 if (!assignLeft->followStmtProcessed) {
11119 lenAssign.clear();
11120 }
11121 }
10410 popScope(); 11122 popScope();
10411 temp.push_back(indent() + "end"s + nlr(whileNode)); 11123 temp.push_back(indent() + "end"s + nlr(whileNode));
10412 if (expList) { 11124 if (expList) {
@@ -10442,15 +11154,26 @@ private:
10442 addToScope(accumVar); 11154 addToScope(accumVar);
10443 auto lenVar = getUnusedName("_len_"sv); 11155 auto lenVar = getUnusedName("_len_"sv);
10444 addToScope(lenVar); 11156 addToScope(lenVar);
10445 temp.push_back(indent() + "local "s + accumVar + " = { }"s + nll(whileNode)); 11157 auto breakLoopType = getBreakLoopType(whileNode->body, accumVar);
10446 temp.push_back(indent() + "local "s + lenVar + " = 1"s + nll(whileNode)); 11158 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(whileNode);
11159 temp.emplace_back(clearBuf());
11160 auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nll(whileNode));
10447 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 11161 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
10448 auto condStr = transformCondExp(whileNode->condition, isUntil); 11162 auto condStr = transformCondExp(whileNode->condition, isUntil);
10449 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); 11163 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode));
10450 pushScope(); 11164 pushScope();
10451 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); 11165 if (hasBreakWithValue(breakLoopType)) {
10452 auto lenLine = lenVar + " = "s + lenVar + " + 1"s + nlr(whileNode); 11166 lenAssign.clear();
10453 transformLoopBody(whileNode->body, temp, lenLine, ExpUsage::Assignment, assignLeft); 11167 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common);
11168 } else {
11169 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x);
11170 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, whileNode);
11171 assignLeft->followStmt = followStmt.get();
11172 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
11173 if (!assignLeft->followStmtProcessed) {
11174 lenAssign.clear();
11175 }
11176 }
10454 popScope(); 11177 popScope();
10455 temp.push_back(indent() + "end"s + nlr(whileNode)); 11178 temp.push_back(indent() + "end"s + nlr(whileNode));
10456 temp.push_back(indent() + "return "s + accumVar + nlr(whileNode)); 11179 temp.push_back(indent() + "return "s + accumVar + nlr(whileNode));
@@ -10485,9 +11208,7 @@ private:
10485 expListAssign->expList.set(expList); 11208 expListAssign->expList.set(expList);
10486 auto stmt = x->new_ptr<Statement_t>(); 11209 auto stmt = x->new_ptr<Statement_t>();
10487 stmt->content.set(expListAssign); 11210 stmt->content.set(expListAssign);
10488 auto body = x->new_ptr<Body_t>(); 11211 repeat->body.set(stmt);
10489 body->content.set(stmt);
10490 repeat->body.set(body);
10491 transformRepeat(repeat, out); 11212 transformRepeat(repeat, out);
10492 return; 11213 return;
10493 } 11214 }
@@ -10495,7 +11216,8 @@ private:
10495 pushScope(); 11216 pushScope();
10496 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 11217 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
10497 auto condStr = transformCondExp(whileNode->condition, isUntil); 11218 auto condStr = transformCondExp(whileNode->condition, isUntil);
10498 transformLoopBody(whileNode->body, temp, Empty, ExpUsage::Common); 11219 auto breakLoopType = getBreakLoopType(whileNode->body, Empty);
11220 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common);
10499 popScope(); 11221 popScope();
10500 _buf << indent() << "while "sv << condStr << " do"sv << nll(whileNode); 11222 _buf << indent() << "while "sv << condStr << " do"sv << nll(whileNode);
10501 _buf << temp.back(); 11223 _buf << temp.back();
@@ -10503,6 +11225,106 @@ private:
10503 out.push_back(clearBuf()); 11225 out.push_back(clearBuf());
10504 } 11226 }
10505 11227
11228 void transformRepeatInPlace(Repeat_t* repeatNode, str_list& out, ExpList_t* expList = nullptr) {
11229 auto x = repeatNode;
11230 str_list temp;
11231 bool extraScope = false;
11232 if (expList) {
11233 if (!currentScope().lastStatement) {
11234 extraScope = true;
11235 temp.push_back(indent() + "do"s + nll(repeatNode));
11236 pushScope();
11237 }
11238 }
11239 auto accumVar = getUnusedName("_accum_"sv);
11240 addToScope(accumVar);
11241 auto lenVar = getUnusedName("_len_"sv);
11242 addToScope(lenVar);
11243 auto breakLoopType = getBreakLoopType(repeatNode->body, accumVar);
11244 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(repeatNode);
11245 temp.emplace_back(clearBuf());
11246 _buf << indent() << "local "s << lenVar << " = 1"s << nll(repeatNode);
11247 auto& lenAssign = temp.emplace_back(clearBuf());
11248 auto condStr = transformCondExp(repeatNode->condition, false);
11249 temp.push_back(indent() + "repeat"s + nll(repeatNode));
11250 pushScope();
11251 if (hasBreakWithValue(breakLoopType)) {
11252 lenAssign.clear();
11253 transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Common);
11254 } else {
11255 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x);
11256 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, repeatNode);
11257 assignLeft->followStmt = followStmt.get();
11258 transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
11259 if (!assignLeft->followStmtProcessed) {
11260 lenAssign.clear();
11261 }
11262 }
11263 popScope();
11264 temp.push_back(indent() + "until "s + condStr + nlr(repeatNode));
11265 if (expList) {
11266 auto assign = x->new_ptr<Assign_t>();
11267 assign->values.push_back(toAst<Exp_t>(accumVar, x));
11268 auto assignment = x->new_ptr<ExpListAssign_t>();
11269 assignment->expList.set(expList);
11270 assignment->action.set(assign);
11271 transformAssignment(assignment, temp);
11272 if (extraScope) popScope();
11273 } else {
11274 temp.push_back(indent() + "return "s + accumVar + nlr(repeatNode));
11275 }
11276 if (expList && extraScope) {
11277 temp.push_back(indent() + "end"s + nlr(repeatNode));
11278 }
11279 out.push_back(join(temp));
11280 }
11281
11282 void transformRepeatClosure(Repeat_t* repeatNode, str_list& out) {
11283 auto x = repeatNode;
11284 auto simpleValue = x->new_ptr<SimpleValue_t>();
11285 simpleValue->value.set(repeatNode);
11286 if (transformAsUpValueFunc(newExp(simpleValue, x), out)) {
11287 return;
11288 }
11289 str_list temp;
11290 pushAnonFunctionScope();
11291 pushAnonVarArg();
11292 std::string& funcStart = temp.emplace_back();
11293 pushScope();
11294 auto accumVar = getUnusedName("_accum_"sv);
11295 addToScope(accumVar);
11296 auto lenVar = getUnusedName("_len_"sv);
11297 addToScope(lenVar);
11298 auto breakLoopType = getBreakLoopType(repeatNode->body, accumVar);
11299 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(repeatNode);
11300 temp.emplace_back(clearBuf());
11301 auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nll(repeatNode));
11302 auto condStr = transformCondExp(repeatNode->condition, false);
11303 temp.push_back(indent() + "repeat"s + nll(repeatNode));
11304 pushScope();
11305 if (hasBreakWithValue(breakLoopType)) {
11306 lenAssign.clear();
11307 transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Common);
11308 } else {
11309 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x);
11310 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, repeatNode);
11311 assignLeft->followStmt = followStmt.get();
11312 transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
11313 if (!assignLeft->followStmtProcessed) {
11314 lenAssign.clear();
11315 }
11316 }
11317 popScope();
11318 temp.push_back(indent() + "until "s + condStr + nlr(repeatNode));
11319 temp.push_back(indent() + "return "s + accumVar + nlr(repeatNode));
11320 popScope();
11321 funcStart = anonFuncStart() + nll(repeatNode);
11322 temp.push_back(indent() + anonFuncEnd());
11323 popAnonVarArg();
11324 popFunctionScope();
11325 out.push_back(join(temp));
11326 }
11327
10506 void transformRepeat(Repeat_t* repeat, str_list& out) { 11328 void transformRepeat(Repeat_t* repeat, str_list& out) {
10507 str_list temp; 11329 str_list temp;
10508 pushScope(); 11330 pushScope();
@@ -10536,10 +11358,26 @@ private:
10536 pushScope(); 11358 pushScope();
10537 } 11359 }
10538 bool extraScope = false; 11360 bool extraScope = false;
11361 if (switchNode->assignment) {
11362 if (needScope) {
11363 extraScope = true;
11364 temp.push_back(indent() + "do"s + nll(x));
11365 pushScope();
11366 }
11367 auto asmt = x->new_ptr<ExpListAssign_t>();
11368 auto expList = x->new_ptr<ExpList_t>();
11369 expList->exprs.push_back(switchNode->target);
11370 if (switchNode->assignment->expList) {
11371 expList->exprs.dup(switchNode->assignment->expList->exprs);
11372 }
11373 asmt->expList.set(expList);
11374 asmt->action.set(switchNode->assignment->assign);
11375 transformAssignment(asmt, temp);
11376 }
10539 auto objVar = singleVariableFrom(switchNode->target, AccessType::Read); 11377 auto objVar = singleVariableFrom(switchNode->target, AccessType::Read);
10540 if (objVar.empty() || !isLocal(objVar)) { 11378 if (objVar.empty() || !isLocal(objVar)) {
10541 if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) { 11379 if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) {
10542 if (needScope) { 11380 if (needScope && !extraScope) {
10543 extraScope = true; 11381 extraScope = true;
10544 temp.push_back(indent() + "do"s + nll(x)); 11382 temp.push_back(indent() + "do"s + nll(x));
10545 pushScope(); 11383 pushScope();
@@ -10597,8 +11435,9 @@ private:
10597 } 11435 }
10598 temp.back().append(indent() + "if "s + tabCheckVar + " then"s + nll(branch)); 11436 temp.back().append(indent() + "if "s + tabCheckVar + " then"s + nll(branch));
10599 pushScope(); 11437 pushScope();
10600 auto assignment = assignmentFrom(static_cast<Exp_t*>(valueList->exprs.front()), toAst<Exp_t>(objVar, branch), branch); 11438 auto chainValue = toAst<ChainValue_t>(objVar, branch);
10601 auto info = extractDestructureInfo(assignment, true, false); 11439 auto assignment = assignmentFrom(static_cast<Exp_t*>(valueList->exprs.front()), newExp(chainValue, branch), branch);
11440 auto info = extractDestructureInfo(assignment, true, true);
10602 transformAssignment(assignment, temp, true); 11441 transformAssignment(assignment, temp, true);
10603 str_list conds; 11442 str_list conds;
10604 for (const auto& des : info.destructures) { 11443 for (const auto& des : info.destructures) {
@@ -10608,8 +11447,31 @@ private:
10608 const auto& destruct = std::get<Destructure>(des); 11447 const auto& destruct = std::get<Destructure>(des);
10609 for (const auto& item : destruct.items) { 11448 for (const auto& item : destruct.items) {
10610 if (!item.defVal) { 11449 if (!item.defVal) {
10611 transformExp(item.target, conds, ExpUsage::Closure); 11450 if (!isAssignable(item.target)) {
10612 conds.back().append(" ~= nil"s); 11451 auto callable = chainValue->items.front();
11452 auto chain = callable->new_ptr<ChainValue_t>();
11453 chain->items.push_back(callable);
11454 chain->items.dup(item.structure->items);
11455 if (specialChainValue(chain) == ChainType::Common) {
11456 transformChainValue(chain, conds, ExpUsage::Closure);
11457 auto vStr = conds.back();
11458 conds.pop_back();
11459 transformExp(item.target, conds, ExpUsage::Closure);
11460 conds.back().append(" == "s);
11461 conds.back().append(vStr);
11462 } else {
11463 auto varName = getUnusedName("_val_"sv);
11464 auto vExp = toAst<Exp_t>(varName, chain);
11465 auto asmt = assignmentFrom(vExp, newExp(chain, chain), chain);
11466 transformAssignment(asmt, temp);
11467 transformExp(item.target, conds, ExpUsage::Closure);
11468 conds.back().append(" == "s);
11469 conds.back().append(varName);
11470 }
11471 } else {
11472 transformExp(item.target, conds, ExpUsage::Closure);
11473 conds.back().append(" ~= nil"s);
11474 }
10613 } 11475 }
10614 } 11476 }
10615 } 11477 }
@@ -10907,7 +11769,7 @@ private:
10907 } 11769 }
10908 transformAssignment(assignment, temp); 11770 transformAssignment(assignment, temp);
10909 for (const auto& name : vars) { 11771 for (const auto& name : vars) {
10910 markVarConst(name); 11772 markVarLocalConst(name);
10911 } 11773 }
10912 if (localAttrib->attrib.is<CloseAttrib_t>()) { 11774 if (localAttrib->attrib.is<CloseAttrib_t>()) {
10913 str_list leftVars, rightVars; 11775 str_list leftVars, rightVars;
@@ -10979,7 +11841,7 @@ private:
10979 temp.push_back(indent() + "local "s + join(leftVars, ", "sv) + " = "s + join(items, ", "sv) + nll(x)); 11841 temp.push_back(indent() + "local "s + join(leftVars, ", "sv) + " = "s + join(items, ", "sv) + nll(x));
10980 } 11842 }
10981 for (const auto& var : vars) { 11843 for (const auto& var : vars) {
10982 markVarConst(var); 11844 markVarLocalConst(var);
10983 } 11845 }
10984 } 11846 }
10985 if (!listB->exprs.empty()) { 11847 if (!listB->exprs.empty()) {
@@ -11004,18 +11866,24 @@ private:
11004 temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x)); 11866 temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x));
11005 transformAssignment(assignment, temp); 11867 transformAssignment(assignment, temp);
11006 for (const auto& name : vars) { 11868 for (const auto& name : vars) {
11007 markVarConst(name); 11869 markVarLocalConst(name);
11008 } 11870 }
11009 } 11871 }
11010 out.push_back(join(temp)); 11872 out.push_back(join(temp));
11011 } 11873 }
11012 11874
11013 void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) { 11875 void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) {
11014 auto keyword = _parser.toString(breakLoop); 11876 auto isBreak = breakLoop->type.is<Break_t>();
11877 auto keyword = isBreak ? "break"s : "continue"s;
11015 if (_enableBreakLoop.empty() || !_enableBreakLoop.top()) { 11878 if (_enableBreakLoop.empty() || !_enableBreakLoop.top()) {
11016 throw CompileError(keyword + " is not inside a loop"s, breakLoop); 11879 throw CompileError(keyword + " is not inside a loop"s, breakLoop);
11017 } 11880 }
11018 if (keyword == "break"sv) { 11881 if (isBreak) {
11882 if (breakLoop->value) {
11883 auto exp = toAst<Exp_t>(breakLoop->varBWV, breakLoop->value);
11884 auto assignment = assignmentFrom(exp, breakLoop->value, breakLoop);
11885 transformAssignment(assignment, out);
11886 }
11019 out.push_back(indent() + keyword + nll(breakLoop)); 11887 out.push_back(indent() + keyword + nll(breakLoop));
11020 return; 11888 return;
11021 } 11889 }
diff --git a/src/yuescript/yue_compiler.h b/src/yuescript/yue_compiler.h
index d352636..aff5978 100644
--- a/src/yuescript/yue_compiler.h
+++ b/src/yuescript/yue_compiler.h
@@ -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;
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp
index 77c5901..1942e23 100644
--- a/src/yuescript/yue_parser.cpp
+++ b/src/yuescript/yue_parser.cpp
@@ -118,8 +118,8 @@ YueParser::YueParser() {
118 return false; 118 return false;
119 }); 119 });
120 120
121 if_assignment_syntax_error = pl::user(true_(), [](const item_t& item) { 121 assignment_expression_syntax_error = pl::user(true_(), [](const item_t& item) {
122 throw ParserError("use := for if-assignment expression"sv, item.begin); 122 throw ParserError("use := for assignment expression"sv, item.begin);
123 return false; 123 return false;
124 }); 124 });
125 125
@@ -162,6 +162,13 @@ YueParser::YueParser() {
162 ) \ 162 ) \
163 ) 163 )
164 164
165 #define disable_until_rule(patt) ( \
166 disable_until >> ( \
167 (patt) >> enable_until | \
168 enable_until >> cut \
169 ) \
170 )
171
165 #define body_with(str) ( \ 172 #define body_with(str) ( \
166 key(str) >> space >> (in_block | Statement) | \ 173 key(str) >> space >> (in_block | Statement) | \
167 in_block | \ 174 in_block | \
@@ -325,7 +332,7 @@ YueParser::YueParser() {
325 Exp; 332 Exp;
326 import_tab_list = import_tab_item >> *(space >> ',' >> space >> import_tab_item); 333 import_tab_list = import_tab_item >> *(space >> ',' >> space >> import_tab_item);
327 import_tab_line = ( 334 import_tab_line = (
328 push_indent_match >> (space >> import_tab_list >> pop_indent | pop_indent) 335 push_indent_match >> ensure(space >> import_tab_list, pop_indent)
329 ) | space; 336 ) | space;
330 import_tab_lines = space_break >> import_tab_line >> *(-(space >> ',') >> space_break >> import_tab_line) >> -(space >> ','); 337 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; 338 import_tab_key_value = key_value | ':' >> MacroName | MacroNamePair | ImportAllMacro;
@@ -342,7 +349,9 @@ YueParser::YueParser() {
342 349
343 ImportAs = ImportLiteral >> -(space >> key("as") >> space >> (ImportTabLit | Variable | ImportAllMacro)); 350 ImportAs = ImportLiteral >> -(space >> key("as") >> space >> (ImportTabLit | Variable | ImportAllMacro));
344 351
345 Import = key("import") >> space >> (ImportAs | ImportFrom) | FromImport; 352 ImportGlobal = Seperator >> UnicodeName >> *('.' >> UnicodeName) >> -(space >> key("as") >> space >> Variable);
353
354 Import = key("import") >> space >> (ImportAs | ImportFrom | ImportGlobal) | FromImport;
346 355
347 Label = "::" >> LabelName >> "::"; 356 Label = "::" >> LabelName >> "::";
348 357
@@ -350,11 +359,13 @@ YueParser::YueParser() {
350 359
351 ShortTabAppending = "[]" >> space >> Assign; 360 ShortTabAppending = "[]" >> space >> Assign;
352 361
353 BreakLoop = (expr("break") | "continue") >> not_alpha_num; 362 Break = key("break");
363 Continue = key("continue");
364 BreakLoop = (Break >> -(space >> Exp) | Continue) >> not_alpha_num;
354 365
355 Return = key("return") >> -(space >> (TableBlock | ExpListLow)); 366 Return = key("return") >> -(space >> (TableBlock | ExpListLow));
356 367
357 with_exp = ExpList >> -(space >> Assign); 368 with_exp = ExpList >> -(space >> (':' >> Assign | and_('=') >> assignment_expression_syntax_error));
358 369
359 With = key("with") >> -ExistentialOp >> space >> disable_do_chain_arg_table_block_rule(with_exp) >> space >> body_with("do"); 370 With = key("with") >> -ExistentialOp >> space >> disable_do_chain_arg_table_block_rule(with_exp) >> space >> body_with("do");
360 SwitchCase = key("when") >> space >> disable_chain_rule(disable_arg_table_block_rule(SwitchList)) >> space >> body_with("then"); 371 SwitchCase = key("when") >> space >> disable_chain_rule(disable_arg_table_block_rule(SwitchList)) >> space >> body_with("then");
@@ -370,7 +381,8 @@ YueParser::YueParser() {
370 and_(SimpleTable | TableLit) >> Exp | 381 and_(SimpleTable | TableLit) >> Exp |
371 exp_not_tab >> *(space >> ',' >> space >> exp_not_tab) 382 exp_not_tab >> *(space >> ',' >> space >> exp_not_tab)
372 ); 383 );
373 Switch = key("switch") >> space >> Exp >> 384 Switch = key("switch") >> space >>
385 Exp >> -(space >> Assignment) >>
374 space >> Seperator >> ( 386 space >> Seperator >> (
375 SwitchCase >> space >> ( 387 SwitchCase >> space >> (
376 switch_block | 388 switch_block |
@@ -379,20 +391,26 @@ YueParser::YueParser() {
379 +space_break >> advance_match >> space >> SwitchCase >> switch_block >> pop_indent 391 +space_break >> advance_match >> space >> SwitchCase >> switch_block >> pop_indent
380 ); 392 );
381 393
382 Assignment = -(',' >> space >> ExpList >> space) >> (':' >> Assign | and_('=') >> if_assignment_syntax_error); 394 Assignment = -(',' >> space >> ExpList >> space) >> (':' >> Assign | and_('=') >> assignment_expression_syntax_error);
383 IfCond = disable_chain_rule(disable_arg_table_block_rule(Exp >> -(space >> Assignment))); 395 IfCond = disable_chain_rule(disable_arg_table_block_rule(Exp >> -(space >> Assignment)));
384 if_else_if = -(line_break >> *space_break >> check_indent_match) >> space >> key("elseif") >> space >> IfCond >> space >> body_with("then"); 396 if_else_if = -(line_break >> *space_break >> check_indent_match) >> space >> key("elseif") >> space >> IfCond >> space >> body_with("then");
385 if_else = -(line_break >> *space_break >> check_indent_match) >> space >> key("else") >> space >> body; 397 if_else = -(line_break >> *space_break >> check_indent_match) >> space >> key("else") >> space >> body;
386 IfType = (expr("if") | "unless") >> not_alpha_num; 398 IfType = (expr("if") | "unless") >> not_alpha_num;
387 If = IfType >> space >> IfCond >> space >> opt_body_with("then") >> *if_else_if >> -if_else; 399 If = IfType >> space >> IfCond >> space >> opt_body_with("then") >> *if_else_if >> -if_else;
388 400
389 WhileType = (expr("while") | "until") >> not_alpha_num; 401 WhileType = (expr("while") | pl::user("until", [](const item_t& item) {
390 While = WhileType >> space >> disable_do_chain_arg_table_block_rule(Exp >> -(space >> Assignment)) >> space >> opt_body_with("do"); 402 State* st = reinterpret_cast<State*>(item.user_data);
391 Repeat = key("repeat") >> space >> Body >> line_break >> *space_break >> check_indent_match >> space >> key("until") >> space >> Exp; 403 return st->noUntilStack.empty() || !st->noUntilStack.back();
404 })) >> not_alpha_num;
405 While = key(WhileType) >> space >> disable_do_chain_arg_table_block_rule(Exp >> -(space >> Assignment)) >> space >> opt_body_with("do");
406 Repeat = key("repeat") >> space >> (
407 in_block >> line_break >> *space_break >> check_indent_match |
408 disable_until_rule(Statement)
409 ) >> space >> key("until") >> space >> Exp;
392 410
393 for_key = pl::user(key("for"), [](const item_t& item) { 411 for_key = pl::user(key("for"), [](const item_t& item) {
394 State* st = reinterpret_cast<State*>(item.user_data); 412 State* st = reinterpret_cast<State*>(item.user_data);
395 return st->noForStack.empty() || !st->noForStack.top(); 413 return st->noForStack.empty() || !st->noForStack.back();
396 }); 414 });
397 ForStepValue = ',' >> space >> Exp; 415 ForStepValue = ',' >> space >> Exp;
398 for_args = Variable >> space >> '=' >> space >> Exp >> space >> ',' >> space >> Exp >> space >> -ForStepValue; 416 for_args = Variable >> space >> '=' >> space >> Exp >> space >> ',' >> space >> Exp >> space >> -ForStepValue;
@@ -406,18 +424,18 @@ YueParser::YueParser() {
406 424
407 Do = pl::user(key("do"), [](const item_t& item) { 425 Do = pl::user(key("do"), [](const item_t& item) {
408 State* st = reinterpret_cast<State*>(item.user_data); 426 State* st = reinterpret_cast<State*>(item.user_data);
409 return st->noDoStack.empty() || !st->noDoStack.top(); 427 return st->noDoStack.empty() || !st->noDoStack.back();
410 }) >> space >> Body; 428 }) >> space >> Body;
411 429
412 disable_do = pl::user(true_(), [](const item_t& item) { 430 disable_do = pl::user(true_(), [](const item_t& item) {
413 State* st = reinterpret_cast<State*>(item.user_data); 431 State* st = reinterpret_cast<State*>(item.user_data);
414 st->noDoStack.push(true); 432 st->noDoStack.push_back(true);
415 return true; 433 return true;
416 }); 434 });
417 435
418 enable_do = pl::user(true_(), [](const item_t& item) { 436 enable_do = pl::user(true_(), [](const item_t& item) {
419 State* st = reinterpret_cast<State*>(item.user_data); 437 State* st = reinterpret_cast<State*>(item.user_data);
420 st->noDoStack.pop(); 438 st->noDoStack.pop_back();
421 return true; 439 return true;
422 }); 440 });
423 441
@@ -435,46 +453,58 @@ YueParser::YueParser() {
435 453
436 disable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) { 454 disable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) {
437 State* st = reinterpret_cast<State*>(item.user_data); 455 State* st = reinterpret_cast<State*>(item.user_data);
438 st->noDoStack.push(true); 456 st->noDoStack.push_back(true);
439 st->noChainBlockStack.push(true); 457 st->noChainBlockStack.push_back(true);
440 st->noTableBlockStack.push(true); 458 st->noTableBlockStack.push_back(true);
441 return true; 459 return true;
442 }); 460 });
443 461
444 enable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) { 462 enable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) {
445 State* st = reinterpret_cast<State*>(item.user_data); 463 State* st = reinterpret_cast<State*>(item.user_data);
446 st->noDoStack.pop(); 464 st->noDoStack.pop_back();
447 st->noChainBlockStack.pop(); 465 st->noChainBlockStack.pop_back();
448 st->noTableBlockStack.pop(); 466 st->noTableBlockStack.pop_back();
449 return true; 467 return true;
450 }); 468 });
451 469
452 disable_arg_table_block = pl::user(true_(), [](const item_t& item) { 470 disable_arg_table_block = pl::user(true_(), [](const item_t& item) {
453 State* st = reinterpret_cast<State*>(item.user_data); 471 State* st = reinterpret_cast<State*>(item.user_data);
454 st->noTableBlockStack.push(true); 472 st->noTableBlockStack.push_back(true);
455 return true; 473 return true;
456 }); 474 });
457 475
458 enable_arg_table_block = pl::user(true_(), [](const item_t& item) { 476 enable_arg_table_block = pl::user(true_(), [](const item_t& item) {
459 State* st = reinterpret_cast<State*>(item.user_data); 477 State* st = reinterpret_cast<State*>(item.user_data);
460 st->noTableBlockStack.pop(); 478 st->noTableBlockStack.pop_back();
461 return true; 479 return true;
462 }); 480 });
463 481
464 disable_for = pl::user(true_(), [](const item_t& item) { 482 disable_for = pl::user(true_(), [](const item_t& item) {
465 State* st = reinterpret_cast<State*>(item.user_data); 483 State* st = reinterpret_cast<State*>(item.user_data);
466 st->noForStack.push(true); 484 st->noForStack.push_back(true);
467 return true; 485 return true;
468 }); 486 });
469 487
470 enable_for = pl::user(true_(), [](const item_t& item) { 488 enable_for = pl::user(true_(), [](const item_t& item) {
471 State* st = reinterpret_cast<State*>(item.user_data); 489 State* st = reinterpret_cast<State*>(item.user_data);
472 st->noForStack.pop(); 490 st->noForStack.pop_back();
491 return true;
492 });
493
494 disable_until = pl::user(true_(), [](const item_t& item) {
495 State* st = reinterpret_cast<State*>(item.user_data);
496 st->noUntilStack.push_back(true);
497 return true;
498 });
499
500 enable_until = pl::user(true_(), [](const item_t& item) {
501 State* st = reinterpret_cast<State*>(item.user_data);
502 st->noUntilStack.pop_back();
473 return true; 503 return true;
474 }); 504 });
475 505
476 CatchBlock = line_break >> *space_break >> check_indent_match >> space >> key("catch") >> space >> Variable >> space >> in_block; 506 CatchBlock = line_break >> *space_break >> check_indent_match >> space >> key("catch") >> space >> Variable >> space >> in_block;
477 Try = key("try") >> space >> (in_block | Exp) >> -CatchBlock; 507 Try = key("try") >> -ExistentialOp >> space >> (in_block | Exp) >> -CatchBlock;
478 508
479 list_value = 509 list_value =
480 and_( 510 and_(
@@ -561,20 +591,20 @@ YueParser::YueParser() {
561 591
562 disable_chain = pl::user(true_(), [](const item_t& item) { 592 disable_chain = pl::user(true_(), [](const item_t& item) {
563 State* st = reinterpret_cast<State*>(item.user_data); 593 State* st = reinterpret_cast<State*>(item.user_data);
564 st->noChainBlockStack.push(true); 594 st->noChainBlockStack.push_back(true);
565 return true; 595 return true;
566 }); 596 });
567 597
568 enable_chain = pl::user(true_(), [](const item_t& item) { 598 enable_chain = pl::user(true_(), [](const item_t& item) {
569 State* st = reinterpret_cast<State*>(item.user_data); 599 State* st = reinterpret_cast<State*>(item.user_data);
570 st->noChainBlockStack.pop(); 600 st->noChainBlockStack.pop_back();
571 return true; 601 return true;
572 }); 602 });
573 603
574 chain_line = check_indent_match >> space >> (chain_dot_chain | colon_chain) >> -InvokeArgs; 604 chain_line = check_indent_match >> space >> (chain_dot_chain | colon_chain) >> -InvokeArgs;
575 chain_block = pl::user(true_(), [](const item_t& item) { 605 chain_block = pl::user(true_(), [](const item_t& item) {
576 State* st = reinterpret_cast<State*>(item.user_data); 606 State* st = reinterpret_cast<State*>(item.user_data);
577 return st->noChainBlockStack.empty() || !st->noChainBlockStack.top(); 607 return st->noChainBlockStack.empty() || !st->noChainBlockStack.back();
578 }) >> +space_break >> advance_match >> ensure( 608 }) >> +space_break >> advance_match >> ensure(
579 chain_line >> *(+space_break >> chain_line), pop_indent); 609 chain_line >> *(+space_break >> chain_line), pop_indent);
580 ChainValue = 610 ChainValue =
@@ -611,7 +641,15 @@ YueParser::YueParser() {
611 DoubleStringInner = +(not_("#{") >> double_string_plain); 641 DoubleStringInner = +(not_("#{") >> double_string_plain);
612 DoubleStringContent = DoubleStringInner | interp; 642 DoubleStringContent = DoubleStringInner | interp;
613 DoubleString = '"' >> Seperator >> *DoubleStringContent >> '"'; 643 DoubleString = '"' >> Seperator >> *DoubleStringContent >> '"';
614 String = DoubleString | SingleString | LuaString; 644
645 YAMLIndent = +set(" \t");
646 YAMLLineInner = +('\\' >> set("\"\\#") | not_("#{" | stop) >> any_char);
647 YAMLLineContent = YAMLLineInner | interp;
648 YAMLLine = check_indent_match >> YAMLIndent >> +(YAMLLineContent) |
649 advance_match >> YAMLIndent >> ensure(+YAMLLineContent, pop_indent);
650 YAMLMultiline = '|' >> space >> Seperator >> +(*set(" \t") >> line_break) >> advance_match >> ensure(YAMLLine >> *(+(*set(" \t") >> line_break) >> YAMLLine), pop_indent);
651
652 String = DoubleString | SingleString | LuaString | YAMLMultiline;
615 653
616 lua_string_open = '[' >> *expr('=') >> '['; 654 lua_string_open = '[' >> *expr('=') >> '[';
617 lua_string_close = ']' >> *expr('=') >> ']'; 655 lua_string_close = ']' >> *expr('=') >> ']';
@@ -639,7 +677,7 @@ YueParser::YueParser() {
639 fn_args_value_list = Exp >> *(space >> ',' >> space >> Exp); 677 fn_args_value_list = Exp >> *(space >> ',' >> space >> Exp);
640 678
641 fn_args_lit_line = ( 679 fn_args_lit_line = (
642 push_indent_match >> (space >> fn_args_value_list >> pop_indent | pop_indent) 680 push_indent_match >> ensure(space >> fn_args_value_list, pop_indent)
643 ) | ( 681 ) | (
644 space 682 space
645 ); 683 );
@@ -681,7 +719,8 @@ YueParser::YueParser() {
681 chain_with_colon = +chain_item >> -colon_chain; 719 chain_with_colon = +chain_item >> -colon_chain;
682 chain_items = chain_with_colon | colon_chain; 720 chain_items = chain_with_colon | colon_chain;
683 721
684 index = '[' >> not_('[') >> space >> Exp >> space >> ']'; 722 index = '[' >> not_('[') >> space >> (ReversedIndex >> and_(space >> ']') | Exp) >> space >> ']';
723 ReversedIndex = '#' >> space >> -('-' >> space >> Exp);
685 chain_item = 724 chain_item =
686 Invoke >> -ExistentialOp | 725 Invoke >> -ExistentialOp |
687 DotChainItem >> -ExistentialOp | 726 DotChainItem >> -ExistentialOp |
@@ -738,7 +777,7 @@ YueParser::YueParser() {
738 777
739 table_block_inner = Seperator >> key_value_line >> *(+space_break >> key_value_line); 778 table_block_inner = Seperator >> key_value_line >> *(+space_break >> key_value_line);
740 TableBlock = +space_break >> advance_match >> ensure(table_block_inner, pop_indent); 779 TableBlock = +space_break >> advance_match >> ensure(table_block_inner, pop_indent);
741 TableBlockIndent = '*' >> Seperator >> disable_arg_table_block_rule( 780 TableBlockIndent = ('*' | '-' >> space_one) >> Seperator >> disable_arg_table_block_rule(
742 space >> key_value_list >> -(space >> ',') >> 781 space >> key_value_list >> -(space >> ',') >>
743 -(+space_break >> advance_match >> space >> ensure(key_value_list >> -(space >> ',') >> *(+space_break >> key_value_line), pop_indent))); 782 -(+space_break >> advance_match >> space >> ensure(key_value_list >> -(space >> ',') >> *(+space_break >> key_value_line), pop_indent)));
744 783
@@ -759,7 +798,7 @@ YueParser::YueParser() {
759 798
760 GlobalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpListLow)); 799 GlobalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpListLow));
761 GlobalOp = expr('*') | '^'; 800 GlobalOp = expr('*') | '^';
762 Global = key("global") >> space >> (ClassDecl | GlobalOp | GlobalValues); 801 Global = key("global") >> space >> (-(ConstAttrib >> space) >> ClassDecl | GlobalOp | -(ConstAttrib >> space) >> GlobalValues);
763 802
764 ExportDefault = key("default"); 803 ExportDefault = key("default");
765 804
@@ -841,24 +880,24 @@ YueParser::YueParser() {
841 key_value_line = check_indent_match >> space >> ( 880 key_value_line = check_indent_match >> space >> (
842 key_value_list >> -(space >> ',') | 881 key_value_list >> -(space >> ',') |
843 TableBlockIndent | 882 TableBlockIndent |
844 '*' >> space >> (SpreadExp | Exp | TableBlock) 883 ('*' | '-' >> space_one) >> space >> (SpreadExp | Exp | TableBlock)
845 ); 884 );
846 885
847 fn_arg_def_list = FnArgDef >> *(space >> ',' >> space >> FnArgDef); 886 fn_arg_def_list = FnArgDef >> *(space >> ',' >> space >> FnArgDef);
848 887
849 fn_arg_def_lit_line = ( 888 fn_arg_def_lit_line = (
850 push_indent_match >> (space >> fn_arg_def_list >> pop_indent | pop_indent) 889 push_indent_match >> ensure(space >> fn_arg_def_list, pop_indent)
851 ) | ( 890 ) | (
852 space 891 space
853 ); 892 );
854 893
855 fn_arg_def_lit_lines = fn_arg_def_lit_line >> *(-(space >> ',') >> space_break >> fn_arg_def_lit_line); 894 fn_arg_def_lit_lines = fn_arg_def_lit_line >> *(-(space >> ',') >> space_break >> fn_arg_def_lit_line);
856 895
857 FnArgDef = (Variable | SelfItem >> -ExistentialOp) >> -(space >> '=' >> space >> Exp); 896 FnArgDef = (Variable | SelfItem >> -ExistentialOp) >> -(space >> '`' >> space >> Name) >> -(space >> '=' >> space >> Exp);
858 897
859 FnArgDefList = Seperator >> ( 898 FnArgDefList = Seperator >> (
860 fn_arg_def_lit_lines >> -(-(space >> ',') >> white >> VarArg) | 899 fn_arg_def_lit_lines >> -(-(space >> ',') >> white >> VarArg >> -(space >> '`' >> space >> Name)) |
861 white >> VarArg 900 white >> VarArg >> -(space >> '`' >> space >> Name)
862 ); 901 );
863 902
864 OuterVarShadow = key("using") >> space >> (NameList | key("nil")); 903 OuterVarShadow = key("using") >> space >> (NameList | key("nil"));
@@ -887,6 +926,7 @@ YueParser::YueParser() {
887 926
888 FnArrowBack = '<' >> set("-="); 927 FnArrowBack = '<' >> set("-=");
889 Backcall = -(FnArgsDef >> space) >> FnArrowBack >> space >> ChainValue; 928 Backcall = -(FnArgsDef >> space) >> FnArrowBack >> space >> ChainValue;
929 SubBackcall = FnArrowBack >> space >> ChainValue;
890 930
891 PipeBody = Seperator >> 931 PipeBody = Seperator >>
892 pipe_operator >> space >> UnaryExp >> 932 pipe_operator >> space >> UnaryExp >>
@@ -900,7 +940,7 @@ YueParser::YueParser() {
900 940
901 arg_table_block = pl::user(true_(), [](const item_t& item) { 941 arg_table_block = pl::user(true_(), [](const item_t& item) {
902 State* st = reinterpret_cast<State*>(item.user_data); 942 State* st = reinterpret_cast<State*>(item.user_data);
903 return st->noTableBlockStack.empty() || !st->noTableBlockStack.top(); 943 return st->noTableBlockStack.empty() || !st->noTableBlockStack.back();
904 }) >> TableBlock; 944 }) >> TableBlock;
905 945
906 invoke_args_with_table = 946 invoke_args_with_table =
@@ -940,11 +980,11 @@ YueParser::YueParser() {
940 980
941 SimpleValue = 981 SimpleValue =
942 TableLit | ConstValue | If | Switch | Try | With | 982 TableLit | ConstValue | If | Switch | Try | With |
943 ClassDecl | ForEach | For | While | Do | 983 ClassDecl | ForEach | For | While | Repeat | Do |
944 UnaryValue | TblComprehension | Comprehension | 984 UnaryValue | TblComprehension | Comprehension |
945 FunLit | Num | VarArg; 985 FunLit | Num | VarArg;
946 986
947 ExpListAssign = ExpList >> -(space >> (Update | Assign)) >> not_(space >> '='); 987 ExpListAssign = ExpList >> -(space >> (Update | Assign | SubBackcall)) >> not_(space >> '=');
948 988
949 IfLine = IfType >> space >> IfCond; 989 IfLine = IfType >> space >> IfCond;
950 WhileLine = WhileType >> space >> Exp; 990 WhileLine = WhileType >> space >> Exp;
@@ -1001,11 +1041,16 @@ YueParser::YueParser() {
1001 empty_line_break | 1041 empty_line_break |
1002 advance_match >> ensure(space >> (indentation_error | Statement), pop_indent) 1042 advance_match >> ensure(space >> (indentation_error | Statement), pop_indent)
1003 ); 1043 );
1004 Block = Seperator >> line >> *(+line_break >> line); 1044 Block = Seperator >> (pl::user(true_(), [](const item_t& item) {
1045 State* st = reinterpret_cast<State*>(item.user_data);
1046 return st->lax;
1047 }) >> lax_line >> *(+line_break >> lax_line) | line >> *(+line_break >> line));
1005 1048
1006 shebang = "#!" >> *(not_(stop) >> any_char); 1049 shebang = "#!" >> *(not_(stop) >> any_char);
1007 BlockEnd = Block >> white >> stop; 1050 BlockEnd = Block >> white >> stop;
1008 File = -shebang >> -Block >> white >> stop; 1051 File = -shebang >> -Block >> white >> stop;
1052
1053 lax_line = advance_match >> ensure(*(not_(stop) >> any()), pop_indent) | line >> and_(stop) | check_indent_match >> *(not_(stop) >> any());
1009} 1054}
1010// clang-format on 1055// clang-format on
1011 1056
@@ -1035,7 +1080,7 @@ bool YueParser::startWith(std::string_view codes, rule& r) {
1035 return true; 1080 return true;
1036} 1081}
1037 1082
1038ParseInfo YueParser::parse(std::string_view codes, rule& r) { 1083ParseInfo YueParser::parse(std::string_view codes, rule& r, bool lax) {
1039 ParseInfo res; 1084 ParseInfo res;
1040 if (codes.substr(0, 3) == "\xEF\xBB\xBF"sv) { 1085 if (codes.substr(0, 3) == "\xEF\xBB\xBF"sv) {
1041 codes = codes.substr(3); 1086 codes = codes.substr(3);
@@ -1053,6 +1098,7 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) {
1053 error_list errors; 1098 error_list errors;
1054 try { 1099 try {
1055 State state; 1100 State state;
1101 state.lax = lax;
1056 res.node.set(::yue::parse(*(res.codes), r, errors, &state)); 1102 res.node.set(::yue::parse(*(res.codes), r, errors, &state));
1057 if (state.exportCount > 0) { 1103 if (state.exportCount > 0) {
1058 int index = 0; 1104 int index = 0;
@@ -1090,19 +1136,21 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) {
1090 return res; 1136 return res;
1091} 1137}
1092 1138
1093ParseInfo YueParser::parse(std::string_view astName, std::string_view codes) { 1139ParseInfo YueParser::parse(std::string_view astName, std::string_view codes, bool lax) {
1094 auto it = _rules.find(astName); 1140 auto it = _rules.find(astName);
1095 if (it != _rules.end()) { 1141 if (it != _rules.end()) {
1096 return parse(codes, *it->second); 1142 return parse(codes, *it->second, lax);
1097 } 1143 }
1098 return {}; 1144 ParseInfo info{};
1145 info.error = ParseInfo::Error{"invalid rule: "s + std::string{astName}, 1, 1};
1146 return info;
1099} 1147}
1100 1148
1101bool YueParser::match(std::string_view astName, std::string_view codes) { 1149bool YueParser::match(std::string_view astName, std::string_view codes) {
1102 auto it = _rules.find(astName); 1150 auto it = _rules.find(astName);
1103 if (it != _rules.end()) { 1151 if (it != _rules.end()) {
1104 auto rEnd = rule(*it->second >> eof()); 1152 auto rEnd = rule(*it->second >> eof());
1105 return parse(codes, rEnd).node; 1153 return parse(codes, rEnd, false).node;
1106 } 1154 }
1107 return false; 1155 return false;
1108} 1156}
@@ -1138,6 +1186,24 @@ void trim(std::string& str) {
1138 str.erase(0, str.find_first_not_of(" \t\r\n")); 1186 str.erase(0, str.find_first_not_of(" \t\r\n"));
1139 str.erase(str.find_last_not_of(" \t\r\n") + 1); 1187 str.erase(str.find_last_not_of(" \t\r\n") + 1);
1140} 1188}
1189
1190std::string toLuaDoubleString(const std::string& input) {
1191 std::string luaStr = "\"";
1192 for (char c : input) {
1193 switch (c) {
1194 case '\"': luaStr += "\\\""; break;
1195 case '\\': luaStr += "\\\\"; break;
1196 case '\n': luaStr += "\\n"; break;
1197 case '\r': luaStr += "\\r"; break;
1198 case '\t': luaStr += "\\t"; break;
1199 default:
1200 luaStr += c;
1201 break;
1202 }
1203 }
1204 luaStr += "\"";
1205 return luaStr;
1206}
1141} // namespace Utils 1207} // namespace Utils
1142 1208
1143std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCol, int lineOffset) const { 1209std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCol, int lineOffset) const {
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h
index 7281ec3..c91e530 100644
--- a/src/yuescript/yue_parser.h
+++ b/src/yuescript/yue_parser.h
@@ -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;
@@ -119,10 +120,11 @@ protected:
119 size_t stringOpen = 0; 120 size_t stringOpen = 0;
120 std::string buffer; 121 std::string buffer;
121 std::stack<int> indents; 122 std::stack<int> indents;
122 std::stack<bool> noDoStack; 123 std::vector<bool> noDoStack;
123 std::stack<bool> noChainBlockStack; 124 std::vector<bool> noChainBlockStack;
124 std::stack<bool> noTableBlockStack; 125 std::vector<bool> noTableBlockStack;
125 std::stack<bool> noForStack; 126 std::vector<bool> noForStack;
127 std::vector<bool> noUntilStack;
126 std::unordered_set<std::string> usedNames; 128 std::unordered_set<std::string> usedNames;
127 }; 129 };
128 130
@@ -156,7 +158,7 @@ private:
156 NONE_AST_RULE(invalid_interpolation_error); 158 NONE_AST_RULE(invalid_interpolation_error);
157 NONE_AST_RULE(confusing_unary_not_error); 159 NONE_AST_RULE(confusing_unary_not_error);
158 NONE_AST_RULE(table_key_pair_error); 160 NONE_AST_RULE(table_key_pair_error);
159 NONE_AST_RULE(if_assignment_syntax_error); 161 NONE_AST_RULE(assignment_expression_syntax_error);
160 162
161 NONE_AST_RULE(inc_exp_level); 163 NONE_AST_RULE(inc_exp_level);
162 NONE_AST_RULE(dec_exp_level); 164 NONE_AST_RULE(dec_exp_level);
@@ -217,6 +219,8 @@ private:
217 NONE_AST_RULE(enable_for); 219 NONE_AST_RULE(enable_for);
218 NONE_AST_RULE(enable_fun_lit); 220 NONE_AST_RULE(enable_fun_lit);
219 NONE_AST_RULE(disable_fun_lit); 221 NONE_AST_RULE(disable_fun_lit);
222 NONE_AST_RULE(disable_until);
223 NONE_AST_RULE(enable_until);
220 NONE_AST_RULE(switch_else); 224 NONE_AST_RULE(switch_else);
221 NONE_AST_RULE(switch_block); 225 NONE_AST_RULE(switch_block);
222 NONE_AST_RULE(if_else_if); 226 NONE_AST_RULE(if_else_if);
@@ -284,6 +288,7 @@ private:
284 NONE_AST_RULE(yue_line_comment); 288 NONE_AST_RULE(yue_line_comment);
285 NONE_AST_RULE(line); 289 NONE_AST_RULE(line);
286 NONE_AST_RULE(shebang); 290 NONE_AST_RULE(shebang);
291 NONE_AST_RULE(lax_line);
287 292
288 AST_RULE(Num); 293 AST_RULE(Num);
289 AST_RULE(Name); 294 AST_RULE(Name);
@@ -315,12 +320,14 @@ private:
315 AST_RULE(ImportAllMacro); 320 AST_RULE(ImportAllMacro);
316 AST_RULE(ImportTabLit); 321 AST_RULE(ImportTabLit);
317 AST_RULE(ImportAs); 322 AST_RULE(ImportAs);
323 AST_RULE(ImportGlobal);
318 AST_RULE(Import); 324 AST_RULE(Import);
319 AST_RULE(Label); 325 AST_RULE(Label);
320 AST_RULE(Goto); 326 AST_RULE(Goto);
321 AST_RULE(ShortTabAppending); 327 AST_RULE(ShortTabAppending);
322 AST_RULE(FnArrowBack); 328 AST_RULE(FnArrowBack);
323 AST_RULE(Backcall); 329 AST_RULE(Backcall);
330 AST_RULE(SubBackcall);
324 AST_RULE(PipeBody); 331 AST_RULE(PipeBody);
325 AST_RULE(ExpListLow); 332 AST_RULE(ExpListLow);
326 AST_RULE(ExpList); 333 AST_RULE(ExpList);
@@ -359,6 +366,7 @@ private:
359 AST_RULE(ExpOpValue); 366 AST_RULE(ExpOpValue);
360 AST_RULE(Exp); 367 AST_RULE(Exp);
361 AST_RULE(Callable); 368 AST_RULE(Callable);
369 AST_RULE(ReversedIndex);
362 AST_RULE(ChainValue); 370 AST_RULE(ChainValue);
363 AST_RULE(SimpleTable); 371 AST_RULE(SimpleTable);
364 AST_RULE(SimpleValue); 372 AST_RULE(SimpleValue);
@@ -371,6 +379,11 @@ private:
371 AST_RULE(DoubleStringInner); 379 AST_RULE(DoubleStringInner);
372 AST_RULE(DoubleStringContent); 380 AST_RULE(DoubleStringContent);
373 AST_RULE(DoubleString); 381 AST_RULE(DoubleString);
382 AST_RULE(YAMLIndent);
383 AST_RULE(YAMLLineInner);
384 AST_RULE(YAMLLineContent);
385 AST_RULE(YAMLLine);
386 AST_RULE(YAMLMultiline);
374 AST_RULE(String); 387 AST_RULE(String);
375 AST_RULE(Parens); 388 AST_RULE(Parens);
376 AST_RULE(DotChainItem); 389 AST_RULE(DotChainItem);
@@ -427,6 +440,8 @@ private:
427 AST_RULE(ExpListAssign); 440 AST_RULE(ExpListAssign);
428 AST_RULE(IfLine); 441 AST_RULE(IfLine);
429 AST_RULE(WhileLine); 442 AST_RULE(WhileLine);
443 AST_RULE(Break);
444 AST_RULE(Continue);
430 AST_RULE(BreakLoop); 445 AST_RULE(BreakLoop);
431 AST_RULE(StatementAppendix); 446 AST_RULE(StatementAppendix);
432 AST_RULE(Statement); 447 AST_RULE(Statement);
@@ -444,6 +459,7 @@ private:
444namespace Utils { 459namespace Utils {
445void replace(std::string& str, std::string_view from, std::string_view to); 460void replace(std::string& str, std::string_view from, std::string_view to);
446void trim(std::string& str); 461void trim(std::string& str);
462std::string toLuaDoubleString(const std::string& input);
447} // namespace Utils 463} // namespace Utils
448 464
449} // namespace yue 465} // namespace yue
diff --git a/src/yuescript/yuescript.cpp b/src/yuescript/yuescript.cpp
index 7e8e8b7..61e3949 100644
--- a/src/yuescript/yuescript.cpp
+++ b/src/yuescript/yuescript.cpp
@@ -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) {
@@ -180,7 +186,7 @@ static int yueformat(lua_State* L) {
180 tabSize = static_cast<int>(luaL_checkinteger(L, 2)); 186 tabSize = static_cast<int>(luaL_checkinteger(L, 2));
181 } 187 }
182 std::string_view codes(input, len); 188 std::string_view codes(input, len);
183 auto info = yue::YueParser::shared().parse<yue::File_t>(codes); 189 auto info = yue::YueParser::shared().parse<yue::File_t>(codes, false);
184 if (info.error) { 190 if (info.error) {
185 const auto& error = info.error.value(); 191 const auto& error = info.error.value();
186 if (!info.codes) { 192 if (!info.codes) {
@@ -201,6 +207,7 @@ static int yueformat(lua_State* L) {
201 formatter.spaceOverTab = false; 207 formatter.spaceOverTab = false;
202 } 208 }
203 auto result = formatter.toString(info.node.get()); 209 auto result = formatter.toString(info.node.get());
210 yue::Utils::replace(result, "\n\n", "\n");
204 lua_pushlstring(L, result.c_str(), result.size()); 211 lua_pushlstring(L, result.c_str(), result.size());
205 return 1; 212 return 1;
206} 213}
@@ -282,8 +289,13 @@ static int yuetoast(lua_State* L) {
282 ruleName = {name, nameSize}; 289 ruleName = {name, nameSize};
283 } 290 }
284 } 291 }
292 bool lax = false;
293 if (!lua_isnoneornil(L, 4)) {
294 luaL_checktype(L, 4, LUA_TBOOLEAN);
295 lax = lua_toboolean(L, 4) != 0;
296 }
285 auto& yueParser = yue::YueParser::shared(); 297 auto& yueParser = yue::YueParser::shared();
286 auto info = ruleName.empty() ? yueParser.parse<yue::File_t>({input, size}) : yueParser.parse(ruleName, {input, size}); 298 auto info = ruleName.empty() ? yueParser.parse<yue::File_t>({input, size}, lax) : yueParser.parse(ruleName, {input, size}, lax);
287 if (!info.error) { 299 if (!info.error) {
288 lua_createtable(L, 0, 0); 300 lua_createtable(L, 0, 0);
289 int tableIndex = lua_gettop(L); 301 int tableIndex = lua_gettop(L);