From 0f5bdeaeba0f04e49c47f4a2be55b14185a7dfdd Mon Sep 17 00:00:00 2001 From: Li Jin Date: Tue, 26 Jul 2022 18:05:23 +0800 Subject: fix missing checks and issues related to destrucuring in if branches. --- src/yuescript/yue_compiler.cpp | 200 +++++++++++++++++++++++------------------ 1 file changed, 114 insertions(+), 86 deletions(-) (limited to 'src') diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 2a703d0..1a44832 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.1"sv; +const std::string_view version = "0.14.2"sv; const std::string_view extension = "yue"sv; class YueCompilerImpl { @@ -1355,13 +1355,31 @@ private: } throw std::logic_error(_info.errorMessage(clearBuf(), values.front())); } + bool checkValuesLater = false; if (exprs.size() > values.size()) { BLOCK_START + switch (values.back()->getId()) { + case id(): + case id(): + checkValuesLater = true; + break; + } + BREAK_IF(checkValuesLater); auto value = singleValueFrom(values.back()); BREAK_IF(!value); + if (auto val = value->item.as()) { + switch (val->value->getId()) { + case id(): + case id(): + case id(): + case id(): + checkValuesLater = true; + break; + } + BREAK_IF(checkValuesLater); + } auto chainValue = value->item.as(); - BREAK_IF(!chainValue); - if (!ast_is(chainValue->items.back())) { + if (!chainValue || !ast_is(chainValue->items.back())) { _buf << exprs.size() << " right values expected, got "sv << values.size(); throw std::logic_error(_info.errorMessage(clearBuf(), values.front())); } @@ -1430,96 +1448,107 @@ private: return; BLOCK_END } - auto vit = values.begin(); - for (auto it = exprs.begin(); it != exprs.end(); ++it) { - BLOCK_START - auto value = singleValueFrom(*it); - BREAK_IF(!value); - auto chainValue = value->item.as(); - BREAK_IF(!chainValue); - str_list temp; - if (auto dot = ast_cast(chainValue->items.back())) { - BREAK_IF(!dot->name.is()); - str_list args; - chainValue->items.pop_back(); - if (chainValue->items.empty()) { - if (_withVars.empty()) { - throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, x)); + if (!checkValuesLater) { + auto vit = values.begin(); + for (auto it = exprs.begin(); it != exprs.end(); ++it) { + BLOCK_START + auto value = singleValueFrom(*it); + BREAK_IF(!value); + auto chainValue = value->item.as(); + BREAK_IF(!chainValue); + str_list temp; + if (auto dot = ast_cast(chainValue->items.back())) { + BREAK_IF(!dot->name.is()); + str_list args; + auto tmpChain = chainValue->new_ptr(); + tmpChain->items.dup(chainValue->items); + tmpChain->items.pop_back(); + if (tmpChain->items.empty()) { + if (_withVars.empty()) { + throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, x)); + } else { + args.push_back(_withVars.top()); + } } else { - args.push_back(_withVars.top()); + auto value = tmpChain->new_ptr(); + value->item.set(tmpChain); + transformExp(newExp(value, tmpChain), args, ExpUsage::Closure); } - } else { - transformExp(static_cast(*it), args, ExpUsage::Closure); - } - if (vit != values.end()) transformAssignItem(*vit, args); - else args.push_back("nil"s); - _buf << indent() << globalVar("setmetatable"sv, x) << '(' << join(args, ", "sv) << ')' << nll(x); - temp.push_back(clearBuf()); - } else if (ast_is(chainValue->items.back())) { - chainValue->items.pop_back(); - if (chainValue->items.empty()) { - if (_withVars.empty()) { - throw std::logic_error(_info.errorMessage("short table appending must be called within a with block"sv, x)); - } else { - chainValue->items.push_back(toAst(_withVars.top(), chainValue)); + if (vit == values.end()) { + throw std::logic_error(_info.errorMessage("right value missing"sv, values.front())); + } + transformAssignItem(*vit, args); + _buf << indent() << globalVar("setmetatable"sv, x) << '(' << join(args, ", "sv) << ')' << nll(x); + temp.push_back(clearBuf()); + } else if (ast_is(chainValue->items.back())) { + auto tmpChain = chainValue->new_ptr(); + tmpChain->items.dup(chainValue->items); + tmpChain->items.pop_back(); + if (tmpChain->items.empty()) { + if (_withVars.empty()) { + throw std::logic_error(_info.errorMessage("short table appending must be called within a with block"sv, x)); + } else { + tmpChain->items.push_back(toAst(_withVars.top(), chainValue)); + } + } + auto varName = singleVariableFrom(tmpChain); + bool isScoped = false; + if (varName.empty() || !isLocal(varName)) { + isScoped = true; + temp.push_back(indent() + "do"s + nll(x)); + pushScope(); + auto objVar = getUnusedName("_obj_"sv); + auto newAssignment = x->new_ptr(); + newAssignment->expList.set(toAst(objVar, x)); + auto assign = x->new_ptr(); + auto value = tmpChain->new_ptr(); + value->item.set(tmpChain); + assign->values.push_back(newExp(value, tmpChain)); + newAssignment->action.set(assign); + transformAssignment(newAssignment, temp); + varName = objVar; } - } - auto varName = singleVariableFrom(chainValue); - bool isScoped = false; - if (varName.empty() || !isLocal(varName)) { - isScoped = true; - temp.push_back(indent() + "do"s + nll(x)); - pushScope(); - auto objVar = getUnusedName("_obj_"sv); auto newAssignment = x->new_ptr(); - newAssignment->expList.set(toAst(objVar, x)); + newAssignment->expList.set(toAst(varName + "[#"s + varName + "+1]"s, x)); auto assign = x->new_ptr(); - assign->values.push_back(*it); + if (vit == values.end()) { + throw std::logic_error(_info.errorMessage("right value missing"sv, values.front())); + } + assign->values.push_back(*vit); newAssignment->action.set(assign); transformAssignment(newAssignment, temp); - varName = objVar; - } + if (isScoped) { + popScope(); + temp.push_back(indent() + "end"s + nlr(x)); + } + } else break; + auto newExpList = x->new_ptr(); + auto newAssign = x->new_ptr(); auto newAssignment = x->new_ptr(); - newAssignment->expList.set(toAst(varName + "[#"s + varName + "+1]"s, x)); - auto assign = x->new_ptr(); - if (vit != values.end()) { - assign->values.push_back(*vit); - } else { - assign->values.push_back(toAst("nil"sv, *vit)); + newAssignment->expList.set(newExpList); + newAssignment->action.set(newAssign); + for (auto exp : exprs) { + if (exp != *it) newExpList->exprs.push_back(exp); } - newAssignment->action.set(assign); - transformAssignment(newAssignment, temp); - if (isScoped) { - popScope(); - temp.push_back(indent() + "end"s + nlr(x)); + for (auto value : values) { + if (value != *vit) newAssign->values.push_back(value); } - } else break; - auto newExpList = x->new_ptr(); - auto newAssign = x->new_ptr(); - auto newAssignment = x->new_ptr(); - newAssignment->expList.set(newExpList); - newAssignment->action.set(newAssign); - for (auto exp : exprs) { - if (exp != *it) newExpList->exprs.push_back(exp); - } - for (auto value : values) { - if (value != *vit) newAssign->values.push_back(value); - } - if (newExpList->exprs.empty() && newAssign->values.empty()) { + if (newExpList->exprs.empty() && newAssign->values.empty()) { + out.push_back(join(temp)); + return; + } + if (newExpList->exprs.size() < newAssign->values.size()) { + auto exp = toAst("_"sv, x); + while (newExpList->exprs.size() < newAssign->values.size()) { + newExpList->exprs.push_back(exp); + } + } + transformAssignment(newAssignment, temp); out.push_back(join(temp)); return; + BLOCK_END + if (vit != values.end()) ++vit; } - if (newExpList->exprs.size() < newAssign->values.size()) { - auto exp = toAst("_"sv, x); - while (newExpList->exprs.size() < newAssign->values.size()) { - newExpList->exprs.push_back(exp); - } - } - transformAssignment(newAssignment, temp); - out.push_back(join(temp)); - return; - BLOCK_END - if (vit != values.end()) ++vit; } BREAK_IF(assign->values.objects().size() != 1); auto value = assign->values.objects().back(); @@ -1530,12 +1559,11 @@ private: } switch (value->getId()) { case id(): { - auto expList = assignment->expList.get(); - str_list temp; - auto defs = transformAssignDefs(expList, DefOp::Mark); - if (!defs.empty()) temp.push_back(toLocalDecl(defs) + nll(expList)); - transformIf(static_cast(value), temp, ExpUsage::Assignment, expList); - out.push_back(join(temp)); + auto ifNode = static_cast(value); + auto assignList = assignment->expList.get(); + std::string preDefine = getPreDefineLine(assignment); + transformIf(ifNode, out, ExpUsage::Assignment, assignList); + out.back().insert(0, preDefine); return; } case id(): { -- cgit v1.2.3-55-g6feb