diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/yuescript/yue_compiler.cpp | 326 |
1 files changed, 310 insertions, 16 deletions
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index c205031..7f6a042 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
| @@ -75,7 +75,7 @@ static std::unordered_set<std::string> Metamethods = { | |||
| 75 | "close"s // Lua 5.4 | 75 | "close"s // Lua 5.4 |
| 76 | }; | 76 | }; |
| 77 | 77 | ||
| 78 | const std::string_view version = "0.23.4"sv; | 78 | const std::string_view version = "0.23.6"sv; |
| 79 | const std::string_view extension = "yue"sv; | 79 | const std::string_view extension = "yue"sv; |
| 80 | 80 | ||
| 81 | class CompileError : public std::logic_error { | 81 | class CompileError : public std::logic_error { |
| @@ -577,6 +577,273 @@ private: | |||
| 577 | } | 577 | } |
| 578 | } | 578 | } |
| 579 | 579 | ||
| 580 | bool isConstTableItem(ast_node* item) { | ||
| 581 | switch (item->get_id()) { | ||
| 582 | case id<VariablePairDef_t>(): { | ||
| 583 | auto pair = static_cast<VariablePairDef_t*>(item); | ||
| 584 | if (pair->defVal) return false; | ||
| 585 | return isConstTableItem(pair->pair); | ||
| 586 | } | ||
| 587 | case id<NormalPairDef_t>(): { | ||
| 588 | auto pair = static_cast<NormalPairDef_t*>(item); | ||
| 589 | if (pair->defVal) return false; | ||
| 590 | return isConstTableItem(pair->pair); | ||
| 591 | } | ||
| 592 | case id<MetaVariablePairDef_t>(): { | ||
| 593 | auto pair = static_cast<MetaVariablePairDef_t*>(item); | ||
| 594 | if (pair->defVal) return false; | ||
| 595 | return isConstTableItem(pair->pair); | ||
| 596 | } | ||
| 597 | case id<MetaNormalPairDef_t>(): { | ||
| 598 | auto pair = static_cast<MetaNormalPairDef_t*>(item); | ||
| 599 | if (pair->defVal) return false; | ||
| 600 | return isConstTableItem(pair->pair); | ||
| 601 | } | ||
| 602 | case id<NormalDef_t>(): { | ||
| 603 | auto pair = static_cast<NormalDef_t*>(item); | ||
| 604 | if (pair->defVal) return false; | ||
| 605 | return isConstTableItem(pair->item); | ||
| 606 | } | ||
| 607 | case id<Exp_t>(): { | ||
| 608 | auto pair = static_cast<Exp_t*>(item); | ||
| 609 | return isConstExp(pair); | ||
| 610 | } | ||
| 611 | case id<VariablePair_t>(): { | ||
| 612 | auto pair = static_cast<VariablePair_t*>(item); | ||
| 613 | return isLocal(variableToString(pair->name)); | ||
| 614 | } | ||
| 615 | case id<NormalPair_t>(): { | ||
| 616 | auto pair = static_cast<NormalPair_t*>(item); | ||
| 617 | if (auto exp = pair->key.as<Exp_t>()) { | ||
| 618 | if (!isConstExp(exp)) { | ||
| 619 | return false; | ||
| 620 | } | ||
| 621 | } | ||
| 622 | if (auto exp = pair->value.as<Exp_t>()) { | ||
| 623 | if (!isConstExp(exp)) { | ||
| 624 | return false; | ||
| 625 | } | ||
| 626 | } else if (auto tbBlock = pair->value.as<TableBlock_t>()) { | ||
| 627 | if (!isConstTable(tbBlock)) { | ||
| 628 | return false; | ||
| 629 | } | ||
| 630 | } else { | ||
| 631 | return false; | ||
| 632 | } | ||
| 633 | return true; | ||
| 634 | } | ||
| 635 | case id<TableBlockIndent_t>(): { | ||
| 636 | auto pair = static_cast<TableBlockIndent_t*>(item); | ||
| 637 | return isConstTable(pair); | ||
| 638 | } | ||
| 639 | case id<TableBlock_t>(): { | ||
| 640 | auto pair = static_cast<TableBlock_t*>(item); | ||
| 641 | return isConstTable(pair); | ||
| 642 | break; | ||
| 643 | } | ||
| 644 | case id<MetaVariablePair_t>(): { | ||
| 645 | auto pair = static_cast<MetaVariablePair_t*>(item); | ||
| 646 | return isLocal(variableToString(pair->name)); | ||
| 647 | } | ||
| 648 | case id<MetaNormalPair_t>(): { | ||
| 649 | auto pair = static_cast<MetaNormalPair_t*>(item); | ||
| 650 | if (auto str = pair->key.as<String_t>()) { | ||
| 651 | if (!ast_is<SingleString_t, LuaString_t>(str)) { | ||
| 652 | return false; | ||
| 653 | } | ||
| 654 | } else if (auto exp = pair->key.as<Exp_t>()) { | ||
| 655 | if (!isConstExp(exp)) { | ||
| 656 | return false; | ||
| 657 | } | ||
| 658 | } else if (pair->key.is<Name_t>()) { | ||
| 659 | return true; | ||
| 660 | } else { | ||
| 661 | return false; | ||
| 662 | } | ||
| 663 | if (auto exp = pair->value.as<Exp_t>()) { | ||
| 664 | if (!isConstExp(exp)) { | ||
| 665 | return false; | ||
| 666 | } | ||
| 667 | } else if (auto tbBlock = pair->value.as<TableBlock_t>()) { | ||
| 668 | if (!isConstTable(tbBlock)) { | ||
| 669 | return false; | ||
| 670 | } | ||
| 671 | } else { | ||
| 672 | return false; | ||
| 673 | } | ||
| 674 | return true; | ||
| 675 | } | ||
| 676 | } | ||
| 677 | return false; | ||
| 678 | } | ||
| 679 | |||
| 680 | bool isConstTable(TableLit_t* tableLit) { | ||
| 681 | for (auto value : tableLit->values.objects()) { | ||
| 682 | if (!isConstTableItem(value)) { | ||
| 683 | return false; | ||
| 684 | } | ||
| 685 | } | ||
| 686 | return true; | ||
| 687 | } | ||
| 688 | |||
| 689 | bool isConstTable(TableBlock_t* tableBlock) { | ||
| 690 | for (auto value : tableBlock->values.objects()) { | ||
| 691 | if (!isConstTableItem(value)) { | ||
| 692 | return false; | ||
| 693 | } | ||
| 694 | } | ||
| 695 | return true; | ||
| 696 | } | ||
| 697 | |||
| 698 | bool isConstTable(SimpleTable_t* stable) { | ||
| 699 | for (auto value : stable->pairs.objects()) { | ||
| 700 | if (!isConstTableItem(value)) { | ||
| 701 | return false; | ||
| 702 | } | ||
| 703 | } | ||
| 704 | return true; | ||
| 705 | } | ||
| 706 | |||
| 707 | bool isConstTable(TableBlockIndent_t* table) { | ||
| 708 | for (auto value : table->values.objects()) { | ||
| 709 | if (!isConstTableItem(value)) { | ||
| 710 | return false; | ||
| 711 | } | ||
| 712 | } | ||
| 713 | return true; | ||
| 714 | } | ||
| 715 | |||
| 716 | bool isConstChainValue(ChainValue_t* value) { | ||
| 717 | auto var = singleVariableFrom(value, AccessType::None); | ||
| 718 | return isLocal(var); | ||
| 719 | } | ||
| 720 | |||
| 721 | bool isConstUnaryValue(UnaryValue_t* value) { | ||
| 722 | if (value->ops.size() > 1) { | ||
| 723 | return false; | ||
| 724 | } | ||
| 725 | auto unaryStr = _parser.toString(value->ops.front()); | ||
| 726 | if (unaryStr == "-"sv) { | ||
| 727 | return value->value->item->get_by_path<SimpleValue_t, Num_t>(); | ||
| 728 | } else if (unaryStr == "#"sv) { | ||
| 729 | return false; | ||
| 730 | } else if (unaryStr == "not"sv) { | ||
| 731 | return isConstValue(value->value); | ||
| 732 | } | ||
| 733 | return false; | ||
| 734 | } | ||
| 735 | |||
| 736 | bool isConstNum(Value_t* value) { | ||
| 737 | return value->get_by_path<SimpleValue_t, Num_t>(); | ||
| 738 | } | ||
| 739 | |||
| 740 | bool isConstUnaryExp(UnaryExp_t* value) { | ||
| 741 | if (value->inExp) return false; | ||
| 742 | if (value->ops.size() == 0) { | ||
| 743 | if (value->expos.size() == 1) { | ||
| 744 | return isConstValue(static_cast<Value_t*>(value->expos.front())); | ||
| 745 | } | ||
| 746 | for (auto expo : value->expos.objects()) { | ||
| 747 | if (!isConstNum(static_cast<Value_t*>(expo))) { | ||
| 748 | return false; | ||
| 749 | } | ||
| 750 | } | ||
| 751 | return true; | ||
| 752 | } | ||
| 753 | if (value->ops.size() > 1) { | ||
| 754 | return false; | ||
| 755 | } | ||
| 756 | auto unaryStr = _parser.toString(value->ops.front()); | ||
| 757 | if (unaryStr == "-"sv) { | ||
| 758 | for (auto expo : value->expos.objects()) { | ||
| 759 | if (!isConstNum(static_cast<Value_t*>(expo))) { | ||
| 760 | return false; | ||
| 761 | } | ||
| 762 | } | ||
| 763 | return true; | ||
| 764 | } else if (unaryStr == "#"sv) { | ||
| 765 | return false; | ||
| 766 | } else if (unaryStr == "not"sv) { | ||
| 767 | if (value->expos.size() == 1) { | ||
| 768 | return isConstValue(static_cast<Value_t*>(value->expos.front())); | ||
| 769 | } | ||
| 770 | for (auto expo : value->expos.objects()) { | ||
| 771 | if (!isConstNum(static_cast<Value_t*>(expo))) { | ||
| 772 | return false; | ||
| 773 | } | ||
| 774 | } | ||
| 775 | return true; | ||
| 776 | } | ||
| 777 | return false; | ||
| 778 | } | ||
| 779 | |||
| 780 | bool isConstValue(Value_t* value) { | ||
| 781 | if (auto strNode = value->item.as<String_t>()) { | ||
| 782 | switch (strNode->str->get_id()) { | ||
| 783 | case id<SingleString_t>(): | ||
| 784 | case id<LuaString_t>(): | ||
| 785 | return true; | ||
| 786 | case id<DoubleString_t>(): | ||
| 787 | return false; | ||
| 788 | default: | ||
| 789 | YUEE("AST node mismatch", strNode->str); | ||
| 790 | return false; | ||
| 791 | } | ||
| 792 | } else if (auto chainValue = value->item.as<ChainValue_t>()) { | ||
| 793 | return isConstChainValue(chainValue); | ||
| 794 | } else if (auto simpleValue = value->item.as<SimpleValue_t>()) { | ||
| 795 | if (ast_is<ConstValue_t, Num_t, VarArg_t, FunLit_t>(simpleValue->value.get())) { | ||
| 796 | return true; | ||
| 797 | } else if (auto uValue = simpleValue->value.as<UnaryValue_t>()) { | ||
| 798 | return isConstUnaryValue(uValue); | ||
| 799 | } else if (auto comp = simpleValue->value.as<Comprehension_t>()) { | ||
| 800 | for (auto item : comp->items.objects()) { | ||
| 801 | if (auto ndef = ast_cast<NormalDef_t>(item)) { | ||
| 802 | if (ndef->defVal) { | ||
| 803 | return false; | ||
| 804 | } | ||
| 805 | if (!isConstExp(ndef->item)) { | ||
| 806 | return false; | ||
| 807 | } | ||
| 808 | } else { | ||
| 809 | return false; | ||
| 810 | } | ||
| 811 | } | ||
| 812 | return true; | ||
| 813 | } else if (auto tableLit = simpleValue->value.as<TableLit_t>()) { | ||
| 814 | return isConstTable(tableLit); | ||
| 815 | } else { | ||
| 816 | return false; | ||
| 817 | } | ||
| 818 | } else if (auto simpleTable = value->item.as<SimpleTable_t>()) { | ||
| 819 | return isConstTable(simpleTable); | ||
| 820 | } | ||
| 821 | return false; | ||
| 822 | } | ||
| 823 | |||
| 824 | bool isConstUnaryExps(const ast_list<true, UnaryExp_t>& list) { | ||
| 825 | if (list.size() > 1) { | ||
| 826 | return false; | ||
| 827 | } | ||
| 828 | if (!isConstUnaryExp(static_cast<UnaryExp_t*>(list.front()))) { | ||
| 829 | return false; | ||
| 830 | } | ||
| 831 | return true; | ||
| 832 | } | ||
| 833 | |||
| 834 | bool isConstExp(Exp_t* exp) { | ||
| 835 | if (exp->nilCoalesed) { | ||
| 836 | return false; | ||
| 837 | } | ||
| 838 | if (!isConstUnaryExps(exp->pipeExprs)) { | ||
| 839 | return false; | ||
| 840 | } | ||
| 841 | if (exp->opValues.empty()) { | ||
| 842 | return true; | ||
| 843 | } | ||
| 844 | return false; | ||
| 845 | } | ||
| 846 | |||
| 580 | void markVarConst(const std::string& name) { | 847 | void markVarConst(const std::string& name) { |
| 581 | auto& scope = _scopes.back(); | 848 | auto& scope = _scopes.back(); |
| 582 | scope.vars->insert_or_assign(name, VarType::Const); | 849 | scope.vars->insert_or_assign(name, VarType::Const); |
| @@ -3691,7 +3958,7 @@ private: | |||
| 3691 | }) != traversal::Stop; | 3958 | }) != traversal::Stop; |
| 3692 | } | 3959 | } |
| 3693 | 3960 | ||
| 3694 | std::optional<std::pair<std::string, str_list>> getUpValueFuncFromBlock(Block_t* block, str_list* ensureArgListInTheEnd) { | 3961 | std::optional<std::pair<std::string, str_list>> getUpValueFuncFromBlock(Block_t* block, str_list* ensureArgListInTheEnd, bool noGlobalVarPassing) { |
| 3695 | if (_funcLevel <= 1) return std::nullopt; | 3962 | if (_funcLevel <= 1) return std::nullopt; |
| 3696 | auto result = block->traverse([&](ast_node* node) { | 3963 | auto result = block->traverse([&](ast_node* node) { |
| 3697 | switch (node->get_id()) { | 3964 | switch (node->get_id()) { |
| @@ -3754,6 +4021,9 @@ private: | |||
| 3754 | } else if (std::find(args.begin(), args.end(), global.name) == args.end()) { | 4021 | } else if (std::find(args.begin(), args.end(), global.name) == args.end()) { |
| 3755 | args.push_back(global.name); | 4022 | args.push_back(global.name); |
| 3756 | } | 4023 | } |
| 4024 | if (noGlobalVarPassing && !isLocal(global.name)) { | ||
| 4025 | return std::nullopt; | ||
| 4026 | } | ||
| 3757 | } | 4027 | } |
| 3758 | } | 4028 | } |
| 3759 | } | 4029 | } |
| @@ -3809,9 +4079,9 @@ private: | |||
| 3809 | } | 4079 | } |
| 3810 | 4080 | ||
| 3811 | 4081 | ||
| 3812 | std::optional<std::pair<std::string, str_list>> upValueFuncFrom(Block_t* block, str_list* ensureArgListInTheEnd = nullptr) { | 4082 | std::optional<std::pair<std::string, str_list>> upValueFuncFrom(Block_t* block, str_list* ensureArgListInTheEnd = nullptr, bool noGlobalVarPassing = false) { |
| 3813 | if (checkUpValueFuncAvailable(block)) { | 4083 | if (checkUpValueFuncAvailable(block)) { |
| 3814 | return getUpValueFuncFromBlock(block, ensureArgListInTheEnd); | 4084 | return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, noGlobalVarPassing); |
| 3815 | } | 4085 | } |
| 3816 | return std::nullopt; | 4086 | return std::nullopt; |
| 3817 | } | 4087 | } |
| @@ -3826,7 +4096,7 @@ private: | |||
| 3826 | auto stmt = exp->new_ptr<Statement_t>(); | 4096 | auto stmt = exp->new_ptr<Statement_t>(); |
| 3827 | stmt->content.set(returnNode); | 4097 | stmt->content.set(returnNode); |
| 3828 | block->statements.push_back(stmt); | 4098 | block->statements.push_back(stmt); |
| 3829 | return getUpValueFuncFromBlock(block, ensureArgListInTheEnd); | 4099 | return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false); |
| 3830 | } | 4100 | } |
| 3831 | return std::nullopt; | 4101 | return std::nullopt; |
| 3832 | } | 4102 | } |
| @@ -9135,23 +9405,47 @@ private: | |||
| 9135 | BREAK_IF(var.empty()); | 9405 | BREAK_IF(var.empty()); |
| 9136 | tryFunc.set(expListAssign->expList->exprs.front()); | 9406 | tryFunc.set(expListAssign->expList->exprs.front()); |
| 9137 | BLOCK_END | 9407 | BLOCK_END |
| 9138 | } else { | 9408 | } |
| 9139 | auto tryExp = tryFunc.as<Exp_t>(); | 9409 | if (auto tryExp = tryFunc.as<Exp_t>()) { |
| 9140 | bool needWrap = singleVariableFrom(tryExp, AccessType::None).empty(); | 9410 | bool wrapped = true; |
| 9141 | BLOCK_START | 9411 | BLOCK_START |
| 9142 | auto value = singleValueFrom(tryExp); | 9412 | auto value = singleValueFrom(tryExp); |
| 9143 | BREAK_IF(!value); | 9413 | BREAK_IF(!value); |
| 9144 | auto chainValue = value->item.as<ChainValue_t>(); | 9414 | auto chainValue = value->item.as<ChainValue_t>(); |
| 9145 | BREAK_IF(!chainValue); | 9415 | BREAK_IF(!chainValue); |
| 9146 | BREAK_IF(!isChainValueCall(chainValue)); | 9416 | BREAK_IF(!isChainValueCall(chainValue)); |
| 9147 | auto tmpChain = chainValue->new_ptr<ChainValue_t>(); | 9417 | auto chainCaller = chainValue->new_ptr<ChainValue_t>(); |
| 9148 | tmpChain->items.dup(chainValue->items); | 9418 | chainCaller->items.dup(chainValue->items); |
| 9149 | tmpChain->items.pop_back(); | 9419 | chainCaller->items.pop_back(); |
| 9150 | auto var = singleVariableFrom(tmpChain, AccessType::None); | 9420 | BREAK_IF(!isConstChainValue(chainCaller)); |
| 9151 | BREAK_IF(var.empty()); | 9421 | _ast_list* args = nullptr; |
| 9152 | needWrap = false; | 9422 | if (auto invoke = ast_cast<InvokeArgs_t>(chainValue->items.back())) { |
| 9423 | args = &invoke->args; | ||
| 9424 | } else { | ||
| 9425 | args = &(ast_to<Invoke_t>(chainValue->items.back())->args); | ||
| 9426 | } | ||
| 9427 | wrapped = false; | ||
| 9428 | for (auto arg : args->objects()) { | ||
| 9429 | switch (arg->get_id()) { | ||
| 9430 | case id<Exp_t>(): | ||
| 9431 | if (isConstExp(static_cast<Exp_t*>(arg))) continue; | ||
| 9432 | break; | ||
| 9433 | case id<SingleString_t>(): | ||
| 9434 | case id<LuaString_t>(): | ||
| 9435 | continue; | ||
| 9436 | case id<DoubleString_t>(): | ||
| 9437 | break; | ||
| 9438 | case id<TableLit_t>(): | ||
| 9439 | if (isConstTable(static_cast<TableLit_t*>(arg))) continue; | ||
| 9440 | break; | ||
| 9441 | case id<TableBlock_t>(): | ||
| 9442 | if (isConstTable(static_cast<TableBlock_t*>(arg))) continue; | ||
| 9443 | break; | ||
| 9444 | } | ||
| 9445 | wrapped = true; | ||
| 9446 | } | ||
| 9153 | BLOCK_END | 9447 | BLOCK_END |
| 9154 | if (needWrap) { | 9448 | if (wrapped) { |
| 9155 | auto expList = x->new_ptr<ExpList_t>(); | 9449 | auto expList = x->new_ptr<ExpList_t>(); |
| 9156 | expList->exprs.push_back(tryFunc); | 9450 | expList->exprs.push_back(tryFunc); |
| 9157 | auto expListAssign = x->new_ptr<ExpListAssign_t>(); | 9451 | auto expListAssign = x->new_ptr<ExpListAssign_t>(); |
| @@ -9165,7 +9459,7 @@ private: | |||
| 9165 | } | 9459 | } |
| 9166 | if (auto tryBlock = tryFunc.as<Block_t>()) { | 9460 | if (auto tryBlock = tryFunc.as<Block_t>()) { |
| 9167 | if (getLuaTarget(tryBlock) >= 502 || !errHandler) { | 9461 | if (getLuaTarget(tryBlock) >= 502 || !errHandler) { |
| 9168 | if (auto result = upValueFuncFrom(tryBlock)) { | 9462 | if (auto result = upValueFuncFrom(tryBlock, nullptr, true)) { |
| 9169 | auto [funcName, args] = std::move(*result); | 9463 | auto [funcName, args] = std::move(*result); |
| 9170 | if (errHandler) { | 9464 | if (errHandler) { |
| 9171 | auto xpcall = toAst<ChainValue_t>("xpcall()", x); | 9465 | auto xpcall = toAst<ChainValue_t>("xpcall()", x); |
