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