diff options
author | Li Jin <dragon-fly@qq.com> | 2024-09-04 12:16:10 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2024-09-04 12:16:25 +0800 |
commit | 461bf7c32408553125d71b23e04e21fed690c4f5 (patch) | |
tree | 4442efd0fc2524e82be63e12e3e046a0532b26dd /src | |
parent | 2f8215df7288e0aac690c8e8b1ff79865f114302 (diff) | |
download | yuescript-461bf7c32408553125d71b23e04e21fed690c4f5.tar.gz yuescript-461bf7c32408553125d71b23e04e21fed690c4f5.tar.bz2 yuescript-461bf7c32408553125d71b23e04e21fed690c4f5.zip |
fix more cases for evaluation order of multi-value assignments.v0.25.1
Diffstat (limited to 'src')
-rw-r--r-- | src/yuescript/yue_compiler.cpp | 121 |
1 files changed, 74 insertions, 47 deletions
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index cbb5f81..5d031db 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
@@ -75,7 +75,7 @@ static std::unordered_set<std::string> Metamethods = { | |||
75 | "close"s // Lua 5.4 | 75 | "close"s // Lua 5.4 |
76 | }; | 76 | }; |
77 | 77 | ||
78 | const std::string_view version = "0.25.0"sv; | 78 | const std::string_view version = "0.25.1"sv; |
79 | const std::string_view extension = "yue"sv; | 79 | const std::string_view extension = "yue"sv; |
80 | 80 | ||
81 | class CompileError : public std::logic_error { | 81 | class CompileError : public std::logic_error { |
@@ -2047,34 +2047,34 @@ private: | |||
2047 | } | 2047 | } |
2048 | throw CompileError(clearBuf(), values.front()); | 2048 | throw CompileError(clearBuf(), values.front()); |
2049 | } | 2049 | } |
2050 | bool checkValuesLater = false; | ||
2051 | if (exprs.size() > values.size()) { | 2050 | if (exprs.size() > values.size()) { |
2052 | BLOCK_START | 2051 | BLOCK_START |
2052 | bool needHoldValues = false; | ||
2053 | switch (values.back()->get_id()) { | 2053 | switch (values.back()->get_id()) { |
2054 | case id<If_t>(): | 2054 | case id<If_t>(): |
2055 | case id<Switch_t>(): | 2055 | case id<Switch_t>(): |
2056 | checkValuesLater = true; | 2056 | needHoldValues = true; |
2057 | break; | 2057 | break; |
2058 | } | 2058 | } |
2059 | BREAK_IF(checkValuesLater); | 2059 | if (!needHoldValues) { |
2060 | auto value = singleValueFrom(values.back()); | 2060 | if (auto value = singleValueFrom(values.back())) { |
2061 | if (!value) { | 2061 | if (auto val = value->item.as<SimpleValue_t>()) { |
2062 | _buf << exprs.size() << " right values expected, got "sv << values.size(); | 2062 | switch (val->value->get_id()) { |
2063 | throw CompileError(clearBuf(), values.front()); | 2063 | case id<If_t>(): |
2064 | } | 2064 | case id<Switch_t>(): |
2065 | if (auto val = value->item.as<SimpleValue_t>()) { | 2065 | case id<Do_t>(): |
2066 | switch (val->value->get_id()) { | 2066 | case id<Try_t>(): |
2067 | case id<If_t>(): | 2067 | needHoldValues = true; |
2068 | case id<Switch_t>(): | 2068 | break; |
2069 | case id<Do_t>(): | 2069 | } |
2070 | case id<Try_t>(): | 2070 | } else if (auto chainValue = value->item.as<ChainValue_t>()) { |
2071 | checkValuesLater = true; | 2071 | if (chainValue && ast_is<Invoke_t, InvokeArgs_t>(chainValue->items.back())) { |
2072 | break; | 2072 | needHoldValues = true; |
2073 | } | ||
2074 | } | ||
2073 | } | 2075 | } |
2074 | BREAK_IF(checkValuesLater); | ||
2075 | } | 2076 | } |
2076 | auto chainValue = value->item.as<ChainValue_t>(); | 2077 | if (!needHoldValues) { |
2077 | if (!chainValue || !ast_is<Invoke_t, InvokeArgs_t>(chainValue->items.back())) { | ||
2078 | _buf << exprs.size() << " right values expected, got "sv << values.size(); | 2078 | _buf << exprs.size() << " right values expected, got "sv << values.size(); |
2079 | throw CompileError(clearBuf(), values.front()); | 2079 | throw CompileError(clearBuf(), values.front()); |
2080 | } | 2080 | } |
@@ -2138,7 +2138,7 @@ private: | |||
2138 | temp.push_back(indent() + "do"s + nll(assignment)); | 2138 | temp.push_back(indent() + "do"s + nll(assignment)); |
2139 | pushScope(); | 2139 | pushScope(); |
2140 | } | 2140 | } |
2141 | transformAssignmentCommon(preAssignment, temp); | 2141 | transformAssignment(preAssignment, temp); |
2142 | transformAssignment(assignment, temp); | 2142 | transformAssignment(assignment, temp); |
2143 | if (needScope) { | 2143 | if (needScope) { |
2144 | popScope(); | 2144 | popScope(); |
@@ -2148,17 +2148,52 @@ private: | |||
2148 | return; | 2148 | return; |
2149 | BLOCK_END | 2149 | BLOCK_END |
2150 | } | 2150 | } |
2151 | if (!checkValuesLater) { | 2151 | { |
2152 | auto vit = values.begin(); | 2152 | auto vit = values.begin(); |
2153 | for (auto it = exprs.begin(); it != exprs.end(); ++it) { | 2153 | for (auto it = exprs.begin(); it != exprs.end(); ++it) { |
2154 | auto splitAssignment = [&]() { | ||
2155 | auto beforeAssignment = x->new_ptr<ExpListAssign_t>(); | ||
2156 | auto afterAssignment = x->new_ptr<ExpListAssign_t>(); | ||
2157 | { | ||
2158 | auto beforeExpList = x->new_ptr<ExpList_t>(); | ||
2159 | auto beforeAssign = x->new_ptr<Assign_t>(); | ||
2160 | beforeAssignment->expList.set(beforeExpList); | ||
2161 | beforeAssignment->action.set(beforeAssign); | ||
2162 | auto afterExpList = x->new_ptr<ExpList_t>(); | ||
2163 | auto afterAssign = x->new_ptr<Assign_t>(); | ||
2164 | afterAssignment->expList.set(afterExpList); | ||
2165 | afterAssignment->action.set(afterAssign); | ||
2166 | ExpList_t* currentExpList = beforeExpList.get(); | ||
2167 | for (auto exp : exprs) { | ||
2168 | if (exp != *it) { | ||
2169 | currentExpList->exprs.push_back(exp); | ||
2170 | } else { | ||
2171 | currentExpList = afterExpList.get(); | ||
2172 | } | ||
2173 | } | ||
2174 | Assign_t* currentAssign = beforeAssign.get(); | ||
2175 | for (auto value : values) { | ||
2176 | if (value != *vit) { | ||
2177 | currentAssign->values.push_back(value); | ||
2178 | } else { | ||
2179 | currentAssign = afterAssign.get(); | ||
2180 | } | ||
2181 | } | ||
2182 | } | ||
2183 | return std::make_pair(beforeAssignment, afterAssignment); | ||
2184 | }; | ||
2154 | BLOCK_START | 2185 | BLOCK_START |
2155 | auto value = singleValueFrom(*it); | 2186 | auto value = singleValueFrom(*it); |
2156 | BREAK_IF(!value); | 2187 | BREAK_IF(!value); |
2157 | auto chainValue = value->item.as<ChainValue_t>(); | 2188 | auto chainValue = value->item.as<ChainValue_t>(); |
2158 | BREAK_IF(!chainValue); | 2189 | BREAK_IF(!chainValue); |
2159 | str_list temp; | ||
2160 | if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) { | 2190 | if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) { |
2161 | BREAK_IF(!dot->name.is<Metatable_t>()); | 2191 | BREAK_IF(!dot->name.is<Metatable_t>()); |
2192 | str_list temp; | ||
2193 | auto [beforeAssignment, afterAssignment] = splitAssignment(); | ||
2194 | if (!beforeAssignment->expList->exprs.empty()) { | ||
2195 | transformAssignment(beforeAssignment, temp); | ||
2196 | } | ||
2162 | str_list args; | 2197 | str_list args; |
2163 | auto tmpChain = chainValue->new_ptr<ChainValue_t>(); | 2198 | auto tmpChain = chainValue->new_ptr<ChainValue_t>(); |
2164 | tmpChain->items.dup(chainValue->items); | 2199 | tmpChain->items.dup(chainValue->items); |
@@ -2178,7 +2213,17 @@ private: | |||
2178 | transformAssignItem(*vit, args); | 2213 | transformAssignItem(*vit, args); |
2179 | _buf << indent() << globalVar("setmetatable"sv, x, AccessType::Read) << '(' << join(args, ", "sv) << ')' << nll(x); | 2214 | _buf << indent() << globalVar("setmetatable"sv, x, AccessType::Read) << '(' << join(args, ", "sv) << ')' << nll(x); |
2180 | temp.push_back(clearBuf()); | 2215 | temp.push_back(clearBuf()); |
2216 | if (!afterAssignment->expList->exprs.empty()) { | ||
2217 | transformAssignment(afterAssignment, temp); | ||
2218 | } | ||
2219 | out.push_back(join(temp)); | ||
2220 | return; | ||
2181 | } else if (ast_is<TableAppendingOp_t>(chainValue->items.back())) { | 2221 | } else if (ast_is<TableAppendingOp_t>(chainValue->items.back())) { |
2222 | str_list temp; | ||
2223 | auto [beforeAssignment, afterAssignment] = splitAssignment(); | ||
2224 | if (!beforeAssignment->expList->exprs.empty()) { | ||
2225 | transformAssignment(beforeAssignment, temp); | ||
2226 | } | ||
2182 | auto tmpChain = chainValue->new_ptr<ChainValue_t>(); | 2227 | auto tmpChain = chainValue->new_ptr<ChainValue_t>(); |
2183 | tmpChain->items.dup(chainValue->items); | 2228 | tmpChain->items.dup(chainValue->items); |
2184 | tmpChain->items.pop_back(); | 2229 | tmpChain->items.pop_back(); |
@@ -2220,32 +2265,14 @@ private: | |||
2220 | popScope(); | 2265 | popScope(); |
2221 | temp.push_back(indent() + "end"s + nlr(x)); | 2266 | temp.push_back(indent() + "end"s + nlr(x)); |
2222 | } | 2267 | } |
2223 | } else | 2268 | if (!afterAssignment->expList->exprs.empty()) { |
2224 | break; | 2269 | transformAssignment(afterAssignment, temp); |
2225 | auto newExpList = x->new_ptr<ExpList_t>(); | 2270 | } |
2226 | auto newAssign = x->new_ptr<Assign_t>(); | ||
2227 | auto newAssignment = x->new_ptr<ExpListAssign_t>(); | ||
2228 | newAssignment->expList.set(newExpList); | ||
2229 | newAssignment->action.set(newAssign); | ||
2230 | for (auto exp : exprs) { | ||
2231 | if (exp != *it) newExpList->exprs.push_back(exp); | ||
2232 | } | ||
2233 | for (auto value : values) { | ||
2234 | if (value != *vit) newAssign->values.push_back(value); | ||
2235 | } | ||
2236 | if (newExpList->exprs.empty() && newAssign->values.empty()) { | ||
2237 | out.push_back(join(temp)); | 2271 | out.push_back(join(temp)); |
2238 | return; | 2272 | return; |
2273 | } else { | ||
2274 | break; | ||
2239 | } | 2275 | } |
2240 | if (newExpList->exprs.size() < newAssign->values.size()) { | ||
2241 | auto exp = toAst<Exp_t>("_"sv, x); | ||
2242 | while (newExpList->exprs.size() < newAssign->values.size()) { | ||
2243 | newExpList->exprs.push_back(exp); | ||
2244 | } | ||
2245 | } | ||
2246 | transformAssignment(newAssignment, temp); | ||
2247 | out.push_back(join(temp)); | ||
2248 | return; | ||
2249 | BLOCK_END | 2276 | BLOCK_END |
2250 | if (vit != values.end()) ++vit; | 2277 | if (vit != values.end()) ++vit; |
2251 | } | 2278 | } |
@@ -2432,7 +2459,7 @@ private: | |||
2432 | if (!assignment.extraAssignment) { | 2459 | if (!assignment.extraAssignment) { |
2433 | auto names = transformAssignDefs(assignment.ptr->expList, DefOp::Get); | 2460 | auto names = transformAssignDefs(assignment.ptr->expList, DefOp::Get); |
2434 | for (const auto& name : names) { | 2461 | for (const auto& name : names) { |
2435 | if (addToScope(name.first)) { | 2462 | if (!isDefined(name.first)) { |
2436 | defs.push_back(name.first); | 2463 | defs.push_back(name.first); |
2437 | } | 2464 | } |
2438 | } | 2465 | } |