From 04e3cd43cee426cd5c2fa1d0fab5fabc7f19c039 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Tue, 26 May 2020 16:12:44 +0800 Subject: make back call operator use highest priority for operator precedence. --- src/MoonP/moon_compiler.cpp | 169 ++++++++++++++++++++++++++++---------------- 1 file changed, 107 insertions(+), 62 deletions(-) (limited to 'src') 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) { } const std::string_view version() { - return "0.3.13"sv; + return "0.3.14"sv; } // name of table stored in lua registry @@ -1612,79 +1612,123 @@ private: out.push_back(join(temp, ", "sv)); } - void transformExp(Exp_t* exp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { - auto x = exp; - const auto& opValues = exp->opValues.objects(); - for (auto it = opValues.begin(); it != opValues.end(); ++it) { + ast_ptr transformBackcall(Value_t* first, node_container::const_iterator begin, node_container::const_iterator end) { + auto arg = first->new_ptr(); + arg->value.set(first); + for (auto it = begin; it != end; ++it) { auto opValue = static_cast(*it); - if (opValue->op.is()) { - if (auto chainValue = opValue->value->item.as()) { - auto newExp = x->new_ptr(); - { - auto arg = x->new_ptr(); - arg->value.set(exp->value); - for (auto i = opValues.begin(); i != it; ++i) { - arg->opValues.push_back(*i); - } - auto next = it; ++next; - for (auto i = next; i != opValues.end(); ++i) { - newExp->opValues.push_back(*i); + if (auto chainValue = opValue->value->item.as()) { + auto newArg = first->new_ptr(); + { + if (isChainValueCall(chainValue)) { + auto last = chainValue->items.back(); + _ast_list* args = nullptr; + if (auto invoke = ast_cast(last)) { + args = &invoke->args; + } else { + args = &(ast_to(last)->args); } - if (isChainValueCall(chainValue)) { - auto last = chainValue->items.back(); - _ast_list* args = nullptr; - if (auto invoke = ast_cast(last)) { - args = &invoke->args; - } else { - args = &(ast_to(last)->args); - } - bool findPlaceHolder = false; - for (auto a : args->objects()) { - bool lintGlobal = _config.lintGlobalVariable; - _config.lintGlobalVariable = false; - auto name = singleVariableFrom(a); - _config.lintGlobalVariable = lintGlobal; - if (name == "_"sv) { - if (!findPlaceHolder) { - args->swap(a, arg); - findPlaceHolder = true; - } else { - throw std::logic_error(_info.errorMessage("backcall placeholder can be used only in one place"sv, a)); - } + bool findPlaceHolder = false; + for (auto a : args->objects()) { + bool lintGlobal = _config.lintGlobalVariable; + _config.lintGlobalVariable = false; + auto name = singleVariableFrom(a); + _config.lintGlobalVariable = lintGlobal; + if (name == "_"sv) { + if (!findPlaceHolder) { + args->swap(a, arg); + findPlaceHolder = true; + } else { + throw std::logic_error(_info.errorMessage("backcall placeholder can be used only in one place"sv, a)); } } - if (!findPlaceHolder) { - args->push_front(arg); - } - } else { - auto invoke = x->new_ptr(); - invoke->args.push_front(arg); - chainValue->items.push_back(invoke); } - auto value = x->new_ptr(); - value->item.set(chainValue); - newExp->value.set(value); - } - if (newExp->opValues.size() == 0) { - if (usage == ExpUsage::Assignment) { - auto assign = x->new_ptr(); - assign->values.push_back(newExp); - auto assignment = x->new_ptr(); - assignment->expList.set(assignList); - assignment->action.set(assign); - transformAssignment(assignment, out); - } else { - transformChainValue(chainValue, out, usage); + if (!findPlaceHolder) { + args->push_front(arg); } } else { - transformExp(newExp, out, usage, assignList); + auto invoke = first->new_ptr(); + invoke->args.push_front(arg); + chainValue->items.push_back(invoke); + } + auto value = first->new_ptr(); + value->item.set(chainValue); + newArg->value.set(value); + arg.set(newArg); + } + } else { + throw std::logic_error(_info.errorMessage("backcall operator must be followed by chain value"sv, opValue->value)); + } + } + return arg; + } + + void transformExp(Exp_t* exp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { + const auto& opValues = exp->opValues.objects(); + for (auto it = opValues.begin(); it != opValues.end(); ++it) { + auto opValue = static_cast(*it); + if (opValue->op.is()) { + auto end = std::find_if_not(it, opValues.end(), [](ast_node* node) { + return static_cast(node)->op.is(); + }); + ast_ptr backcall; + if (it == opValues.begin()) { + auto first = exp->value.get(); + backcall = transformBackcall(first, it, end); + for (auto i = end; i != opValues.end(); ++i) { + backcall->opValues.push_back(*i); } - return; } else { - throw std::logic_error(_info.errorMessage("backcall operator must be followed by chain value"sv, opValue->value)); + auto prev = it; --prev; + auto first = static_cast(*prev)->value.get(); + backcall = transformBackcall(first, it, end); + for (auto i = opValues.begin(); i != it; ++i) { + backcall->opValues.push_back(*i); + } + static_cast(backcall->opValues.back())->value.set(backcall->value); + backcall->value.set(exp->value); + for (auto i = end; i != opValues.end(); ++i) { + backcall->opValues.push_back(*i); + } + } + auto x = exp; + switch (usage) { + case ExpUsage::Assignment: { + auto assignment = x->new_ptr(); + auto assign = x->new_ptr(); + assign->values.push_back(backcall); + assignment->action.set(assign); + assignment->expList.set(assignList); + transformAssignment(assignment, out); + return; + } + case ExpUsage::Common: { + if (backcall->opValues.empty() && backcall->value->item.is()) { + transformChainValue(backcall->value->item.to(), out, ExpUsage::Common); + } else { + transformExp(backcall, out, ExpUsage::Closure); + out.back().insert(0, indent()); + out.back().append(nlr(x)); + } + return; + } + case ExpUsage::Return: { + auto ret = x->new_ptr(); + auto expListLow = x->new_ptr(); + expListLow->exprs.push_back(backcall); + ret->valueList.set(expListLow); + transformReturn(ret, out); + return; + } + case ExpUsage::Closure: { + transformExp(backcall, out, ExpUsage::Closure); + return; + } + default: assert(false); return; } } } + assert(usage == ExpUsage::Closure); str_list temp; transformValue(exp->value, temp); for (auto _opValue : exp->opValues.objects()) { @@ -2954,6 +2998,7 @@ private: case ExpUsage::Return: out.push_back(indent() + s("return "sv) + join(temp) + nll(chainList.front())); break; + case ExpUsage::Assignment: assert(false); break; default: out.push_back(join(temp)); break; -- cgit v1.2.3-55-g6feb