aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2022-07-12 17:41:19 +0800
committerLi Jin <dragon-fly@qq.com>2022-07-12 17:41:19 +0800
commit68e167e9f0b90968ea67b7f21fdc50a48d129173 (patch)
tree64612476c7cc5636d7a9eea68ea1e5b449bb9732 /src
parent1a7c8e3c38fcf0af94ca799a3cd9fa7c4ef1bf08 (diff)
downloadyuescript-68e167e9f0b90968ea67b7f21fdc50a48d129173.tar.gz
yuescript-68e167e9f0b90968ea67b7f21fdc50a48d129173.tar.bz2
yuescript-68e167e9f0b90968ea67b7f21fdc50a48d129173.zip
add table pattern matching syntax and fix issue #93, remove a confusing default value syntax for destructuring.
Diffstat (limited to 'src')
-rwxr-xr-xsrc/yuescript/yue_ast.h8
-rwxr-xr-xsrc/yuescript/yue_compiler.cpp615
-rwxr-xr-xsrc/yuescript/yue_parser.cpp9
-rwxr-xr-xsrc/yuescript/yue_parser.h2
4 files changed, 374 insertions, 260 deletions
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h
index 571c18e..05ac5ef 100755
--- a/src/yuescript/yue_ast.h
+++ b/src/yuescript/yue_ast.h
@@ -249,8 +249,14 @@ AST_NODE(With)
249 AST_MEMBER(With, &eop, &valueList, &assigns, &body) 249 AST_MEMBER(With, &eop, &valueList, &assigns, &body)
250AST_END(With, "with"sv) 250AST_END(With, "with"sv)
251 251
252AST_NODE(SwitchList)
253 ast_ptr<true, Seperator_t> sep;
254 ast_list<true, Exp_t> exprs;
255 AST_MEMBER(SwitchList, &sep, &exprs)
256AST_END(SwitchList, "switch_list"sv)
257
252AST_NODE(SwitchCase) 258AST_NODE(SwitchCase)
253 ast_ptr<true, ExpList_t> valueList; 259 ast_ptr<true, SwitchList_t> valueList;
254 ast_sel<true, Block_t, Statement_t> body; 260 ast_sel<true, Block_t, Statement_t> body;
255 AST_MEMBER(SwitchCase, &valueList, &body) 261 AST_MEMBER(SwitchCase, &valueList, &body)
256AST_END(SwitchCase, "switch_case"sv) 262AST_END(SwitchCase, "switch_case"sv)
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index 84cbf37..468dc23 100755
--- a/src/yuescript/yue_compiler.cpp
+++ b/src/yuescript/yue_compiler.cpp
@@ -56,7 +56,7 @@ using namespace parserlib;
56 56
57typedef std::list<std::string> str_list; 57typedef std::list<std::string> str_list;
58 58
59const std::string_view version = "0.12.0"sv; 59const std::string_view version = "0.13.0"sv;
60const std::string_view extension = "yue"sv; 60const std::string_view extension = "yue"sv;
61 61
62class YueCompilerImpl { 62class YueCompilerImpl {
@@ -283,15 +283,15 @@ private:
283 }; 283 };
284 284
285 struct DestructItem { 285 struct DestructItem {
286 bool isVariable = false; 286 ast_ptr<true, Exp_t> target;
287 std::string name; 287 std::string targetVar;
288 std::string structure; 288 std::string structure;
289 ast_ptr<true, Exp_t> defVal; 289 ast_ptr<true, Exp_t> defVal;
290 bool isMetatable = false;
291 }; 290 };
292 291
293 struct Destructure { 292 struct Destructure {
294 std::string value; 293 ast_ptr<true, ast_node> value;
294 std::string valueVar;
295 std::list<DestructItem> items; 295 std::list<DestructItem> items;
296 }; 296 };
297 297
@@ -562,6 +562,13 @@ private:
562 } 562 }
563 break; 563 break;
564 } 564 }
565 case id<SwitchList_t>(): {
566 auto expList = static_cast<SwitchList_t*>(item);
567 if (expList->exprs.size() == 1) {
568 exp = static_cast<Exp_t*>(expList->exprs.front());
569 }
570 break;
571 }
565 case id<unary_exp_t>(): { 572 case id<unary_exp_t>(): {
566 auto unary = static_cast<unary_exp_t*>(item); 573 auto unary = static_cast<unary_exp_t*>(item);
567 if (unary->expos.size() == 1) { 574 if (unary->expos.size() == 1) {
@@ -800,7 +807,7 @@ private:
800 return Empty; 807 return Empty;
801 } 808 }
802 809
803 std::string singleVariableFrom(ast_node* expList) { 810 std::string singleVariableFrom(ast_node* expList, bool accessing) {
804 if (!ast_is<Exp_t, ExpList_t>(expList)) return Empty; 811 if (!ast_is<Exp_t, ExpList_t>(expList)) return Empty;
805 BLOCK_START 812 BLOCK_START
806 auto value = singleValueFrom(expList); 813 auto value = singleValueFrom(expList);
@@ -809,9 +816,16 @@ private:
809 BREAK_IF(!chainValue); 816 BREAK_IF(!chainValue);
810 BREAK_IF(chainValue->items.size() != 1); 817 BREAK_IF(chainValue->items.size() != 1);
811 auto callable = ast_cast<Callable_t>(chainValue->items.front()); 818 auto callable = ast_cast<Callable_t>(chainValue->items.front());
812 BREAK_IF(!callable || !(callable->item.is<Variable_t>() || callable->getByPath<SelfName_t,self_t>())); 819 BREAK_IF(!callable || !(callable->item.is<Variable_t>() || callable->getByPath<SelfName_t, self_t>()));
813 str_list tmp; 820 str_list tmp;
814 transformCallable(callable, tmp); 821 if (accessing) {
822 transformCallable(callable, tmp);
823 } else {
824 bool lintGlobal = _config.lintGlobalVariable;
825 _config.lintGlobalVariable = false;
826 transformCallable(callable, tmp);
827 _config.lintGlobalVariable = lintGlobal;
828 }
815 return tmp.back(); 829 return tmp.back();
816 BLOCK_END 830 BLOCK_END
817 return Empty; 831 return Empty;
@@ -1173,7 +1187,7 @@ private:
1173 _config.lintGlobalVariable = false; 1187 _config.lintGlobalVariable = false;
1174 if (!assignment->action.is<Assign_t>()) return vars; 1188 if (!assignment->action.is<Assign_t>()) return vars;
1175 for (auto exp : assignment->expList->exprs.objects()) { 1189 for (auto exp : assignment->expList->exprs.objects()) {
1176 auto var = singleVariableFrom(exp); 1190 auto var = singleVariableFrom(exp, true);
1177 vars.push_back(var.empty() ? Empty : var); 1191 vars.push_back(var.empty() ? Empty : var);
1178 } 1192 }
1179 _config.lintGlobalVariable = lintGlobal; 1193 _config.lintGlobalVariable = lintGlobal;
@@ -1185,7 +1199,7 @@ private:
1185 bool lintGlobal = _config.lintGlobalVariable; 1199 bool lintGlobal = _config.lintGlobalVariable;
1186 _config.lintGlobalVariable = false; 1200 _config.lintGlobalVariable = false;
1187 for (auto exp : with->valueList->exprs.objects()) { 1201 for (auto exp : with->valueList->exprs.objects()) {
1188 auto var = singleVariableFrom(exp); 1202 auto var = singleVariableFrom(exp, true);
1189 vars.push_back(var.empty() ? Empty : var); 1203 vars.push_back(var.empty() ? Empty : var);
1190 } 1204 }
1191 _config.lintGlobalVariable = lintGlobal; 1205 _config.lintGlobalVariable = lintGlobal;
@@ -1241,13 +1255,15 @@ private:
1241 } 1255 }
1242 1256
1243 std::string getDestrucureDefine(ExpListAssign_t* assignment) { 1257 std::string getDestrucureDefine(ExpListAssign_t* assignment) {
1244 auto info = extractDestructureInfo(assignment, true); 1258 auto info = extractDestructureInfo(assignment, true, false);
1245 if (!info.first.empty()) { 1259 if (!info.first.empty()) {
1246 for (const auto& destruct : info.first) { 1260 for (const auto& destruct : info.first) {
1247 str_list defs; 1261 str_list defs;
1248 for (const auto& item : destruct.items) { 1262 for (const auto& item : destruct.items) {
1249 if (item.isVariable && addToScope(item.name)) { 1263 if (!item.targetVar.empty()) {
1250 defs.push_back(item.name); 1264 if (addToScope(item.targetVar)) {
1265 defs.push_back(item.targetVar);
1266 }
1251 } 1267 }
1252 } 1268 }
1253 if (!defs.empty()) _buf << indent() << "local "sv << join(defs,", "sv); 1269 if (!defs.empty()) _buf << indent() << "local "sv << join(defs,", "sv);
@@ -1282,7 +1298,18 @@ private:
1282 return nullptr; 1298 return nullptr;
1283 } 1299 }
1284 1300
1285 void transformAssignment(ExpListAssign_t* assignment, str_list& out) { 1301 ast_ptr<false, ExpListAssign_t> assignmentFrom(Exp_t* target, ast_node* value, ast_node* x) {
1302 auto assignment = x->new_ptr<ExpListAssign_t>();
1303 auto assignList = x->new_ptr<ExpList_t>();
1304 assignList->exprs.push_back(target);
1305 assignment->expList.set(assignList);
1306 auto assign = x->new_ptr<Assign_t>();
1307 assign->values.push_back(value);
1308 assignment->action.set(assign);
1309 return assignment;
1310 }
1311
1312 void transformAssignment(ExpListAssign_t* assignment, str_list& out, bool optionalDestruct = false) {
1286 checkAssignable(assignment->expList); 1313 checkAssignable(assignment->expList);
1287 BLOCK_START 1314 BLOCK_START
1288 auto assign = ast_cast<Assign_t>(assignment->action); 1315 auto assign = ast_cast<Assign_t>(assignment->action);
@@ -1516,7 +1543,7 @@ private:
1516 } 1543 }
1517 } 1544 }
1518 BLOCK_END 1545 BLOCK_END
1519 auto info = extractDestructureInfo(assignment, false); 1546 auto info = extractDestructureInfo(assignment, false, optionalDestruct);
1520 if (info.first.empty()) { 1547 if (info.first.empty()) {
1521 transformAssignmentCommon(assignment, out); 1548 transformAssignmentCommon(assignment, out);
1522 } else { 1549 } else {
@@ -1524,126 +1551,165 @@ private:
1524 if (info.second) { 1551 if (info.second) {
1525 transformAssignmentCommon(info.second, temp); 1552 transformAssignmentCommon(info.second, temp);
1526 } 1553 }
1554 auto x = assignment;
1527 for (auto& destruct : info.first) { 1555 for (auto& destruct : info.first) {
1528 std::list<std::pair<std::string, std::string>> leftPairs; 1556 std::list<std::pair<ast_ptr<true, Exp_t>, ast_ptr<true, Exp_t>>> leftPairs;
1557 bool extraScope = false;
1529 if (destruct.items.size() == 1) { 1558 if (destruct.items.size() == 1) {
1530 auto& pair = destruct.items.front(); 1559 auto& pair = destruct.items.front();
1531 if (!pair.isVariable && pair.defVal) { 1560 if (pair.targetVar.empty() && pair.defVal) {
1532 auto objVar = getUnusedName("_obj_"sv); 1561 extraScope = true;
1533 leftPairs.push_back({pair.name, objVar}); 1562 auto objVar = getUnusedName("_tmp_"sv);
1534 pair.name = objVar; 1563 auto objExp = toAst<Exp_t>(objVar, pair.target);
1535 pair.isVariable = true; 1564 leftPairs.push_back({pair.target, objExp.get()});
1536 } 1565 pair.target.set(objExp);
1537 if (pair.isMetatable) { 1566 pair.targetVar = objVar;
1538 if (pair.isVariable) { 1567 } else if (auto val = singleValueFrom(destruct.value); val->item.is<ChainValue_t>()) {
1539 checkConst(pair.name, assignment); 1568 auto chainValue = static_cast<ChainValue_t*>(val->item.get());
1540 if (addToScope(pair.name)) { 1569 int added = 0;
1541 _buf << indent() << "local "sv << pair.name << nll(assignment); 1570 if (!pair.structure.empty()) {
1571 auto appendChain = toAst<ChainValue_t>("x"s + pair.structure, x);
1572 appendChain->items.pop_front();
1573 for (auto item : appendChain->items.objects()) {
1574 chainValue->items.push_back(item);
1575 added++;
1542 } 1576 }
1543 } 1577 }
1544 bool isLocalValue = isLocal(destruct.value); 1578 auto newAssignment = assignmentFrom(pair.target, destruct.value, x);
1545 std::string objVar; 1579 transformAssignment(newAssignment, temp);
1546 if (isLocalValue) { 1580 while (added > 0) {
1547 objVar = destruct.value; 1581 chainValue->items.pop_back();
1548 } else { 1582 added--;
1549 _buf << indent() << "do"sv << nll(assignment);
1550 pushScope();
1551 objVar = getUnusedName("_obj_"sv);
1552 addToScope(objVar);
1553 _buf << indent() << "local "sv << objVar << " = "sv << destruct.value << nll(assignment);
1554 temp.push_back(clearBuf());
1555 } 1583 }
1556 auto valueExp = toAst<Exp_t>(objVar + pair.structure, assignment); 1584 if (pair.defVal) {
1557 transformExp(valueExp, temp, ExpUsage::Closure); 1585 auto stmt = toAst<Statement_t>(pair.targetVar + "=nil if "s + pair.targetVar + "==nil", pair.defVal);
1558 _buf << indent() << pair.name << " = "sv << temp.back() << nll(assignment); 1586 auto defAssign = stmt->content.as<ExpListAssign_t>();
1559 if (!isLocalValue) { 1587 auto assign = defAssign->action.as<Assign_t>();
1560 popScope(); 1588 assign->values.clear();
1561 _buf << indent() << "end"sv << nlr(assignment); 1589 assign->values.push_back(pair.defVal);
1590 transformStatement(stmt, temp);
1562 } 1591 }
1563 temp.back() = clearBuf(); 1592 continue;
1564 } else {
1565 _buf << indent();
1566 if (pair.isVariable) {
1567 checkConst(pair.name, assignment);
1568 if (addToScope(pair.name)) _buf << "local "sv;
1569 }
1570 _buf << pair.name << " = "sv << destruct.value << pair.structure << nll(assignment);
1571 temp.push_back(clearBuf());
1572 } 1593 }
1573 } else if (_parser.match<Name_t>(destruct.value) && isLocal(destruct.value)) { 1594 if (extraScope) {
1574 str_list defs, names, values; 1595 temp.push_back(indent() + "do"s + nll(x));
1575 bool isMetatable = false; 1596 pushScope();
1576 for (auto& item : destruct.items) { 1597 }
1577 if (item.isVariable) { 1598 if (!pair.targetVar.empty()) {
1578 checkConst(item.name, assignment); 1599 checkConst(pair.targetVar, x);
1579 if (addToScope(item.name)) defs.push_back(item.name); 1600 if (addToScope(pair.targetVar)) {
1580 } else if (item.defVal) { 1601 _buf << indent() << "local "sv << pair.targetVar << nll(x);
1581 auto objVar = getUnusedName("_obj_"sv); 1602 temp.push_back(clearBuf());
1582 addToScope(objVar);
1583 defs.push_back(objVar);
1584 leftPairs.push_back({item.name, objVar});
1585 item.name = objVar;
1586 } 1603 }
1587 if (item.isMetatable) isMetatable = true;
1588 names.push_back(item.name);
1589 values.push_back(item.structure);
1590 } 1604 }
1591 for (auto& v : values) v.insert(0, destruct.value); 1605 bool isLocalValue = isLocal(destruct.valueVar);
1592 if (isMetatable) { 1606 std::string objVar;
1593 auto newExpList = toAst<ExpList_t>(join(values, ","sv), assignment); 1607 if (isLocalValue) {
1594 transformExpList(newExpList, temp); 1608 objVar = destruct.valueVar;
1595 } else { 1609 } else {
1596 temp.push_back(join(values, ", "sv)); 1610 temp.push_back(indent() + "do"s + nll(x));
1611 pushScope();
1612 objVar = getUnusedName("_obj_"sv);
1613 auto newAssignment = assignmentFrom(toAst<Exp_t>(objVar, x), destruct.value, x);
1614 transformAssignment(newAssignment, temp);
1597 } 1615 }
1598 if (defs.empty()) { 1616 auto valueExp = toAst<Exp_t>(objVar + pair.structure, x);
1599 _buf << indent() << join(names, ", "sv) << " = "sv << temp.back() << nll(assignment); 1617 auto newAssignment = assignmentFrom(pair.target, valueExp, x);
1600 } else { 1618 transformAssignment(newAssignment, temp);
1601 _buf << indent() << "local "sv; 1619 if (!isLocalValue) {
1602 if (defs.size() != names.size()) { 1620 popScope();
1603 _buf << join(defs, ", "sv) << nll(assignment) << indent(); 1621 _buf << indent() << "end"sv << nlr(x);
1604 } 1622 temp.push_back(clearBuf());
1605 _buf << join(names, ", "sv) << " = "sv << temp.back() << nll(assignment);
1606 } 1623 }
1607 temp.back() = clearBuf();
1608 } else { 1624 } else {
1609 str_list defs, names, values; 1625 str_list values, defs;
1610 bool isMetatable = false; 1626 std::list<Exp_t*> names;
1627 pushScope();
1611 for (auto& item : destruct.items) { 1628 for (auto& item : destruct.items) {
1612 if (item.isVariable) { 1629 if (!item.targetVar.empty()) {
1613 checkConst(item.name, assignment); 1630 if (!isDefined(item.targetVar)) {
1614 if (addToScope(item.name)) defs.push_back(item.name); 1631 defs.push_back(item.targetVar);
1632 }
1615 } else if (item.defVal) { 1633 } else if (item.defVal) {
1616 auto objVar = getUnusedName("_obj_"sv); 1634 extraScope = true;
1635 auto objVar = getUnusedName("_tmp_"sv);
1617 addToScope(objVar); 1636 addToScope(objVar);
1618 defs.push_back(objVar); 1637 auto objExp = toAst<Exp_t>(objVar, item.target);
1619 leftPairs.push_back({item.name, objVar}); 1638 leftPairs.push_back({item.target, objExp.get()});
1620 item.name = objVar; 1639 item.target.set(objExp);
1640 item.targetVar = objVar;
1621 } 1641 }
1622 if (item.isMetatable) isMetatable = true; 1642 names.push_back(item.target);
1623 names.push_back(item.name);
1624 values.push_back(item.structure); 1643 values.push_back(item.structure);
1625 } 1644 }
1626 if (!defs.empty()) _buf << indent() << "local "sv << join(defs,", "sv) << nll(assignment); 1645 popScope();
1627 _buf << indent() << "do"sv << nll(assignment); 1646 if (_parser.match<Name_t>(destruct.valueVar) && isLocal(destruct.valueVar)) {
1628 pushScope(); 1647 for (auto& v : values) {
1629 auto objVar = getUnusedName("_obj_"sv); 1648 v.insert(0, destruct.valueVar);
1630 addToScope(objVar); 1649 }
1631 for (auto& v : values) v.insert(0, objVar); 1650 if (extraScope) {
1632 if (isMetatable) { 1651 if (!defs.empty()) {
1633 auto newExpList = toAst<ExpList_t>(join(values, ","sv), assignment); 1652 for (const auto& def : defs) {
1634 transformExpList(newExpList, temp); 1653 checkConst(def, x);
1654 addToScope(def);
1655 }
1656 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nll(x));
1657 }
1658 temp.push_back(indent() + "do"s + nll(x));
1659 pushScope();
1660 }
1635 } else { 1661 } else {
1636 temp.push_back(join(values, ", "sv)); 1662 if (!defs.empty()) {
1663 for (const auto& def : defs) {
1664 checkConst(def, x);
1665 addToScope(def);
1666 }
1667 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nll(x));
1668 }
1669 extraScope = true;
1670 temp.push_back(indent() + "do"s + nll(x));
1671 pushScope();
1672 auto valVar = getUnusedName("_obj_"sv);
1673 auto targetVar = toAst<Exp_t>(valVar, destruct.value);
1674 auto newAssignment = assignmentFrom(targetVar, destruct.value, destruct.value);
1675 transformAssignment(newAssignment, temp);
1676 for (auto& v : values) {
1677 v.insert(0, valVar);
1678 }
1679 }
1680 if (optionalDestruct) {
1681 while (!names.empty()) {
1682 auto name = names.front();
1683 names.pop_front();
1684 auto value = values.front();
1685 values.pop_front();
1686 auto valueList = toAst<ExpList_t>(value, x);
1687 auto newAssignment = x->new_ptr<ExpListAssign_t>();
1688 auto assignList = x->new_ptr<ExpList_t>();
1689 assignList->exprs.push_back(name);
1690 newAssignment->expList.set(assignList);
1691 auto assign = x->new_ptr<Assign_t>();
1692 assign->values.dup(valueList->exprs);
1693 newAssignment->action.set(assign);
1694 transformAssignment(newAssignment, temp);
1695 }
1696 } else {
1697 auto valueList = toAst<ExpList_t>(join(values, ","sv), x);
1698 auto newAssignment = x->new_ptr<ExpListAssign_t>();
1699 auto assignList = x->new_ptr<ExpList_t>();
1700 for (auto name : names) {
1701 assignList->exprs.push_back(name);
1702 }
1703 newAssignment->expList.set(assignList);
1704 auto assign = x->new_ptr<Assign_t>();
1705 assign->values.dup(valueList->exprs);
1706 newAssignment->action.set(assign);
1707 transformAssignment(newAssignment, temp);
1637 } 1708 }
1638 _buf << indent() << "local "sv << objVar << " = "sv << destruct.value << nll(assignment);
1639 _buf << indent() << join(names, ", "sv) << " = "sv << temp.back() << nll(assignment);
1640 popScope();
1641 _buf << indent() << "end"sv << nll(assignment);
1642 temp.back() = clearBuf();
1643 } 1709 }
1644 for (const auto& item : destruct.items) { 1710 for (const auto& item : destruct.items) {
1645 if (item.defVal) { 1711 if (item.defVal) {
1646 auto stmt = toAst<Statement_t>(item.name + "=nil if "s + item.name + "==nil", item.defVal); 1712 auto stmt = toAst<Statement_t>(item.targetVar + "=nil if "s + item.targetVar + "==nil", item.defVal);
1647 auto defAssign = stmt->content.as<ExpListAssign_t>(); 1713 auto defAssign = stmt->content.as<ExpListAssign_t>();
1648 auto assign = defAssign->action.as<Assign_t>(); 1714 auto assign = defAssign->action.as<Assign_t>();
1649 assign->values.clear(); 1715 assign->values.clear();
@@ -1652,9 +1718,14 @@ private:
1652 } 1718 }
1653 } 1719 }
1654 for (const auto& item : leftPairs) { 1720 for (const auto& item : leftPairs) {
1655 _buf << indent() << item.first << " = "sv << item.second << nll(assignment); 1721 auto newAssignment = assignmentFrom(item.first, item.second, x);
1722 transformAssignment(newAssignment, temp);
1723 }
1724 if (extraScope) {
1725 popScope();
1726 _buf << indent() << "end"sv << nlr(x);
1727 temp.push_back(clearBuf());
1656 } 1728 }
1657 temp.push_back(clearBuf());
1658 } 1729 }
1659 out.push_back(join(temp)); 1730 out.push_back(join(temp));
1660 } 1731 }
@@ -1671,8 +1742,9 @@ private:
1671 } 1742 }
1672 } 1743 }
1673 1744
1674 std::list<DestructItem> destructFromExp(ast_node* node) { 1745 std::list<DestructItem> destructFromExp(ast_node* node, bool optional) {
1675 const node_container* tableItems = nullptr; 1746 const node_container* tableItems = nullptr;
1747 auto sep = optional ? "?"s : Empty;
1676 switch (node->getId()) { 1748 switch (node->getId()) {
1677 case id<Exp_t>(): { 1749 case id<Exp_t>(): {
1678 auto item = singleValueFrom(node)->item.get(); 1750 auto item = singleValueFrom(node)->item.get();
@@ -1713,27 +1785,18 @@ private:
1713 auto item = value->item.get(); 1785 auto item = value->item.get();
1714 if (ast_is<simple_table_t>(item) || 1786 if (ast_is<simple_table_t>(item) ||
1715 item->getByPath<TableLit_t>()) { 1787 item->getByPath<TableLit_t>()) {
1716 auto subPairs = destructFromExp(pair); 1788 auto subPairs = destructFromExp(pair, optional);
1717 for (auto& p : subPairs) { 1789 for (auto& p : subPairs) {
1718 pairs.push_back({p.isVariable, p.name, 1790 pairs.push_back({p.target, p.targetVar,
1719 '[' + std::to_string(index) + ']' + p.structure, 1791 '[' + std::to_string(index) + ']' + sep + p.structure,
1720 p.defVal, p.isMetatable}); 1792 p.defVal});
1721 } 1793 }
1722 } else { 1794 } else {
1723 bool lintGlobal = _config.lintGlobalVariable;
1724 _config.lintGlobalVariable = false;
1725 auto exp = static_cast<Exp_t*>(pair); 1795 auto exp = static_cast<Exp_t*>(pair);
1726 auto varName = singleVariableFrom(exp); 1796 auto varName = singleVariableFrom(exp, false);
1727 if (varName == "_"sv) break; 1797 if (varName == "_"sv) break;
1728 bool isVariable = !varName.empty();
1729 if (!isVariable) {
1730 str_list temp;
1731 transformExp(exp, temp, ExpUsage::Closure);
1732 varName = std::move(temp.back());
1733 }
1734 _config.lintGlobalVariable = lintGlobal;
1735 pairs.push_back({ 1798 pairs.push_back({
1736 isVariable, 1799 exp,
1737 varName, 1800 varName,
1738 '[' + std::to_string(index) + ']', 1801 '[' + std::to_string(index) + ']',
1739 nullptr 1802 nullptr
@@ -1744,11 +1807,7 @@ private:
1744 case id<variable_pair_t>(): { 1807 case id<variable_pair_t>(): {
1745 auto vp = static_cast<variable_pair_t*>(pair); 1808 auto vp = static_cast<variable_pair_t*>(pair);
1746 auto name = _parser.toString(vp->name); 1809 auto name = _parser.toString(vp->name);
1747 if (LuaKeywords.find(name) != LuaKeywords.end()) { 1810 pairs.push_back({toAst<Exp_t>(name, vp).get(), name, '.' + name, nullptr});
1748 pairs.push_back({true, name, "[\""s + name + "\"]"s, nullptr});
1749 } else {
1750 pairs.push_back({true, name, '.' + name, nullptr});
1751 }
1752 break; 1811 break;
1753 } 1812 }
1754 case id<normal_pair_t>(): { 1813 case id<normal_pair_t>(): {
@@ -1769,29 +1828,19 @@ private:
1769 auto item = singleValueFrom(exp)->item.get(); 1828 auto item = singleValueFrom(exp)->item.get();
1770 if (ast_is<simple_table_t>(item) || 1829 if (ast_is<simple_table_t>(item) ||
1771 item->getByPath<TableLit_t>()) { 1830 item->getByPath<TableLit_t>()) {
1772 auto subPairs = destructFromExp(exp); 1831 auto subPairs = destructFromExp(exp, optional);
1773 for (auto& p : subPairs) { 1832 for (auto& p : subPairs) {
1774 pairs.push_back({ 1833 pairs.push_back({
1775 p.isVariable, 1834 p.target,
1776 p.name, 1835 p.targetVar,
1777 keyName + p.structure, 1836 keyName + sep + p.structure,
1778 p.defVal, 1837 p.defVal
1779 p.isMetatable
1780 }); 1838 });
1781 } 1839 }
1782 } else { 1840 } else {
1783 bool lintGlobal = _config.lintGlobalVariable; 1841 auto varName = singleVariableFrom(exp, false);
1784 _config.lintGlobalVariable = false;
1785 auto varName = singleVariableFrom(exp);
1786 bool isVariable = !varName.empty();
1787 if (!isVariable) {
1788 str_list temp;
1789 transformExp(exp, temp, ExpUsage::Closure);
1790 varName = std::move(temp.back());
1791 }
1792 _config.lintGlobalVariable = lintGlobal;
1793 pairs.push_back({ 1842 pairs.push_back({
1794 isVariable, 1843 exp,
1795 varName, 1844 varName,
1796 keyName, 1845 keyName,
1797 nullptr 1846 nullptr
@@ -1800,14 +1849,13 @@ private:
1800 break; 1849 break;
1801 } 1850 }
1802 if (np->value.is<TableBlock_t>()) { 1851 if (np->value.is<TableBlock_t>()) {
1803 auto subPairs = destructFromExp(np->value); 1852 auto subPairs = destructFromExp(np->value, optional);
1804 for (auto& p : subPairs) { 1853 for (auto& p : subPairs) {
1805 pairs.push_back({ 1854 pairs.push_back({
1806 p.isVariable, 1855 p.target,
1807 p.name, 1856 p.targetVar,
1808 keyName + p.structure, 1857 keyName + sep + p.structure,
1809 p.defVal, 1858 p.defVal
1810 p.isMetatable
1811 }); 1859 });
1812 } 1860 }
1813 } 1861 }
@@ -1816,14 +1864,13 @@ private:
1816 case id<TableBlockIndent_t>(): { 1864 case id<TableBlockIndent_t>(): {
1817 auto tb = static_cast<TableBlockIndent_t*>(pair); 1865 auto tb = static_cast<TableBlockIndent_t*>(pair);
1818 ++index; 1866 ++index;
1819 auto subPairs = destructFromExp(tb); 1867 auto subPairs = destructFromExp(tb, optional);
1820 for (auto& p : subPairs) { 1868 for (auto& p : subPairs) {
1821 pairs.push_back({ 1869 pairs.push_back({
1822 p.isVariable, 1870 p.target,
1823 p.name, 1871 p.targetVar,
1824 '[' + std::to_string(index) + ']' + p.structure, 1872 '[' + std::to_string(index) + ']' + sep + p.structure,
1825 p.defVal, 1873 p.defVal
1826 p.isMetatable
1827 }); 1874 });
1828 } 1875 }
1829 break; 1876 break;
@@ -1841,18 +1888,9 @@ private:
1841 item->getByPath<TableLit_t>()) { 1888 item->getByPath<TableLit_t>()) {
1842 throw std::logic_error(_info.errorMessage("invalid use of default value"sv, dp->defVal)); 1889 throw std::logic_error(_info.errorMessage("invalid use of default value"sv, dp->defVal));
1843 } else { 1890 } else {
1844 bool lintGlobal = _config.lintGlobalVariable; 1891 auto varName = singleVariableFrom(exp, false);
1845 _config.lintGlobalVariable = false;
1846 auto varName = singleVariableFrom(exp);
1847 bool isVariable = !varName.empty();
1848 if (!isVariable) {
1849 str_list temp;
1850 transformExp(exp, temp, ExpUsage::Closure);
1851 varName = std::move(temp.back());
1852 }
1853 _config.lintGlobalVariable = lintGlobal;
1854 pairs.push_back({ 1892 pairs.push_back({
1855 isVariable, 1893 exp,
1856 varName, 1894 varName,
1857 '[' + std::to_string(index) + ']', 1895 '[' + std::to_string(index) + ']',
1858 dp->defVal 1896 dp->defVal
@@ -1872,27 +1910,18 @@ private:
1872 keyName = "."s + keyName; 1910 keyName = "."s + keyName;
1873 } 1911 }
1874 } 1912 }
1875 if (auto exp = dp->value.as<Exp_t>()) { 1913 if (auto exp = dp->value.get()) {
1876 if (!isAssignable(exp)) throw std::logic_error(_info.errorMessage("can't destructure value"sv, exp)); 1914 if (!isAssignable(exp)) throw std::logic_error(_info.errorMessage("can't destructure value"sv, exp));
1877 bool lintGlobal = _config.lintGlobalVariable; 1915 auto varName = singleVariableFrom(exp, false);
1878 _config.lintGlobalVariable = false;
1879 auto varName = singleVariableFrom(exp);
1880 bool isVariable = !varName.empty();
1881 if (!isVariable) {
1882 str_list temp;
1883 transformExp(exp, temp, ExpUsage::Closure);
1884 varName = std::move(temp.back());
1885 }
1886 _config.lintGlobalVariable = lintGlobal;
1887 pairs.push_back({ 1916 pairs.push_back({
1888 isVariable, 1917 exp,
1889 varName, 1918 varName,
1890 keyName, 1919 keyName,
1891 dp->defVal 1920 dp->defVal
1892 }); 1921 });
1893 } else { 1922 } else {
1894 pairs.push_back({ 1923 pairs.push_back({
1895 true, 1924 toAst<Exp_t>(valueStr, dp).get(),
1896 valueStr, 1925 valueStr,
1897 keyName, 1926 keyName,
1898 dp->defVal 1927 dp->defVal
@@ -1910,8 +1939,7 @@ private:
1910 newPair->key.set(newKey); 1939 newPair->key.set(newKey);
1911 if (newPair->value) { 1940 if (newPair->value) {
1912 newPair->value.set(mp->value); 1941 newPair->value.set(mp->value);
1913 } 1942 } else {
1914 else {
1915 newPair->value.set(toAst<Exp_t>(key, mp->key)); 1943 newPair->value.set(toAst<Exp_t>(key, mp->key));
1916 } 1944 }
1917 } else { 1945 } else {
@@ -1959,14 +1987,13 @@ private:
1959 simpleValue->value.set(subMetaDestruct); 1987 simpleValue->value.set(subMetaDestruct);
1960 auto value = subMetaDestruct->new_ptr<Value_t>(); 1988 auto value = subMetaDestruct->new_ptr<Value_t>();
1961 value->item.set(simpleValue); 1989 value->item.set(simpleValue);
1962 auto subPairs = destructFromExp(newExp(value, subMetaDestruct)); 1990 auto subPairs = destructFromExp(newExp(value, subMetaDestruct), optional);
1963 for (const auto& p : subPairs) { 1991 for (const auto& p : subPairs) {
1964 pairs.push_back({ 1992 pairs.push_back({
1965 p.isVariable, 1993 p.target,
1966 p.name, 1994 p.targetVar,
1967 ".#"s + p.structure, 1995 ".#"s + sep + p.structure,
1968 p.defVal, 1996 p.defVal
1969 true
1970 }); 1997 });
1971 } 1998 }
1972 } 1999 }
@@ -1974,7 +2001,7 @@ private:
1974 } 2001 }
1975 2002
1976 std::pair<std::list<Destructure>, ast_ptr<false, ExpListAssign_t>> 2003 std::pair<std::list<Destructure>, ast_ptr<false, ExpListAssign_t>>
1977 extractDestructureInfo(ExpListAssign_t* assignment, bool varDefOnly) { 2004 extractDestructureInfo(ExpListAssign_t* assignment, bool varDefOnly, bool optional) {
1978 auto x = assignment; 2005 auto x = assignment;
1979 std::list<Destructure> destructs; 2006 std::list<Destructure> destructs;
1980 if (!assignment->action.is<Assign_t>()) return {destructs, nullptr}; 2007 if (!assignment->action.is<Assign_t>()) return {destructs, nullptr};
@@ -1993,10 +2020,10 @@ private:
1993 while (values.size() < size) values.emplace_back(nullNode); 2020 while (values.size() < size) values.emplace_back(nullNode);
1994 } 2021 }
1995 using iter = node_container::iterator; 2022 using iter = node_container::iterator;
1996 std::vector<std::pair<iter,iter>> destructPairs; 2023 std::vector<std::pair<iter, iter>> destructPairs;
1997 ast_list<false, ast_node> valueItems; 2024 ast_list<false, ast_node> valueItems;
1998 if (!varDefOnly) pushScope();
1999 str_list temp; 2025 str_list temp;
2026 pushScope();
2000 for (auto i = exprs.begin(), j = values.begin(); i != exprs.end(); ++i, ++j) { 2027 for (auto i = exprs.begin(), j = values.begin(); i != exprs.end(); ++i, ++j) {
2001 auto expr = *i; 2028 auto expr = *i;
2002 auto value = singleValueFrom(expr); 2029 auto value = singleValueFrom(expr);
@@ -2019,7 +2046,7 @@ private:
2019 } else { 2046 } else {
2020 throw std::logic_error(_info.errorMessage("can not destructure a nil value"sv, destructNode)); 2047 throw std::logic_error(_info.errorMessage("can not destructure a nil value"sv, destructNode));
2021 } 2048 }
2022 destructPairs.push_back({i,j}); 2049 destructPairs.push_back({i, j});
2023 auto subDestruct = destructNode->new_ptr<TableLit_t>(); 2050 auto subDestruct = destructNode->new_ptr<TableLit_t>();
2024 auto subMetaDestruct = destructNode->new_ptr<TableLit_t>(); 2051 auto subMetaDestruct = destructNode->new_ptr<TableLit_t>();
2025 const node_container* dlist = nullptr; 2052 const node_container* dlist = nullptr;
@@ -2103,15 +2130,14 @@ private:
2103 if (!tab->values.empty()) { 2130 if (!tab->values.empty()) {
2104 auto& destruct = destructs.emplace_back(); 2131 auto& destruct = destructs.emplace_back();
2105 if (!varDefOnly) { 2132 if (!varDefOnly) {
2106 transformAssignItem(valueItems.back(), temp); 2133 destruct.value = valueItems.back();
2107 destruct.value = std::move(temp.back()); 2134 destruct.valueVar = singleVariableFrom(destruct.value, false);
2108 temp.pop_back();
2109 } 2135 }
2110 auto simpleValue = tab->new_ptr<SimpleValue_t>(); 2136 auto simpleValue = tab->new_ptr<SimpleValue_t>();
2111 simpleValue->value.set(tab); 2137 simpleValue->value.set(tab);
2112 auto value = tab->new_ptr<Value_t>(); 2138 auto value = tab->new_ptr<Value_t>();
2113 value->item.set(simpleValue); 2139 value->item.set(simpleValue);
2114 auto pairs = destructFromExp(newExp(value, expr)); 2140 auto pairs = destructFromExp(newExp(value, expr), optional);
2115 if (pairs.empty()) { 2141 if (pairs.empty()) {
2116 throw std::logic_error(_info.errorMessage("expect items to be destructured"sv, tab)); 2142 throw std::logic_error(_info.errorMessage("expect items to be destructured"sv, tab));
2117 } 2143 }
@@ -2122,18 +2148,34 @@ private:
2122 item.structure.clear(); 2148 item.structure.clear();
2123 } 2149 }
2124 } else if (tab == subMetaDestruct.get()) { 2150 } else if (tab == subMetaDestruct.get()) {
2125 destruct.value.insert(0, globalVar("getmetatable"sv, tab) + '('); 2151 auto p = destruct.value.get();
2126 destruct.value.append(")"sv); 2152 auto chainValue = toAst<ChainValue_t>("getmetatable()", p);
2153 static_cast<Invoke_t*>(chainValue->items.back())->args.push_back(destruct.value);
2154 auto value = p->new_ptr<Value_t>();
2155 value->item.set(chainValue);
2156 auto exp = newExp(value, p);
2157 destruct.value.set(exp);
2158 destruct.valueVar.clear();
2127 } else if (destruct.items.size() == 1 && !singleValueFrom(*j)) { 2159 } else if (destruct.items.size() == 1 && !singleValueFrom(*j)) {
2128 destruct.value.insert(0, "("sv); 2160 auto p = destruct.value.get();
2129 destruct.value.append(")"sv); 2161 auto parens = p->new_ptr<Parens_t>();
2162 parens->expr.set(p);
2163 auto callable = p->new_ptr<Callable_t>();
2164 callable->item.set(parens);
2165 auto chainValue = p->new_ptr<ChainValue_t>();
2166 chainValue->items.push_back(callable);
2167 auto value = p->new_ptr<Value_t>();
2168 value->item.set(chainValue);
2169 auto exp = newExp(value, p);
2170 destruct.value.set(exp);
2171 destruct.valueVar.clear();
2130 } 2172 }
2131 } 2173 }
2132 } 2174 }
2133 } 2175 }
2134 } 2176 }
2135 } 2177 }
2136 if (!varDefOnly) popScope(); 2178 popScope();
2137 for (const auto& p : destructPairs) { 2179 for (const auto& p : destructPairs) {
2138 exprs.erase(p.first); 2180 exprs.erase(p.first);
2139 values.erase(p.second); 2181 values.erase(p.second);
@@ -2211,7 +2253,7 @@ private:
2211 BLOCK_START 2253 BLOCK_START
2212 auto exp = ast_cast<Exp_t>(item); 2254 auto exp = ast_cast<Exp_t>(item);
2213 BREAK_IF(!exp); 2255 BREAK_IF(!exp);
2214 auto var = singleVariableFrom(exp); 2256 auto var = singleVariableFrom(exp, true);
2215 BREAK_IF(!var.empty()); 2257 BREAK_IF(!var.empty());
2216 auto upVar = getUnusedName("_update_"sv); 2258 auto upVar = getUnusedName("_update_"sv);
2217 auto newAssignment = x->new_ptr<ExpListAssign_t>(); 2259 auto newAssignment = x->new_ptr<ExpListAssign_t>();
@@ -2373,15 +2415,12 @@ private:
2373 if (asmt) { 2415 if (asmt) {
2374 ast_ptr<false, ast_node> exp = asmt->expList->exprs.front(); 2416 ast_ptr<false, ast_node> exp = asmt->expList->exprs.front();
2375 auto x = exp; 2417 auto x = exp;
2376 bool lintGlobal = _config.lintGlobalVariable; 2418 auto var = singleVariableFrom(exp, false);
2377 _config.lintGlobalVariable = false;
2378 auto var = singleVariableFrom(exp);
2379 _config.lintGlobalVariable = lintGlobal;
2380 if (var.empty() || isGlobal(var)) { 2419 if (var.empty() || isGlobal(var)) {
2381 storingValue = true; 2420 storingValue = true;
2382 auto desVar = getUnusedName("_des_"sv); 2421 auto desVar = getUnusedName("_des_"sv);
2383 if (asmt->assign->values.objects().size() == 1) { 2422 if (asmt->assign->values.objects().size() == 1) {
2384 auto var = singleVariableFrom(asmt->assign->values.objects().front()); 2423 auto var = singleVariableFrom(asmt->assign->values.objects().front(), true);
2385 if (!var.empty() && isLocal(var)) { 2424 if (!var.empty() && isLocal(var)) {
2386 desVar = var; 2425 desVar = var;
2387 storingValue = false; 2426 storingValue = false;
@@ -2524,10 +2563,7 @@ private:
2524 } 2563 }
2525 bool findPlaceHolder = false; 2564 bool findPlaceHolder = false;
2526 for (auto a : args->objects()) { 2565 for (auto a : args->objects()) {
2527 bool lintGlobal = _config.lintGlobalVariable; 2566 auto name = singleVariableFrom(a, false);
2528 _config.lintGlobalVariable = false;
2529 auto name = singleVariableFrom(a);
2530 _config.lintGlobalVariable = lintGlobal;
2531 if (name == "_"sv) { 2567 if (name == "_"sv) {
2532 if (!findPlaceHolder) { 2568 if (!findPlaceHolder) {
2533 args->swap(a, arg); 2569 args->swap(a, arg);
@@ -2643,7 +2679,7 @@ private:
2643 funcStart = &temp.emplace_back(); 2679 funcStart = &temp.emplace_back();
2644 pushScope(); 2680 pushScope();
2645 } 2681 }
2646 auto objVar = singleVariableFrom(left); 2682 auto objVar = singleVariableFrom(left, true);
2647 auto prepareValue = [&](bool forAssignment = false) { 2683 auto prepareValue = [&](bool forAssignment = false) {
2648 if (objVar.empty() || !isLocal(objVar)) { 2684 if (objVar.empty() || !isLocal(objVar)) {
2649 if (forAssignment) { 2685 if (forAssignment) {
@@ -2953,10 +2989,7 @@ private:
2953 } 2989 }
2954 bool findPlaceHolder = false; 2990 bool findPlaceHolder = false;
2955 for (auto a : args->objects()) { 2991 for (auto a : args->objects()) {
2956 bool lintGlobal = _config.lintGlobalVariable; 2992 auto name = singleVariableFrom(a, false);
2957 _config.lintGlobalVariable = false;
2958 auto name = singleVariableFrom(a);
2959 _config.lintGlobalVariable = lintGlobal;
2960 if (name == "_"sv) { 2993 if (name == "_"sv) {
2961 if (!findPlaceHolder) { 2994 if (!findPlaceHolder) {
2962 args->swap(a, arg); 2995 args->swap(a, arg);
@@ -3040,14 +3073,14 @@ private:
3040 any->decls.push_back(var); 3073 any->decls.push_back(var);
3041 } 3074 }
3042 } 3075 }
3043 auto info = extractDestructureInfo(assignment, true); 3076 auto info = extractDestructureInfo(assignment, true, false);
3044 if (!info.first.empty()) { 3077 if (!info.first.empty()) {
3045 for (const auto& destruct : info.first) 3078 for (const auto& destruct : info.first)
3046 for (const auto& item : destruct.items) 3079 for (const auto& item : destruct.items)
3047 if (item.isVariable) { 3080 if (!item.targetVar.empty()) {
3048 if (std::isupper(item.name[0]) && capital) { capital->decls.push_back(item.name); 3081 if (std::isupper(item.targetVar[0]) && capital) { capital->decls.push_back(item.targetVar);
3049 } else if (any) { 3082 } else if (any) {
3050 any->decls.push_back(item.name); 3083 any->decls.push_back(item.targetVar);
3051 } 3084 }
3052 } 3085 }
3053 } 3086 }
@@ -4043,7 +4076,7 @@ private:
4043 auto value = x->new_ptr<Value_t>(); 4076 auto value = x->new_ptr<Value_t>();
4044 value->item.set(chainValue); 4077 value->item.set(chainValue);
4045 auto exp = newExp(value, x); 4078 auto exp = newExp(value, x);
4046 callVar = singleVariableFrom(exp); 4079 callVar = singleVariableFrom(exp, true);
4047 if (callVar.empty()) { 4080 if (callVar.empty()) {
4048 callVar = getUnusedName("_call_"s); 4081 callVar = getUnusedName("_call_"s);
4049 auto assignment = x->new_ptr<ExpListAssign_t>(); 4082 auto assignment = x->new_ptr<ExpListAssign_t>();
@@ -4672,7 +4705,7 @@ private:
4672 std::string indexVar = getUnusedName("_idx_"sv); 4705 std::string indexVar = getUnusedName("_idx_"sv);
4673 std::string keyVar = getUnusedName("_key_"sv); 4706 std::string keyVar = getUnusedName("_key_"sv);
4674 std::string valueVar = getUnusedName("_value_"sv); 4707 std::string valueVar = getUnusedName("_value_"sv);
4675 auto objVar = singleVariableFrom(spread->exp); 4708 auto objVar = singleVariableFrom(spread->exp, true);
4676 if (objVar.empty()) { 4709 if (objVar.empty()) {
4677 objVar = getUnusedName("_obj_"); 4710 objVar = getUnusedName("_obj_");
4678 auto assignment = toAst<ExpListAssign_t>(objVar + "=nil"s, item); 4711 auto assignment = toAst<ExpListAssign_t>(objVar + "=nil"s, item);
@@ -5146,7 +5179,7 @@ private:
5146 switch (loopTarget->getId()) { 5179 switch (loopTarget->getId()) {
5147 case id<star_exp_t>(): { 5180 case id<star_exp_t>(): {
5148 auto star_exp = static_cast<star_exp_t*>(loopTarget); 5181 auto star_exp = static_cast<star_exp_t*>(loopTarget);
5149 auto listVar = singleVariableFrom(star_exp->value); 5182 auto listVar = singleVariableFrom(star_exp->value, true);
5150 if (!isLocal(listVar)) listVar.clear(); 5183 if (!isLocal(listVar)) listVar.clear();
5151 auto indexVar = getUnusedName("_index_"sv); 5184 auto indexVar = getUnusedName("_index_"sv);
5152 varAfter.push_back(indexVar); 5185 varAfter.push_back(indexVar);
@@ -5816,7 +5849,7 @@ private:
5816 assignItem = std::move(temp.back()); 5849 assignItem = std::move(temp.back());
5817 temp.pop_back(); 5850 temp.pop_back();
5818 } else if (expList) { 5851 } else if (expList) {
5819 auto name = singleVariableFrom(expList); 5852 auto name = singleVariableFrom(expList, true);
5820 if (!name.empty()) { 5853 if (!name.empty()) {
5821 className = '\"' + name + '\"'; 5854 className = '\"' + name + '\"';
5822 } 5855 }
@@ -5834,12 +5867,12 @@ private:
5834 if (auto assignment = assignmentFrom(statement)) { 5867 if (auto assignment = assignmentFrom(statement)) {
5835 auto names = transformAssignDefs(assignment->expList.get(), DefOp::Mark); 5868 auto names = transformAssignDefs(assignment->expList.get(), DefOp::Mark);
5836 varDefs.insert(varDefs.end(), names.begin(), names.end()); 5869 varDefs.insert(varDefs.end(), names.begin(), names.end());
5837 auto info = extractDestructureInfo(assignment, true); 5870 auto info = extractDestructureInfo(assignment, true, false);
5838 if (!info.first.empty()) { 5871 if (!info.first.empty()) {
5839 for (const auto& destruct : info.first) 5872 for (const auto& destruct : info.first)
5840 for (const auto& item : destruct.items) 5873 for (const auto& item : destruct.items)
5841 if (item.isVariable && addToScope(item.name)) 5874 if (!item.targetVar.empty() && addToScope(item.targetVar))
5842 varDefs.push_back(item.name); 5875 varDefs.push_back(item.targetVar);
5843 } 5876 }
5844 BLOCK_START 5877 BLOCK_START
5845 auto assign = assignment->action.as<Assign_t>(); 5878 auto assign = assignment->action.as<Assign_t>();
@@ -6193,7 +6226,7 @@ private:
6193 auto vars = getAssignVars(with); 6226 auto vars = getAssignVars(with);
6194 if (vars.front().empty() || isGlobal(vars.front())) { 6227 if (vars.front().empty() || isGlobal(vars.front())) {
6195 if (with->assigns->values.objects().size() == 1) { 6228 if (with->assigns->values.objects().size() == 1) {
6196 auto var = singleVariableFrom(with->assigns->values.objects().front()); 6229 auto var = singleVariableFrom(with->assigns->values.objects().front(), true);
6197 if (!var.empty() && isLocal(var)) { 6230 if (!var.empty() && isLocal(var)) {
6198 withVar = var; 6231 withVar = var;
6199 } 6232 }
@@ -6239,7 +6272,7 @@ private:
6239 transformAssignment(assignment, temp); 6272 transformAssignment(assignment, temp);
6240 } 6273 }
6241 } else { 6274 } else {
6242 withVar = singleVariableFrom(with->valueList); 6275 withVar = singleVariableFrom(with->valueList, true);
6243 if (withVar.empty() || !isLocal(withVar)) { 6276 if (withVar.empty() || !isLocal(withVar)) {
6244 withVar = getUnusedName("_with_"sv); 6277 withVar = getUnusedName("_with_"sv);
6245 auto assignment = x->new_ptr<ExpListAssign_t>(); 6278 auto assignment = x->new_ptr<ExpListAssign_t>();
@@ -6265,11 +6298,11 @@ private:
6265 if (!names.empty()) { 6298 if (!names.empty()) {
6266 return traversal::Stop; 6299 return traversal::Stop;
6267 } 6300 }
6268 auto info = extractDestructureInfo(assignment, true); 6301 auto info = extractDestructureInfo(assignment, true, false);
6269 if (!info.first.empty()) { 6302 if (!info.first.empty()) {
6270 for (const auto& destruct : info.first) 6303 for (const auto& destruct : info.first)
6271 for (const auto& item : destruct.items) 6304 for (const auto& item : destruct.items)
6272 if (item.isVariable && !isDefined(item.name)) 6305 if (!item.targetVar.empty() && !isDefined(item.targetVar))
6273 return traversal::Stop; 6306 return traversal::Stop;
6274 } 6307 }
6275 BLOCK_START 6308 BLOCK_START
@@ -6417,12 +6450,12 @@ private:
6417 assignment->action.set(exportNode->assign); 6450 assignment->action.set(exportNode->assign);
6418 transformAssignment(assignment, out); 6451 transformAssignment(assignment, out);
6419 str_list names = transformAssignDefs(expList, DefOp::Get); 6452 str_list names = transformAssignDefs(expList, DefOp::Get);
6420 auto info = extractDestructureInfo(assignment, true); 6453 auto info = extractDestructureInfo(assignment, true, false);
6421 if (!info.first.empty()) { 6454 if (!info.first.empty()) {
6422 for (const auto& destruct : info.first) 6455 for (const auto& destruct : info.first)
6423 for (const auto& item : destruct.items) 6456 for (const auto& item : destruct.items)
6424 if (item.isVariable) 6457 if (!item.targetVar.empty())
6425 names.push_back(item.name); 6458 names.push_back(item.targetVar);
6426 } 6459 }
6427 if (_info.exportDefault) { 6460 if (_info.exportDefault) {
6428 out.back().append(indent() + _info.moduleName + " = "s + names.back() + nlr(exportNode)); 6461 out.back().append(indent() + _info.moduleName + " = "s + names.back() + nlr(exportNode));
@@ -6699,7 +6732,7 @@ private:
6699 void transformImportFrom(ImportFrom_t* import, str_list& out) { 6732 void transformImportFrom(ImportFrom_t* import, str_list& out) {
6700 str_list temp; 6733 str_list temp;
6701 auto x = import; 6734 auto x = import;
6702 auto objVar = singleVariableFrom(import->exp); 6735 auto objVar = singleVariableFrom(import->exp, true);
6703 ast_ptr<false, ExpListAssign_t> objAssign; 6736 ast_ptr<false, ExpListAssign_t> objAssign;
6704 if (objVar.empty()) { 6737 if (objVar.empty()) {
6705 objVar = getUnusedName("_obj_"sv); 6738 objVar = getUnusedName("_obj_"sv);
@@ -7065,7 +7098,7 @@ private:
7065 pushScope(); 7098 pushScope();
7066 } 7099 }
7067 bool extraScope = false; 7100 bool extraScope = false;
7068 auto objVar = singleVariableFrom(switchNode->target); 7101 auto objVar = singleVariableFrom(switchNode->target, true);
7069 if (objVar.empty() || !isLocal(objVar)) { 7102 if (objVar.empty() || !isLocal(objVar)) {
7070 if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) { 7103 if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) {
7071 extraScope = true; 7104 extraScope = true;
@@ -7082,24 +7115,89 @@ private:
7082 transformAssignment(assignment, temp); 7115 transformAssignment(assignment, temp);
7083 } 7116 }
7084 const auto& branches = switchNode->branches.objects(); 7117 const auto& branches = switchNode->branches.objects();
7118 int addScope = 0;
7119 bool firstBranch = true;
7120 std::string tabCheckVar;
7085 for (auto branch_ : branches) { 7121 for (auto branch_ : branches) {
7086 auto branch = static_cast<SwitchCase_t*>(branch_); 7122 auto branch = static_cast<SwitchCase_t*>(branch_);
7087 temp.push_back(indent() + (branches.front() == branch ? "if"s : "elseif"s)); 7123 if (auto value = singleValueFrom(branch->valueList);
7088 str_list tmp; 7124 value->item.is<simple_table_t>() ||
7089 const auto& exprs = branch->valueList->exprs.objects(); 7125 value->getByPath<SimpleValue_t, TableLit_t>()) {
7090 for (auto exp_ : exprs) { 7126 if (!firstBranch) {
7091 auto exp = static_cast<Exp_t*>(exp_); 7127 temp.push_back(indent() + "else"s + nll(branch));
7092 transformExp(exp, tmp, ExpUsage::Closure); 7128 pushScope();
7093 if (!singleValueFrom(exp)) { 7129 addScope++;
7094 tmp.back() = '(' + tmp.back() + ')'; 7130 }
7131 if (tabCheckVar.empty()) {
7132 if (!extraScope) {
7133 temp.push_back(indent() + "do"s + nll(branch));
7134 pushScope();
7135 extraScope = true;
7136 }
7137 tabCheckVar = getUnusedName("_tab_");
7138 forceAddToScope(tabCheckVar);
7139 temp.push_back(indent() + "local "s + tabCheckVar + " = \"table\" == "s + globalVar("type", branch) + '(' + objVar + ')' + nll(branch));
7140 }
7141 std::string matchVar;
7142 bool lastBranch = branches.back() == branch_;
7143 if (!lastBranch) {
7144 matchVar = getUnusedName("_match_");
7145 forceAddToScope(matchVar);
7146 temp.push_back(indent() + "local "s + matchVar + " = false"s + nll(branch));
7147 }
7148 temp.back().append(indent() + "if "s + tabCheckVar + " then"s + nll(branch));
7149 pushScope();
7150 auto assignment = assignmentFrom(static_cast<Exp_t*>(branch->valueList->exprs.front()), toAst<Exp_t>(objVar, branch), branch);
7151 auto info = extractDestructureInfo(assignment, true, false);
7152 transformAssignment(assignment, temp, true);
7153 temp.push_back(indent() + "if"s);
7154 bool firstItem = true;
7155 for (const auto& destruct : info.first) {
7156 for (const auto& item : destruct.items) {
7157 str_list tmp;
7158 transformExp(item.target, tmp, ExpUsage::Closure);
7159 temp.back().append((firstItem ? " " : " and "s) + tmp.back() + " ~= nil"s);
7160 if (firstItem) firstItem = false;
7161 }
7162 }
7163 temp.back().append(" then"s + nll(branch));
7164 pushScope();
7165 transform_plain_body(branch->body, temp, usage, assignList);
7166 if (!lastBranch) {
7167 temp.push_back(indent() + matchVar + " = true"s + nll(branch));
7168 }
7169 popScope();
7170 if (!lastBranch) {
7171 temp.push_back(indent() + "end"s + nll(branch));
7172 popScope();
7173 temp.push_back(indent() + "end"s + nll(branch));
7174 temp.push_back(indent() + "if not "s + matchVar + " then"s + nll(branch));
7175 pushScope();
7176 addScope++;
7177 } else {
7178 temp.push_back(indent() + "end"s + nll(branch));
7179 popScope();
7180 }
7181 firstBranch = true;
7182 } else {
7183 temp.push_back(indent() + (firstBranch ? "if"s : "elseif"s));
7184 firstBranch = false;
7185 str_list tmp;
7186 const auto& exprs = branch->valueList->exprs.objects();
7187 for (auto exp_ : exprs) {
7188 auto exp = static_cast<Exp_t*>(exp_);
7189 transformExp(exp, tmp, ExpUsage::Closure);
7190 if (!singleValueFrom(exp)) {
7191 tmp.back() = '(' + tmp.back() + ')';
7192 }
7193 temp.back().append(' ' + tmp.back() + " == "s +
7194 (exp == exprs.back() ? objVar : objVar + " or"s));
7095 } 7195 }
7096 temp.back().append(' ' + tmp.back() + " == "s + 7196 temp.back().append(" then"s + nll(branch));
7097 (exp == exprs.back() ? objVar : objVar + " or"s)); 7197 pushScope();
7198 transform_plain_body(branch->body, temp, usage, assignList);
7199 popScope();
7098 } 7200 }
7099 temp.back().append(" then"s + nll(branch));
7100 pushScope();
7101 transform_plain_body(branch->body, temp, usage, assignList);
7102 popScope();
7103 } 7201 }
7104 if (switchNode->lastBranch) { 7202 if (switchNode->lastBranch) {
7105 temp.push_back(indent() + "else"s + nll(switchNode->lastBranch)); 7203 temp.push_back(indent() + "else"s + nll(switchNode->lastBranch));
@@ -7107,6 +7205,11 @@ private:
7107 transform_plain_body(switchNode->lastBranch, temp, usage, assignList); 7205 transform_plain_body(switchNode->lastBranch, temp, usage, assignList);
7108 popScope(); 7206 popScope();
7109 } 7207 }
7208 while (addScope > 0) {
7209 addScope--;
7210 temp.push_back(indent() + "end"s + nlr(switchNode));
7211 popScope();
7212 }
7110 temp.push_back(indent() + "end"s + nlr(switchNode)); 7213 temp.push_back(indent() + "end"s + nlr(switchNode));
7111 if (usage == ExpUsage::Closure) { 7214 if (usage == ExpUsage::Closure) {
7112 _enableReturn.pop(); 7215 _enableReturn.pop();
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp
index 78b4713..199c0bd 100755
--- a/src/yuescript/yue_parser.cpp
+++ b/src/yuescript/yue_parser.cpp
@@ -225,7 +225,7 @@ YueParser::YueParser() {
225 WithExp = ExpList >> -Assign; 225 WithExp = ExpList >> -Assign;
226 226
227 With = Space >> key("with") >> -existential_op >> disable_do_chain_arg_table_block(WithExp) >> plain_body_with("do"); 227 With = Space >> key("with") >> -existential_op >> disable_do_chain_arg_table_block(WithExp) >> plain_body_with("do");
228 SwitchCase = Space >> key("when") >> disable_chain(disable_arg_table_block(ExpList)) >> plain_body_with("then"); 228 SwitchCase = Space >> key("when") >> disable_chain(disable_arg_table_block(SwitchList)) >> plain_body_with("then");
229 SwitchElse = Space >> key("else") >> plain_body; 229 SwitchElse = Space >> key("else") >> plain_body;
230 230
231 SwitchBlock = *EmptyLine >> 231 SwitchBlock = *EmptyLine >>
@@ -235,6 +235,9 @@ YueParser::YueParser() {
235 -(Break >> *EmptyLine >> CheckIndent >> SwitchElse) >> 235 -(Break >> *EmptyLine >> CheckIndent >> SwitchElse) >>
236 PopIndent; 236 PopIndent;
237 237
238 exp_not_tab = not_(simple_table | TableLit) >> Exp;
239
240 SwitchList = Seperator >> Exp >> *(sym(',') >> exp_not_tab);
238 Switch = Space >> key("switch") >> disable_do(Exp) >> -(Space >> key("do")) 241 Switch = Space >> key("switch") >> disable_do(Exp) >> -(Space >> key("do"))
239 >> -Space >> Break >> SwitchBlock; 242 >> -Space >> Break >> SwitchBlock;
240 243
@@ -550,14 +553,14 @@ YueParser::YueParser() {
550 symx(':') >> not_(':') >> 553 symx(':') >> not_(':') >>
551 (Exp | TableBlock | +SpaceBreak >> Exp); 554 (Exp | TableBlock | +SpaceBreak >> Exp);
552 555
553 default_pair = (sym(':') >> Variable >> not_('#') >> Seperator | KeyName >> symx(':') >> Seperator >> Exp | Exp >> Seperator) >> sym('=') >> Exp; 556 default_pair = (sym(':') >> Variable >> not_('#') >> Seperator | KeyName >> symx(':') >> Seperator >> exp_not_tab | exp_not_tab >> Seperator) >> sym('=') >> Exp;
554 557
555 meta_variable_pair = sym(':') >> Variable >> expr('#'); 558 meta_variable_pair = sym(':') >> Variable >> expr('#');
556 559
557 meta_normal_pair = Space >> -(Name | symx('[') >> not_('[') >> Exp >> sym(']')) >> expr("#:") >> 560 meta_normal_pair = Space >> -(Name | symx('[') >> not_('[') >> Exp >> sym(']')) >> expr("#:") >>
558 (Exp | TableBlock | +(SpaceBreak) >> Exp); 561 (Exp | TableBlock | +(SpaceBreak) >> Exp);
559 562
560 meta_default_pair = (sym(':') >> Variable >> expr('#') >> Seperator | Space >> -Name >> expr("#:") >> Seperator >> Exp) >> sym('=') >> Exp; 563 meta_default_pair = (sym(':') >> Variable >> expr('#') >> Seperator | Space >> -Name >> expr("#:") >> Seperator >> exp_not_tab) >> sym('=') >> Exp;
561 564
562 KeyValue = variable_pair | normal_pair | meta_variable_pair | meta_normal_pair; 565 KeyValue = variable_pair | normal_pair | meta_variable_pair | meta_normal_pair;
563 KeyValueList = KeyValue >> *(sym(',') >> KeyValue); 566 KeyValueList = KeyValue >> *(sym(',') >> KeyValue);
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h
index eea3027..b71a67c 100755
--- a/src/yuescript/yue_parser.h
+++ b/src/yuescript/yue_parser.h
@@ -188,6 +188,7 @@ private:
188 rule pipe_exp; 188 rule pipe_exp;
189 rule expo_value; 189 rule expo_value;
190 rule expo_exp; 190 rule expo_exp;
191 rule exp_not_tab;
191 rule empty_line_stop; 192 rule empty_line_stop;
192 rule Line; 193 rule Line;
193 rule Shebang; 194 rule Shebang;
@@ -230,6 +231,7 @@ private:
230 AST_RULE(ExpList) 231 AST_RULE(ExpList)
231 AST_RULE(Return) 232 AST_RULE(Return)
232 AST_RULE(With) 233 AST_RULE(With)
234 AST_RULE(SwitchList)
233 AST_RULE(SwitchCase) 235 AST_RULE(SwitchCase)
234 AST_RULE(Switch) 236 AST_RULE(Switch)
235 AST_RULE(assignment) 237 AST_RULE(assignment)