From 58cf1a70971ad37ef9260aa93851e92fd6e4c1ce Mon Sep 17 00:00:00 2001 From: Li Jin Date: Mon, 21 Nov 2022 16:56:43 +0800 Subject: fix table pattern matching. confirm fixing issue #116. --- spec/outputs/destructure.lua | 33 +++++++++++++++++--------- spec/outputs/switch.lua | 48 ++++++++++++++++++++++++------------- src/yuescript/yue_compiler.cpp | 54 ++++++++++++++++++++++++------------------ src/yuescript/yue_parser.cpp | 17 +++++++------ 4 files changed, 95 insertions(+), 57 deletions(-) diff --git a/spec/outputs/destructure.lua b/spec/outputs/destructure.lua index f40a658..8953a2a 100644 --- a/spec/outputs/destructure.lua +++ b/spec/outputs/destructure.lua @@ -472,7 +472,8 @@ do end do local _exp_0 = tb - local _tab_0 = "table" == type(_exp_0) + local _tab_0 = type(_exp_0) + _tab_0 = "table" == _tab_0 or "userdata" == _tab_0 if _tab_0 then local name, meta_field do @@ -531,14 +532,17 @@ do end do local _exp_0 = tb - local _tab_0 = "table" == type(_exp_0) + local _tab_0 = type(_exp_0) + _tab_0 = "table" == _tab_0 or "userdata" == _tab_0 if _tab_0 then do local _obj_0 = _exp_0.a - if _obj_0 ~= nil then + local _type_0 = type(_obj_0) + if "table" == _type_0 or "userdata" == _type_0 then do local _obj_1 = getmetatable(_obj_0) - if _obj_1 ~= nil then + local _type_1 = type(_obj_1) + if "table" == _type_1 or "userdata" == _type_1 then add = _obj_1.__add end end @@ -546,10 +550,12 @@ do end do local _obj_0 = _exp_0.b - if _obj_0 ~= nil then + local _type_0 = type(_obj_0) + if "table" == _type_0 or "userdata" == _type_0 then do local _obj_1 = getmetatable(_obj_0) - if _obj_1 ~= nil then + local _type_1 = type(_obj_1) + if "table" == _type_1 or "userdata" == _type_1 then field = _obj_1[fieldName] end end @@ -566,15 +572,18 @@ do end do local _exp_0 = tb - local _tab_0 = "table" == type(_exp_0) + local _tab_0 = type(_exp_0) + _tab_0 = "table" == _tab_0 or "userdata" == _tab_0 if _tab_0 then local _obj_0 = _exp_0 do local _obj_1 = _obj_0.c - if _obj_1 ~= nil then + local _type_0 = type(_obj_1) + if "table" == _type_0 or "userdata" == _type_0 then do local _obj_2 = getmetatable(_obj_1) - if _obj_2 ~= nil then + local _type_1 = type(_obj_2) + if "table" == _type_1 or "userdata" == _type_1 then meta_field = _obj_2["abc"] end end @@ -587,13 +596,15 @@ do local _obj_1 = getmetatable(_obj_0) do local _obj_2 = _obj_1[ [[any string]]] - if _obj_2 ~= nil then + local _type_0 = type(_obj_2) + if "table" == _type_0 or "userdata" == _type_0 then abc = _obj_2.d end end do local _obj_2 = _obj_1['str'] - if _obj_2 ~= nil then + local _type_0 = type(_obj_2) + if "table" == _type_0 or "userdata" == _type_0 then def = _obj_2.e end end diff --git a/spec/outputs/switch.lua b/spec/outputs/switch.lua index 4358027..3c48120 100644 --- a/spec/outputs/switch.lua +++ b/spec/outputs/switch.lua @@ -107,37 +107,43 @@ do } } do - local _tab_0 = "table" == type(dict) + local _tab_0 = type(dict) + _tab_0 = "table" == _tab_0 or "userdata" == _tab_0 if _tab_0 then local first = dict[1] local one do local _obj_0 = dict[2] - if _obj_0 ~= nil then + local _type_0 = type(_obj_0) + if "table" == _type_0 or "userdata" == _type_0 then one = _obj_0[1] end end local two do local _obj_0 = dict[2] - if _obj_0 ~= nil then + local _type_0 = type(_obj_0) + if "table" == _type_0 or "userdata" == _type_0 then two = _obj_0[2] end end local three do local _obj_0 = dict[2] - if _obj_0 ~= nil then + local _type_0 = type(_obj_0) + if "table" == _type_0 or "userdata" == _type_0 then three = _obj_0[3] end end local c do local _obj_0 = dict.a - if _obj_0 ~= nil then + local _type_0 = type(_obj_0) + if "table" == _type_0 or "userdata" == _type_0 then do local _obj_1 = _obj_0.b - if _obj_1 ~= nil then + local _type_1 = type(_obj_1) + if "table" == _type_1 or "userdata" == _type_1 then c = _obj_1.c end end @@ -146,10 +152,12 @@ do local z do local _obj_0 = dict.x - if _obj_0 ~= nil then + local _type_0 = type(_obj_0) + if "table" == _type_0 or "userdata" == _type_0 then do local _obj_1 = _obj_0.y - if _obj_1 ~= nil then + local _type_1 = type(_obj_1) + if "table" == _type_1 or "userdata" == _type_1 then z = _obj_1.z end end @@ -176,7 +184,8 @@ do for _index_0 = 1, #items do local item = items[_index_0] do - local _tab_0 = "table" == type(item) + local _tab_0 = type(item) + _tab_0 = "table" == _tab_0 or "userdata" == _tab_0 local _match_0 = false if _tab_0 then local x = item.x @@ -234,7 +243,8 @@ end do local tb = { } do - local _tab_0 = "table" == type(tb) + local _tab_0 = type(tb) + _tab_0 = "table" == _tab_0 or "userdata" == _tab_0 if _tab_0 then local a = tb.a local b = tb.b @@ -248,7 +258,8 @@ do end end do - local _tab_0 = "table" == type(tb) + local _tab_0 = type(tb) + _tab_0 = "table" == _tab_0 or "userdata" == _tab_0 if _tab_0 then local a = tb.a local b = tb.b @@ -261,7 +272,8 @@ do end end do - local _tab_0 = "table" == type(tb) + local _tab_0 = type(tb) + _tab_0 = "table" == _tab_0 or "userdata" == _tab_0 local _match_0 = false if _tab_0 then local a = tb.a @@ -281,7 +293,8 @@ do x = "abc" } do - local _tab_0 = "table" == type(tb) + local _tab_0 = type(tb) + _tab_0 = "table" == _tab_0 or "userdata" == _tab_0 local _match_0 = false if _tab_0 then local x = tb.x @@ -308,7 +321,8 @@ do if 1 == _exp_0 then matched = "1" else - local _tab_0 = "table" == type(_exp_0) + local _tab_0 = type(_exp_0) + _tab_0 = "table" == _tab_0 or "userdata" == _tab_0 local _match_0 = false if _tab_0 then local x = _exp_0.x @@ -333,7 +347,8 @@ do return "invalid" else do - local _tab_0 = "table" == type(_exp_0) + local _tab_0 = type(_exp_0) + _tab_0 = "table" == _tab_0 or "userdata" == _tab_0 local _match_0 = false if _tab_0 then local a = _exp_0.a @@ -367,7 +382,8 @@ end do do local _exp_0 = y - local _tab_0 = "table" == type(_exp_0) + local _tab_0 = type(_exp_0) + _tab_0 = "table" == _tab_0 or "userdata" == _tab_0 if _tab_0 then local mt = (function() local _obj_0 = _exp_0.x diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 066a661..cd91c97 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp @@ -60,7 +60,7 @@ namespace yue { typedef std::list str_list; -const std::string_view version = "0.15.14"sv; +const std::string_view version = "0.15.15"sv; const std::string_view extension = "yue"sv; class YueCompilerImpl { @@ -1806,7 +1806,7 @@ private: case ChainType::EndWithColon: case ChainType::MetaFieldInvocation: { std::string preDefine = getPreDefineLine(assignment); - transformChainValue(chainValue, out, ExpUsage::Assignment, expList); + transformChainValue(chainValue, out, ExpUsage::Assignment, expList, false, optionalDestruct); out.back().insert(0, preDefine); return; } @@ -1850,7 +1850,7 @@ private: newChain->items.dup(pair.structure->items); } auto newAssignment = assignmentFrom(pair.target, newExp(newChain, val->item), x); - transformAssignment(newAssignment, temp); + transformAssignment(newAssignment, temp, optionalDestruct); if (pair.defVal) { bool isNil = false; if (auto v1 = singleValueFrom(pair.defVal)) { @@ -1898,7 +1898,7 @@ private: chain->items.dup(pair.structure->items); auto valueExp = newExp(chain, pair.target); auto newAssignment = assignmentFrom(pair.target, valueExp, x); - transformAssignment(newAssignment, temp); + transformAssignment(newAssignment, temp, optionalDestruct); if (!isLocalValue) { popScope(); _buf << indent() << "end"sv << nlr(x); @@ -1986,7 +1986,7 @@ private: auto assign = x->new_ptr(); assign->values.dup(valueList->exprs); newAssignment->action.set(assign); - transformAssignment(newAssignment, temp); + transformAssignment(newAssignment, temp, true); } } else { auto valueList = x->new_ptr(); @@ -2114,10 +2114,10 @@ private: throw std::logic_error(_info.errorMessage("default value is not supported here"sv, defVal)); } } + auto indexItem = toAst(std::to_string(index), value); for (auto& p : subPairs) { if (sep) p.structure->items.push_front(sep); - p.structure->items.push_front( - toAst(std::to_string(index), p.target)); + p.structure->items.push_front(indexItem); pairs.push_back(p); } } else { @@ -2125,7 +2125,8 @@ private: auto varName = singleVariableFrom(exp, false); if (varName == "_"sv) break; auto chain = exp->new_ptr(); - chain->items.push_back(toAst(std::to_string(index), exp)); + auto indexItem = toAst(std::to_string(index), exp); + chain->items.push_back(indexItem); pairs.push_back({exp, varName, chain, @@ -2229,9 +2230,10 @@ private: auto tb = static_cast(pair); ++index; auto subPairs = destructFromExp(tb, optional); + auto indexItem = toAst(std::to_string(index), tb); for (auto& p : subPairs) { if (sep) p.structure->items.push_front(sep); - p.structure->items.push_front(toAst(std::to_string(index), tb)); + p.structure->items.push_front(indexItem); pairs.push_back(p); } break; @@ -2290,13 +2292,13 @@ private: auto simpleValue = subMetaDestruct->new_ptr(); simpleValue->value.set(subMetaDestruct); auto subPairs = destructFromExp(newExp(simpleValue, subMetaDestruct), optional); + auto mt = simpleValue->new_ptr(); + auto dot = mt->new_ptr(); + dot->name.set(mt); for (const auto& p : subPairs) { if (!p.structure->items.empty()) { if (sep) p.structure->items.push_front(sep); } - auto mt = p.structure->new_ptr(); - auto dot = mt->new_ptr(); - dot->name.set(mt); p.structure->items.push_front(dot); pairs.push_back(p); } @@ -2511,7 +2513,6 @@ private: } } } - popScope(); for (const auto& p : destructPairs) { exprs.erase(p.first); values.erase(p.second); @@ -2529,7 +2530,6 @@ private: newAssignment = newAssign; } if (!varDefOnly) { - pushScope(); for (auto& des : destructs) { for (const auto& item : des.items) { for (auto node : item.structure->items.objects()) { @@ -2552,7 +2552,7 @@ private: auto assignList = des.inlineAssignment->expList.get(); auto assign = des.inlineAssignment->action.to(); auto tmpVar = getUnusedName("_tmp_"sv); - addToScope(tmpVar); + forceAddToScope(tmpVar); auto tmpExp = toAst(tmpVar, exp); assignList->exprs.push_back(tmpExp); auto vExp = exp->new_ptr(); @@ -2571,8 +2571,8 @@ private: } } } - popScope(); } + popScope(); return {std::move(destructs), newAssignment}; } @@ -4098,7 +4098,7 @@ private: return false; } - bool transformChainWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) { + bool transformChainWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList, bool optionalDestruct) { auto opIt = std::find_if(chainList.begin(), chainList.end(), [](ast_node* node) { return ast_is(node); }); if (opIt != chainList.end()) { auto x = chainList.front(); @@ -4185,7 +4185,6 @@ private: auto it = opIt; ++it; if (it != chainList.end() && ast_is(*it)) { - if (auto invoke = ast_cast(*it)) { invoke->args.push_front(toAst(objVar, x)); } else { @@ -4203,7 +4202,15 @@ private: expListAssign->action.set(assign); transformAssignment(expListAssign, temp); } - _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); + if (optionalDestruct) { + auto typeVar = getUnusedName("_type_"sv); + _buf << typeVar << "=type "sv << objVar; + auto typeAssign = toAst(clearBuf(), partOne); + transformAssignment(typeAssign, temp); + _buf << indent() << "if \"table\" == " << typeVar << " or \"userdata\" == "sv << typeVar << " then"sv << nll(x); + } else { + _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); + } temp.push_back(clearBuf()); pushScope(); auto partTwo = x->new_ptr(); @@ -4222,7 +4229,7 @@ private: auto assignment = x->new_ptr(); assignment->expList.set(assignList); assignment->action.set(assign); - transformAssignment(assignment, temp); + transformAssignment(assignment, temp, optionalDestruct); break; } case ExpUsage::Return: @@ -5018,7 +5025,7 @@ private: } #endif // YUE_NO_MACRO - void transformChainValue(ChainValue_t* chainValue, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr, bool allowBlockMacroReturn = false) { + void transformChainValue(ChainValue_t* chainValue, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr, bool allowBlockMacroReturn = false, bool optionalDestruct = false) { if (isMacroChain(chainValue)) { #ifndef YUE_NO_MACRO ast_ptr node; @@ -5072,7 +5079,7 @@ private: if (transformChainEndWithEOP(chainList, out, usage, assignList)) { return; } - if (transformChainWithEOP(chainList, out, usage, assignList)) { + if (transformChainWithEOP(chainList, out, usage, assignList, optionalDestruct)) { return; } if (transformChainWithMetatable(chainList, out, usage, assignList)) { @@ -7837,7 +7844,8 @@ private: } tabCheckVar = getUnusedName("_tab_"); forceAddToScope(tabCheckVar); - temp.push_back(indent() + "local "s + tabCheckVar + " = \"table\" == "s + globalVar("type", branch) + '(' + objVar + ')' + nll(branch)); + temp.push_back(indent() + "local "s + tabCheckVar + " = "s + globalVar("type", branch) + '(' + objVar + ')' + nll(branch)); + temp.push_back(indent() + tabCheckVar + " = \"table\" == "s + tabCheckVar + " or \"userdata\" == "s + tabCheckVar + nll(branch)); } std::string matchVar; bool lastBranch = branches.back() == branch_ && !switchNode->lastBranch; diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index 3f1b9a1..24f821c 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp @@ -242,18 +242,21 @@ YueParser::YueParser() { SwitchCase = Space >> key("when") >> disable_chain(disable_arg_table_block(SwitchList)) >> body_with("then"); SwitchElse = Space >> key("else") >> body; - SwitchBlock = *EmptyLine >> - Advance >> Seperator >> - SwitchCase >> + SwitchBlock = *(Break >> *EmptyLine >> CheckIndent >> SwitchCase) >> - -(Break >> *EmptyLine >> CheckIndent >> SwitchElse) >> - PopIndent; + -(Break >> *EmptyLine >> CheckIndent >> SwitchElse); exp_not_tab = not_(simple_table | TableLit) >> Exp; SwitchList = Seperator >> (and_(simple_table | TableLit) >> Exp | exp_not_tab >> *(sym(',') >> exp_not_tab)); - Switch = Space >> key("switch") >> disable_do(Exp) >> -(Space >> key("do")) - >> -Space >> Break >> SwitchBlock; + Switch = Space >> key("switch") >> Exp >> + Seperator >> ( + SwitchCase >> Space >> ( + Break >> *EmptyLine >> CheckIndent >> SwitchCase >> SwitchBlock | + *SwitchCase >> -SwitchElse + ) | + SpaceBreak >> *EmptyLine >> Advance >> SwitchCase >> SwitchBlock >> PopIndent + ) >> SwitchBlock; assignment = ExpList >> Assign; IfCond = disable_chain(disable_arg_table_block(assignment | Exp)); -- cgit v1.2.3-55-g6feb