From f7150a004e26f446fbf7a47bae368f209248fa67 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Tue, 26 Jul 2022 11:34:34 +0800 Subject: make destructuring work on function multiple returned values, fix `a, b[] = 1` crashing issue, no longer support implicit declaring variable to be nil. --- src/yue.cpp | 8 +- src/yuescript/yue_compiler.cpp | 191 +++++++++++++++++++++++++++++------------ 2 files changed, 141 insertions(+), 58 deletions(-) (limited to 'src') diff --git a/src/yue.cpp b/src/yue.cpp index cb27db8..6011d94 100644 --- a/src/yue.cpp +++ b/src/yue.cpp @@ -446,7 +446,7 @@ int main(int narg, const char** args) { return 0; } if (!resultFile.empty() && files.size() > 1) { - std::cout << "Error: -o can not be used with multiple input files.\n"sv; + std::cout << "Error: -o can not be used with multiple input files\n"sv; std::cout << help; } std::list>> results; @@ -485,7 +485,7 @@ int main(int narg, const char** args) { return std::tuple{0, file.first, buf.str()}; } else { std::ostringstream buf; - buf << "Failed to compile: "sv << file.first << ".\n"sv; + buf << "Failed to compile: "sv << file.first << '\n'; buf << result.error << '\n'; return std::tuple{1, file.first, buf.str()}; } @@ -543,12 +543,12 @@ int main(int narg, const char** args) { } } else { std::ostringstream buf; - buf << "Failed to compile: "sv << file.first << ".\n"; + buf << "Failed to compile: "sv << file.first << '\n'; buf << result.error << '\n'; return std::tuple{1, std::string(), buf.str()}; } } else { - return std::tuple{1, std::string(), "Failed to read file: "s + file.first + ".\n"}; + return std::tuple{1, std::string(), "Failed to read file: "s + file.first + '\n'}; } }); results.push_back(std::move(task)); diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index c10c6fd..2a703d0 100755 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp @@ -54,7 +54,7 @@ namespace yue { typedef std::list str_list; -const std::string_view version = "0.14.0"sv; +const std::string_view version = "0.14.1"sv; const std::string_view extension = "yue"sv; class YueCompilerImpl { @@ -979,8 +979,8 @@ private: auto x = statement; if (statement->appendix) { if (auto assignment = assignmentFrom(statement)) { - auto preDefine = getPredefine(assignment); - if (!preDefine.empty()) out.push_back(preDefine + nll(statement)); + auto preDefine = getPreDefineLine(assignment); + if (!preDefine.empty()) out.push_back(preDefine); } else if (auto local = statement->content.as()) { if (!local->defined) { local->defined = true; @@ -1257,13 +1257,16 @@ private: return defs; } - std::string getPredefine(const str_list& defs) { + std::string toLocalDecl(const str_list& defs) { if (defs.empty()) return Empty; return indent() + "local "s + join(defs, ", "sv); } std::string getDestrucureDefine(ExpListAssign_t* assignment) { auto info = extractDestructureInfo(assignment, true, false); + if (info.assignment) { + _buf << getPreDefineLine(info.assignment); + } if (!info.destructures.empty()) { for (const auto& destruct : info.destructures) { str_list defs; @@ -1280,14 +1283,20 @@ private: return clearBuf(); } - std::string getPredefine(ExpListAssign_t* assignment) { + std::string getPreDefine(ExpListAssign_t* assignment) { auto preDefine = getDestrucureDefine(assignment); if (preDefine.empty()) { - preDefine = getPredefine(transformAssignDefs(assignment->expList, DefOp::Mark)); + preDefine = toLocalDecl(transformAssignDefs(assignment->expList, DefOp::Mark)); } return preDefine; } + std::string getPreDefineLine(ExpListAssign_t* assignment) { + auto preDefine = getPreDefine(assignment); + if (!preDefine.empty()) preDefine += nll(assignment); + return preDefine; + } + ExpList_t* expListFrom(Statement_t* statement) { if (auto expListAssign = statement->content.as()) { if (!expListAssign->action) { @@ -1334,18 +1343,93 @@ private: BLOCK_START auto assign = ast_cast(assignment->action); BREAK_IF(!assign); - if (assignment->expList->exprs.size() < assign->values.size()) { - auto num = assignment->expList->exprs.size(); + auto x = assignment; + const auto& exprs = x->expList->exprs.objects(); + const auto& values = assign->values.objects(); + if (exprs.size() < values.size()) { + auto num = exprs.size(); if (num > 1) { - _buf << "no more than "sv << num << " right values expected, got "sv << assign->values.size(); + _buf << "no more than "sv << num << " right values expected, got "sv << values.size(); } else { - _buf << "only one right value expected, got "sv << assign->values.size(); + _buf << "only one right value expected, got "sv << values.size(); } - throw std::logic_error(_info.errorMessage(clearBuf(), assign->values.front())); + throw std::logic_error(_info.errorMessage(clearBuf(), values.front())); + } + if (exprs.size() > values.size()) { + BLOCK_START + auto value = singleValueFrom(values.back()); + BREAK_IF(!value); + auto chainValue = value->item.as(); + BREAK_IF(!chainValue); + if (!ast_is(chainValue->items.back())) { + _buf << exprs.size() << " right values expected, got "sv << values.size(); + throw std::logic_error(_info.errorMessage(clearBuf(), values.front())); + } + auto newAssign = assign->new_ptr(); + newAssign->values.dup(assign->values); + auto i = exprs.begin(); + auto j = values.begin(); + auto je = --values.end(); + while (j != je) { + ++i; ++j; + } + bool holdItem = false; + for (auto it = i; it != exprs.end(); ++it) { + BLOCK_START + auto value = singleValueFrom(*it); + BREAK_IF(!value); + if (value->item.is() || + value->getByPath()) { + holdItem = true; + break; + } + auto chainValue = value->item.as(); + BREAK_IF(!chainValue); + str_list temp; + if (auto dot = ast_cast(chainValue->items.back())) { + BREAK_IF(!dot->name.is()); + holdItem = true; + } else if (ast_is(chainValue->items.back())) { + holdItem = true; + } + BLOCK_END + if (holdItem) { + break; + } + } + BREAK_IF(!holdItem); + pushScope(); + std::list> extraExprs; + for (; i != exprs.end(); ++i) { + auto var = getUnusedName("_obj_"sv); + addToScope(var); + extraExprs.push_back(toAst(var, *i)); + } + popScope(); + ast_ptr funcCall = values.back(); + assign->values.pop_back(); + auto preAssignment = funcCall->new_ptr(); + auto preAssign = funcCall->new_ptr(); + preAssign->values.push_back(funcCall); + preAssignment->action.set(preAssign); + auto preExplist = funcCall->new_ptr(); + for (const auto& item : extraExprs) { + preExplist->exprs.push_back(item.get()); + assign->values.push_back(item.get()); + } + preAssignment->expList.set(preExplist); + str_list temp; + temp.push_back(getPreDefineLine(assignment)); + temp.push_back(indent() + "do"s + nll(assignment)); + pushScope(); + transformAssignmentCommon(preAssignment, temp); + transformAssignment(assignment, temp); + popScope(); + temp.push_back(indent() + "end"s + nll(assignment)); + out.push_back(join(temp)); + return; + BLOCK_END } - auto x = assignment; - const auto& exprs = assignment->expList->exprs.objects(); - const auto& values = assign->values.objects(); auto vit = values.begin(); for (auto it = exprs.begin(); it != exprs.end(); ++it) { BLOCK_START @@ -1398,7 +1482,11 @@ private: auto newAssignment = x->new_ptr(); newAssignment->expList.set(toAst(varName + "[#"s + varName + "+1]"s, x)); auto assign = x->new_ptr(); - assign->values.push_back(*vit); + if (vit != values.end()) { + assign->values.push_back(*vit); + } else { + assign->values.push_back(toAst("nil"sv, *vit)); + } newAssignment->action.set(assign); transformAssignment(newAssignment, temp); if (isScoped) { @@ -1445,7 +1533,7 @@ private: auto expList = assignment->expList.get(); str_list temp; auto defs = transformAssignDefs(expList, DefOp::Mark); - if (!defs.empty()) temp.push_back(getPredefine(defs) + nll(expList)); + if (!defs.empty()) temp.push_back(toLocalDecl(defs) + nll(expList)); transformIf(static_cast(value), temp, ExpUsage::Assignment, expList); out.push_back(join(temp)); return; @@ -1453,76 +1541,76 @@ private: case id(): { auto switchNode = static_cast(value); auto assignList = assignment->expList.get(); - std::string preDefine = getPredefine(assignment); + std::string preDefine = getPreDefineLine(assignment); transformSwitch(switchNode, out, ExpUsage::Assignment, assignList); - out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment)); + out.back().insert(0, preDefine); return; } case id(): { auto withNode = static_cast(value); auto expList = assignment->expList.get(); - std::string preDefine = getPredefine(assignment); + std::string preDefine = getPreDefineLine(assignment); transformWith(withNode, out, expList); - out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment)); + out.back().insert(0, preDefine); return; } case id(): { auto expList = assignment->expList.get(); auto doNode = static_cast(value); - std::string preDefine = getPredefine(assignment); + std::string preDefine = getPreDefineLine(assignment); transformDo(doNode, out, ExpUsage::Assignment, expList); - out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment)); + out.back().insert(0, preDefine); return; } case id(): { auto expList = assignment->expList.get(); - std::string preDefine = getPredefine(assignment); + std::string preDefine = getPreDefineLine(assignment); transformComprehension(static_cast(value), out, ExpUsage::Assignment, expList); - out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment)); + out.back().insert(0, preDefine); return; } case id(): { auto expList = assignment->expList.get(); - std::string preDefine = getPredefine(assignment); + std::string preDefine = getPreDefineLine(assignment); transformTblComprehension(static_cast(value), out, ExpUsage::Assignment, expList); - out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment)); + out.back().insert(0, preDefine); return; } case id(): { auto expList = assignment->expList.get(); - std::string preDefine = getPredefine(assignment); + std::string preDefine = getPreDefineLine(assignment); transformForInPlace(static_cast(value), out, expList); - out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment)); + out.back().insert(0, preDefine); return; } case id(): { auto expList = assignment->expList.get(); - std::string preDefine = getPredefine(assignment); + std::string preDefine = getPreDefineLine(assignment); transformForEachInPlace(static_cast(value), out, expList); - out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment)); + out.back().insert(0, preDefine); return; } case id(): { auto expList = assignment->expList.get(); - std::string preDefine = getPredefine(assignment); + std::string preDefine = getPreDefineLine(assignment); transformClassDecl(static_cast(value), out, ExpUsage::Assignment, expList); - out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment)); + out.back().insert(0, preDefine); return; } case id(): { auto expList = assignment->expList.get(); - std::string preDefine = getPredefine(assignment); + std::string preDefine = getPreDefineLine(assignment); transformWhileInPlace(static_cast(value), out, expList); - out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment)); + out.back().insert(0, preDefine); return; } case id(): { auto tableLit = static_cast(value); if (hasSpreadExp(tableLit->values.objects())) { auto expList = assignment->expList.get(); - std::string preDefine = getPredefine(assignment); + std::string preDefine = getPreDefineLine(assignment); transformSpreadTable(tableLit->values.objects(), out, ExpUsage::Assignment, expList); - out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment)); + out.back().insert(0, preDefine); return; } } @@ -1530,9 +1618,9 @@ private: auto tableBlock = static_cast(value); if (hasSpreadExp(tableBlock->values.objects())) { auto expList = assignment->expList.get(); - std::string preDefine = getPredefine(assignment); + std::string preDefine = getPreDefineLine(assignment); transformSpreadTable(tableBlock->values.objects(), out, ExpUsage::Assignment, expList); - out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment)); + out.back().insert(0, preDefine); return; } } @@ -1556,9 +1644,9 @@ private: switch (type) { case ChainType::HasEOP: case ChainType::EndWithColon: { - std::string preDefine = getPredefine(assignment); + std::string preDefine = getPreDefineLine(assignment); transformChainValue(chainValue, out, ExpUsage::Assignment, expList); - out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment)); + out.back().insert(0, preDefine); return; } case ChainType::HasKeyword: @@ -2090,8 +2178,6 @@ private: break; } } - } else { - throw std::logic_error(_info.errorMessage("an explicit destructure target required"sv, destructNode)); } destructPairs.push_back({i, j}); auto subDestruct = destructNode->new_ptr(); @@ -2318,17 +2404,17 @@ private: chain->items.dup(tmpChain->items); auto op = _parser.toString(update->op); if (op == "??"sv) { - auto defs = getPredefine(assignment); + auto defs = getPreDefineLine(assignment); + temp.push_back(defs); auto rightExp = x->new_ptr(); rightExp->pipeExprs.dup(leftExp->pipeExprs); rightExp->opValues.dup(leftExp->opValues); rightExp->nilCoalesed.set(update->value); transformNilCoalesedExp(rightExp, temp, ExpUsage::Assignment, assignment->expList, true); - if (!defs.empty()) temp.back().insert(0, defs + nll(x)); out.push_back(join(temp)); return; } - auto defs = getPredefine(assignment); + auto defs = getPreDefine(assignment); transformValue(leftValue, temp); auto left = std::move(temp.back()); temp.pop_back(); @@ -2364,7 +2450,7 @@ private: for (auto value : assign->values.objects()) { transformAssignItem(value, temp); } - std::string preDefine = getPredefine(defs); + std::string preDefine = toLocalDecl(defs); for (const auto& def : defs) { addToScope(def); } @@ -2377,7 +2463,7 @@ private: out.push_back(preDefine + " = "s + join(temp, ", "sv) + nll(assignment)); } } else { - std::string preDefine = getPredefine(defs); + std::string preDefine = toLocalDecl(defs); for (const auto& def : defs) { addToScope(def); } @@ -2779,9 +2865,7 @@ private: bool extraScope = false; if (!nilBranchOnly) { assign->values.push_back(exp); - std::string& predefine = temp.emplace_back(); - auto defs = getPredefine(assignment); - if (!defs.empty()) predefine = defs + nll(x); + temp.push_back(getPreDefineLine(assignment)); extraScope = prepareValue(true); _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); temp.push_back(clearBuf()); @@ -2796,8 +2880,7 @@ private: } else { assign->values.clear(); assign->values.push_back(exp->nilCoalesed); - auto defs = getPredefine(assignment); - if (!defs.empty()) temp.push_back(defs + nll(x)); + temp.push_back(getPreDefineLine(assignment)); transformExp(left, temp, ExpUsage::Closure); _buf << indent() << "if "sv << temp.back() << " == nil then"sv << nll(x); temp.pop_back(); @@ -6891,7 +6974,7 @@ private: } } if (objAssign) { - auto preDef = getPredefine(transformAssignDefs(expList, DefOp::Mark)); + auto preDef = toLocalDecl(transformAssignDefs(expList, DefOp::Mark)); if (!preDef.empty()) { temp.push_back(preDef + nll(import)); } @@ -7350,7 +7433,7 @@ private: defs.push_back(decl); } } - auto preDefine = getPredefine(defs); + auto preDefine = toLocalDecl(defs); if (!preDefine.empty()) { out.push_back(preDefine + nll(local)); } -- cgit v1.2.3-55-g6feb