From 8d1af508f4173e4af6a4ea98584c1a86619f6a20 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Sat, 18 Jan 2020 18:15:24 +0800 Subject: fix Moonscript issue 122, add support for ? operator. --- src/MoonP/ast.hpp | 6 + src/MoonP/moon_ast.cpp | 1 + src/MoonP/moon_ast.h | 5 +- src/MoonP/moon_compiler.cpp | 508 +++++++++++++++++++++++++++++++------------- src/MoonP/moon_parser.cpp | 15 +- src/moonc.cpp | 12 +- 6 files changed, 377 insertions(+), 170 deletions(-) (limited to 'src') diff --git a/src/MoonP/ast.hpp b/src/MoonP/ast.hpp index f2ef76c..0b5ffca 100644 --- a/src/MoonP/ast.hpp +++ b/src/MoonP/ast.hpp @@ -392,6 +392,12 @@ public: node->release(); } + void pop_back() { + auto node = m_objects.back(); + m_objects.pop_back(); + node->release(); + } + const node_container& objects() const { return m_objects; } diff --git a/src/MoonP/moon_ast.cpp b/src/MoonP/moon_ast.cpp index 0ccd0ed..f3fe31e 100644 --- a/src/MoonP/moon_ast.cpp +++ b/src/MoonP/moon_ast.cpp @@ -79,6 +79,7 @@ AST_IMPL(ColonChainItem) AST_IMPL(default_value) AST_IMPL(Slice) AST_IMPL(Invoke) +AST_IMPL(existential_op) AST_IMPL(TableLit) AST_IMPL(TableBlock) AST_IMPL(class_member_list) diff --git a/src/MoonP/moon_ast.h b/src/MoonP/moon_ast.h index a614465..8b80af3 100644 --- a/src/MoonP/moon_ast.h +++ b/src/MoonP/moon_ast.h @@ -407,11 +407,14 @@ AST_NODE(Invoke, "Invoke"_id) AST_MEMBER(Invoke, &sep, &args) AST_END(Invoke) +AST_LEAF(existential_op, "existential_op"_id) +AST_END(existential_op) + class InvokeArgs_t; AST_NODE(ChainValue, "ChainValue"_id) ast_ptr sep; - ast_sel_list items; + ast_sel_list items; AST_MEMBER(ChainValue, &sep, &items) AST_END(ChainValue) diff --git a/src/MoonP/moon_compiler.cpp b/src/MoonP/moon_compiler.cpp index d30f413..9164f6a 100644 --- a/src/MoonP/moon_compiler.cpp +++ b/src/MoonP/moon_compiler.cpp @@ -15,6 +15,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include +#include using namespace std::string_view_literals; #include "MoonP/parser.hpp" #include "MoonP/moon_ast.h" @@ -426,6 +427,35 @@ private: return ast_is(chainValue->items.back()); } + bool isSpecialChainValue(ChainValue_t* chainValue) { + if (ast_is(chainValue->items.back())) { + return true; + } + for (auto item : chainValue->items.objects()) { + if (auto colonChain = ast_cast(item)) { + if (ast_is(colonChain->name)) { + return true; + } + } else if (ast_is(item) && item != chainValue->items.back()) { + return true; + } + } + return false; + } + + std::string singleVariableFrom(ChainValue_t* chainValue) { + BLOCK_START + BREAK_IF(!chainValue); + BREAK_IF(chainValue->items.size() != 1); + auto callable = ast_cast(chainValue->items.front()); + BREAK_IF(!callable || !(callable->item.is() || callable->getByPath())); + str_list tmp; + transformCallable(callable, tmp); + return tmp.back(); + BLOCK_END + return Empty; + } + std::string singleVariableFrom(ast_node* expList) { if (!ast_is(expList)) return Empty; BLOCK_START @@ -435,7 +465,7 @@ private: BREAK_IF(!chainValue); BREAK_IF(chainValue->items.size() != 1); auto callable = ast_cast(chainValue->items.front()); - BREAK_IF(!callable || !callable->item.is()); + BREAK_IF(!callable || !(callable->item.is() || callable->getByPath())); str_list tmp; transformCallable(callable, tmp); return tmp.back(); @@ -443,22 +473,6 @@ private: return Empty; } - bool isColonChain(ChainValue_t* chainValue) { - return ast_is(chainValue->items.back()); - } - - bool hasKeywordColonChainItem(ChainValue_t* chainValue) { - const auto& chainList = chainValue->items.objects(); - for (auto it = chainList.begin(); it != chainList.end(); ++it) { - if (auto colonItem = ast_cast(*it)) { - if (colonItem->name.is()) { - return true; - } - } - } - return false; - } - bool isAssignable(const node_container& chainItems) { if (chainItems.size() == 1) { auto firstItem = chainItems.back(); @@ -539,7 +553,7 @@ private: } auto line = _converter.to_bytes(std::wstring(begin, end)); int oldCol = loc->m_begin.m_col; - int col = loc->m_begin.m_col - 1; + int col = std::max(0, oldCol - 1); auto it = begin; for (int i = 0; i < oldCol; ++i) { if (*it > ASCII) { @@ -558,7 +572,7 @@ private: auto x = statement; if (statement->appendix) { if (auto assignment = assignmentFrom(statement)) { - auto preDefine = getPredefine(transformAssignDefs(assignment->expList)); + auto preDefine = getPredefine(assignment); if (!preDefine.empty()) out.push_back(preDefine + nll(statement)); } auto appendix = statement->appendix.get(); @@ -790,7 +804,7 @@ private: } std::string getDestrucureDefine(ExpListAssign_t* assignment) { - auto info = extractDestructureInfo(assignment); + auto info = extractDestructureInfo(assignment, true); if (!info.first.empty()) { for (const auto& destruct : info.first) { str_list defs; @@ -909,11 +923,10 @@ private: } case "With"_id: { auto withNode = static_cast(value); - str_list temp; auto expList = assignment->expList.get(); std::string preDefine = getPredefine(assignment); - transformWith(withNode, temp, expList); - out.push_back(preDefine + temp.back()); + transformWith(withNode, out, expList); + out.back() = preDefine + out.back(); return; } case "Do"_id: { @@ -940,50 +953,42 @@ private: return; } case "For"_id: { - str_list temp; auto expList = assignment->expList.get(); std::string preDefine = getPredefine(assignment); - transformForInPlace(static_cast(value), temp, expList); - out.push_back(preDefine + temp.back()); + transformForInPlace(static_cast(value), out, expList); + out.back() = preDefine + out.back(); return; } case "ForEach"_id: { - str_list temp; auto expList = assignment->expList.get(); std::string preDefine = getPredefine(assignment); - transformForEachInPlace(static_cast(value), temp, expList); - out.push_back(preDefine + temp.back()); + transformForEachInPlace(static_cast(value), out, expList); + out.back() = preDefine + out.back(); return; } case "ClassDecl"_id: { - str_list temp; auto expList = assignment->expList.get(); std::string preDefine = getPredefine(assignment); - transformClassDecl(static_cast(value), temp, ExpUsage::Assignment, expList); - out.push_back(preDefine + temp.back()); + transformClassDecl(static_cast(value), out, ExpUsage::Assignment, expList); + out.back() = preDefine + out.back(); return; } case "While"_id: { - str_list temp; auto expList = assignment->expList.get(); std::string preDefine = getPredefine(assignment); - transformWhileInPlace(static_cast(value), temp, expList); - out.push_back(preDefine + temp.back()); + transformWhileInPlace(static_cast(value), out, expList); + out.back() = preDefine + out.back(); return; } } auto exp = ast_cast(value); BREAK_IF(!exp); if (auto chainValue = exp->value->item.as()) { - if (isColonChain(chainValue)) { - auto assignable = assignment->expList.get(); - std::string preDefine = getPredefine(transformAssignDefs(assignable)); - transformColonChain(chainValue, out, ExpUsage::Assignment, assignable); - auto nl = preDefine.empty() ? Empty : nll(chainValue); - if (!preDefine.empty()) out.back() = preDefine + nl + out.back(); - return; - } else if (hasKeywordColonChainItem(chainValue)) { - transformChainValue(chainValue, out, ExpUsage::Assignment, assignment->expList); + if (isSpecialChainValue(chainValue)) { + auto expList = assignment->expList.get(); + std::string preDefine = getPredefine(assignment); + transformChainValue(chainValue, out, ExpUsage::Assignment, expList); + out.back() = preDefine + out.back(); return; } } @@ -1169,7 +1174,7 @@ private: } std::pair, ast_ptr> - extractDestructureInfo(ExpListAssign_t* assignment) { + extractDestructureInfo(ExpListAssign_t* assignment, bool varDefOnly = false) { auto x = assignment; std::list destructs; if (!assignment->action.is()) return { destructs, nullptr }; @@ -1187,19 +1192,21 @@ private: while (values.size() < size) values.emplace_back(nullNode); } using iter = node_container::iterator; - std::vector> destructPairs; + std::vector> destructPairs; str_list temp; for (auto i = exprs.begin(), j = values.begin(); i != exprs.end(); ++i, ++j) { auto expr = *i; ast_node* destructNode = expr->getByPath(); if (destructNode || (destructNode = expr->getByPath())) { destructPairs.push_back({i,j}); - pushScope(); - transformAssignItem(*j, temp); - popScope(); auto& destruct = destructs.emplace_back(); - destruct.value = temp.back(); - temp.pop_back(); + if (!varDefOnly) { + pushScope(); + transformAssignItem(*j, temp); + destruct.value = temp.back(); + temp.pop_back(); + popScope(); + } auto pairs = destructFromExp(expr); destruct.items = std::move(pairs); } @@ -1244,7 +1251,7 @@ private: BREAK_IF(!exp); auto var = singleVariableFrom(exp); BREAK_IF(!var.empty()); - auto upVar = getUnusedName("_update_"); + auto upVar = getUnusedName("_update_"sv); auto assignment = x->new_ptr(); assignment->expList.set(toAst(upVar, ExpList, x)); auto assign = x->new_ptr(); @@ -1532,11 +1539,7 @@ private: case "simple_table"_id: transform_simple_table(static_cast(item), out); break; case "ChainValue"_id: { auto chainValue = static_cast(item); - if (isColonChain(chainValue)) { - transformColonChainClosure(chainValue, out); - } else { - transformChainValue(chainValue, out); - } + transformChainValue(chainValue, out); break; } case "String"_id: transformString(static_cast(item), out); break; @@ -1689,7 +1692,7 @@ private: any->decls.push_back(var); } } - auto info = extractDestructureInfo(assignment); + auto info = extractDestructureInfo(assignment, true); if (!info.first.empty()) { for (const auto& destruct : info.first) for (const auto& item : destruct.items) @@ -1803,12 +1806,10 @@ private: } } if (auto chainValue = singleValue->item.as()) { - if (isColonChain(chainValue)) { - transformColonChain(chainValue, out, ExpUsage::Return); - } else { + if (isSpecialChainValue(chainValue)) { transformChainValue(chainValue, out, ExpUsage::Return); + return; } - return; } transformValue(singleValue, out); out.back() = indent() + s("return "sv) + out.back() + nlr(returnNode); @@ -1980,111 +1981,292 @@ private: } } - void transformColonChainClosure(ChainValue_t* chainValue, str_list& out) { - str_list temp; - temp.push_back(s("(function()"sv) + nll(chainValue)); - pushScope(); - transformColonChain(chainValue, temp, ExpUsage::Return); - popScope(); - temp.push_back(indent() + s("end)()"sv)); - out.push_back(join(temp)); + bool transformChainEndWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t*) { + auto x = chainList.front(); + if (ast_cast(chainList.back())) { + auto parens = x->new_ptr(); + { + auto chainValue = x->new_ptr(); + for (auto item : chainList) { + chainValue->items.push_back(item); + } + chainValue->items.pop_back(); + auto value = x->new_ptr(); + value->item.set(chainValue); + auto opValue = x->new_ptr(); + opValue->op.set(toAst("!="sv, BinaryOperator, x)); + opValue->value.set(toAst("nil"sv, Value, x)); + auto exp = x->new_ptr(); + exp->value.set(value); + exp->opValues.push_back(opValue); + parens->expr.set(exp); + } + transformParens(parens, out); + if (usage == ExpUsage::Return) { + out.back().insert(0, indent() + s("return "sv)); + out.back().append(nlr(x)); + } + return true; + } + return false; } - void transformColonChain(ChainValue_t* chainValue, str_list& out, ExpUsage usage = ExpUsage::Common, ExpList_t* expList = nullptr) { - auto x = chainValue; - const auto& chainList = chainValue->items.objects(); - auto baseChain = x->new_ptr(); - switch (chainList.front()->getId()) { - case "DotChainItem"_id: - case "ColonChainItem"_id: - if (_withVars.empty()) { - throw std::logic_error(debugInfo("Short dot/colon syntax must be called within a with block."sv, chainList.front())); - } else { - baseChain->items.push_back(toAst(_withVars.top(), Callable, x)); - } + bool transformChainWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) { + auto opIt = std::find_if(chainList.begin(), chainList.end(), [](ast_node* node) { return ast_is(node); }); + if (opIt != chainList.end()) { + auto x = chainList.front(); + str_list temp; + if (usage == ExpUsage::Closure) { + temp.push_back(s("(function()"sv) + nll(x)); + pushScope(); + } + auto partOne = x->new_ptr(); + for (auto it = chainList.begin();it != opIt;++it) { + partOne->items.push_back(*it); + } + BLOCK_START + auto back = ast_cast(partOne->items.back()); + BREAK_IF(!back); + auto selfName = ast_cast(back->item); + BREAK_IF(!selfName); + if (auto sname = ast_cast(selfName->name)) { + auto colonItem = x->new_ptr(); + colonItem->name.set(sname->name); + partOne->items.pop_back(); + partOne->items.push_back(toAst("@"sv, Callable, x)); + partOne->items.push_back(colonItem); break; - } - auto end = --chainList.end(); - for (auto it = chainList.begin(); it != end; ++it) { - baseChain->items.push_back(*it); - } - auto colonChainItem = static_cast(chainList.back()); - auto funcName = toString(colonChainItem->name); - if (usage != ExpUsage::Return) pushScope(); - auto baseVar = getUnusedName("_base_"sv); - auto fnVar = getUnusedName("_fn_"sv); - str_list temp; - { - auto value = x->new_ptr(); - value->item.set(baseChain); - auto exp = x->new_ptr(); - exp->value.set(value); - auto assign = x->new_ptr(); - assign->values.push_back(exp); - auto assignment = x->new_ptr(); - assignment->expList.set(toAst(baseVar, ExpList, x)); - assignment->action.set(assign); - transformAssignment(assignment, temp); - } - { - auto assign = x->new_ptr(); - assign->values.push_back(toAst(baseVar + "." + funcName, Exp, x)); - auto assignment = x->new_ptr(); - assignment->expList.set(toAst(fnVar, ExpList, x)); - assignment->action.set(assign); - transformAssignment(assignment, temp); - } - auto funLit = toAst(s("(...)-> "sv) + fnVar + s(" "sv) + baseVar + s(", ..."sv), Exp, x); - switch (usage) { - case ExpUsage::Return: - transformExp(funLit, temp); - _buf << temp.front(); - _buf << *(++temp.begin()); - _buf << indent() << "return " << temp.back() << nll(chainValue); + } + if (auto cname = ast_cast(selfName->name)) { + auto colonItem = x->new_ptr(); + colonItem->name.set(cname->name); + partOne->items.pop_back(); + partOne->items.push_back(toAst("@@"sv, Callable, x)); + partOne->items.push_back(colonItem); break; - case ExpUsage::Assignment: { + } + BLOCK_END + auto objVar = singleVariableFrom(partOne); + if (objVar.empty()) { + objVar = getUnusedName("_obj_"sv); + if (auto colonItem = ast_cast(partOne->items.back())) { + auto chainValue = x->new_ptr(); + chainValue->items.dup(partOne->items); + chainValue->items.pop_back(); + if (chainValue->items.empty()) { + if (_withVars.empty()) { + throw std::logic_error(debugInfo("Short dot/colon syntax must be called within a with block."sv, x)); + } + chainValue->items.push_back(toAst(_withVars.top(), Callable, x)); + } + auto newObj = singleVariableFrom(chainValue); + if (!newObj.empty()) { + objVar = newObj; + } else { + auto value = x->new_ptr(); + value->item.set(chainValue); + auto exp = x->new_ptr(); + exp->value.set(value); + auto assign = x->new_ptr(); + assign->values.push_back(exp); + auto expListAssign = x->new_ptr(); + expListAssign->expList.set(toAst(objVar, ExpList, x)); + expListAssign->action.set(assign); + transformAssignment(expListAssign, temp); + } + auto dotItem = x->new_ptr(); + auto name = colonItem->name.get(); + if (auto keyword = ast_cast(name)) { + name = keyword->name.get(); + } + dotItem->name.set(name); + partOne->items.clear(); + partOne->items.push_back(toAst(objVar, Callable, x)); + partOne->items.push_back(dotItem); + auto it = opIt; ++it; + if (it != chainList.end() && ast_is(*it)) { + + if (auto invoke = ast_cast(*it)) { + invoke->args.push_front(toAst(objVar, Exp, x)); + } else { + auto invokeArgs = static_cast(*it); + invokeArgs->args.push_front(toAst(objVar, Exp, x)); + } + } + objVar = getUnusedName("_obj_"sv); + } + auto value = x->new_ptr(); + value->item.set(partOne); + auto exp = x->new_ptr(); + exp->value.set(value); + auto assign = x->new_ptr(); + assign->values.push_back(exp); + auto expListAssign = x->new_ptr(); + expListAssign->expList.set(toAst(objVar, ExpList, x)); + expListAssign->action.set(assign); + transformAssignment(expListAssign, temp); + } + _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); + temp.push_back(clearBuf()); + pushScope(); + auto partTwo = x->new_ptr(); + partTwo->items.push_back(toAst(objVar, Callable, x)); + for (auto it = ++opIt;it != chainList.end();++it) { + partTwo->items.push_back(*it); + } + switch (usage) { + case ExpUsage::Common: + transformChainValue(partTwo, temp, ExpUsage::Common); + break; + case ExpUsage::Assignment: { + auto value = x->new_ptr(); + value->item.set(partTwo); + auto exp = x->new_ptr(); + exp->value.set(value); + auto assign = x->new_ptr(); + assign->values.push_back(exp); + auto assignment = x->new_ptr(); + assignment->expList.set(assignList); + assignment->action.set(assign); + transformAssignment(assignment, temp); + break; + } + case ExpUsage::Return: + case ExpUsage::Closure: { + auto value = x->new_ptr(); + value->item.set(partTwo); + auto exp = x->new_ptr(); + exp->value.set(value); + auto ret = x->new_ptr(); + auto expListLow = x->new_ptr(); + expListLow->exprs.push_back(exp); + ret->valueList.set(expListLow); + transformReturn(ret, temp); + break; + } + } + popScope(); + temp.push_back(indent() + s("end"sv) + nlr(x)); + switch (usage) { + case ExpUsage::Return: + temp.push_back(indent() + s("return nil"sv) + nlr(x)); + break; + case ExpUsage::Closure: + temp.push_back(indent() + s("return nil"sv) + nlr(x)); + popScope(); + temp.push_back(indent() + s("end)()"sv)); + break; + default: + break; + } + out.push_back(join(temp)); + return true; + } + return false; + } + + bool transformChainEndWithColonItem(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) { + if (ast_is(chainList.back())) { + auto x = chainList.front(); + str_list temp; + switch (usage) { + case ExpUsage::Assignment: + temp.push_back(indent() + s("do"sv) + nll(x)); + pushScope(); + break; + case ExpUsage::Closure: + temp.push_back(s("(function()"sv) + nll(x)); + pushScope(); + break; + default: + break; + } + auto baseChain = x->new_ptr(); + switch (chainList.front()->getId()) { + case "DotChainItem"_id: + case "ColonChainItem"_id: + if (_withVars.empty()) { + throw std::logic_error(debugInfo("Short dot/colon syntax must be called within a with block."sv, chainList.front())); + } else { + baseChain->items.push_back(toAst(_withVars.top(), Callable, x)); + } + break; + } + auto end = --chainList.end(); + for (auto it = chainList.begin(); it != end; ++it) { + baseChain->items.push_back(*it); + } + auto colonChainItem = static_cast(chainList.back()); + auto funcName = toString(colonChainItem->name); + auto baseVar = getUnusedName("_base_"sv); + auto fnVar = getUnusedName("_fn_"sv); + { + auto value = x->new_ptr(); + value->item.set(baseChain); + auto exp = x->new_ptr(); + exp->value.set(value); auto assign = x->new_ptr(); - assign->values.push_back(funLit); + assign->values.push_back(exp); auto assignment = x->new_ptr(); - assignment->expList.set(expList); + assignment->expList.set(toAst(baseVar, ExpList, x)); assignment->action.set(assign); transformAssignment(assignment, temp); - _buf << indent(-1) << "do"sv << nll(chainValue); - _buf << temp.front(); - _buf << *(++temp.begin()); - _buf << temp.back(); - popScope(); - _buf << indent() << "end"sv << nll(chainValue); - break; } - case ExpUsage::Common: { + { auto assign = x->new_ptr(); - assign->values.push_back(funLit); + assign->values.push_back(toAst(baseVar + "." + funcName, Exp, x)); auto assignment = x->new_ptr(); - assignment->expList.set(toAst("_"sv, ExpList, x)); + assignment->expList.set(toAst(fnVar, ExpList, x)); assignment->action.set(assign); transformAssignment(assignment, temp); - _buf << indent(-1) << "do"sv << nll(chainValue); - _buf << temp.front(); - _buf << *(++temp.begin()); - _buf << temp.back(); - popScope(); - _buf << indent() << "end"sv << nll(chainValue); - break; } - default: break; + auto funLit = toAst(s("(...)-> "sv) + fnVar + s(" "sv) + baseVar + s(", ..."sv), Exp, x); + switch (usage) { + case ExpUsage::Closure: + case ExpUsage::Return: + transformExp(funLit, temp); + _buf << temp.front(); + _buf << *(++temp.begin()); + _buf << indent() << "return " << temp.back() << nll(x); + break; + case ExpUsage::Assignment: { + auto assign = x->new_ptr(); + assign->values.push_back(funLit); + auto assignment = x->new_ptr(); + assignment->expList.set(assignList); + assignment->action.set(assign); + transformAssignment(assignment, temp); + break; + } + default: + break; + } + switch (usage) { + case ExpUsage::Assignment: + popScope(); + temp.push_back(indent() + s("end"sv) + nlr(x)); + break; + case ExpUsage::Closure: + popScope(); + temp.push_back(indent() + s("end)()"sv)); + break; + default: + break; + } + out.push_back(join(temp)); + return true; } - out.push_back(clearBuf()); + return false; } void transformChainList(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { auto x = chainList.front(); str_list temp; - switch (chainList.front()->getId()) { + switch (x->getId()) { case "DotChainItem"_id: case "ColonChainItem"_id: if (_withVars.empty()) { - throw std::logic_error(debugInfo("Short dot/colon syntax must be called within a with block."sv, chainList.front())); + throw std::logic_error(debugInfo("Short dot/colon syntax must be called within a with block."sv, x)); } else { temp.push_back(_withVars.top()); } @@ -2101,8 +2283,20 @@ private: break; case "ColonChainItem"_id: { auto colonItem = static_cast(item); - auto next = it; ++next; + auto current = it; + auto next = current; ++next; auto followItem = next != chainList.end() ? *next : nullptr; + if (current != chainList.begin()) { + --current; + if (!ast_is(*current)) { + ++current; + } + } + if (ast_is(followItem)) { + ++next; + followItem = next != chainList.end() ? *next : nullptr; + --next; + } if (!ast_is(followItem)) { throw std::logic_error(debugInfo("Colon chain item must be followed by invoke arguments."sv, colonItem)); } @@ -2117,7 +2311,7 @@ private: chainValue->items.push_back(toAst(_withVars.top(), Callable, x)); break; } - for (auto i = chainList.begin(); i != it; ++i) { + for (auto i = chainList.begin(); i != current; ++i) { chainValue->items.push_back(*i); } auto value = x->new_ptr(); @@ -2141,6 +2335,9 @@ private: auto name = toString(colonItem->name); auto chainValue = x->new_ptr(); chainValue->items.push_back(toAst(callVar, Callable, x)); + if (ast_is(*current)) { + chainValue->items.push_back(x->new_ptr()); + } chainValue->items.push_back(toAst(s("\""sv) + name + s("\""sv), Exp, x)); if (auto invoke = ast_cast(followItem)) { invoke->args.push_front(toAst(callVar, Exp, x)); @@ -2148,8 +2345,7 @@ private: auto invokeArgs = static_cast(followItem); invokeArgs->args.push_front(toAst(callVar, Exp, x)); } - chainValue->items.push_back(followItem); - for (auto i = ++next; i != chainList.end(); ++i) { + for (auto i = next; i != chainList.end(); ++i) { chainValue->items.push_back(*i); } auto value = x->new_ptr(); @@ -2244,7 +2440,17 @@ private: } void transformChainValue(ChainValue_t* chainValue, str_list& out, ExpUsage usage = ExpUsage::Closure, ExpList_t* assignList = nullptr) { - transformChainList(chainValue->items.objects(), out, usage, assignList); + const auto& chainList = chainValue->items.objects(); + if (transformChainEndWithEOP(chainList, out, usage, assignList)) { + return; + } + if (transformChainWithEOP(chainList, out, usage, assignList)) { + return; + } + if (transformChainEndWithColonItem(chainList, out, usage, assignList)) { + return; + } + transformChainList(chainList, out, usage, assignList); } void transformAssignableChain(AssignableChain_t* chain, str_list& out) { @@ -2957,7 +3163,7 @@ private: if (auto assignment = assignmentFrom(statement)) { auto names = transformAssignDefs(assignment->expList.get()); varDefs.insert(varDefs.end(), names.begin(), names.end()); - auto info = extractDestructureInfo(assignment); + auto info = extractDestructureInfo(assignment, true); if (!info.first.empty()) { for (const auto& destruct : info.first) for (const auto& item : destruct.items) @@ -3342,7 +3548,7 @@ private: if (!names.empty()) { return traversal::Stop; } - auto info = extractDestructureInfo(assignment); + auto info = extractDestructureInfo(assignment, true); if (!info.first.empty()) { for (const auto& destruct : info.first) for (const auto& item : destruct.items) diff --git a/src/MoonP/moon_parser.cpp b/src/MoonP/moon_parser.cpp index 1005463..7cc4129 100644 --- a/src/MoonP/moon_parser.cpp +++ b/src/MoonP/moon_parser.cpp @@ -289,9 +289,9 @@ extern rule Value; rule exp_op_value = Space >> BinaryOperator >> *SpaceBreak >> Value; rule Exp = Value >> *exp_op_value; -extern rule Chain, Callable, InvokeArgs; +extern rule Chain, Callable, InvokeArgs, existential_op; -rule ChainValue = Seperator >> (Chain | Callable) >> -InvokeArgs; +rule ChainValue = Seperator >> (Chain | Callable) >> -existential_op >> -InvokeArgs; extern rule KeyValue, String, SimpleValue; @@ -345,9 +345,10 @@ rule FnArgs = (symx('(') >> *SpaceBreak >> -FnArgsExpList >> *SpaceBreak >> sym( extern rule ChainItems, DotChainItem, ColonChain; -rule chain_call = (Callable | String) >> ChainItems; +rule existential_op = expr('?'); +rule chain_call = (Callable | String) >> -existential_op >> ChainItems; rule chain_item = and_(set(".\\")) >> ChainItems; -rule chain_dot_chain = DotChainItem >> -ChainItems; +rule chain_dot_chain = DotChainItem >> -existential_op >> -ChainItems; rule Chain = chain_call | chain_item | Space >> (chain_dot_chain | ColonChain); @@ -362,11 +363,11 @@ rule ChainItems = chain_with_colon | ColonChain; extern rule Invoke, Slice; rule Index = symx('[') >> Exp >> sym(']'); -rule ChainItem = Invoke | DotChainItem | Slice | Index; +rule ChainItem = Invoke >> -existential_op | DotChainItem >> -existential_op | Slice | Index >> -existential_op; rule DotChainItem = symx('.') >> Name; rule ColonChainItem = symx('\\') >> (LuaKeyword | Name); -rule invoke_chain = Invoke >> -ChainItems; -rule ColonChain = ColonChainItem >> -invoke_chain; +rule invoke_chain = Invoke >> -existential_op >> -ChainItems; +rule ColonChain = ColonChainItem >> -existential_op >> -invoke_chain; rule default_value = true_(); rule Slice = diff --git a/src/moonc.cpp b/src/moonc.cpp index 02d5275..4498bee 100644 --- a/src/moonc.cpp +++ b/src/moonc.cpp @@ -22,14 +22,13 @@ int main(int narg, const char** args) { " -p Write output to standard out\n" " -b Dump compile time (doesn't write output)\n" " -l Write line numbers from source codes\n" -" -a Allow expression list not in the end of body block\n" -" -s Use space over tab\n" " -v Print version\n"; if (narg == 0) { std::cout << help; return 0; } MoonP::MoonConfig config; + config.reserveLineNumber = false; bool writeToFile = true; bool dumpCompileTime = false; std::string targetPath; @@ -37,18 +36,9 @@ int main(int narg, const char** args) { std::list files; for (int i = 1; i < narg; ++i) { switch (hash(args[i])) { - case "-a"_id: - config.allowExprNotInTheEndOfBody = true; - break; - case "-s"_id: - config.spaceOverTab = true; - break; case "-l"_id: config.reserveLineNumber = true; break; - case "-r"_id: - config.reuseVariable = true; - break; case "-p"_id: writeToFile = false; break; -- cgit v1.2.3-55-g6feb