diff options
-rw-r--r-- | makefile | 2 | ||||
-rw-r--r-- | spec/inputs/backcall.moon | 4 | ||||
-rw-r--r-- | src/MoonP/moon_compiler.cpp | 169 |
3 files changed, 112 insertions, 63 deletions
@@ -212,7 +212,7 @@ clean: | |||
212 | 212 | ||
213 | # Test Moonscript compiler | 213 | # Test Moonscript compiler |
214 | .PHONY: test | 214 | .PHONY: test |
215 | test: release | 215 | test: debug |
216 | @echo "Compiling Moonscript codes..." | 216 | @echo "Compiling Moonscript codes..." |
217 | @$(START_TIME) | 217 | @$(START_TIME) |
218 | @./$(BIN_NAME) $(TEST_INPUT) -t $(TEST_OUTPUT) | 218 | @./$(BIN_NAME) $(TEST_INPUT) -t $(TEST_OUTPUT) |
diff --git a/spec/inputs/backcall.moon b/spec/inputs/backcall.moon index 30a0f8f..5f53f9e 100644 --- a/spec/inputs/backcall.moon +++ b/spec/inputs/backcall.moon | |||
@@ -107,3 +107,7 @@ alert "hi" | |||
107 | 107 | ||
108 | x = 123 |> a |> b or 456 |> c |> d or a.if\then("abc") or a?.b\c?(123) or x\y | 108 | x = 123 |> a |> b or 456 |> c |> d or a.if\then("abc") or a?.b\c?(123) or x\y |
109 | 109 | ||
110 | y = 1 + # 2 |> a ^ c |> b(3,_) ^ 4 * -123 |> f |> f1 or 123 | ||
111 | |||
112 | nil | ||
113 | |||
diff --git a/src/MoonP/moon_compiler.cpp b/src/MoonP/moon_compiler.cpp index 36b6b11..189a428 100644 --- a/src/MoonP/moon_compiler.cpp +++ b/src/MoonP/moon_compiler.cpp | |||
@@ -43,7 +43,7 @@ inline std::string s(std::string_view sv) { | |||
43 | } | 43 | } |
44 | 44 | ||
45 | const std::string_view version() { | 45 | const std::string_view version() { |
46 | return "0.3.13"sv; | 46 | return "0.3.14"sv; |
47 | } | 47 | } |
48 | 48 | ||
49 | // name of table stored in lua registry | 49 | // name of table stored in lua registry |
@@ -1612,79 +1612,123 @@ private: | |||
1612 | out.push_back(join(temp, ", "sv)); | 1612 | out.push_back(join(temp, ", "sv)); |
1613 | } | 1613 | } |
1614 | 1614 | ||
1615 | void transformExp(Exp_t* exp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { | 1615 | ast_ptr<false, Exp_t> transformBackcall(Value_t* first, node_container::const_iterator begin, node_container::const_iterator end) { |
1616 | auto x = exp; | 1616 | auto arg = first->new_ptr<Exp_t>(); |
1617 | const auto& opValues = exp->opValues.objects(); | 1617 | arg->value.set(first); |
1618 | for (auto it = opValues.begin(); it != opValues.end(); ++it) { | 1618 | for (auto it = begin; it != end; ++it) { |
1619 | auto opValue = static_cast<exp_op_value_t*>(*it); | 1619 | auto opValue = static_cast<exp_op_value_t*>(*it); |
1620 | if (opValue->op.is<BackcallOperator_t>()) { | 1620 | if (auto chainValue = opValue->value->item.as<ChainValue_t>()) { |
1621 | if (auto chainValue = opValue->value->item.as<ChainValue_t>()) { | 1621 | auto newArg = first->new_ptr<Exp_t>(); |
1622 | auto newExp = x->new_ptr<Exp_t>(); | 1622 | { |
1623 | { | 1623 | if (isChainValueCall(chainValue)) { |
1624 | auto arg = x->new_ptr<Exp_t>(); | 1624 | auto last = chainValue->items.back(); |
1625 | arg->value.set(exp->value); | 1625 | _ast_list* args = nullptr; |
1626 | for (auto i = opValues.begin(); i != it; ++i) { | 1626 | if (auto invoke = ast_cast<InvokeArgs_t>(last)) { |
1627 | arg->opValues.push_back(*i); | 1627 | args = &invoke->args; |
1628 | } | 1628 | } else { |
1629 | auto next = it; ++next; | 1629 | args = &(ast_to<Invoke_t>(last)->args); |
1630 | for (auto i = next; i != opValues.end(); ++i) { | ||
1631 | newExp->opValues.push_back(*i); | ||
1632 | } | 1630 | } |
1633 | if (isChainValueCall(chainValue)) { | 1631 | bool findPlaceHolder = false; |
1634 | auto last = chainValue->items.back(); | 1632 | for (auto a : args->objects()) { |
1635 | _ast_list* args = nullptr; | 1633 | bool lintGlobal = _config.lintGlobalVariable; |
1636 | if (auto invoke = ast_cast<InvokeArgs_t>(last)) { | 1634 | _config.lintGlobalVariable = false; |
1637 | args = &invoke->args; | 1635 | auto name = singleVariableFrom(a); |
1638 | } else { | 1636 | _config.lintGlobalVariable = lintGlobal; |
1639 | args = &(ast_to<Invoke_t>(last)->args); | 1637 | if (name == "_"sv) { |
1640 | } | 1638 | if (!findPlaceHolder) { |
1641 | bool findPlaceHolder = false; | 1639 | args->swap(a, arg); |
1642 | for (auto a : args->objects()) { | 1640 | findPlaceHolder = true; |
1643 | bool lintGlobal = _config.lintGlobalVariable; | 1641 | } else { |
1644 | _config.lintGlobalVariable = false; | 1642 | throw std::logic_error(_info.errorMessage("backcall placeholder can be used only in one place"sv, a)); |
1645 | auto name = singleVariableFrom(a); | ||
1646 | _config.lintGlobalVariable = lintGlobal; | ||
1647 | if (name == "_"sv) { | ||
1648 | if (!findPlaceHolder) { | ||
1649 | args->swap(a, arg); | ||
1650 | findPlaceHolder = true; | ||
1651 | } else { | ||
1652 | throw std::logic_error(_info.errorMessage("backcall placeholder can be used only in one place"sv, a)); | ||
1653 | } | ||
1654 | } | 1643 | } |
1655 | } | 1644 | } |
1656 | if (!findPlaceHolder) { | ||
1657 | args->push_front(arg); | ||
1658 | } | ||
1659 | } else { | ||
1660 | auto invoke = x->new_ptr<Invoke_t>(); | ||
1661 | invoke->args.push_front(arg); | ||
1662 | chainValue->items.push_back(invoke); | ||
1663 | } | 1645 | } |
1664 | auto value = x->new_ptr<Value_t>(); | 1646 | if (!findPlaceHolder) { |
1665 | value->item.set(chainValue); | 1647 | args->push_front(arg); |
1666 | newExp->value.set(value); | ||
1667 | } | ||
1668 | if (newExp->opValues.size() == 0) { | ||
1669 | if (usage == ExpUsage::Assignment) { | ||
1670 | auto assign = x->new_ptr<Assign_t>(); | ||
1671 | assign->values.push_back(newExp); | ||
1672 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
1673 | assignment->expList.set(assignList); | ||
1674 | assignment->action.set(assign); | ||
1675 | transformAssignment(assignment, out); | ||
1676 | } else { | ||
1677 | transformChainValue(chainValue, out, usage); | ||
1678 | } | 1648 | } |
1679 | } else { | 1649 | } else { |
1680 | transformExp(newExp, out, usage, assignList); | 1650 | auto invoke = first->new_ptr<Invoke_t>(); |
1651 | invoke->args.push_front(arg); | ||
1652 | chainValue->items.push_back(invoke); | ||
1653 | } | ||
1654 | auto value = first->new_ptr<Value_t>(); | ||
1655 | value->item.set(chainValue); | ||
1656 | newArg->value.set(value); | ||
1657 | arg.set(newArg); | ||
1658 | } | ||
1659 | } else { | ||
1660 | throw std::logic_error(_info.errorMessage("backcall operator must be followed by chain value"sv, opValue->value)); | ||
1661 | } | ||
1662 | } | ||
1663 | return arg; | ||
1664 | } | ||
1665 | |||
1666 | void transformExp(Exp_t* exp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { | ||
1667 | const auto& opValues = exp->opValues.objects(); | ||
1668 | for (auto it = opValues.begin(); it != opValues.end(); ++it) { | ||
1669 | auto opValue = static_cast<exp_op_value_t*>(*it); | ||
1670 | if (opValue->op.is<BackcallOperator_t>()) { | ||
1671 | auto end = std::find_if_not(it, opValues.end(), [](ast_node* node) { | ||
1672 | return static_cast<exp_op_value_t*>(node)->op.is<BackcallOperator_t>(); | ||
1673 | }); | ||
1674 | ast_ptr<false, Exp_t> backcall; | ||
1675 | if (it == opValues.begin()) { | ||
1676 | auto first = exp->value.get(); | ||
1677 | backcall = transformBackcall(first, it, end); | ||
1678 | for (auto i = end; i != opValues.end(); ++i) { | ||
1679 | backcall->opValues.push_back(*i); | ||
1681 | } | 1680 | } |
1682 | return; | ||
1683 | } else { | 1681 | } else { |
1684 | throw std::logic_error(_info.errorMessage("backcall operator must be followed by chain value"sv, opValue->value)); | 1682 | auto prev = it; --prev; |
1683 | auto first = static_cast<exp_op_value_t*>(*prev)->value.get(); | ||
1684 | backcall = transformBackcall(first, it, end); | ||
1685 | for (auto i = opValues.begin(); i != it; ++i) { | ||
1686 | backcall->opValues.push_back(*i); | ||
1687 | } | ||
1688 | static_cast<exp_op_value_t*>(backcall->opValues.back())->value.set(backcall->value); | ||
1689 | backcall->value.set(exp->value); | ||
1690 | for (auto i = end; i != opValues.end(); ++i) { | ||
1691 | backcall->opValues.push_back(*i); | ||
1692 | } | ||
1693 | } | ||
1694 | auto x = exp; | ||
1695 | switch (usage) { | ||
1696 | case ExpUsage::Assignment: { | ||
1697 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
1698 | auto assign = x->new_ptr<Assign_t>(); | ||
1699 | assign->values.push_back(backcall); | ||
1700 | assignment->action.set(assign); | ||
1701 | assignment->expList.set(assignList); | ||
1702 | transformAssignment(assignment, out); | ||
1703 | return; | ||
1704 | } | ||
1705 | case ExpUsage::Common: { | ||
1706 | if (backcall->opValues.empty() && backcall->value->item.is<ChainValue_t>()) { | ||
1707 | transformChainValue(backcall->value->item.to<ChainValue_t>(), out, ExpUsage::Common); | ||
1708 | } else { | ||
1709 | transformExp(backcall, out, ExpUsage::Closure); | ||
1710 | out.back().insert(0, indent()); | ||
1711 | out.back().append(nlr(x)); | ||
1712 | } | ||
1713 | return; | ||
1714 | } | ||
1715 | case ExpUsage::Return: { | ||
1716 | auto ret = x->new_ptr<Return_t>(); | ||
1717 | auto expListLow = x->new_ptr<ExpListLow_t>(); | ||
1718 | expListLow->exprs.push_back(backcall); | ||
1719 | ret->valueList.set(expListLow); | ||
1720 | transformReturn(ret, out); | ||
1721 | return; | ||
1722 | } | ||
1723 | case ExpUsage::Closure: { | ||
1724 | transformExp(backcall, out, ExpUsage::Closure); | ||
1725 | return; | ||
1726 | } | ||
1727 | default: assert(false); return; | ||
1685 | } | 1728 | } |
1686 | } | 1729 | } |
1687 | } | 1730 | } |
1731 | assert(usage == ExpUsage::Closure); | ||
1688 | str_list temp; | 1732 | str_list temp; |
1689 | transformValue(exp->value, temp); | 1733 | transformValue(exp->value, temp); |
1690 | for (auto _opValue : exp->opValues.objects()) { | 1734 | for (auto _opValue : exp->opValues.objects()) { |
@@ -2954,6 +2998,7 @@ private: | |||
2954 | case ExpUsage::Return: | 2998 | case ExpUsage::Return: |
2955 | out.push_back(indent() + s("return "sv) + join(temp) + nll(chainList.front())); | 2999 | out.push_back(indent() + s("return "sv) + join(temp) + nll(chainList.front())); |
2956 | break; | 3000 | break; |
3001 | case ExpUsage::Assignment: assert(false); break; | ||
2957 | default: | 3002 | default: |
2958 | out.push_back(join(temp)); | 3003 | out.push_back(join(temp)); |
2959 | break; | 3004 | break; |