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.cpp1238
-rw-r--r--src/yuescript/yue_compiler.h1
-rw-r--r--src/yuescript/yue_parser.cpp190
-rw-r--r--src/yuescript/yue_parser.h37
-rw-r--r--src/yuescript/yuescript.cpp16
8 files changed, 1483 insertions, 302 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 68ce9b5..d676750 100644
--- a/src/yuescript/yue_compiler.cpp
+++ b/src/yuescript/yue_compiler.cpp
@@ -7,9 +7,12 @@ The above copyright notice and this permission notice shall be included in all c
7THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.*/ 7THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.*/
8 8
9#include <chrono> 9#include <chrono>
10#include <cmath>
11#include <iomanip>
10#include <memory> 12#include <memory>
11#include <optional> 13#include <optional>
12#include <set> 14#include <set>
15#include <sstream>
13#include <stack> 16#include <stack>
14#include <string> 17#include <string>
15#include <unordered_map> 18#include <unordered_map>
@@ -75,7 +78,7 @@ static std::unordered_set<std::string> Metamethods = {
75 "close"s // Lua 5.4 78 "close"s // Lua 5.4
76}; 79};
77 80
78const std::string_view version = "0.27.4"sv; 81const std::string_view version = "0.29.3"sv;
79const std::string_view extension = "yue"sv; 82const std::string_view extension = "yue"sv;
80 83
81class CompileError : public std::logic_error { 84class CompileError : public std::logic_error {
@@ -162,12 +165,12 @@ public:
162 double compileTime = 0.0; 165 double compileTime = 0.0;
163 if (config.profiling) { 166 if (config.profiling) {
164 auto start = std::chrono::high_resolution_clock::now(); 167 auto start = std::chrono::high_resolution_clock::now();
165 _info = _parser.parse<File_t>(codes); 168 _info = _parser.parse<File_t>(codes, config.lax);
166 auto stop = std::chrono::high_resolution_clock::now(); 169 auto stop = std::chrono::high_resolution_clock::now();
167 std::chrono::duration<double> diff = stop - start; 170 std::chrono::duration<double> diff = stop - start;
168 parseTime = diff.count(); 171 parseTime = diff.count();
169 } else { 172 } else {
170 _info = _parser.parse<File_t>(codes); 173 _info = _parser.parse<File_t>(codes, config.lax);
171 } 174 }
172 std::unique_ptr<GlobalVars> globals; 175 std::unique_ptr<GlobalVars> globals;
173 std::unique_ptr<Options> options; 176 std::unique_ptr<Options> options;
@@ -426,8 +429,9 @@ private:
426 }; 429 };
427 enum class VarType { 430 enum class VarType {
428 Local = 0, 431 Local = 0,
429 Const = 1, 432 LocalConst = 1,
430 Global = 2 433 Global = 2,
434 GlobalConst = 3
431 }; 435 };
432 struct Scope { 436 struct Scope {
433 GlobalMode mode = GlobalMode::None; 437 GlobalMode mode = GlobalMode::None;
@@ -555,7 +559,7 @@ private:
555 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) { 559 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) {
556 auto vars = it->vars.get(); 560 auto vars = it->vars.get();
557 auto vit = vars->find(name); 561 auto vit = vars->find(name);
558 if (vit != vars->end() && vit->second != VarType::Global) { 562 if (vit != vars->end() && (vit->second == VarType::Local || vit->second == VarType::LocalConst)) {
559 local = true; 563 local = true;
560 break; 564 break;
561 } 565 }
@@ -568,7 +572,7 @@ private:
568 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) { 572 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) {
569 auto vars = it->vars.get(); 573 auto vars = it->vars.get();
570 auto vit = vars->find(name); 574 auto vit = vars->find(name);
571 if (vit != vars->end() && vit->second == VarType::Global) { 575 if (vit != vars->end() && (vit->second == VarType::Global || vit->second == VarType::GlobalConst)) {
572 global = true; 576 global = true;
573 break; 577 break;
574 } 578 }
@@ -590,7 +594,7 @@ private:
590 auto vars = it->vars.get(); 594 auto vars = it->vars.get();
591 auto vit = vars->find(name); 595 auto vit = vars->find(name);
592 if (vit != vars->end()) { 596 if (vit != vars->end()) {
593 isConst = (vit->second == VarType::Const); 597 isConst = (vit->second == VarType::LocalConst || vit->second == VarType::GlobalConst);
594 break; 598 break;
595 } 599 }
596 if (checkShadowScopeOnly && it->allows) break; 600 if (checkShadowScopeOnly && it->allows) break;
@@ -871,9 +875,9 @@ private:
871 return false; 875 return false;
872 } 876 }
873 877
874 void markVarConst(const std::string& name) { 878 void markVarLocalConst(const std::string& name) {
875 auto& scope = _scopes.back(); 879 auto& scope = _scopes.back();
876 scope.vars->insert_or_assign(name, VarType::Const); 880 scope.vars->insert_or_assign(name, VarType::LocalConst);
877 } 881 }
878 882
879 void markVarShadowed() { 883 void markVarShadowed() {
@@ -892,6 +896,11 @@ private:
892 scope.vars->insert_or_assign(name, VarType::Global); 896 scope.vars->insert_or_assign(name, VarType::Global);
893 } 897 }
894 898
899 void markVarGlobalConst(const std::string& name) {
900 auto& scope = _scopes.back();
901 scope.vars->insert_or_assign(name, VarType::GlobalConst);
902 }
903
895 void addToAllowList(const std::string& name) { 904 void addToAllowList(const std::string& name) {
896 auto& scope = _scopes.back(); 905 auto& scope = _scopes.back();
897 scope.allows->insert(name); 906 scope.allows->insert(name);
@@ -1249,7 +1258,7 @@ private:
1249 1258
1250 template <class T> 1259 template <class T>
1251 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) {
1252 auto res = _parser.parse<T>(std::string(codes)); 1261 auto res = _parser.parse<T>(std::string(codes), false);
1253 if (res.error) { 1262 if (res.error) {
1254 throw CompileError(res.error.value().msg, parent); 1263 throw CompileError(res.error.value().msg, parent);
1255 } 1264 }
@@ -1272,6 +1281,8 @@ private:
1272 Common, 1281 Common,
1273 EndWithColon, 1282 EndWithColon,
1274 EndWithEOP, 1283 EndWithEOP,
1284 EndWithSlice,
1285 HasRIndex,
1275 HasEOP, 1286 HasEOP,
1276 HasKeyword, 1287 HasKeyword,
1277 HasUnicode, 1288 HasUnicode,
@@ -1290,6 +1301,9 @@ private:
1290 if (ast_is<ExistentialOp_t>(chainValue->items.back())) { 1301 if (ast_is<ExistentialOp_t>(chainValue->items.back())) {
1291 return ChainType::EndWithEOP; 1302 return ChainType::EndWithEOP;
1292 } 1303 }
1304 if (ast_is<Slice_t>(chainValue->items.back())) {
1305 return ChainType::EndWithSlice;
1306 }
1293 if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) { 1307 if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) {
1294 if (dot->name.is<Metatable_t>()) { 1308 if (dot->name.is<Metatable_t>()) {
1295 return ChainType::Metatable; 1309 return ChainType::Metatable;
@@ -1315,6 +1329,8 @@ private:
1315 } 1329 }
1316 } else if (ast_is<ExistentialOp_t>(item)) { 1330 } else if (ast_is<ExistentialOp_t>(item)) {
1317 return ChainType::HasEOP; 1331 return ChainType::HasEOP;
1332 } else if (ast_is<ReversedIndex_t>(item)) {
1333 return ChainType::HasRIndex;
1318 } 1334 }
1319 } 1335 }
1320 return type; 1336 return type;
@@ -1837,6 +1853,7 @@ private:
1837 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;
1838 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;
1839 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;
1840 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;
1841 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;
1842 case id<Comprehension_t>(): { 1859 case id<Comprehension_t>(): {
@@ -2048,13 +2065,16 @@ private:
2048 if (item.targetVar.empty()) { 2065 if (item.targetVar.empty()) {
2049 throw CompileError("can only declare variable as const"sv, item.target); 2066 throw CompileError("can only declare variable as const"sv, item.target);
2050 } 2067 }
2051 markVarConst(item.targetVar); 2068 markVarLocalConst(item.targetVar);
2052 } 2069 }
2053 } 2070 }
2054 } 2071 }
2055 } 2072 }
2056 2073
2057 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 }
2058 checkAssignable(assignment->expList); 2078 checkAssignable(assignment->expList);
2059 BLOCK_START 2079 BLOCK_START
2060 auto assign = ast_cast<Assign_t>(assignment->action); 2080 auto assign = ast_cast<Assign_t>(assignment->action);
@@ -2317,6 +2337,17 @@ private:
2317 out.back().insert(0, preDefine); 2337 out.back().insert(0, preDefine);
2318 return false; 2338 return false;
2319 } 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 }
2320 case id<Switch_t>(): { 2351 case id<Switch_t>(): {
2321 auto switchNode = static_cast<Switch_t*>(value); 2352 auto switchNode = static_cast<Switch_t*>(value);
2322 auto assignList = assignment->expList.get(); 2353 auto assignList = assignment->expList.get();
@@ -2388,6 +2419,13 @@ private:
2388 out.back().insert(0, preDefine); 2419 out.back().insert(0, preDefine);
2389 return false; 2420 return false;
2390 } 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 }
2391 case id<TableLit_t>(): { 2429 case id<TableLit_t>(): {
2392 auto tableLit = static_cast<TableLit_t*>(value); 2430 auto tableLit = static_cast<TableLit_t*>(value);
2393 if (hasSpreadExp(tableLit->values.objects())) { 2431 if (hasSpreadExp(tableLit->values.objects())) {
@@ -2440,12 +2478,14 @@ private:
2440 switch (type) { 2478 switch (type) {
2441 case ChainType::HasEOP: 2479 case ChainType::HasEOP:
2442 case ChainType::EndWithColon: 2480 case ChainType::EndWithColon:
2481 case ChainType::EndWithSlice:
2443 case ChainType::MetaFieldInvocation: { 2482 case ChainType::MetaFieldInvocation: {
2444 std::string preDefine = getPreDefineLine(assignment); 2483 std::string preDefine = getPreDefineLine(assignment);
2445 transformChainValue(chainValue, out, ExpUsage::Assignment, expList, false, optionalDestruct); 2484 transformChainValue(chainValue, out, ExpUsage::Assignment, expList, false, optionalDestruct);
2446 out.back().insert(0, preDefine); 2485 out.back().insert(0, preDefine);
2447 return false; 2486 return false;
2448 } 2487 }
2488 case ChainType::HasRIndex:
2449 case ChainType::HasKeyword: 2489 case ChainType::HasKeyword:
2450 case ChainType::HasUnicode: 2490 case ChainType::HasUnicode:
2451 case ChainType::Macro: 2491 case ChainType::Macro:
@@ -2461,6 +2501,10 @@ private:
2461 auto info = extractDestructureInfo(assignment, false, optionalDestruct); 2501 auto info = extractDestructureInfo(assignment, false, optionalDestruct);
2462 if (info.destructures.empty()) { 2502 if (info.destructures.empty()) {
2463 transformAssignmentCommon(assignment, out); 2503 transformAssignmentCommon(assignment, out);
2504 if (assignment->expList->followStmt) {
2505 transformStatement(assignment->expList->followStmt, out);
2506 assignment->expList->followStmtProcessed = true;
2507 }
2464 return true; 2508 return true;
2465 } else { 2509 } else {
2466 auto x = assignment; 2510 auto x = assignment;
@@ -2726,8 +2770,12 @@ private:
2726 temp.push_back(indent() + "end"s + nlr(x)); 2770 temp.push_back(indent() + "end"s + nlr(x));
2727 } 2771 }
2728 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;
2729 } 2778 }
2730 return false;
2731 } 2779 }
2732 2780
2733 void transformAssignItem(ast_node* value, str_list& out) { 2781 void transformAssignItem(ast_node* value, str_list& out) {
@@ -2793,20 +2841,46 @@ private:
2793 if (!tableItems) throw CompileError("invalid destructure value"sv, node); 2841 if (!tableItems) throw CompileError("invalid destructure value"sv, node);
2794 std::list<DestructItem> pairs; 2842 std::list<DestructItem> pairs;
2795 int index = 0; 2843 int index = 0;
2844 int count = 0;
2845 bool hasSpread = false;
2796 auto subMetaDestruct = node->new_ptr<TableLit_t>(); 2846 auto subMetaDestruct = node->new_ptr<TableLit_t>();
2797 for (auto pair : *tableItems) { 2847 for (auto pair : *tableItems) {
2798 switch (pair->get_id()) { 2848 switch (pair->get_id()) {
2799 case id<Exp_t>(): 2849 case id<Exp_t>():
2800 case id<NormalDef_t>(): { 2850 case id<NormalDef_t>(): {
2851 ++index;
2801 Exp_t* defVal = nullptr; 2852 Exp_t* defVal = nullptr;
2802 if (auto nd = ast_cast<NormalDef_t>(pair)) { 2853 if (auto nd = ast_cast<NormalDef_t>(pair)) {
2803 pair = nd->item.get(); 2854 pair = nd->item.get();
2804 defVal = nd->defVal.get(); 2855 defVal = nd->defVal.get();
2805 } 2856 }
2806 ++index; 2857 bool assignable = false;
2807 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;
2808 throw CompileError("can't destructure value"sv, pair); 2865 throw CompileError("can't destructure value"sv, pair);
2809 } 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 }
2810 auto value = singleValueFrom(pair); 2884 auto value = singleValueFrom(pair);
2811 auto item = value->item.get(); 2885 auto item = value->item.get();
2812 ast_node* subExp = ast_cast<SimpleTable_t>(item); 2886 ast_node* subExp = ast_cast<SimpleTable_t>(item);
@@ -2817,7 +2891,6 @@ private:
2817 throw CompileError("default value is not supported here"sv, defVal); 2891 throw CompileError("default value is not supported here"sv, defVal);
2818 } 2892 }
2819 } 2893 }
2820 auto indexItem = toAst<Exp_t>(std::to_string(index), value);
2821 for (auto& p : subPairs) { 2894 for (auto& p : subPairs) {
2822 if (sep) p.structure->items.push_front(sep); 2895 if (sep) p.structure->items.push_front(sep);
2823 p.structure->items.push_front(indexItem); 2896 p.structure->items.push_front(indexItem);
@@ -2828,7 +2901,6 @@ private:
2828 auto varName = singleVariableFrom(exp, AccessType::None); 2901 auto varName = singleVariableFrom(exp, AccessType::None);
2829 if (varName == "_"sv) break; 2902 if (varName == "_"sv) break;
2830 auto chain = exp->new_ptr<ChainValue_t>(); 2903 auto chain = exp->new_ptr<ChainValue_t>();
2831 auto indexItem = toAst<Exp_t>(std::to_string(index), exp);
2832 chain->items.push_back(indexItem); 2904 chain->items.push_back(indexItem);
2833 pairs.push_back({exp, 2905 pairs.push_back({exp,
2834 varName, 2906 varName,
@@ -2886,7 +2958,25 @@ private:
2886 } 2958 }
2887 } 2959 }
2888 if (auto exp = np->value.as<Exp_t>()) { 2960 if (auto exp = np->value.as<Exp_t>()) {
2889 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 }
2890 auto item = singleValueFrom(exp)->item.get(); 2980 auto item = singleValueFrom(exp)->item.get();
2891 ast_node* subExp = ast_cast<SimpleTable_t>(item); 2981 ast_node* subExp = ast_cast<SimpleTable_t>(item);
2892 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>())) {
@@ -2935,7 +3025,13 @@ private:
2935 auto tb = static_cast<TableBlockIndent_t*>(pair); 3025 auto tb = static_cast<TableBlockIndent_t*>(pair);
2936 ++index; 3026 ++index;
2937 auto subPairs = destructFromExp(tb, varDefOnly, optional); 3027 auto subPairs = destructFromExp(tb, varDefOnly, optional);
2938 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 }
2939 for (auto& p : subPairs) { 3035 for (auto& p : subPairs) {
2940 if (sep) p.structure->items.push_front(sep); 3036 if (sep) p.structure->items.push_front(sep);
2941 p.structure->items.push_front(indexItem); 3037 p.structure->items.push_front(indexItem);
@@ -2992,6 +3088,42 @@ private:
2992 subMetaDestruct->values.push_back(newPairDef); 3088 subMetaDestruct->values.push_back(newPairDef);
2993 break; 3089 break;
2994 } 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 }
2995 default: YUEE("AST node mismatch", pair); break; 3127 default: YUEE("AST node mismatch", pair); break;
2996 } 3128 }
2997 } 3129 }
@@ -3108,7 +3240,11 @@ private:
3108 break; 3240 break;
3109 default: YUEE("AST node mismatch", destructNode); break; 3241 default: YUEE("AST node mismatch", destructNode); break;
3110 } 3242 }
3111 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 }
3112 for (auto item : *dlist) { 3248 for (auto item : *dlist) {
3113 switch (item->get_id()) { 3249 switch (item->get_id()) {
3114 case id<MetaVariablePairDef_t>(): { 3250 case id<MetaVariablePairDef_t>(): {
@@ -3244,7 +3380,9 @@ private:
3244 simpleValue->value.set(tab); 3380 simpleValue->value.set(tab);
3245 auto pairs = destructFromExp(newExp(simpleValue, expr), varDefOnly, optional); 3381 auto pairs = destructFromExp(newExp(simpleValue, expr), varDefOnly, optional);
3246 if (pairs.empty()) { 3382 if (pairs.empty()) {
3247 throw CompileError("expect items to be destructured"sv, tab); 3383 if (!optional) {
3384 throw CompileError("expect items to be destructured"sv, tab);
3385 }
3248 } 3386 }
3249 destruct.items = std::move(pairs); 3387 destruct.items = std::move(pairs);
3250 if (!varDefOnly) { 3388 if (!varDefOnly) {
@@ -3283,7 +3421,7 @@ private:
3283 destruct.valueVar.clear(); 3421 destruct.valueVar.clear();
3284 } 3422 }
3285 } 3423 }
3286 destructs.push_back(destruct); 3424 destructs.push_back(std::move(destruct));
3287 } 3425 }
3288 } 3426 }
3289 } else { 3427 } else {
@@ -4202,12 +4340,22 @@ private:
4202 4340
4203 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) {
4204 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 }
4205 auto returnNode = exp->new_ptr<Return_t>(); 4354 auto returnNode = exp->new_ptr<Return_t>();
4206 returnNode->explicitReturn = false; 4355 returnNode->explicitReturn = false;
4207 auto returnList = exp->new_ptr<ExpListLow_t>(); 4356 auto returnList = exp->new_ptr<ExpListLow_t>();
4208 returnList->exprs.push_back(exp); 4357 returnList->exprs.push_back(exp);
4209 returnNode->valueList.set(returnList); 4358 returnNode->valueList.set(returnList);
4210 auto block = exp->new_ptr<Block_t>();
4211 auto stmt = exp->new_ptr<Statement_t>(); 4359 auto stmt = exp->new_ptr<Statement_t>();
4212 stmt->content.set(returnNode); 4360 stmt->content.set(returnNode);
4213 block->statements.push_back(stmt); 4361 block->statements.push_back(stmt);
@@ -4284,7 +4432,9 @@ private:
4284 return false; 4432 return false;
4285 }; 4433 };
4286 switch (usage) { 4434 switch (usage) {
4287 case ExpUsage::Common: YUEE("AST node mismatch", x); return; 4435 case ExpUsage::Common:
4436 YUEE("AST node mismatch", x);
4437 return;
4288 case ExpUsage::Return: 4438 case ExpUsage::Return:
4289 case ExpUsage::Closure: { 4439 case ExpUsage::Closure: {
4290 prepareValue(); 4440 prepareValue();
@@ -4407,6 +4557,7 @@ private:
4407 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;
4408 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;
4409 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;
4410 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;
4411 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;
4412 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;
@@ -4726,11 +4877,7 @@ private:
4726 auto newBody = x->new_ptr<Body_t>(); 4877 auto newBody = x->new_ptr<Body_t>();
4727 newBody->content.set(followingBlock); 4878 newBody->content.set(followingBlock);
4728 { 4879 {
4729 auto doNode = x->new_ptr<Do_t>(); 4880 if (auto result = upValueFuncFromBlock(followingBlock.get(), &argNames, false, true)) {
4730 doNode->body.set(newBody);
4731 auto simpleValue = x->new_ptr<SimpleValue_t>();
4732 simpleValue->value.set(doNode);
4733 if (auto result = upValueFuncFromExp(newExp(simpleValue, x), &argNames, true)) {
4734 auto [funcName, args] = std::move(*result); 4881 auto [funcName, args] = std::move(*result);
4735 str_list finalArgs; 4882 str_list finalArgs;
4736 for (const auto& arg : args) { 4883 for (const auto& arg : args) {
@@ -4738,9 +4885,13 @@ private:
4738 finalArgs.push_back(arg); 4885 finalArgs.push_back(arg);
4739 } 4886 }
4740 } 4887 }
4741 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));
4742 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);
4743 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);
4744 transformBlock(newBlock, out, usage, assignList, isRoot); 4895 transformBlock(newBlock, out, usage, assignList, isRoot);
4745 return; 4896 return;
4746 } 4897 }
@@ -4797,7 +4948,7 @@ private:
4797 auto varName = variableToString(ast_to<Variable_t>(var)); 4948 auto varName = variableToString(ast_to<Variable_t>(var));
4798 auto closeVar = getUnusedName("_close_"sv); 4949 auto closeVar = getUnusedName("_close_"sv);
4799 addToScope(closeVar); 4950 addToScope(closeVar);
4800 getCloses.push_back(closeVar + "=if type("s + varName + ") in ['table', 'userdata'] then assert "s + varName + ".<> and "s + varName +".<close>, \""s + "variable '"s + varName + "' got a non-closable value\" elseif "s + varName + " == nil then nil else error \""s + "variable '"s + varName + "' got a non-closable value\""); 4951 getCloses.push_back(closeVar + "=if type("s + varName + ") in ['table', 'userdata'] then assert "s + varName + ".<> and "s + varName + ".<close>, \""s + "variable '"s + varName + "' got a non-closable value\" elseif "s + varName + " == nil then nil else error \""s + "variable '"s + varName + "' got a non-closable value\"");
4801 doCloses.push_front(closeVar + "? "s + varName); 4952 doCloses.push_front(closeVar + "? "s + varName);
4802 } 4953 }
4803 popScope(); 4954 popScope();
@@ -4817,6 +4968,38 @@ private:
4817 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));
4818 transformBlock(newBlock, out, usage, assignList, isRoot); 4969 transformBlock(newBlock, out, usage, assignList, isRoot);
4819 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;
4820 } 5003 }
4821 if (auto local = stmt->content.as<Local_t>()) { 5004 if (auto local = stmt->content.as<Local_t>()) {
4822 if (!local->collected) { 5005 if (!local->collected) {
@@ -4988,36 +5171,45 @@ private:
4988 if (!nodes.empty()) { 5171 if (!nodes.empty()) {
4989 str_list temp; 5172 str_list temp;
4990 for (auto node : nodes) { 5173 for (auto node : nodes) {
4991 currentScope().lastStatement = (node == nodes.back()) && currentScope().mode == GlobalMode::None; 5174 auto transformNode = [&]() {
4992 transformStatement(static_cast<Statement_t*>(node), temp); 5175 currentScope().lastStatement = (node == nodes.back()) && currentScope().mode == GlobalMode::None;
4993 if (isRoot && !_rootDefs.empty()) { 5176 transformStatement(static_cast<Statement_t*>(node), temp);
4994 auto last = std::move(temp.back()); 5177 if (isRoot && !_rootDefs.empty()) {
4995 temp.pop_back(); 5178 auto last = std::move(temp.back());
4996 temp.insert(temp.end(), _rootDefs.begin(), _rootDefs.end()); 5179 temp.pop_back();
4997 _rootDefs.clear(); 5180 temp.insert(temp.end(), _rootDefs.begin(), _rootDefs.end());
4998 temp.push_back(std::move(last)); 5181 _rootDefs.clear();
4999 } 5182 temp.push_back(std::move(last));
5000 if (!temp.empty() && _parser.startWith<StatementSep_t>(temp.back())) { 5183 }
5001 auto rit = ++temp.rbegin(); 5184 if (!temp.empty() && _parser.startWith<StatementSep_t>(temp.back())) {
5002 if (rit != temp.rend() && !rit->empty()) { 5185 auto rit = ++temp.rbegin();
5003 auto index = std::string::npos; 5186 if (rit != temp.rend() && !rit->empty()) {
5004 if (_config.reserveLineNumber) { 5187 auto index = std::string::npos;
5005 index = rit->rfind(" -- "sv); 5188 if (_config.reserveLineNumber) {
5006 } else { 5189 index = rit->rfind(" -- "sv);
5007 index = rit->find_last_not_of('\n'); 5190 } else {
5008 if (index != std::string::npos) index++; 5191 index = rit->find_last_not_of('\n');
5009 } 5192 if (index != std::string::npos) index++;
5010 if (index != std::string::npos) {
5011 auto ending = rit->substr(0, index);
5012 auto ind = ending.find_last_of(" \t\n"sv);
5013 if (ind != std::string::npos) {
5014 ending = ending.substr(ind + 1);
5015 } 5193 }
5016 if (LuaKeywords.find(ending) == LuaKeywords.end()) { 5194 if (index != std::string::npos) {
5017 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 }
5018 } 5203 }
5019 } 5204 }
5020 } 5205 }
5206 };
5207 if (_config.lax) {
5208 try {
5209 transformNode();
5210 } catch (const CompileError&) { }
5211 } else {
5212 transformNode();
5021 } 5213 }
5022 } 5214 }
5023 out.push_back(join(temp)); 5215 out.push_back(join(temp));
@@ -5226,18 +5418,29 @@ private:
5226 auto macroLit = macro->decl.to<MacroLit_t>(); 5418 auto macroLit = macro->decl.to<MacroLit_t>();
5227 auto argsDef = macroLit->argsDef.get(); 5419 auto argsDef = macroLit->argsDef.get();
5228 str_list newArgs; 5420 str_list newArgs;
5421 str_list argChecks;
5422 bool hasCheck = false;
5229 if (argsDef) { 5423 if (argsDef) {
5230 for (auto def_ : argsDef->definitions.objects()) { 5424 for (auto def_ : argsDef->definitions.objects()) {
5231 auto def = static_cast<FnArgDef_t*>(def_); 5425 auto def = static_cast<FnArgDef_t*>(def_);
5232 if (def->name.is<SelfItem_t>()) { 5426 if (def->name.is<SelfItem_t>()) {
5233 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);
5234 } 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 }
5235 std::string defVal; 5439 std::string defVal;
5236 if (def->defaultValue) { 5440 if (def->defaultValue) {
5237 defVal = _parser.toString(def->defaultValue); 5441 defVal = _parser.toString(def->defaultValue);
5238 Utils::trim(defVal); 5442 Utils::trim(defVal);
5239 defVal.insert(0, "=[==========["sv); 5443 defVal = '=' + Utils::toLuaDoubleString(defVal);
5240 defVal.append("]==========]"sv);
5241 } 5444 }
5242 newArgs.emplace_back(_parser.toString(def->name) + defVal); 5445 newArgs.emplace_back(_parser.toString(def->name) + defVal);
5243 } 5446 }
@@ -5245,6 +5448,14 @@ private:
5245 if (argsDef->varArg) { 5448 if (argsDef->varArg) {
5246 newArgs.emplace_back(_parser.toString(argsDef->varArg)); 5449 newArgs.emplace_back(_parser.toString(argsDef->varArg));
5247 } 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 }
5248 } 5459 }
5249 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);
5250 auto chunkName = "=(macro "s + macroName + ')'; 5461 auto chunkName = "=(macro "s + macroName + ')';
@@ -5275,6 +5486,24 @@ private:
5275 throw CompileError("failed to generate macro function\n"s + err, macroLit); 5486 throw CompileError("failed to generate macro function\n"s + err, macroLit);
5276 } // cur true macro 5487 } // cur true macro
5277 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
5278 if (exporting && _config.exporting && !_config.module.empty()) { 5507 if (exporting && _config.exporting && !_config.module.empty()) {
5279 pushModuleTable(_config.module); // cur macro module 5508 pushModuleTable(_config.module); // cur macro module
5280 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
@@ -5349,6 +5578,9 @@ private:
5349 case id<While_t>(): 5578 case id<While_t>():
5350 transformWhileInPlace(static_cast<While_t*>(value), out); 5579 transformWhileInPlace(static_cast<While_t*>(value), out);
5351 return; 5580 return;
5581 case id<Repeat_t>():
5582 transformRepeatInPlace(static_cast<Repeat_t*>(value), out);
5583 return;
5352 case id<For_t>(): 5584 case id<For_t>():
5353 transformForInPlace(static_cast<For_t*>(value), out); 5585 transformForInPlace(static_cast<For_t*>(value), out);
5354 return; 5586 return;
@@ -5429,7 +5661,11 @@ private:
5429 auto def = static_cast<FnArgDef_t*>(_def); 5661 auto def = static_cast<FnArgDef_t*>(_def);
5430 auto& arg = argItems.emplace_back(); 5662 auto& arg = argItems.emplace_back();
5431 switch (def->name->get_id()) { 5663 switch (def->name->get_id()) {
5432 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 }
5433 case id<SelfItem_t>(): { 5669 case id<SelfItem_t>(): {
5434 assignSelf = true; 5670 assignSelf = true;
5435 if (def->op) { 5671 if (def->op) {
@@ -5568,6 +5804,45 @@ private:
5568 } 5804 }
5569 } 5805 }
5570 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
5571 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) {
5572 auto x = chainList.front(); 5847 auto x = chainList.front();
5573 if (ast_is<ExistentialOp_t>(chainList.back())) { 5848 if (ast_is<ExistentialOp_t>(chainList.back())) {
@@ -6085,7 +6360,7 @@ private:
6085 case id<ColonChainItem_t>(): 6360 case id<ColonChainItem_t>():
6086 case id<Exp_t>(): 6361 case id<Exp_t>():
6087 if (_withVars.empty()) { 6362 if (_withVars.empty()) {
6088 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);
6089 } else { 6364 } else {
6090 temp.push_back(_withVars.top()); 6365 temp.push_back(_withVars.top());
6091 } 6366 }
@@ -6231,6 +6506,93 @@ private:
6231 } 6506 }
6232 return; 6507 return;
6233 } 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;
6234 } 6596 }
6235 } 6597 }
6236 } 6598 }
@@ -6415,7 +6777,7 @@ private:
6415 } 6777 }
6416 } 6778 }
6417 } 6779 }
6418 int len = lua_objlen(L, -1); 6780 int len = static_cast<int>(lua_objlen(L, -1));
6419 lua_pushnil(L); // cur nil 6781 lua_pushnil(L); // cur nil
6420 for (int i = len; i >= 1; i--) { 6782 for (int i = len; i >= 1; i--) {
6421 lua_pop(L, 1); // cur 6783 lua_pop(L, 1); // cur
@@ -6427,7 +6789,25 @@ private:
6427 break; 6789 break;
6428 } 6790 }
6429 } 6791 }
6430 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)) {
6431 auto code = expandBuiltinMacro(macroName, x); 6811 auto code = expandBuiltinMacro(macroName, x);
6432 if (!code.empty()) return code; 6812 if (!code.empty()) return code;
6433 if (macroName == "is_ast"sv) { 6813 if (macroName == "is_ast"sv) {
@@ -6472,11 +6852,34 @@ private:
6472 } // cur macroFunc 6852 } // cur macroFunc
6473 pushYue("pcall"sv); // cur macroFunc pcall 6853 pushYue("pcall"sv); // cur macroFunc pcall
6474 lua_insert(L, -2); // cur pcall macroFunc 6854 lua_insert(L, -2); // cur pcall macroFunc
6475 if (!lua_checkstack(L, argStrs.size())) { 6855 if (!lua_checkstack(L, static_cast<int>(argStrs.size()))) {
6476 throw CompileError("too much macro params"s, x); 6856 throw CompileError("too much macro params"s, x);
6477 } 6857 }
6858 auto checkIt = checks.begin();
6859 node_container::const_iterator argIt;
6860 if (args) {
6861 argIt = args->begin();
6862 }
6478 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 }
6479 lua_pushlstring(L, arg.c_str(), arg.size()); 6881 lua_pushlstring(L, arg.c_str(), arg.size());
6882 ++argIt;
6480 } // cur pcall macroFunc args... 6883 } // cur pcall macroFunc args...
6481 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;
6482 if (!success) { // cur err 6885 if (!success) { // cur err
@@ -6606,14 +7009,14 @@ private:
6606 } else { 7009 } else {
6607 if (!codes.empty()) { 7010 if (!codes.empty()) {
6608 if (isBlock) { 7011 if (isBlock) {
6609 info = _parser.parse<BlockEnd_t>(codes); 7012 info = _parser.parse<BlockEnd_t>(codes, false);
6610 if (info.error) { 7013 if (info.error) {
6611 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);
6612 } 7015 }
6613 } else { 7016 } else {
6614 info = _parser.parse<Exp_t>(codes); 7017 info = _parser.parse<Exp_t>(codes, false);
6615 if (!info.node && allowBlockMacroReturn) { 7018 if (!info.node && allowBlockMacroReturn) {
6616 info = _parser.parse<BlockEnd_t>(codes); 7019 info = _parser.parse<BlockEnd_t>(codes, false);
6617 if (info.error) { 7020 if (info.error) {
6618 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);
6619 } 7022 }
@@ -6749,6 +7152,9 @@ private:
6749 if (transformChainEndWithColonItem(chainList, out, usage, assignList)) { 7152 if (transformChainEndWithColonItem(chainList, out, usage, assignList)) {
6750 return; 7153 return;
6751 } 7154 }
7155 if (transformChainEndWithSlice(chainList, out, usage, assignList)) {
7156 return;
7157 }
6752 transformChainList(chainList, out, usage, assignList); 7158 transformChainList(chainList, out, usage, assignList);
6753 } 7159 }
6754 7160
@@ -7144,6 +7550,33 @@ private:
7144 void transformNum(Num_t* num, str_list& out) { 7550 void transformNum(Num_t* num, str_list& out) {
7145 std::string numStr = _parser.toString(num); 7551 std::string numStr = _parser.toString(num);
7146 numStr.erase(std::remove(numStr.begin(), numStr.end(), '_'), numStr.end()); 7552 numStr.erase(std::remove(numStr.begin(), numStr.end(), '_'), numStr.end());
7553 if (numStr.size() > 2 && numStr[0] == '0') {
7554 if (numStr[1] == 'b' || numStr[1] == 'B') {
7555 std::string binaryPart = numStr.substr(2);
7556 try {
7557 unsigned long long value = std::stoull(binaryPart, nullptr, 2);
7558 numStr = std::to_string(value);
7559 } catch (const std::exception&) {
7560 throw CompileError("invalid binary literal"sv, num);
7561 }
7562 } else if (getLuaTarget(num) < 502) {
7563 if (numStr[1] == 'x' || numStr[1] == 'X') {
7564 if (numStr.find_first_of(".-"sv) != std::string::npos) {
7565 std::stringstream ss(numStr);
7566 double v;
7567 ss >> std::hexfloat >> v;
7568 if (ss.fail() || !std::isfinite(v)) {
7569 throw CompileError("invalid hex‑float literal"sv, num);
7570 }
7571 std::ostringstream outSs;
7572 outSs << std::setprecision(17) << v;
7573 numStr = outSs.str();
7574 } else {
7575 numStr.erase(std::remove(numStr.begin(), numStr.end(), '+'), numStr.end());
7576 }
7577 }
7578 }
7579 }
7147 out.push_back(numStr); 7580 out.push_back(numStr);
7148 } 7581 }
7149 7582
@@ -7829,6 +8262,11 @@ private:
7829 } 8262 }
7830 8263
7831 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 };
7832 auto x = nameList; 8270 auto x = nameList;
7833 str_list temp; 8271 str_list temp;
7834 str_list vars; 8272 str_list vars;
@@ -7895,15 +8333,35 @@ private:
7895 for (auto item : chainList) { 8333 for (auto item : chainList) {
7896 chain->items.push_back(item); 8334 chain->items.push_back(item);
7897 } 8335 }
7898 std::string startValue("1"sv); 8336 std::string startValue;
8337 NumState startStatus = NumState::Unknown;
7899 if (auto exp = slice->startValue.as<Exp_t>()) { 8338 if (auto exp = slice->startValue.as<Exp_t>()) {
7900 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 }
7901 startValue = std::move(temp.back()); 8349 startValue = std::move(temp.back());
7902 temp.pop_back(); 8350 temp.pop_back();
7903 } 8351 }
7904 std::string stopValue; 8352 std::string stopValue;
8353 NumState stopStatus = NumState::Unknown;
7905 if (auto exp = slice->stopValue.as<Exp_t>()) { 8354 if (auto exp = slice->stopValue.as<Exp_t>()) {
7906 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 }
7907 stopValue = std::move(temp.back()); 8365 stopValue = std::move(temp.back());
7908 temp.pop_back(); 8366 temp.pop_back();
7909 } 8367 }
@@ -7925,8 +8383,33 @@ private:
7925 transformChainValue(chain, temp, ExpUsage::Closure); 8383 transformChainValue(chain, temp, ExpUsage::Closure);
7926 _buf << prefix << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList); 8384 _buf << prefix << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList);
7927 } 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 }
7928 std::string maxVar; 8411 std::string maxVar;
7929 if (!stopValue.empty()) { 8412 if (stopStatus != NumState::Positive) {
7930 std::string prefix; 8413 std::string prefix;
7931 if (!extraScope && !inClosure && needScope) { 8414 if (!extraScope && !inClosure && needScope) {
7932 extraScope = true; 8415 extraScope = true;
@@ -7935,14 +8418,45 @@ private:
7935 } 8418 }
7936 maxVar = getUnusedName("_max_"sv); 8419 maxVar = getUnusedName("_max_"sv);
7937 varBefore.push_back(maxVar); 8420 varBefore.push_back(maxVar);
7938 _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);
7939 } 8432 }
7940 _buf << indent() << "for "sv << indexVar << " = "sv; 8433 _buf << indent() << "for "sv << indexVar << " = "sv;
7941 _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;
7942 if (stopValue.empty()) { 8448 if (stopValue.empty()) {
7943 _buf << "#"sv << listVar; 8449 _buf << "#"sv << listVar;
7944 } else { 8450 } else {
7945 _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 }
7946 } 8460 }
7947 if (!stepValue.empty()) { 8461 if (!stepValue.empty()) {
7948 _buf << ", "sv << stepValue; 8462 _buf << ", "sv << stepValue;
@@ -7982,7 +8496,7 @@ private:
7982 pushScope(); 8496 pushScope();
7983 for (const auto& var : vars) forceAddToScope(var); 8497 for (const auto& var : vars) forceAddToScope(var);
7984 for (const auto& var : varAfter) addToScope(var); 8498 for (const auto& var : varAfter) addToScope(var);
7985 if (!varConstAfter.empty()) markVarConst(varConstAfter); 8499 if (!varConstAfter.empty()) markVarLocalConst(varConstAfter);
7986 if (!destructPairs.empty()) { 8500 if (!destructPairs.empty()) {
7987 temp.clear(); 8501 temp.clear();
7988 for (auto& pair : destructPairs) { 8502 for (auto& pair : destructPairs) {
@@ -8067,7 +8581,7 @@ private:
8067 _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);
8068 pushScope(); 8582 pushScope();
8069 forceAddToScope(varName); 8583 forceAddToScope(varName);
8070 markVarConst(varName); 8584 markVarLocalConst(varName);
8071 out.push_back(clearBuf()); 8585 out.push_back(clearBuf());
8072 } 8586 }
8073 8587
@@ -8075,26 +8589,59 @@ private:
8075 transformForHead(forNode->varName, forNode->startValue, forNode->stopValue, forNode->stepValue, out); 8589 transformForHead(forNode->varName, forNode->startValue, forNode->stopValue, forNode->stepValue, out);
8076 } 8590 }
8077 8591
8078 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) {
8079 switch (body->get_id()) { 8593 switch (bodyOrStmt->get_id()) {
8080 case id<Block_t>(): 8594 case id<Block_t>():
8081 transformBlock(static_cast<Block_t*>(body), out, usage, assignList); 8595 transformBlock(static_cast<Block_t*>(bodyOrStmt), out, usage, assignList);
8082 break; 8596 break;
8083 case id<Statement_t>(): { 8597 case id<Statement_t>(): {
8084 auto newBlock = body->new_ptr<Block_t>(); 8598 auto newBlock = bodyOrStmt->new_ptr<Block_t>();
8085 newBlock->statements.push_back(body); 8599 newBlock->statements.push_back(bodyOrStmt);
8086 transformBlock(newBlock, out, usage, assignList); 8600 transformBlock(newBlock, out, usage, assignList);
8087 break; 8601 break;
8088 } 8602 }
8089 default: YUEE("AST node mismatch", body); break; 8603 default: YUEE("AST node mismatch", bodyOrStmt); break;
8090 } 8604 }
8091 } 8605 }
8092 8606
8093 bool hasContinueStatement(ast_node* body) { 8607 enum class BreakLoopType {
8094 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) {
8095 if (auto stmt = ast_cast<Statement_t>(node)) { 8629 if (auto stmt = ast_cast<Statement_t>(node)) {
8096 if (stmt->content.is<BreakLoop_t>()) { 8630 if (auto breakLoop = stmt->content.as<BreakLoop_t>()) {
8097 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 }
8098 } else if (auto expList = expListFrom(stmt)) { 8645 } else if (auto expList = expListFrom(stmt)) {
8099 BLOCK_START 8646 BLOCK_START
8100 auto value = singleValueFrom(expList); 8647 auto value = singleValueFrom(expList);
@@ -8105,40 +8652,30 @@ private:
8105 switch (sVal->get_id()) { 8652 switch (sVal->get_id()) {
8106 case id<With_t>(): { 8653 case id<With_t>(): {
8107 auto withNode = static_cast<With_t*>(sVal); 8654 auto withNode = static_cast<With_t*>(sVal);
8108 if (hasContinueStatement(withNode->body)) { 8655 type |= getBreakLoopType(withNode->body, varBWV);
8109 return traversal::Stop; 8656 return traversal::Return;
8110 }
8111 break;
8112 } 8657 }
8113 case id<Do_t>(): { 8658 case id<Do_t>(): {
8114 auto doNode = static_cast<Do_t*>(sVal); 8659 auto doNode = static_cast<Do_t*>(sVal);
8115 if (hasContinueStatement(doNode->body)) { 8660 type |= getBreakLoopType(doNode->body, varBWV);
8116 return traversal::Stop; 8661 return traversal::Return;
8117 }
8118 break;
8119 } 8662 }
8120 case id<If_t>(): { 8663 case id<If_t>(): {
8121 auto ifNode = static_cast<If_t*>(sVal); 8664 auto ifNode = static_cast<If_t*>(sVal);
8122 for (auto n : ifNode->nodes.objects()) { 8665 for (auto n : ifNode->nodes.objects()) {
8123 if (hasContinueStatement(n)) { 8666 type |= getBreakLoopType(n, varBWV);
8124 return traversal::Stop;
8125 }
8126 } 8667 }
8127 break; 8668 return traversal::Return;
8128 } 8669 }
8129 case id<Switch_t>(): { 8670 case id<Switch_t>(): {
8130 auto switchNode = static_cast<Switch_t*>(sVal); 8671 auto switchNode = static_cast<Switch_t*>(sVal);
8131 for (auto branch : switchNode->branches.objects()) { 8672 for (auto branch : switchNode->branches.objects()) {
8132 if (hasContinueStatement(static_cast<SwitchCase_t*>(branch)->body)) { 8673 type |= getBreakLoopType(static_cast<SwitchCase_t*>(branch)->body, varBWV);
8133 return traversal::Stop;
8134 }
8135 } 8674 }
8136 if (switchNode->lastBranch) { 8675 if (switchNode->lastBranch) {
8137 if (hasContinueStatement(switchNode->lastBranch)) { 8676 type |= getBreakLoopType(switchNode->lastBranch, varBWV);
8138 return traversal::Stop;
8139 }
8140 } 8677 }
8141 break; 8678 return traversal::Return;
8142 } 8679 }
8143 } 8680 }
8144 BLOCK_END 8681 BLOCK_END
@@ -8152,6 +8689,7 @@ private:
8152 } 8689 }
8153 return traversal::Return; 8690 return traversal::Return;
8154 }); 8691 });
8692 return type;
8155 } 8693 }
8156 8694
8157 void addDoToLastLineReturn(ast_node* body) { 8695 void addDoToLastLineReturn(ast_node* body) {
@@ -8175,10 +8713,10 @@ private:
8175 } 8713 }
8176 } 8714 }
8177 8715
8178 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) {
8179 str_list temp; 8717 str_list temp;
8180 bool extraDo = false; 8718 bool extraDo = false;
8181 bool withContinue = hasContinueStatement(body); 8719 bool withContinue = hasContinue(breakLoopType);
8182 int target = getLuaTarget(body); 8720 int target = getLuaTarget(body);
8183 std::string extraLabel; 8721 std::string extraLabel;
8184 if (withContinue) { 8722 if (withContinue) {
@@ -8187,7 +8725,7 @@ private:
8187 if (!block->statements.empty()) { 8725 if (!block->statements.empty()) {
8188 auto stmt = static_cast<Statement_t*>(block->statements.back()); 8726 auto stmt = static_cast<Statement_t*>(block->statements.back());
8189 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { 8727 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) {
8190 extraDo = _parser.toString(breakLoop) == "break"sv; 8728 extraDo = breakLoop->type.is<Break_t>();
8191 } 8729 }
8192 } 8730 }
8193 } 8731 }
@@ -8220,9 +8758,6 @@ private:
8220 popScope(); 8758 popScope();
8221 _buf << indent() << "end"sv << nll(body); 8759 _buf << indent() << "end"sv << nll(body);
8222 } 8760 }
8223 if (!appendContent.empty()) {
8224 _buf << indent() << appendContent;
8225 }
8226 _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); 8761 _buf << indent() << _continueVars.top().var << " = true"sv << nll(body);
8227 popScope(); 8762 popScope();
8228 _buf << indent() << "until true"sv << nlr(body); 8763 _buf << indent() << "until true"sv << nlr(body);
@@ -8232,14 +8767,9 @@ private:
8232 temp.push_back(clearBuf()); 8767 temp.push_back(clearBuf());
8233 _continueVars.pop(); 8768 _continueVars.pop();
8234 } else { 8769 } else {
8235 if (!appendContent.empty()) {
8236 temp.push_back(indent() + appendContent);
8237 }
8238 temp.push_back(extraLabel); 8770 temp.push_back(extraLabel);
8239 _continueVars.pop(); 8771 _continueVars.pop();
8240 } 8772 }
8241 } else if (!appendContent.empty()) {
8242 temp.back().append(indent() + appendContent);
8243 } 8773 }
8244 out.push_back(join(temp)); 8774 out.push_back(join(temp));
8245 } 8775 }
@@ -8247,8 +8777,9 @@ private:
8247 std::string transformRepeatBody(Repeat_t* repeatNode, str_list& out) { 8777 std::string transformRepeatBody(Repeat_t* repeatNode, str_list& out) {
8248 str_list temp; 8778 str_list temp;
8249 bool extraDo = false; 8779 bool extraDo = false;
8250 auto body = repeatNode->body->content.get(); 8780 auto body = repeatNode->body.get();
8251 bool withContinue = hasContinueStatement(body); 8781 auto breakLoopType = getBreakLoopType(body, Empty);
8782 bool withContinue = hasContinue(breakLoopType);
8252 std::string conditionVar; 8783 std::string conditionVar;
8253 std::string extraLabel; 8784 std::string extraLabel;
8254 ast_ptr<false, ExpListAssign_t> condAssign; 8785 ast_ptr<false, ExpListAssign_t> condAssign;
@@ -8259,7 +8790,7 @@ private:
8259 if (!block->statements.empty()) { 8790 if (!block->statements.empty()) {
8260 auto stmt = static_cast<Statement_t*>(block->statements.back()); 8791 auto stmt = static_cast<Statement_t*>(block->statements.back());
8261 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { 8792 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) {
8262 extraDo = _parser.toString(breakLoop) == "break"sv; 8793 extraDo = breakLoop->type.is<Break_t>();
8263 } 8794 }
8264 } 8795 }
8265 } 8796 }
@@ -8322,7 +8853,8 @@ private:
8322 void transformFor(For_t* forNode, str_list& out) { 8853 void transformFor(For_t* forNode, str_list& out) {
8323 str_list temp; 8854 str_list temp;
8324 transformForHead(forNode, temp); 8855 transformForHead(forNode, temp);
8325 transformLoopBody(forNode->body, temp, Empty, ExpUsage::Common); 8856 auto breakLoopType = getBreakLoopType(forNode->body, Empty);
8857 transformLoopBody(forNode->body, temp, breakLoopType, ExpUsage::Common);
8326 popScope(); 8858 popScope();
8327 out.push_back(join(temp) + indent() + "end"s + nlr(forNode)); 8859 out.push_back(join(temp) + indent() + "end"s + nlr(forNode));
8328 } 8860 }
@@ -8333,13 +8865,24 @@ private:
8333 addToScope(accum); 8865 addToScope(accum);
8334 std::string len = getUnusedName("_len_"sv); 8866 std::string len = getUnusedName("_len_"sv);
8335 addToScope(len); 8867 addToScope(len);
8336 _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());
8337 _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode); 8871 _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode);
8338 out.push_back(clearBuf()); 8872 auto& lenAssign = out.emplace_back(clearBuf());
8339 transformForHead(forNode, out); 8873 transformForHead(forNode, out);
8340 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); 8874 if (hasBreakWithValue(breakLoopType)) {
8341 auto lenLine = len + " = "s + len + " + 1"s + nlr(forNode->body); 8875 lenAssign.clear();
8342 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 }
8343 popScope(); 8886 popScope();
8344 out.push_back(indent() + "end"s + nlr(forNode)); 8887 out.push_back(indent() + "end"s + nlr(forNode));
8345 return accum; 8888 return accum;
@@ -8418,7 +8961,8 @@ private:
8418 void transformForEach(ForEach_t* forEach, str_list& out) { 8961 void transformForEach(ForEach_t* forEach, str_list& out) {
8419 str_list temp; 8962 str_list temp;
8420 bool extraScoped = transformForEachHead(forEach->nameList, forEach->loopValue, temp, false); 8963 bool extraScoped = transformForEachHead(forEach->nameList, forEach->loopValue, temp, false);
8421 transformLoopBody(forEach->body, temp, Empty, ExpUsage::Common); 8964 auto breakLoopType = getBreakLoopType(forEach->body, Empty);
8965 transformLoopBody(forEach->body, temp, breakLoopType, ExpUsage::Common);
8422 popScope(); 8966 popScope();
8423 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));
8424 if (extraScoped) { 8968 if (extraScoped) {
@@ -8433,13 +8977,24 @@ private:
8433 addToScope(accum); 8977 addToScope(accum);
8434 std::string len = getUnusedName("_len_"sv); 8978 std::string len = getUnusedName("_len_"sv);
8435 addToScope(len); 8979 addToScope(len);
8436 _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());
8437 _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach); 8983 _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach);
8438 out.push_back(clearBuf()); 8984 auto& lenAssign = out.emplace_back(clearBuf());
8439 transformForEachHead(forEach->nameList, forEach->loopValue, out, true); 8985 transformForEachHead(forEach->nameList, forEach->loopValue, out, true);
8440 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); 8986 if (hasBreakWithValue(breakLoopType)) {
8441 auto lenLine = len + " = "s + len + " + 1"s + nlr(forEach->body); 8987 lenAssign.clear();
8442 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 }
8443 popScope(); 8998 popScope();
8444 out.push_back(indent() + "end"s + nlr(forEach)); 8999 out.push_back(indent() + "end"s + nlr(forEach));
8445 return accum; 9000 return accum;
@@ -8623,12 +9178,64 @@ private:
8623 out.push_back(temp.empty() ? "\"\""s : join(temp, " .. "sv)); 9178 out.push_back(temp.empty() ? "\"\""s : join(temp, " .. "sv));
8624 } 9179 }
8625 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
8626 void transformString(String_t* string, str_list& out) { 9232 void transformString(String_t* string, str_list& out) {
8627 auto str = string->str.get(); 9233 auto str = string->str.get();
8628 switch (str->get_id()) { 9234 switch (str->get_id()) {
8629 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;
8630 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;
8631 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;
8632 default: YUEE("AST node mismatch", str); break; 9239 default: YUEE("AST node mismatch", str); break;
8633 } 9240 }
8634 } 9241 }
@@ -8810,7 +9417,7 @@ private:
8810 auto names = transformAssignDefs(assignment->expList.get(), DefOp::Get); 9417 auto names = transformAssignDefs(assignment->expList.get(), DefOp::Get);
8811 for (const auto& name : names) { 9418 for (const auto& name : names) {
8812 forceAddToScope(name.first); 9419 forceAddToScope(name.first);
8813 markVarConst(name.first); 9420 markVarLocalConst(name.first);
8814 varDefs.push_back(name.first); 9421 varDefs.push_back(name.first);
8815 classConstVars.push_back(name.first); 9422 classConstVars.push_back(name.first);
8816 } 9423 }
@@ -8824,7 +9431,7 @@ private:
8824 for (const auto& item : destruct.items) { 9431 for (const auto& item : destruct.items) {
8825 if (!item.targetVar.empty()) { 9432 if (!item.targetVar.empty()) {
8826 forceAddToScope(item.targetVar); 9433 forceAddToScope(item.targetVar);
8827 markVarConst(item.targetVar); 9434 markVarLocalConst(item.targetVar);
8828 varDefs.push_back(item.targetVar); 9435 varDefs.push_back(item.targetVar);
8829 classConstVars.push_back(item.targetVar); 9436 classConstVars.push_back(item.targetVar);
8830 } 9437 }
@@ -9206,11 +9813,11 @@ private:
9206 std::string withVar; 9813 std::string withVar;
9207 bool needScope = !currentScope().lastStatement && !returnValue; 9814 bool needScope = !currentScope().lastStatement && !returnValue;
9208 bool extraScope = false; 9815 bool extraScope = false;
9209 if (with->assigns) { 9816 if (with->assign) {
9210 auto vars = getAssignVars(with); 9817 auto vars = getAssignVars(with);
9211 if (vars.front().empty() || isDeclaredAsGlobal(vars.front())) { 9818 if (vars.front().empty() || isDeclaredAsGlobal(vars.front())) {
9212 if (with->assigns->values.objects().size() == 1) { 9819 if (with->assign->values.objects().size() == 1) {
9213 auto var = singleVariableFrom(with->assigns->values.objects().front(), AccessType::Read); 9820 auto var = singleVariableFrom(with->assign->values.objects().front(), AccessType::Read);
9214 if (!var.empty() && isLocal(var)) { 9821 if (!var.empty() && isLocal(var)) {
9215 withVar = var; 9822 withVar = var;
9216 } 9823 }
@@ -9220,7 +9827,7 @@ private:
9220 auto assignment = x->new_ptr<ExpListAssign_t>(); 9827 auto assignment = x->new_ptr<ExpListAssign_t>();
9221 assignment->expList.set(toAst<ExpList_t>(withVar, x)); 9828 assignment->expList.set(toAst<ExpList_t>(withVar, x));
9222 auto assign = x->new_ptr<Assign_t>(); 9829 auto assign = x->new_ptr<Assign_t>();
9223 assign->values.push_back(with->assigns->values.objects().front()); 9830 assign->values.push_back(with->assign->values.objects().front());
9224 assignment->action.set(assign); 9831 assignment->action.set(assign);
9225 if (needScope) { 9832 if (needScope) {
9226 extraScope = true; 9833 extraScope = true;
@@ -9234,7 +9841,7 @@ private:
9234 auto assign = x->new_ptr<Assign_t>(); 9841 auto assign = x->new_ptr<Assign_t>();
9235 assign->values.push_back(toAst<Exp_t>(withVar, x)); 9842 assign->values.push_back(toAst<Exp_t>(withVar, x));
9236 bool skipFirst = true; 9843 bool skipFirst = true;
9237 for (auto value : with->assigns->values.objects()) { 9844 for (auto value : with->assign->values.objects()) {
9238 if (skipFirst) { 9845 if (skipFirst) {
9239 skipFirst = false; 9846 skipFirst = false;
9240 continue; 9847 continue;
@@ -9247,7 +9854,7 @@ private:
9247 withVar = vars.front(); 9854 withVar = vars.front();
9248 auto assignment = x->new_ptr<ExpListAssign_t>(); 9855 auto assignment = x->new_ptr<ExpListAssign_t>();
9249 assignment->expList.set(with->valueList); 9856 assignment->expList.set(with->valueList);
9250 assignment->action.set(with->assigns); 9857 assignment->action.set(with->assign);
9251 if (needScope) { 9858 if (needScope) {
9252 extraScope = true; 9859 extraScope = true;
9253 temp.push_back(indent() + "do"s + nll(with)); 9860 temp.push_back(indent() + "do"s + nll(with));
@@ -9325,15 +9932,57 @@ private:
9325 } 9932 }
9326 } 9933 }
9327 _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 }
9328 if (with->eop) { 9942 if (with->eop) {
9329 auto ifNode = x->new_ptr<If_t>(); 9943 auto ifNode = x->new_ptr<If_t>();
9330 ifNode->type.set(toAst<IfType_t>("if"sv, x)); 9944 ifNode->type.set(toAst<IfType_t>("if"sv, x));
9331 ifNode->nodes.push_back(toAst<IfCond_t>(withVar + "~=nil"s, x)); 9945 ifNode->nodes.push_back(toAst<IfCond_t>(withVar + "~=nil"s, x));
9332 ifNode->nodes.push_back(with->body); 9946 ifNode->nodes.push_back(with->body);
9333 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 }
9334 } else { 9968 } else {
9335 bool transformed = false; 9969 bool transformed = false;
9336 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) {
9337 if (auto block = with->body.as<Block_t>()) { 9986 if (auto block = with->body.as<Block_t>()) {
9338 if (!block->statements.empty()) { 9987 if (!block->statements.empty()) {
9339 Statement_t* stmt = static_cast<Statement_t*>(block->statements.back()); 9988 Statement_t* stmt = static_cast<Statement_t*>(block->statements.back());
@@ -9398,12 +10047,18 @@ private:
9398 switch (item->get_id()) { 10047 switch (item->get_id()) {
9399 case id<ClassDecl_t>(): { 10048 case id<ClassDecl_t>(): {
9400 auto classDecl = static_cast<ClassDecl_t*>(item); 10049 auto classDecl = static_cast<ClassDecl_t*>(item);
10050 std::string varName;
9401 if (classDecl->name) { 10051 if (classDecl->name) {
9402 if (auto var = classDecl->name->item.as<Variable_t>()) { 10052 if (auto var = classDecl->name->item.as<Variable_t>()) {
9403 addGlobalVar(variableToString(var), classDecl->name->item); 10053 varName = variableToString(var);
10054 addGlobalVar(varName, var);
9404 } 10055 }
9405 } 10056 }
10057 if (varName.empty()) {
10058 throw CompileError("missing name for class", classDecl);
10059 }
9406 transformClassDecl(classDecl, out, ExpUsage::Common); 10060 transformClassDecl(classDecl, out, ExpUsage::Common);
10061 markVarGlobalConst(varName);
9407 break; 10062 break;
9408 } 10063 }
9409 case id<GlobalOp_t>(): 10064 case id<GlobalOp_t>():
@@ -9417,9 +10072,11 @@ private:
9417 auto values = global->item.to<GlobalValues_t>(); 10072 auto values = global->item.to<GlobalValues_t>();
9418 if (values->valueList) { 10073 if (values->valueList) {
9419 auto expList = x->new_ptr<ExpList_t>(); 10074 auto expList = x->new_ptr<ExpList_t>();
10075 str_list varNames;
9420 for (auto name : values->nameList->names.objects()) { 10076 for (auto name : values->nameList->names.objects()) {
9421 auto var = static_cast<Variable_t*>(name); 10077 auto var = static_cast<Variable_t*>(name);
9422 addGlobalVar(variableToString(var), var); 10078 varNames.emplace_back(variableToString(var));
10079 addGlobalVar(varNames.back(), var);
9423 auto callable = x->new_ptr<Callable_t>(); 10080 auto callable = x->new_ptr<Callable_t>();
9424 callable->item.set(name); 10081 callable->item.set(name);
9425 auto chainValue = x->new_ptr<ChainValue_t>(); 10082 auto chainValue = x->new_ptr<ChainValue_t>();
@@ -9438,10 +10095,17 @@ private:
9438 } 10095 }
9439 assignment->action.set(assign); 10096 assignment->action.set(assign);
9440 transformAssignment(assignment, out); 10097 transformAssignment(assignment, out);
10098 for (const auto& name : varNames) {
10099 markVarGlobalConst(name);
10100 }
9441 } else { 10101 } else {
9442 for (auto name : values->nameList->names.objects()) { 10102 for (auto name : values->nameList->names.objects()) {
9443 auto var = static_cast<Variable_t*>(name); 10103 auto var = static_cast<Variable_t*>(name);
9444 addGlobalVar(variableToString(var), var); 10104 auto varName = variableToString(var);
10105 addGlobalVar(varName, var);
10106 if (global->constAttrib) {
10107 markVarGlobalConst(varName);
10108 }
9445 } 10109 }
9446 } 10110 }
9447 break; 10111 break;
@@ -9790,8 +10454,47 @@ private:
9790 out.push_back(join(temp)); 10454 out.push_back(join(temp));
9791 } 10455 }
9792 10456
9793 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) {
9794 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 }
9795 ast_ptr<true, Exp_t> errHandler; 10498 ast_ptr<true, Exp_t> errHandler;
9796 if (tryNode->catchBlock) { 10499 if (tryNode->catchBlock) {
9797 auto catchBlock = tryNode->catchBlock.get(); 10500 auto catchBlock = tryNode->catchBlock.get();
@@ -10103,7 +10806,7 @@ private:
10103 out.push_back(join(temp)); 10806 out.push_back(join(temp));
10104 auto vars = getAssignVars(assignment); 10807 auto vars = getAssignVars(assignment);
10105 for (const auto& var : vars) { 10808 for (const auto& var : vars) {
10106 markVarConst(var); 10809 markVarLocalConst(var);
10107 } 10810 }
10108 } 10811 }
10109 10812
@@ -10331,12 +11034,36 @@ private:
10331 transformAssignment(assignment, out); 11034 transformAssignment(assignment, out);
10332 if (auto var = ast_cast<Variable_t>(target)) { 11035 if (auto var = ast_cast<Variable_t>(target)) {
10333 auto moduleName = variableToString(var); 11036 auto moduleName = variableToString(var);
10334 markVarConst(moduleName); 11037 markVarLocalConst(moduleName);
10335 } else { 11038 } else {
10336 markDestructureConst(assignment); 11039 markDestructureConst(assignment);
10337 } 11040 }
10338 } 11041 }
10339 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
10340 void transformImport(Import_t* import, str_list& out) { 11067 void transformImport(Import_t* import, str_list& out) {
10341 auto content = import->content.get(); 11068 auto content = import->content.get();
10342 switch (content->get_id()) { 11069 switch (content->get_id()) {
@@ -10349,6 +11076,9 @@ private:
10349 case id<FromImport_t>(): 11076 case id<FromImport_t>():
10350 transformFromImport(static_cast<FromImport_t*>(content), out); 11077 transformFromImport(static_cast<FromImport_t*>(content), out);
10351 break; 11078 break;
11079 case id<ImportGlobal_t>():
11080 transformImportGlobal(static_cast<ImportGlobal_t*>(content), out);
11081 break;
10352 default: YUEE("AST node mismatch", content); break; 11082 default: YUEE("AST node mismatch", content); break;
10353 } 11083 }
10354 } 11084 }
@@ -10368,15 +11098,27 @@ private:
10368 addToScope(accumVar); 11098 addToScope(accumVar);
10369 auto lenVar = getUnusedName("_len_"sv); 11099 auto lenVar = getUnusedName("_len_"sv);
10370 addToScope(lenVar); 11100 addToScope(lenVar);
10371 temp.push_back(indent() + "local "s + accumVar + " = { }"s + nll(whileNode)); 11101 auto breakLoopType = getBreakLoopType(whileNode->body, accumVar);
10372 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());
10373 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 11106 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
10374 auto condStr = transformCondExp(whileNode->condition, isUntil); 11107 auto condStr = transformCondExp(whileNode->condition, isUntil);
10375 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); 11108 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode));
10376 pushScope(); 11109 pushScope();
10377 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); 11110 if (hasBreakWithValue(breakLoopType)) {
10378 auto lenLine = lenVar + " = "s + lenVar + " + 1"s + nlr(whileNode); 11111 lenAssign.clear();
10379 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 }
10380 popScope(); 11122 popScope();
10381 temp.push_back(indent() + "end"s + nlr(whileNode)); 11123 temp.push_back(indent() + "end"s + nlr(whileNode));
10382 if (expList) { 11124 if (expList) {
@@ -10412,15 +11154,26 @@ private:
10412 addToScope(accumVar); 11154 addToScope(accumVar);
10413 auto lenVar = getUnusedName("_len_"sv); 11155 auto lenVar = getUnusedName("_len_"sv);
10414 addToScope(lenVar); 11156 addToScope(lenVar);
10415 temp.push_back(indent() + "local "s + accumVar + " = { }"s + nll(whileNode)); 11157 auto breakLoopType = getBreakLoopType(whileNode->body, accumVar);
10416 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));
10417 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 11161 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
10418 auto condStr = transformCondExp(whileNode->condition, isUntil); 11162 auto condStr = transformCondExp(whileNode->condition, isUntil);
10419 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); 11163 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode));
10420 pushScope(); 11164 pushScope();
10421 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); 11165 if (hasBreakWithValue(breakLoopType)) {
10422 auto lenLine = lenVar + " = "s + lenVar + " + 1"s + nlr(whileNode); 11166 lenAssign.clear();
10423 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 }
10424 popScope(); 11177 popScope();
10425 temp.push_back(indent() + "end"s + nlr(whileNode)); 11178 temp.push_back(indent() + "end"s + nlr(whileNode));
10426 temp.push_back(indent() + "return "s + accumVar + nlr(whileNode)); 11179 temp.push_back(indent() + "return "s + accumVar + nlr(whileNode));
@@ -10455,9 +11208,7 @@ private:
10455 expListAssign->expList.set(expList); 11208 expListAssign->expList.set(expList);
10456 auto stmt = x->new_ptr<Statement_t>(); 11209 auto stmt = x->new_ptr<Statement_t>();
10457 stmt->content.set(expListAssign); 11210 stmt->content.set(expListAssign);
10458 auto body = x->new_ptr<Body_t>(); 11211 repeat->body.set(stmt);
10459 body->content.set(stmt);
10460 repeat->body.set(body);
10461 transformRepeat(repeat, out); 11212 transformRepeat(repeat, out);
10462 return; 11213 return;
10463 } 11214 }
@@ -10465,7 +11216,8 @@ private:
10465 pushScope(); 11216 pushScope();
10466 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 11217 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
10467 auto condStr = transformCondExp(whileNode->condition, isUntil); 11218 auto condStr = transformCondExp(whileNode->condition, isUntil);
10468 transformLoopBody(whileNode->body, temp, Empty, ExpUsage::Common); 11219 auto breakLoopType = getBreakLoopType(whileNode->body, Empty);
11220 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common);
10469 popScope(); 11221 popScope();
10470 _buf << indent() << "while "sv << condStr << " do"sv << nll(whileNode); 11222 _buf << indent() << "while "sv << condStr << " do"sv << nll(whileNode);
10471 _buf << temp.back(); 11223 _buf << temp.back();
@@ -10473,6 +11225,106 @@ private:
10473 out.push_back(clearBuf()); 11225 out.push_back(clearBuf());
10474 } 11226 }
10475 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
10476 void transformRepeat(Repeat_t* repeat, str_list& out) { 11328 void transformRepeat(Repeat_t* repeat, str_list& out) {
10477 str_list temp; 11329 str_list temp;
10478 pushScope(); 11330 pushScope();
@@ -10506,10 +11358,26 @@ private:
10506 pushScope(); 11358 pushScope();
10507 } 11359 }
10508 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 }
10509 auto objVar = singleVariableFrom(switchNode->target, AccessType::Read); 11377 auto objVar = singleVariableFrom(switchNode->target, AccessType::Read);
10510 if (objVar.empty() || !isLocal(objVar)) { 11378 if (objVar.empty() || !isLocal(objVar)) {
10511 if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) { 11379 if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) {
10512 if (needScope) { 11380 if (needScope && !extraScope) {
10513 extraScope = true; 11381 extraScope = true;
10514 temp.push_back(indent() + "do"s + nll(x)); 11382 temp.push_back(indent() + "do"s + nll(x));
10515 pushScope(); 11383 pushScope();
@@ -10567,8 +11435,9 @@ private:
10567 } 11435 }
10568 temp.back().append(indent() + "if "s + tabCheckVar + " then"s + nll(branch)); 11436 temp.back().append(indent() + "if "s + tabCheckVar + " then"s + nll(branch));
10569 pushScope(); 11437 pushScope();
10570 auto assignment = assignmentFrom(static_cast<Exp_t*>(valueList->exprs.front()), toAst<Exp_t>(objVar, branch), branch); 11438 auto chainValue = toAst<ChainValue_t>(objVar, branch);
10571 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);
10572 transformAssignment(assignment, temp, true); 11441 transformAssignment(assignment, temp, true);
10573 str_list conds; 11442 str_list conds;
10574 for (const auto& des : info.destructures) { 11443 for (const auto& des : info.destructures) {
@@ -10578,8 +11447,31 @@ private:
10578 const auto& destruct = std::get<Destructure>(des); 11447 const auto& destruct = std::get<Destructure>(des);
10579 for (const auto& item : destruct.items) { 11448 for (const auto& item : destruct.items) {
10580 if (!item.defVal) { 11449 if (!item.defVal) {
10581 transformExp(item.target, conds, ExpUsage::Closure); 11450 if (!isAssignable(item.target)) {
10582 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 }
10583 } 11475 }
10584 } 11476 }
10585 } 11477 }
@@ -10877,7 +11769,7 @@ private:
10877 } 11769 }
10878 transformAssignment(assignment, temp); 11770 transformAssignment(assignment, temp);
10879 for (const auto& name : vars) { 11771 for (const auto& name : vars) {
10880 markVarConst(name); 11772 markVarLocalConst(name);
10881 } 11773 }
10882 if (localAttrib->attrib.is<CloseAttrib_t>()) { 11774 if (localAttrib->attrib.is<CloseAttrib_t>()) {
10883 str_list leftVars, rightVars; 11775 str_list leftVars, rightVars;
@@ -10949,7 +11841,7 @@ private:
10949 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));
10950 } 11842 }
10951 for (const auto& var : vars) { 11843 for (const auto& var : vars) {
10952 markVarConst(var); 11844 markVarLocalConst(var);
10953 } 11845 }
10954 } 11846 }
10955 if (!listB->exprs.empty()) { 11847 if (!listB->exprs.empty()) {
@@ -10974,18 +11866,24 @@ private:
10974 temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x)); 11866 temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x));
10975 transformAssignment(assignment, temp); 11867 transformAssignment(assignment, temp);
10976 for (const auto& name : vars) { 11868 for (const auto& name : vars) {
10977 markVarConst(name); 11869 markVarLocalConst(name);
10978 } 11870 }
10979 } 11871 }
10980 out.push_back(join(temp)); 11872 out.push_back(join(temp));
10981 } 11873 }
10982 11874
10983 void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) { 11875 void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) {
10984 auto keyword = _parser.toString(breakLoop); 11876 auto isBreak = breakLoop->type.is<Break_t>();
11877 auto keyword = isBreak ? "break"s : "continue"s;
10985 if (_enableBreakLoop.empty() || !_enableBreakLoop.top()) { 11878 if (_enableBreakLoop.empty() || !_enableBreakLoop.top()) {
10986 throw CompileError(keyword + " is not inside a loop"s, breakLoop); 11879 throw CompileError(keyword + " is not inside a loop"s, breakLoop);
10987 } 11880 }
10988 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 }
10989 out.push_back(indent() + keyword + nll(breakLoop)); 11887 out.push_back(indent() + keyword + nll(breakLoop));
10990 return; 11888 return;
10991 } 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 ceb1f7c..1942e23 100644
--- a/src/yuescript/yue_parser.cpp
+++ b/src/yuescript/yue_parser.cpp
@@ -67,24 +67,28 @@ YueParser::YueParser() {
67 num_char = range('0', '9') >> *(range('0', '9') | '_' >> and_(range('0', '9'))); 67 num_char = range('0', '9') >> *(range('0', '9') | '_' >> and_(range('0', '9')));
68 num_char_hex = range('0', '9') | range('a', 'f') | range('A', 'F'); 68 num_char_hex = range('0', '9') | range('a', 'f') | range('A', 'F');
69 num_lit = num_char_hex >> *(num_char_hex | '_' >> and_(num_char_hex)); 69 num_lit = num_char_hex >> *(num_char_hex | '_' >> and_(num_char_hex));
70 num_bin_lit = set("01") >> *(set("01") | '_' >> and_(set("01")));
70 Num = 71 Num =
71 "0x" >> ( 72 '0' >> (
72 +num_lit >> ( 73 set("xX") >> (
73 '.' >> +num_lit >> -num_expo_hex | 74 num_lit >> (
74 num_expo_hex | 75 '.' >> num_lit >> -num_expo_hex |
75 lj_num | 76 num_expo_hex |
76 true_() 77 lj_num |
77 ) | ( 78 true_()
78 '.' >> +num_lit >> -num_expo_hex 79 ) | (
79 ) 80 '.' >> num_lit >> -num_expo_hex
81 )
82 ) |
83 set("bB") >> num_bin_lit
80 ) | 84 ) |
81 +num_char >> ( 85 num_char >> (
82 '.' >> +num_char >> -num_expo | 86 '.' >> num_char >> -num_expo |
83 num_expo | 87 num_expo |
84 lj_num | 88 lj_num |
85 true_() 89 true_()
86 ) | 90 ) |
87 '.' >> +num_char >> -num_expo; 91 '.' >> num_char >> -num_expo;
88 92
89 cut = false_(); 93 cut = false_();
90 Seperator = true_(); 94 Seperator = true_();
@@ -114,8 +118,8 @@ YueParser::YueParser() {
114 return false; 118 return false;
115 }); 119 });
116 120
117 if_assignment_syntax_error = pl::user(true_(), [](const item_t& item) { 121 assignment_expression_syntax_error = pl::user(true_(), [](const item_t& item) {
118 throw ParserError("use := for if-assignment expression"sv, item.begin); 122 throw ParserError("use := for assignment expression"sv, item.begin);
119 return false; 123 return false;
120 }); 124 });
121 125
@@ -158,6 +162,13 @@ YueParser::YueParser() {
158 ) \ 162 ) \
159 ) 163 )
160 164
165 #define disable_until_rule(patt) ( \
166 disable_until >> ( \
167 (patt) >> enable_until | \
168 enable_until >> cut \
169 ) \
170 )
171
161 #define body_with(str) ( \ 172 #define body_with(str) ( \
162 key(str) >> space >> (in_block | Statement) | \ 173 key(str) >> space >> (in_block | Statement) | \
163 in_block | \ 174 in_block | \
@@ -321,7 +332,7 @@ YueParser::YueParser() {
321 Exp; 332 Exp;
322 import_tab_list = import_tab_item >> *(space >> ',' >> space >> import_tab_item); 333 import_tab_list = import_tab_item >> *(space >> ',' >> space >> import_tab_item);
323 import_tab_line = ( 334 import_tab_line = (
324 push_indent_match >> (space >> import_tab_list >> pop_indent | pop_indent) 335 push_indent_match >> ensure(space >> import_tab_list, pop_indent)
325 ) | space; 336 ) | space;
326 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 >> ',');
327 import_tab_key_value = key_value | ':' >> MacroName | MacroNamePair | ImportAllMacro; 338 import_tab_key_value = key_value | ':' >> MacroName | MacroNamePair | ImportAllMacro;
@@ -338,7 +349,9 @@ YueParser::YueParser() {
338 349
339 ImportAs = ImportLiteral >> -(space >> key("as") >> space >> (ImportTabLit | Variable | ImportAllMacro)); 350 ImportAs = ImportLiteral >> -(space >> key("as") >> space >> (ImportTabLit | Variable | ImportAllMacro));
340 351
341 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;
342 355
343 Label = "::" >> LabelName >> "::"; 356 Label = "::" >> LabelName >> "::";
344 357
@@ -346,11 +359,13 @@ YueParser::YueParser() {
346 359
347 ShortTabAppending = "[]" >> space >> Assign; 360 ShortTabAppending = "[]" >> space >> Assign;
348 361
349 BreakLoop = (expr("break") | "continue") >> not_alpha_num; 362 Break = key("break");
363 Continue = key("continue");
364 BreakLoop = (Break >> -(space >> Exp) | Continue) >> not_alpha_num;
350 365
351 Return = key("return") >> -(space >> (TableBlock | ExpListLow)); 366 Return = key("return") >> -(space >> (TableBlock | ExpListLow));
352 367
353 with_exp = ExpList >> -(space >> Assign); 368 with_exp = ExpList >> -(space >> (':' >> Assign | and_('=') >> assignment_expression_syntax_error));
354 369
355 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");
356 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");
@@ -366,7 +381,8 @@ YueParser::YueParser() {
366 and_(SimpleTable | TableLit) >> Exp | 381 and_(SimpleTable | TableLit) >> Exp |
367 exp_not_tab >> *(space >> ',' >> space >> exp_not_tab) 382 exp_not_tab >> *(space >> ',' >> space >> exp_not_tab)
368 ); 383 );
369 Switch = key("switch") >> space >> Exp >> 384 Switch = key("switch") >> space >>
385 Exp >> -(space >> Assignment) >>
370 space >> Seperator >> ( 386 space >> Seperator >> (
371 SwitchCase >> space >> ( 387 SwitchCase >> space >> (
372 switch_block | 388 switch_block |
@@ -375,20 +391,26 @@ YueParser::YueParser() {
375 +space_break >> advance_match >> space >> SwitchCase >> switch_block >> pop_indent 391 +space_break >> advance_match >> space >> SwitchCase >> switch_block >> pop_indent
376 ); 392 );
377 393
378 Assignment = -(',' >> space >> ExpList >> space) >> (':' >> Assign | and_('=') >> if_assignment_syntax_error); 394 Assignment = -(',' >> space >> ExpList >> space) >> (':' >> Assign | and_('=') >> assignment_expression_syntax_error);
379 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)));
380 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");
381 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;
382 IfType = (expr("if") | "unless") >> not_alpha_num; 398 IfType = (expr("if") | "unless") >> not_alpha_num;
383 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;
384 400
385 WhileType = (expr("while") | "until") >> not_alpha_num; 401 WhileType = (expr("while") | pl::user("until", [](const item_t& item) {
386 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);
387 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;
388 410
389 for_key = pl::user(key("for"), [](const item_t& item) { 411 for_key = pl::user(key("for"), [](const item_t& item) {
390 State* st = reinterpret_cast<State*>(item.user_data); 412 State* st = reinterpret_cast<State*>(item.user_data);
391 return st->noForStack.empty() || !st->noForStack.top(); 413 return st->noForStack.empty() || !st->noForStack.back();
392 }); 414 });
393 ForStepValue = ',' >> space >> Exp; 415 ForStepValue = ',' >> space >> Exp;
394 for_args = Variable >> space >> '=' >> space >> Exp >> space >> ',' >> space >> Exp >> space >> -ForStepValue; 416 for_args = Variable >> space >> '=' >> space >> Exp >> space >> ',' >> space >> Exp >> space >> -ForStepValue;
@@ -402,18 +424,18 @@ YueParser::YueParser() {
402 424
403 Do = pl::user(key("do"), [](const item_t& item) { 425 Do = pl::user(key("do"), [](const item_t& item) {
404 State* st = reinterpret_cast<State*>(item.user_data); 426 State* st = reinterpret_cast<State*>(item.user_data);
405 return st->noDoStack.empty() || !st->noDoStack.top(); 427 return st->noDoStack.empty() || !st->noDoStack.back();
406 }) >> space >> Body; 428 }) >> space >> Body;
407 429
408 disable_do = pl::user(true_(), [](const item_t& item) { 430 disable_do = pl::user(true_(), [](const item_t& item) {
409 State* st = reinterpret_cast<State*>(item.user_data); 431 State* st = reinterpret_cast<State*>(item.user_data);
410 st->noDoStack.push(true); 432 st->noDoStack.push_back(true);
411 return true; 433 return true;
412 }); 434 });
413 435
414 enable_do = pl::user(true_(), [](const item_t& item) { 436 enable_do = pl::user(true_(), [](const item_t& item) {
415 State* st = reinterpret_cast<State*>(item.user_data); 437 State* st = reinterpret_cast<State*>(item.user_data);
416 st->noDoStack.pop(); 438 st->noDoStack.pop_back();
417 return true; 439 return true;
418 }); 440 });
419 441
@@ -431,46 +453,58 @@ YueParser::YueParser() {
431 453
432 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) {
433 State* st = reinterpret_cast<State*>(item.user_data); 455 State* st = reinterpret_cast<State*>(item.user_data);
434 st->noDoStack.push(true); 456 st->noDoStack.push_back(true);
435 st->noChainBlockStack.push(true); 457 st->noChainBlockStack.push_back(true);
436 st->noTableBlockStack.push(true); 458 st->noTableBlockStack.push_back(true);
437 return true; 459 return true;
438 }); 460 });
439 461
440 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) {
441 State* st = reinterpret_cast<State*>(item.user_data); 463 State* st = reinterpret_cast<State*>(item.user_data);
442 st->noDoStack.pop(); 464 st->noDoStack.pop_back();
443 st->noChainBlockStack.pop(); 465 st->noChainBlockStack.pop_back();
444 st->noTableBlockStack.pop(); 466 st->noTableBlockStack.pop_back();
445 return true; 467 return true;
446 }); 468 });
447 469
448 disable_arg_table_block = pl::user(true_(), [](const item_t& item) { 470 disable_arg_table_block = pl::user(true_(), [](const item_t& item) {
449 State* st = reinterpret_cast<State*>(item.user_data); 471 State* st = reinterpret_cast<State*>(item.user_data);
450 st->noTableBlockStack.push(true); 472 st->noTableBlockStack.push_back(true);
451 return true; 473 return true;
452 }); 474 });
453 475
454 enable_arg_table_block = pl::user(true_(), [](const item_t& item) { 476 enable_arg_table_block = pl::user(true_(), [](const item_t& item) {
455 State* st = reinterpret_cast<State*>(item.user_data); 477 State* st = reinterpret_cast<State*>(item.user_data);
456 st->noTableBlockStack.pop(); 478 st->noTableBlockStack.pop_back();
457 return true; 479 return true;
458 }); 480 });
459 481
460 disable_for = pl::user(true_(), [](const item_t& item) { 482 disable_for = pl::user(true_(), [](const item_t& item) {
461 State* st = reinterpret_cast<State*>(item.user_data); 483 State* st = reinterpret_cast<State*>(item.user_data);
462 st->noForStack.push(true); 484 st->noForStack.push_back(true);
463 return true; 485 return true;
464 }); 486 });
465 487
466 enable_for = pl::user(true_(), [](const item_t& item) { 488 enable_for = pl::user(true_(), [](const item_t& item) {
467 State* st = reinterpret_cast<State*>(item.user_data); 489 State* st = reinterpret_cast<State*>(item.user_data);
468 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();
469 return true; 503 return true;
470 }); 504 });
471 505
472 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;
473 Try = key("try") >> space >> (in_block | Exp) >> -CatchBlock; 507 Try = key("try") >> -ExistentialOp >> space >> (in_block | Exp) >> -CatchBlock;
474 508
475 list_value = 509 list_value =
476 and_( 510 and_(
@@ -557,20 +591,20 @@ YueParser::YueParser() {
557 591
558 disable_chain = pl::user(true_(), [](const item_t& item) { 592 disable_chain = pl::user(true_(), [](const item_t& item) {
559 State* st = reinterpret_cast<State*>(item.user_data); 593 State* st = reinterpret_cast<State*>(item.user_data);
560 st->noChainBlockStack.push(true); 594 st->noChainBlockStack.push_back(true);
561 return true; 595 return true;
562 }); 596 });
563 597
564 enable_chain = pl::user(true_(), [](const item_t& item) { 598 enable_chain = pl::user(true_(), [](const item_t& item) {
565 State* st = reinterpret_cast<State*>(item.user_data); 599 State* st = reinterpret_cast<State*>(item.user_data);
566 st->noChainBlockStack.pop(); 600 st->noChainBlockStack.pop_back();
567 return true; 601 return true;
568 }); 602 });
569 603
570 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;
571 chain_block = pl::user(true_(), [](const item_t& item) { 605 chain_block = pl::user(true_(), [](const item_t& item) {
572 State* st = reinterpret_cast<State*>(item.user_data); 606 State* st = reinterpret_cast<State*>(item.user_data);
573 return st->noChainBlockStack.empty() || !st->noChainBlockStack.top(); 607 return st->noChainBlockStack.empty() || !st->noChainBlockStack.back();
574 }) >> +space_break >> advance_match >> ensure( 608 }) >> +space_break >> advance_match >> ensure(
575 chain_line >> *(+space_break >> chain_line), pop_indent); 609 chain_line >> *(+space_break >> chain_line), pop_indent);
576 ChainValue = 610 ChainValue =
@@ -607,7 +641,15 @@ YueParser::YueParser() {
607 DoubleStringInner = +(not_("#{") >> double_string_plain); 641 DoubleStringInner = +(not_("#{") >> double_string_plain);
608 DoubleStringContent = DoubleStringInner | interp; 642 DoubleStringContent = DoubleStringInner | interp;
609 DoubleString = '"' >> Seperator >> *DoubleStringContent >> '"'; 643 DoubleString = '"' >> Seperator >> *DoubleStringContent >> '"';
610 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;
611 653
612 lua_string_open = '[' >> *expr('=') >> '['; 654 lua_string_open = '[' >> *expr('=') >> '[';
613 lua_string_close = ']' >> *expr('=') >> ']'; 655 lua_string_close = ']' >> *expr('=') >> ']';
@@ -635,7 +677,7 @@ YueParser::YueParser() {
635 fn_args_value_list = Exp >> *(space >> ',' >> space >> Exp); 677 fn_args_value_list = Exp >> *(space >> ',' >> space >> Exp);
636 678
637 fn_args_lit_line = ( 679 fn_args_lit_line = (
638 push_indent_match >> (space >> fn_args_value_list >> pop_indent | pop_indent) 680 push_indent_match >> ensure(space >> fn_args_value_list, pop_indent)
639 ) | ( 681 ) | (
640 space 682 space
641 ); 683 );
@@ -677,7 +719,8 @@ YueParser::YueParser() {
677 chain_with_colon = +chain_item >> -colon_chain; 719 chain_with_colon = +chain_item >> -colon_chain;
678 chain_items = chain_with_colon | colon_chain; 720 chain_items = chain_with_colon | colon_chain;
679 721
680 index = '[' >> not_('[') >> space >> Exp >> space >> ']'; 722 index = '[' >> not_('[') >> space >> (ReversedIndex >> and_(space >> ']') | Exp) >> space >> ']';
723 ReversedIndex = '#' >> space >> -('-' >> space >> Exp);
681 chain_item = 724 chain_item =
682 Invoke >> -ExistentialOp | 725 Invoke >> -ExistentialOp |
683 DotChainItem >> -ExistentialOp | 726 DotChainItem >> -ExistentialOp |
@@ -734,7 +777,7 @@ YueParser::YueParser() {
734 777
735 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);
736 TableBlock = +space_break >> advance_match >> ensure(table_block_inner, pop_indent); 779 TableBlock = +space_break >> advance_match >> ensure(table_block_inner, pop_indent);
737 TableBlockIndent = '*' >> Seperator >> disable_arg_table_block_rule( 780 TableBlockIndent = ('*' | '-' >> space_one) >> Seperator >> disable_arg_table_block_rule(
738 space >> key_value_list >> -(space >> ',') >> 781 space >> key_value_list >> -(space >> ',') >>
739 -(+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)));
740 783
@@ -755,7 +798,7 @@ YueParser::YueParser() {
755 798
756 GlobalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpListLow)); 799 GlobalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpListLow));
757 GlobalOp = expr('*') | '^'; 800 GlobalOp = expr('*') | '^';
758 Global = key("global") >> space >> (ClassDecl | GlobalOp | GlobalValues); 801 Global = key("global") >> space >> (-(ConstAttrib >> space) >> ClassDecl | GlobalOp | -(ConstAttrib >> space) >> GlobalValues);
759 802
760 ExportDefault = key("default"); 803 ExportDefault = key("default");
761 804
@@ -837,24 +880,24 @@ YueParser::YueParser() {
837 key_value_line = check_indent_match >> space >> ( 880 key_value_line = check_indent_match >> space >> (
838 key_value_list >> -(space >> ',') | 881 key_value_list >> -(space >> ',') |
839 TableBlockIndent | 882 TableBlockIndent |
840 '*' >> space >> (SpreadExp | Exp | TableBlock) 883 ('*' | '-' >> space_one) >> space >> (SpreadExp | Exp | TableBlock)
841 ); 884 );
842 885
843 fn_arg_def_list = FnArgDef >> *(space >> ',' >> space >> FnArgDef); 886 fn_arg_def_list = FnArgDef >> *(space >> ',' >> space >> FnArgDef);
844 887
845 fn_arg_def_lit_line = ( 888 fn_arg_def_lit_line = (
846 push_indent_match >> (space >> fn_arg_def_list >> pop_indent | pop_indent) 889 push_indent_match >> ensure(space >> fn_arg_def_list, pop_indent)
847 ) | ( 890 ) | (
848 space 891 space
849 ); 892 );
850 893
851 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);
852 895
853 FnArgDef = (Variable | SelfItem >> -ExistentialOp) >> -(space >> '=' >> space >> Exp); 896 FnArgDef = (Variable | SelfItem >> -ExistentialOp) >> -(space >> '`' >> space >> Name) >> -(space >> '=' >> space >> Exp);
854 897
855 FnArgDefList = Seperator >> ( 898 FnArgDefList = Seperator >> (
856 fn_arg_def_lit_lines >> -(-(space >> ',') >> white >> VarArg) | 899 fn_arg_def_lit_lines >> -(-(space >> ',') >> white >> VarArg >> -(space >> '`' >> space >> Name)) |
857 white >> VarArg 900 white >> VarArg >> -(space >> '`' >> space >> Name)
858 ); 901 );
859 902
860 OuterVarShadow = key("using") >> space >> (NameList | key("nil")); 903 OuterVarShadow = key("using") >> space >> (NameList | key("nil"));
@@ -883,6 +926,7 @@ YueParser::YueParser() {
883 926
884 FnArrowBack = '<' >> set("-="); 927 FnArrowBack = '<' >> set("-=");
885 Backcall = -(FnArgsDef >> space) >> FnArrowBack >> space >> ChainValue; 928 Backcall = -(FnArgsDef >> space) >> FnArrowBack >> space >> ChainValue;
929 SubBackcall = FnArrowBack >> space >> ChainValue;
886 930
887 PipeBody = Seperator >> 931 PipeBody = Seperator >>
888 pipe_operator >> space >> UnaryExp >> 932 pipe_operator >> space >> UnaryExp >>
@@ -896,7 +940,7 @@ YueParser::YueParser() {
896 940
897 arg_table_block = pl::user(true_(), [](const item_t& item) { 941 arg_table_block = pl::user(true_(), [](const item_t& item) {
898 State* st = reinterpret_cast<State*>(item.user_data); 942 State* st = reinterpret_cast<State*>(item.user_data);
899 return st->noTableBlockStack.empty() || !st->noTableBlockStack.top(); 943 return st->noTableBlockStack.empty() || !st->noTableBlockStack.back();
900 }) >> TableBlock; 944 }) >> TableBlock;
901 945
902 invoke_args_with_table = 946 invoke_args_with_table =
@@ -936,11 +980,11 @@ YueParser::YueParser() {
936 980
937 SimpleValue = 981 SimpleValue =
938 TableLit | ConstValue | If | Switch | Try | With | 982 TableLit | ConstValue | If | Switch | Try | With |
939 ClassDecl | ForEach | For | While | Do | 983 ClassDecl | ForEach | For | While | Repeat | Do |
940 UnaryValue | TblComprehension | Comprehension | 984 UnaryValue | TblComprehension | Comprehension |
941 FunLit | Num | VarArg; 985 FunLit | Num | VarArg;
942 986
943 ExpListAssign = ExpList >> -(space >> (Update | Assign)) >> not_(space >> '='); 987 ExpListAssign = ExpList >> -(space >> (Update | Assign | SubBackcall)) >> not_(space >> '=');
944 988
945 IfLine = IfType >> space >> IfCond; 989 IfLine = IfType >> space >> IfCond;
946 WhileLine = WhileType >> space >> Exp; 990 WhileLine = WhileType >> space >> Exp;
@@ -997,11 +1041,16 @@ YueParser::YueParser() {
997 empty_line_break | 1041 empty_line_break |
998 advance_match >> ensure(space >> (indentation_error | Statement), pop_indent) 1042 advance_match >> ensure(space >> (indentation_error | Statement), pop_indent)
999 ); 1043 );
1000 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));
1001 1048
1002 shebang = "#!" >> *(not_(stop) >> any_char); 1049 shebang = "#!" >> *(not_(stop) >> any_char);
1003 BlockEnd = Block >> white >> stop; 1050 BlockEnd = Block >> white >> stop;
1004 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());
1005} 1054}
1006// clang-format on 1055// clang-format on
1007 1056
@@ -1031,7 +1080,7 @@ bool YueParser::startWith(std::string_view codes, rule& r) {
1031 return true; 1080 return true;
1032} 1081}
1033 1082
1034ParseInfo YueParser::parse(std::string_view codes, rule& r) { 1083ParseInfo YueParser::parse(std::string_view codes, rule& r, bool lax) {
1035 ParseInfo res; 1084 ParseInfo res;
1036 if (codes.substr(0, 3) == "\xEF\xBB\xBF"sv) { 1085 if (codes.substr(0, 3) == "\xEF\xBB\xBF"sv) {
1037 codes = codes.substr(3); 1086 codes = codes.substr(3);
@@ -1049,6 +1098,7 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) {
1049 error_list errors; 1098 error_list errors;
1050 try { 1099 try {
1051 State state; 1100 State state;
1101 state.lax = lax;
1052 res.node.set(::yue::parse(*(res.codes), r, errors, &state)); 1102 res.node.set(::yue::parse(*(res.codes), r, errors, &state));
1053 if (state.exportCount > 0) { 1103 if (state.exportCount > 0) {
1054 int index = 0; 1104 int index = 0;
@@ -1086,19 +1136,21 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) {
1086 return res; 1136 return res;
1087} 1137}
1088 1138
1089ParseInfo YueParser::parse(std::string_view astName, std::string_view codes) { 1139ParseInfo YueParser::parse(std::string_view astName, std::string_view codes, bool lax) {
1090 auto it = _rules.find(astName); 1140 auto it = _rules.find(astName);
1091 if (it != _rules.end()) { 1141 if (it != _rules.end()) {
1092 return parse(codes, *it->second); 1142 return parse(codes, *it->second, lax);
1093 } 1143 }
1094 return {}; 1144 ParseInfo info{};
1145 info.error = ParseInfo::Error{"invalid rule: "s + std::string{astName}, 1, 1};
1146 return info;
1095} 1147}
1096 1148
1097bool YueParser::match(std::string_view astName, std::string_view codes) { 1149bool YueParser::match(std::string_view astName, std::string_view codes) {
1098 auto it = _rules.find(astName); 1150 auto it = _rules.find(astName);
1099 if (it != _rules.end()) { 1151 if (it != _rules.end()) {
1100 auto rEnd = rule(*it->second >> eof()); 1152 auto rEnd = rule(*it->second >> eof());
1101 return parse(codes, rEnd).node; 1153 return parse(codes, rEnd, false).node;
1102 } 1154 }
1103 return false; 1155 return false;
1104} 1156}
@@ -1134,6 +1186,24 @@ void trim(std::string& str) {
1134 str.erase(0, str.find_first_not_of(" \t\r\n")); 1186 str.erase(0, str.find_first_not_of(" \t\r\n"));
1135 str.erase(str.find_last_not_of(" \t\r\n") + 1); 1187 str.erase(str.find_last_not_of(" \t\r\n") + 1);
1136} 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}
1137} // namespace Utils 1207} // namespace Utils
1138 1208
1139std::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 02292e1..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);
@@ -164,6 +166,7 @@ private:
164 NONE_AST_RULE(num_char); 166 NONE_AST_RULE(num_char);
165 NONE_AST_RULE(num_char_hex); 167 NONE_AST_RULE(num_char_hex);
166 NONE_AST_RULE(num_lit); 168 NONE_AST_RULE(num_lit);
169 NONE_AST_RULE(num_bin_lit);
167 NONE_AST_RULE(num_expo); 170 NONE_AST_RULE(num_expo);
168 NONE_AST_RULE(num_expo_hex); 171 NONE_AST_RULE(num_expo_hex);
169 NONE_AST_RULE(lj_num); 172 NONE_AST_RULE(lj_num);
@@ -216,6 +219,8 @@ private:
216 NONE_AST_RULE(enable_for); 219 NONE_AST_RULE(enable_for);
217 NONE_AST_RULE(enable_fun_lit); 220 NONE_AST_RULE(enable_fun_lit);
218 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);
219 NONE_AST_RULE(switch_else); 224 NONE_AST_RULE(switch_else);
220 NONE_AST_RULE(switch_block); 225 NONE_AST_RULE(switch_block);
221 NONE_AST_RULE(if_else_if); 226 NONE_AST_RULE(if_else_if);
@@ -283,6 +288,7 @@ private:
283 NONE_AST_RULE(yue_line_comment); 288 NONE_AST_RULE(yue_line_comment);
284 NONE_AST_RULE(line); 289 NONE_AST_RULE(line);
285 NONE_AST_RULE(shebang); 290 NONE_AST_RULE(shebang);
291 NONE_AST_RULE(lax_line);
286 292
287 AST_RULE(Num); 293 AST_RULE(Num);
288 AST_RULE(Name); 294 AST_RULE(Name);
@@ -314,12 +320,14 @@ private:
314 AST_RULE(ImportAllMacro); 320 AST_RULE(ImportAllMacro);
315 AST_RULE(ImportTabLit); 321 AST_RULE(ImportTabLit);
316 AST_RULE(ImportAs); 322 AST_RULE(ImportAs);
323 AST_RULE(ImportGlobal);
317 AST_RULE(Import); 324 AST_RULE(Import);
318 AST_RULE(Label); 325 AST_RULE(Label);
319 AST_RULE(Goto); 326 AST_RULE(Goto);
320 AST_RULE(ShortTabAppending); 327 AST_RULE(ShortTabAppending);
321 AST_RULE(FnArrowBack); 328 AST_RULE(FnArrowBack);
322 AST_RULE(Backcall); 329 AST_RULE(Backcall);
330 AST_RULE(SubBackcall);
323 AST_RULE(PipeBody); 331 AST_RULE(PipeBody);
324 AST_RULE(ExpListLow); 332 AST_RULE(ExpListLow);
325 AST_RULE(ExpList); 333 AST_RULE(ExpList);
@@ -358,6 +366,7 @@ private:
358 AST_RULE(ExpOpValue); 366 AST_RULE(ExpOpValue);
359 AST_RULE(Exp); 367 AST_RULE(Exp);
360 AST_RULE(Callable); 368 AST_RULE(Callable);
369 AST_RULE(ReversedIndex);
361 AST_RULE(ChainValue); 370 AST_RULE(ChainValue);
362 AST_RULE(SimpleTable); 371 AST_RULE(SimpleTable);
363 AST_RULE(SimpleValue); 372 AST_RULE(SimpleValue);
@@ -370,6 +379,11 @@ private:
370 AST_RULE(DoubleStringInner); 379 AST_RULE(DoubleStringInner);
371 AST_RULE(DoubleStringContent); 380 AST_RULE(DoubleStringContent);
372 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);
373 AST_RULE(String); 387 AST_RULE(String);
374 AST_RULE(Parens); 388 AST_RULE(Parens);
375 AST_RULE(DotChainItem); 389 AST_RULE(DotChainItem);
@@ -426,6 +440,8 @@ private:
426 AST_RULE(ExpListAssign); 440 AST_RULE(ExpListAssign);
427 AST_RULE(IfLine); 441 AST_RULE(IfLine);
428 AST_RULE(WhileLine); 442 AST_RULE(WhileLine);
443 AST_RULE(Break);
444 AST_RULE(Continue);
429 AST_RULE(BreakLoop); 445 AST_RULE(BreakLoop);
430 AST_RULE(StatementAppendix); 446 AST_RULE(StatementAppendix);
431 AST_RULE(Statement); 447 AST_RULE(Statement);
@@ -443,6 +459,7 @@ private:
443namespace Utils { 459namespace Utils {
444void 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);
445void trim(std::string& str); 461void trim(std::string& str);
462std::string toLuaDoubleString(const std::string& input);
446} // namespace Utils 463} // namespace Utils
447 464
448} // 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);