diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/3rdParty/efsw/FileWatcherGeneric.cpp | 2 | ||||
-rw-r--r-- | src/yuescript/yue_ast.cpp | 201 | ||||
-rw-r--r-- | src/yuescript/yue_ast.h | 100 | ||||
-rw-r--r-- | src/yuescript/yue_compiler.cpp | 1238 | ||||
-rw-r--r-- | src/yuescript/yue_compiler.h | 1 | ||||
-rw-r--r-- | src/yuescript/yue_parser.cpp | 190 | ||||
-rw-r--r-- | src/yuescript/yue_parser.h | 37 | ||||
-rw-r--r-- | src/yuescript/yuescript.cpp | 16 |
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 | ||
27 | WatchID FileWatcherGeneric::addWatch( const std::string& directory, FileWatchListener* watcher, | 27 | WatchID 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 { | |||
167 | std::string TableAppendingOp_t::to_string(void*) const { | 167 | std::string TableAppendingOp_t::to_string(void*) const { |
168 | return "[]"s; | 168 | return "[]"s; |
169 | } | 169 | } |
170 | std::string PlainItem_t::to_string(void *) const { | 170 | std::string PlainItem_t::to_string(void*) const { |
171 | return {}; | 171 | return {}; |
172 | } | 172 | } |
173 | std::string GlobalOp_t::to_string(void* ud) const { | 173 | std::string GlobalOp_t::to_string(void*) const { |
174 | auto info = reinterpret_cast<YueFormat*>(ud); | 174 | return "*"s; |
175 | return info->convert(this); | ||
176 | } | 175 | } |
177 | std::string ExportDefault_t::to_string(void*) const { | 176 | std::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 { | |||
188 | std::string NotIn_t::to_string(void*) const { | 187 | std::string NotIn_t::to_string(void*) const { |
189 | return {}; | 188 | return {}; |
190 | } | 189 | } |
190 | std::string Break_t::to_string(void*) const { | ||
191 | return "break"s; | ||
192 | } | ||
193 | std::string Continue_t::to_string(void*) const { | ||
194 | return "continue"s; | ||
195 | } | ||
191 | std::string BreakLoop_t::to_string(void* ud) const { | 196 | std::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 | } |
195 | std::string YueLineComment_t::to_string(void* ud) const { | 202 | std::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 | } |
307 | std::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 | } | ||
300 | std::string Import_t::to_string(void* ud) const { | 318 | std::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 | } |
345 | std::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 | } | ||
327 | std::string PipeBody_t::to_string(void* ud) const { | 351 | std::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 { | |||
406 | std::string Switch_t::to_string(void* ud) const { | 430 | std::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 | } |
512 | std::string Repeat_t::to_string(void* ud) const { | 573 | std::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 | } |
529 | std::string ForStepValue_t::to_string(void* ud) const { | 590 | std::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 { | |||
596 | std::string Try_t::to_string(void* ud) const { | 657 | std::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 | } |
918 | std::string ReversedIndex_t::to_string(void* ud) const { | ||
919 | if (modifier) { | ||
920 | return "[# - "s + modifier->to_string(ud) + ']'; | ||
921 | } | ||
922 | return "[#]"s; | ||
923 | } | ||
854 | std::string Callable_t::to_string(void* ud) const { | 924 | std::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 | } |
1010 | std::string YAMLIndent_t::to_string(void* ud) const { | ||
1011 | auto info = reinterpret_cast<YueFormat*>(ud); | ||
1012 | return info->convert(this); | ||
1013 | } | ||
1014 | std::string YAMLLineInner_t::to_string(void* ud) const { | ||
1015 | auto info = reinterpret_cast<YueFormat*>(ud); | ||
1016 | return info->convert(this); | ||
1017 | } | ||
1018 | std::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 | } | ||
1024 | std::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 | } | ||
1031 | std::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 | } | ||
940 | std::string String_t::to_string(void* ud) const { | 1055 | std::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 | } |
1127 | std::string GlobalValues_t::to_string(void* ud) const { | 1242 | std::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 | } |
1138 | std::string Global_t::to_string(void* ud) const { | 1253 | std::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 | } |
1141 | std::string Export_t::to_string(void* ud) const { | 1256 | std::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) |
234 | AST_END(ImportAs) | 234 | AST_END(ImportAs) |
235 | 235 | ||
236 | AST_NODE(ImportGlobal) | ||
237 | ast_ptr<true, Seperator_t> sep; | ||
238 | ast_list<true, UnicodeName_t> segs; | ||
239 | ast_ptr<false, Variable_t> target; | ||
240 | AST_MEMBER(ImportGlobal, &sep, &segs, &target) | ||
241 | AST_END(ImportGlobal) | ||
242 | |||
236 | AST_NODE(Import) | 243 | AST_NODE(Import) |
237 | ast_sel<true, ImportAs_t, ImportFrom_t, FromImport_t> content; | 244 | ast_sel<true, ImportAs_t, ImportFrom_t, FromImport_t, ImportGlobal_t> content; |
238 | AST_MEMBER(Import, &content) | 245 | AST_MEMBER(Import, &content) |
239 | AST_END(Import) | 246 | AST_END(Import) |
240 | 247 | ||
@@ -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; | ||
276 | AST_END(ExpList) | 285 | AST_END(ExpList) |
277 | 286 | ||
278 | AST_NODE(Return) | 287 | AST_NODE(Return) |
@@ -285,9 +294,9 @@ AST_END(Return) | |||
285 | AST_NODE(With) | 294 | AST_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) |
291 | AST_END(With) | 300 | AST_END(With) |
292 | 301 | ||
293 | AST_NODE(SwitchList) | 302 | AST_NODE(SwitchList) |
@@ -302,20 +311,21 @@ AST_NODE(SwitchCase) | |||
302 | AST_MEMBER(SwitchCase, &condition, &body) | 311 | AST_MEMBER(SwitchCase, &condition, &body) |
303 | AST_END(SwitchCase) | 312 | AST_END(SwitchCase) |
304 | 313 | ||
314 | AST_NODE(Assignment) | ||
315 | ast_ptr<false, ExpList_t> expList; | ||
316 | ast_ptr<true, Assign_t> assign; | ||
317 | AST_MEMBER(Assignment, &expList, &assign) | ||
318 | AST_END(Assignment) | ||
319 | |||
305 | AST_NODE(Switch) | 320 | AST_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) |
311 | AST_END(Switch) | 327 | AST_END(Switch) |
312 | 328 | ||
313 | AST_NODE(Assignment) | ||
314 | ast_ptr<false, ExpList_t> expList; | ||
315 | ast_ptr<true, Assign_t> assign; | ||
316 | AST_MEMBER(Assignment, &expList, &assign) | ||
317 | AST_END(Assignment) | ||
318 | |||
319 | AST_NODE(IfCond) | 329 | AST_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) | |||
343 | AST_END(While) | 353 | AST_END(While) |
344 | 354 | ||
345 | AST_NODE(Repeat) | 355 | AST_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) |
349 | AST_END(Repeat) | 359 | AST_END(Repeat) |
@@ -381,9 +391,10 @@ AST_NODE(CatchBlock) | |||
381 | AST_END(CatchBlock) | 391 | AST_END(CatchBlock) |
382 | 392 | ||
383 | AST_NODE(Try) | 393 | AST_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) |
387 | AST_END(Try) | 398 | AST_END(Try) |
388 | 399 | ||
389 | AST_NODE(Comprehension) | 400 | AST_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) |
588 | AST_END(DoubleString) | 599 | AST_END(DoubleString) |
589 | 600 | ||
601 | AST_LEAF(YAMLIndent) | ||
602 | AST_END(YAMLIndent) | ||
603 | |||
604 | AST_LEAF(YAMLLineInner) | ||
605 | AST_END(YAMLLineInner) | ||
606 | |||
607 | AST_NODE(YAMLLineContent) | ||
608 | ast_sel<true, YAMLLineInner_t, Exp_t> content; | ||
609 | AST_MEMBER(YAMLLineContent, &content) | ||
610 | AST_END(YAMLLineContent) | ||
611 | |||
612 | AST_NODE(YAMLLine) | ||
613 | ast_ptr<true, YAMLIndent_t> indent; | ||
614 | ast_list<true, YAMLLineContent_t> segments; | ||
615 | AST_MEMBER(YAMLLine, &indent, &segments) | ||
616 | AST_END(YAMLLine) | ||
617 | |||
618 | AST_NODE(YAMLMultiline) | ||
619 | ast_ptr<true, Seperator_t> sep; | ||
620 | ast_list<true, YAMLLine_t> lines; | ||
621 | AST_MEMBER(YAMLMultiline, &sep, &lines) | ||
622 | AST_END(YAMLMultiline) | ||
623 | |||
590 | AST_NODE(String) | 624 | AST_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) |
593 | AST_END(String) | 627 | AST_END(String) |
594 | 628 | ||
@@ -639,9 +673,14 @@ AST_END(TableAppendingOp) | |||
639 | AST_LEAF(PlainItem) | 673 | AST_LEAF(PlainItem) |
640 | AST_END(PlainItem) | 674 | AST_END(PlainItem) |
641 | 675 | ||
676 | AST_NODE(ReversedIndex) | ||
677 | ast_ptr<false, Exp_t> modifier; | ||
678 | AST_MEMBER(ReversedIndex, &modifier) | ||
679 | AST_END(ReversedIndex) | ||
680 | |||
642 | AST_NODE(ChainValue) | 681 | AST_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) |
647 | AST_END(ChainValue) | 686 | AST_END(ChainValue) |
@@ -725,8 +764,9 @@ AST_LEAF(GlobalOp) | |||
725 | AST_END(GlobalOp) | 764 | AST_END(GlobalOp) |
726 | 765 | ||
727 | AST_NODE(Global) | 766 | AST_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) |
730 | AST_END(Global) | 770 | AST_END(Global) |
731 | 771 | ||
732 | AST_LEAF(ExportDefault) | 772 | AST_LEAF(ExportDefault) |
@@ -742,15 +782,17 @@ AST_END(Export) | |||
742 | AST_NODE(FnArgDef) | 782 | AST_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) |
747 | AST_END(FnArgDef) | 788 | AST_END(FnArgDef) |
748 | 789 | ||
749 | AST_NODE(FnArgDefList) | 790 | AST_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) | ||
754 | AST_END(FnArgDefList) | 796 | AST_END(FnArgDefList) |
755 | 797 | ||
756 | AST_NODE(OuterVarShadow) | 798 | AST_NODE(OuterVarShadow) |
@@ -838,9 +880,15 @@ AST_NODE(UnaryExp) | |||
838 | AST_MEMBER(UnaryExp, &ops, &expos, &inExp) | 880 | AST_MEMBER(UnaryExp, &ops, &expos, &inExp) |
839 | AST_END(UnaryExp) | 881 | AST_END(UnaryExp) |
840 | 882 | ||
883 | AST_NODE(SubBackcall) | ||
884 | ast_ptr<true, FnArrowBack_t> arrow; | ||
885 | ast_ptr<true, ChainValue_t> value; | ||
886 | AST_MEMBER(SubBackcall, &arrow, &value) | ||
887 | AST_END(SubBackcall) | ||
888 | |||
841 | AST_NODE(ExpListAssign) | 889 | AST_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) |
845 | AST_END(ExpListAssign) | 893 | AST_END(ExpListAssign) |
846 | 894 | ||
@@ -856,7 +904,17 @@ AST_NODE(WhileLine) | |||
856 | AST_MEMBER(WhileLine, &type, &condition) | 904 | AST_MEMBER(WhileLine, &type, &condition) |
857 | AST_END(WhileLine) | 905 | AST_END(WhileLine) |
858 | 906 | ||
859 | AST_LEAF(BreakLoop) | 907 | AST_LEAF(Break) |
908 | AST_END(Break) | ||
909 | |||
910 | AST_LEAF(Continue) | ||
911 | AST_END(Continue) | ||
912 | |||
913 | AST_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; | ||
860 | AST_END(BreakLoop) | 918 | AST_END(BreakLoop) |
861 | 919 | ||
862 | AST_NODE(PipeBody) | 920 | AST_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 | |||
7 | THE 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.*/ | 7 | THE 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 | ||
78 | const std::string_view version = "0.27.4"sv; | 81 | const std::string_view version = "0.29.3"sv; |
79 | const std::string_view extension = "yue"sv; | 82 | const std::string_view extension = "yue"sv; |
80 | 83 | ||
81 | class CompileError : public std::logic_error { | 84 | class 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 | ||
1034 | ParseInfo YueParser::parse(std::string_view codes, rule& r) { | 1083 | ParseInfo 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 | ||
1089 | ParseInfo YueParser::parse(std::string_view astName, std::string_view codes) { | 1139 | ParseInfo 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 | ||
1097 | bool YueParser::match(std::string_view astName, std::string_view codes) { | 1149 | bool 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 | |||
1190 | std::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 | ||
1139 | std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCol, int lineOffset) const { | 1209 | std::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; | |||
74 | class YueParser { | 74 | class YueParser { |
75 | public: | 75 | public: |
76 | template <class AST> | 76 | template <class AST> |
77 | ParseInfo parse(std::string_view codes) { | 77 | ParseInfo parse(std::string_view codes, bool lax) { |
78 | return parse(codes, getRule<AST>()); | 78 | return parse(codes, getRule<AST>(), lax); |
79 | } | 79 | } |
80 | 80 | ||
81 | ParseInfo parse(std::string_view astName, std::string_view codes); | 81 | ParseInfo parse(std::string_view astName, std::string_view codes, bool lax); |
82 | 82 | ||
83 | template <class AST> | 83 | template <class AST> |
84 | bool match(std::string_view codes) { | 84 | bool match(std::string_view codes) { |
85 | auto rEnd = rule(getRule<AST>() >> eof()); | 85 | auto rEnd = rule(getRule<AST>() >> eof()); |
86 | return parse(codes, rEnd).node; | 86 | return parse(codes, rEnd, false).node; |
87 | } | 87 | } |
88 | 88 | ||
89 | bool match(std::string_view astName, std::string_view codes); | 89 | bool match(std::string_view astName, std::string_view codes); |
@@ -102,13 +102,14 @@ public: | |||
102 | 102 | ||
103 | protected: | 103 | protected: |
104 | YueParser(); | 104 | YueParser(); |
105 | ParseInfo parse(std::string_view codes, rule& r); | 105 | ParseInfo parse(std::string_view codes, rule& r, bool lax); |
106 | bool startWith(std::string_view codes, rule& r); | 106 | bool startWith(std::string_view codes, rule& r); |
107 | 107 | ||
108 | struct State { | 108 | struct State { |
109 | State() { | 109 | State() { |
110 | indents.push(0); | 110 | indents.push(0); |
111 | } | 111 | } |
112 | bool lax = false; | ||
112 | bool exportDefault = false; | 113 | bool exportDefault = false; |
113 | bool exportMacro = false; | 114 | bool exportMacro = false; |
114 | bool exportMetatable = false; | 115 | bool exportMetatable = false; |
@@ -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: | |||
443 | namespace Utils { | 459 | namespace Utils { |
444 | void replace(std::string& str, std::string_view from, std::string_view to); | 460 | void replace(std::string& str, std::string_view from, std::string_view to); |
445 | void trim(std::string& str); | 461 | void trim(std::string& str); |
462 | std::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); |