diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/yuescript/yue_ast.cpp | 4 | ||||
| -rw-r--r-- | src/yuescript/yue_ast.h | 6 | ||||
| -rw-r--r-- | src/yuescript/yue_compiler.cpp | 413 | ||||
| -rw-r--r-- | src/yuescript/yue_parser.cpp | 2 |
4 files changed, 305 insertions, 120 deletions
diff --git a/src/yuescript/yue_ast.cpp b/src/yuescript/yue_ast.cpp index 2fccd35..9c398c8 100644 --- a/src/yuescript/yue_ast.cpp +++ b/src/yuescript/yue_ast.cpp | |||
| @@ -201,8 +201,8 @@ std::string Continue_t::to_string(void*) const { | |||
| 201 | return "continue"s; | 201 | return "continue"s; |
| 202 | } | 202 | } |
| 203 | std::string BreakLoop_t::to_string(void* ud) const { | 203 | std::string BreakLoop_t::to_string(void* ud) const { |
| 204 | if (value) { | 204 | if (valueList) { |
| 205 | return type->to_string(ud) + ' ' + value->to_string(ud); | 205 | return type->to_string(ud) + ' ' + valueList->to_string(ud); |
| 206 | } | 206 | } |
| 207 | return type->to_string(ud); | 207 | return type->to_string(ud); |
| 208 | } | 208 | } |
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index 98f9014..91800b0 100644 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h | |||
| @@ -914,9 +914,9 @@ AST_END(Continue) | |||
| 914 | 914 | ||
| 915 | AST_NODE(BreakLoop) | 915 | AST_NODE(BreakLoop) |
| 916 | ast_sel<true, Break_t, Continue_t> type; | 916 | ast_sel<true, Break_t, Continue_t> type; |
| 917 | ast_ptr<false, Exp_t> value; | 917 | ast_ptr<false, ExpList_t> valueList; |
| 918 | AST_MEMBER(BreakLoop, &type, &value) | 918 | AST_MEMBER(BreakLoop, &type, &valueList) |
| 919 | std::string varBWV; | 919 | std::list<std::string> vars; |
| 920 | AST_END(BreakLoop) | 920 | AST_END(BreakLoop) |
| 921 | 921 | ||
| 922 | AST_NODE(PipeBody) | 922 | AST_NODE(PipeBody) |
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index eb31ab5..bd52d33 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
| @@ -78,7 +78,7 @@ static std::unordered_set<std::string> Metamethods = { | |||
| 78 | "close"s // Lua 5.4 | 78 | "close"s // Lua 5.4 |
| 79 | }; | 79 | }; |
| 80 | 80 | ||
| 81 | const std::string_view version = "0.32.9"sv; | 81 | const std::string_view version = "0.33.0"sv; |
| 82 | const std::string_view extension = "yue"sv; | 82 | const std::string_view extension = "yue"sv; |
| 83 | 83 | ||
| 84 | class CompileError : public std::logic_error { | 84 | class CompileError : public std::logic_error { |
| @@ -1996,6 +1996,18 @@ private: | |||
| 1996 | } | 1996 | } |
| 1997 | } | 1997 | } |
| 1998 | 1998 | ||
| 1999 | str_list getAssignVars(ExpList_t* assignList) { | ||
| 2000 | str_list vars; | ||
| 2001 | bool lintGlobal = _config.lintGlobalVariable; | ||
| 2002 | _config.lintGlobalVariable = false; | ||
| 2003 | for (auto exp : assignList->exprs.objects()) { | ||
| 2004 | auto var = singleVariableFrom(exp, AccessType::None); | ||
| 2005 | vars.push_back(var.empty() ? Empty : var); | ||
| 2006 | } | ||
| 2007 | _config.lintGlobalVariable = lintGlobal; | ||
| 2008 | return vars; | ||
| 2009 | } | ||
| 2010 | |||
| 1999 | str_list getAssignVars(ExpListAssign_t* assignment) { | 2011 | str_list getAssignVars(ExpListAssign_t* assignment) { |
| 2000 | str_list vars; | 2012 | str_list vars; |
| 2001 | bool lintGlobal = _config.lintGlobalVariable; | 2013 | bool lintGlobal = _config.lintGlobalVariable; |
| @@ -2211,9 +2223,9 @@ private: | |||
| 2211 | if (exprs.size() < values.size()) { | 2223 | if (exprs.size() < values.size()) { |
| 2212 | auto num = exprs.size(); | 2224 | auto num = exprs.size(); |
| 2213 | if (num > 1) { | 2225 | if (num > 1) { |
| 2214 | _buf << "no more than "sv << num << " right values expected, got "sv << values.size(); | 2226 | _buf << "expected no more than "sv << num << " right values, got "sv << values.size(); |
| 2215 | } else { | 2227 | } else { |
| 2216 | _buf << "only one right value expected, got "sv << values.size(); | 2228 | _buf << "expected only one right value, got "sv << values.size(); |
| 2217 | } | 2229 | } |
| 2218 | throw CompileError(clearBuf(), values.front()); | 2230 | throw CompileError(clearBuf(), values.front()); |
| 2219 | } | 2231 | } |
| @@ -2234,6 +2246,9 @@ private: | |||
| 2234 | case id<Switch_t>(): | 2246 | case id<Switch_t>(): |
| 2235 | case id<Do_t>(): | 2247 | case id<Do_t>(): |
| 2236 | case id<Try_t>(): | 2248 | case id<Try_t>(): |
| 2249 | case id<For_t>(): | ||
| 2250 | case id<While_t>(): | ||
| 2251 | case id<Repeat_t>(): | ||
| 2237 | needHoldValues = true; | 2252 | needHoldValues = true; |
| 2238 | break; | 2253 | break; |
| 2239 | } | 2254 | } |
| @@ -2245,7 +2260,7 @@ private: | |||
| 2245 | } | 2260 | } |
| 2246 | } | 2261 | } |
| 2247 | if (!needHoldValues) { | 2262 | if (!needHoldValues) { |
| 2248 | _buf << exprs.size() << " right values expected, got "sv << values.size(); | 2263 | _buf << "expected "sv << exprs.size() << " right values, got "sv << values.size(); |
| 2249 | throw CompileError(clearBuf(), values.front()); | 2264 | throw CompileError(clearBuf(), values.front()); |
| 2250 | } | 2265 | } |
| 2251 | auto newAssign = assign->new_ptr<Assign_t>(); | 2266 | auto newAssign = assign->new_ptr<Assign_t>(); |
| @@ -8911,7 +8926,7 @@ private: | |||
| 8911 | return (breakLoopType & int(BreakLoopType::Continue)) != 0; | 8926 | return (breakLoopType & int(BreakLoopType::Continue)) != 0; |
| 8912 | } | 8927 | } |
| 8913 | 8928 | ||
| 8914 | uint32_t getBreakLoopType(ast_node* body, const std::string& varBWV) { | 8929 | uint32_t getBreakLoopType(ast_node* body, bool allowBreakWithValues, str_list& breakWithValues) { |
| 8915 | uint32_t type = 0; | 8930 | uint32_t type = 0; |
| 8916 | body->traverse([&](ast_node* node) { | 8931 | body->traverse([&](ast_node* node) { |
| 8917 | if (auto stmt = ast_cast<Statement_t>(node)) { | 8932 | if (auto stmt = ast_cast<Statement_t>(node)) { |
| @@ -8920,12 +8935,25 @@ private: | |||
| 8920 | type |= int(BreakLoopType::Continue); | 8935 | type |= int(BreakLoopType::Continue); |
| 8921 | return traversal::Return; | 8936 | return traversal::Return; |
| 8922 | } else { | 8937 | } else { |
| 8923 | if (breakLoop->value) { | 8938 | if (breakLoop->valueList && breakLoop->vars.empty()) { |
| 8924 | if (varBWV.empty()) { | 8939 | if (!allowBreakWithValues) { |
| 8925 | throw CompileError("break with a value is not allowed here"sv, breakLoop->value); | 8940 | throw CompileError("break with values is not allowed here"sv, breakLoop->valueList->exprs.front()); |
| 8926 | } | 8941 | } |
| 8927 | type |= int(BreakLoopType::BreakWithValue); | 8942 | type |= int(BreakLoopType::BreakWithValue); |
| 8928 | breakLoop->varBWV = varBWV; | 8943 | if (breakWithValues.empty()) { |
| 8944 | pushScope(); | ||
| 8945 | for (size_t i = 0; i < breakLoop->valueList->exprs.size(); i++) { | ||
| 8946 | auto var = getUnusedName("_val_"sv); | ||
| 8947 | breakWithValues.push_back(var); | ||
| 8948 | addToScope(var); | ||
| 8949 | } | ||
| 8950 | popScope(); | ||
| 8951 | } else { | ||
| 8952 | if (breakLoop->valueList->exprs.size() != breakWithValues.size()) { | ||
| 8953 | throw CompileError("expecting "s + std::to_string(breakWithValues.size()) + " break values, got "s + std::to_string(breakLoop->valueList->exprs.size()), breakLoop->valueList->exprs.front()); | ||
| 8954 | } | ||
| 8955 | } | ||
| 8956 | breakLoop->vars = breakWithValues; | ||
| 8929 | } else { | 8957 | } else { |
| 8930 | type |= int(BreakLoopType::Break); | 8958 | type |= int(BreakLoopType::Break); |
| 8931 | } | 8959 | } |
| @@ -8940,28 +8968,28 @@ private: | |||
| 8940 | switch (sVal->get_id()) { | 8968 | switch (sVal->get_id()) { |
| 8941 | case id<With_t>(): { | 8969 | case id<With_t>(): { |
| 8942 | auto withNode = static_cast<With_t*>(sVal); | 8970 | auto withNode = static_cast<With_t*>(sVal); |
| 8943 | type |= getBreakLoopType(withNode->body, varBWV); | 8971 | type |= getBreakLoopType(withNode->body, allowBreakWithValues, breakWithValues); |
| 8944 | return traversal::Return; | 8972 | return traversal::Return; |
| 8945 | } | 8973 | } |
| 8946 | case id<Do_t>(): { | 8974 | case id<Do_t>(): { |
| 8947 | auto doNode = static_cast<Do_t*>(sVal); | 8975 | auto doNode = static_cast<Do_t*>(sVal); |
| 8948 | type |= getBreakLoopType(doNode->body, varBWV); | 8976 | type |= getBreakLoopType(doNode->body, allowBreakWithValues, breakWithValues); |
| 8949 | return traversal::Return; | 8977 | return traversal::Return; |
| 8950 | } | 8978 | } |
| 8951 | case id<If_t>(): { | 8979 | case id<If_t>(): { |
| 8952 | auto ifNode = static_cast<If_t*>(sVal); | 8980 | auto ifNode = static_cast<If_t*>(sVal); |
| 8953 | for (auto n : ifNode->nodes.objects()) { | 8981 | for (auto n : ifNode->nodes.objects()) { |
| 8954 | type |= getBreakLoopType(n, varBWV); | 8982 | type |= getBreakLoopType(n, allowBreakWithValues, breakWithValues); |
| 8955 | } | 8983 | } |
| 8956 | return traversal::Return; | 8984 | return traversal::Return; |
| 8957 | } | 8985 | } |
| 8958 | case id<Switch_t>(): { | 8986 | case id<Switch_t>(): { |
| 8959 | auto switchNode = static_cast<Switch_t*>(sVal); | 8987 | auto switchNode = static_cast<Switch_t*>(sVal); |
| 8960 | for (auto branch : switchNode->branches.objects()) { | 8988 | for (auto branch : switchNode->branches.objects()) { |
| 8961 | type |= getBreakLoopType(static_cast<SwitchCase_t*>(branch)->body, varBWV); | 8989 | type |= getBreakLoopType(static_cast<SwitchCase_t*>(branch)->body, allowBreakWithValues, breakWithValues); |
| 8962 | } | 8990 | } |
| 8963 | if (switchNode->lastBranch) { | 8991 | if (switchNode->lastBranch) { |
| 8964 | type |= getBreakLoopType(switchNode->lastBranch, varBWV); | 8992 | type |= getBreakLoopType(switchNode->lastBranch, allowBreakWithValues, breakWithValues); |
| 8965 | } | 8993 | } |
| 8966 | return traversal::Return; | 8994 | return traversal::Return; |
| 8967 | } | 8995 | } |
| @@ -8980,6 +9008,17 @@ private: | |||
| 8980 | return type; | 9008 | return type; |
| 8981 | } | 9009 | } |
| 8982 | 9010 | ||
| 9011 | uint32_t getBreakLoopTypeNoValues(ast_node* body) { | ||
| 9012 | str_list values; | ||
| 9013 | return getBreakLoopType(body, false, values); | ||
| 9014 | } | ||
| 9015 | |||
| 9016 | std::pair<uint32_t, str_list> getBreakLoopTypeAllowValues(ast_node* body) { | ||
| 9017 | str_list values; | ||
| 9018 | auto breakLoopType = getBreakLoopType(body, true, values); | ||
| 9019 | return {breakLoopType, std::move(values)}; | ||
| 9020 | } | ||
| 9021 | |||
| 8983 | void addDoToLastLineReturn(ast_node* body) { | 9022 | void addDoToLastLineReturn(ast_node* body) { |
| 8984 | if (auto block = ast_cast<Block_t>(body); block && !block->statementOrComments.empty()) { | 9023 | if (auto block = ast_cast<Block_t>(body); block && !block->statementOrComments.empty()) { |
| 8985 | auto last = lastStatementFrom(block); | 9024 | auto last = lastStatementFrom(block); |
| @@ -9066,7 +9105,7 @@ private: | |||
| 9066 | str_list temp; | 9105 | str_list temp; |
| 9067 | bool extraDo = false; | 9106 | bool extraDo = false; |
| 9068 | auto body = repeatNode->body.get(); | 9107 | auto body = repeatNode->body.get(); |
| 9069 | auto breakLoopType = getBreakLoopType(body, Empty); | 9108 | auto breakLoopType = getBreakLoopTypeNoValues(body); |
| 9070 | bool withContinue = hasContinue(breakLoopType); | 9109 | bool withContinue = hasContinue(breakLoopType); |
| 9071 | std::string conditionVar; | 9110 | std::string conditionVar; |
| 9072 | std::string extraLabel; | 9111 | std::string extraLabel; |
| @@ -9141,28 +9180,42 @@ private: | |||
| 9141 | void transformForNum(ForNum_t* forNum, str_list& out) { | 9180 | void transformForNum(ForNum_t* forNum, str_list& out) { |
| 9142 | str_list temp; | 9181 | str_list temp; |
| 9143 | transformForNumHead(forNum, temp); | 9182 | transformForNumHead(forNum, temp); |
| 9144 | auto breakLoopType = getBreakLoopType(forNum->body, Empty); | 9183 | auto breakLoopType = getBreakLoopTypeNoValues(forNum->body); |
| 9145 | transformLoopBody(forNum->body, temp, breakLoopType, ExpUsage::Common); | 9184 | transformLoopBody(forNum->body, temp, breakLoopType, ExpUsage::Common); |
| 9146 | popScope(); | 9185 | popScope(); |
| 9147 | out.push_back(join(temp) + indent() + "end"s + nl(forNum)); | 9186 | out.push_back(join(temp) + indent() + "end"s + nl(forNum)); |
| 9148 | } | 9187 | } |
| 9149 | 9188 | ||
| 9150 | std::string transformForNumInner(ForNum_t* forNum, str_list& out) { | 9189 | str_list transformForNumInner(ForNum_t* forNum, str_list& out, uint32_t breakLoopType, str_list&& vars) { |
| 9151 | auto x = forNum; | 9190 | auto x = forNum; |
| 9152 | std::string accum = getUnusedName("_accum_"sv); | 9191 | std::string accum; |
| 9153 | addToScope(accum); | 9192 | if (hasBreakWithValue(breakLoopType)) { |
| 9154 | std::string len = getUnusedName("_len_"sv); | 9193 | str_list vs; |
| 9155 | addToScope(len); | 9194 | for (const auto& var : vars) { |
| 9156 | auto breakLoopType = getBreakLoopType(forNum->body, accum); | 9195 | if (!isDefined(var)) { |
| 9157 | _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(forNum); | 9196 | addToScope(var); |
| 9197 | vs.push_back(var); | ||
| 9198 | } | ||
| 9199 | } | ||
| 9200 | if (!vs.empty()) { | ||
| 9201 | _buf << indent() << "local "sv << join(vs, ", "sv) << nl(forNum); | ||
| 9202 | } | ||
| 9203 | } else { | ||
| 9204 | accum = getUnusedName("_accum_"sv); | ||
| 9205 | addToScope(accum); | ||
| 9206 | vars = {accum}; | ||
| 9207 | _buf << indent() << "local "sv << accum << " = { }"sv << nl(forNum); | ||
| 9208 | } | ||
| 9158 | out.emplace_back(clearBuf()); | 9209 | out.emplace_back(clearBuf()); |
| 9159 | _buf << indent() << "local "sv << len << " = 1"sv << nl(forNum); | ||
| 9160 | auto& lenAssign = out.emplace_back(clearBuf()); | ||
| 9161 | transformForNumHead(forNum, out); | ||
| 9162 | if (hasBreakWithValue(breakLoopType)) { | 9210 | if (hasBreakWithValue(breakLoopType)) { |
| 9163 | lenAssign.clear(); | 9211 | transformForNumHead(forNum, out); |
| 9164 | transformLoopBody(forNum->body, out, breakLoopType, ExpUsage::Common); | 9212 | transformLoopBody(forNum->body, out, breakLoopType, ExpUsage::Common); |
| 9165 | } else { | 9213 | } else { |
| 9214 | std::string len = getUnusedName("_len_"sv); | ||
| 9215 | addToScope(len); | ||
| 9216 | _buf << indent() << "local "sv << len << " = 1"sv << nl(forNum); | ||
| 9217 | auto& lenAssign = out.emplace_back(clearBuf()); | ||
| 9218 | transformForNumHead(forNum, out); | ||
| 9166 | auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); | 9219 | auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); |
| 9167 | auto followStmt = toAst<Statement_t>(len + "+=1"s, forNum->body); | 9220 | auto followStmt = toAst<Statement_t>(len + "+=1"s, forNum->body); |
| 9168 | expList->followStmt = followStmt.get(); | 9221 | expList->followStmt = followStmt.get(); |
| @@ -9173,7 +9226,7 @@ private: | |||
| 9173 | } | 9226 | } |
| 9174 | popScope(); | 9227 | popScope(); |
| 9175 | out.push_back(indent() + "end"s + nl(forNum)); | 9228 | out.push_back(indent() + "end"s + nl(forNum)); |
| 9176 | return accum; | 9229 | return vars; |
| 9177 | } | 9230 | } |
| 9178 | 9231 | ||
| 9179 | void transformForNumClosure(ForNum_t* forNum, str_list& out) { | 9232 | void transformForNumClosure(ForNum_t* forNum, str_list& out) { |
| @@ -9189,8 +9242,10 @@ private: | |||
| 9189 | pushAnonVarArg(); | 9242 | pushAnonVarArg(); |
| 9190 | std::string& funcStart = temp.emplace_back(); | 9243 | std::string& funcStart = temp.emplace_back(); |
| 9191 | pushScope(); | 9244 | pushScope(); |
| 9192 | auto accum = transformForNumInner(forNum, temp); | 9245 | str_list vars; |
| 9193 | temp.push_back(indent() + "return "s + accum + nl(forNum)); | 9246 | auto breakLoopType = getBreakLoopType(forNum->body, true, vars); |
| 9247 | vars = transformForNumInner(forNum, temp, breakLoopType, std::move(vars)); | ||
| 9248 | temp.push_back(indent() + "return "s + join(vars, ", "sv) + nl(forNum)); | ||
| 9194 | popScope(); | 9249 | popScope(); |
| 9195 | funcStart = anonFuncStart() + nl(forNum); | 9250 | funcStart = anonFuncStart() + nl(forNum); |
| 9196 | temp.push_back(indent() + anonFuncEnd()); | 9251 | temp.push_back(indent() + anonFuncEnd()); |
| @@ -9200,29 +9255,45 @@ private: | |||
| 9200 | } | 9255 | } |
| 9201 | 9256 | ||
| 9202 | void transformForNumInPlace(ForNum_t* forNum, str_list& out, ExpList_t* assignExpList) { | 9257 | void transformForNumInPlace(ForNum_t* forNum, str_list& out, ExpList_t* assignExpList) { |
| 9203 | auto x = forNum; | ||
| 9204 | str_list temp; | 9258 | str_list temp; |
| 9205 | bool isScoped = !currentScope().lastStatement; | ||
| 9206 | if (assignExpList) { | 9259 | if (assignExpList) { |
| 9260 | auto vars = getAssignVars(assignExpList); | ||
| 9261 | bool extraVar = false; | ||
| 9262 | for (const auto& var : vars) { | ||
| 9263 | if (var.empty()) { | ||
| 9264 | vars.clear(); | ||
| 9265 | extraVar = true; | ||
| 9266 | break; | ||
| 9267 | } | ||
| 9268 | } | ||
| 9269 | auto breakLoopType = getBreakLoopType(forNum->body, true, vars); | ||
| 9270 | bool isScoped = true; | ||
| 9271 | if (currentScope().lastStatement) { | ||
| 9272 | isScoped = false; | ||
| 9273 | } else if (!extraVar && hasBreakWithValue(breakLoopType)) { | ||
| 9274 | isScoped = false; | ||
| 9275 | } | ||
| 9207 | if (isScoped) { | 9276 | if (isScoped) { |
| 9208 | _buf << indent() << "do"sv << nl(forNum); | 9277 | _buf << indent() << "do"sv << nl(forNum); |
| 9209 | pushScope(); | 9278 | pushScope(); |
| 9210 | } | 9279 | } |
| 9211 | auto accum = transformForNumInner(forNum, temp); | 9280 | vars = transformForNumInner(forNum, temp, breakLoopType, std::move(vars)); |
| 9212 | auto assign = x->new_ptr<Assign_t>(); | 9281 | if (extraVar || !hasBreakWithValue(breakLoopType)) { |
| 9213 | assign->values.push_back(toAst<Exp_t>(accum, x)); | 9282 | auto assign = toAst<Assign_t>('=' + join(vars, ","sv), assignExpList); |
| 9214 | auto assignment = x->new_ptr<ExpListAssign_t>(); | 9283 | auto assignment = assignExpList->new_ptr<ExpListAssign_t>(); |
| 9215 | assignment->expList.set(assignExpList); | 9284 | assignment->expList.set(assignExpList); |
| 9216 | assignment->action.set(assign); | 9285 | assignment->action.set(assign); |
| 9217 | transformAssignment(assignment, temp); | 9286 | transformAssignment(assignment, temp); |
| 9287 | } | ||
| 9218 | if (isScoped) { | 9288 | if (isScoped) { |
| 9219 | popScope(); | 9289 | popScope(); |
| 9220 | temp.push_back(indent() + "end"s + nl(forNum)); | 9290 | temp.push_back(indent() + "end"s + nl(forNum)); |
| 9221 | } | 9291 | } |
| 9222 | } else { | 9292 | } else { |
| 9223 | auto accum = transformForNumInner(forNum, temp); | 9293 | str_list vars; |
| 9224 | auto returnNode = newReturn(toAst<Exp_t>(accum, forNum)); | 9294 | auto breakLoopType = getBreakLoopType(forNum->body, true, vars); |
| 9225 | transformReturn(returnNode, temp); | 9295 | vars = transformForNumInner(forNum, temp, breakLoopType, std::move(vars)); |
| 9296 | temp.push_back(indent() + "return "s + join(vars, ", "sv) + nl(forNum)); | ||
| 9226 | } | 9297 | } |
| 9227 | out.push_back(join(temp)); | 9298 | out.push_back(join(temp)); |
| 9228 | } | 9299 | } |
| @@ -9248,7 +9319,7 @@ private: | |||
| 9248 | void transformForEach(ForEach_t* forEach, str_list& out) { | 9319 | void transformForEach(ForEach_t* forEach, str_list& out) { |
| 9249 | str_list temp; | 9320 | str_list temp; |
| 9250 | bool extraScoped = transformForEachHead(forEach->nameList, forEach->loopValue, temp, false); | 9321 | bool extraScoped = transformForEachHead(forEach->nameList, forEach->loopValue, temp, false); |
| 9251 | auto breakLoopType = getBreakLoopType(forEach->body, Empty); | 9322 | auto breakLoopType = getBreakLoopTypeNoValues(forEach->body); |
| 9252 | transformLoopBody(forEach->body, temp, breakLoopType, ExpUsage::Common); | 9323 | transformLoopBody(forEach->body, temp, breakLoopType, ExpUsage::Common); |
| 9253 | popScope(); | 9324 | popScope(); |
| 9254 | out.push_back(temp.front() + temp.back() + indent() + "end"s + nl(forEach)); | 9325 | out.push_back(temp.front() + temp.back() + indent() + "end"s + nl(forEach)); |
| @@ -9258,22 +9329,36 @@ private: | |||
| 9258 | } | 9329 | } |
| 9259 | } | 9330 | } |
| 9260 | 9331 | ||
| 9261 | std::string transformForEachInner(ForEach_t* forEach, str_list& out) { | 9332 | str_list transformForEachInner(ForEach_t* forEach, str_list& out, uint32_t breakLoopType, str_list&& vars) { |
| 9262 | auto x = forEach; | 9333 | auto x = forEach; |
| 9263 | std::string accum = getUnusedName("_accum_"sv); | 9334 | std::string accum; |
| 9264 | addToScope(accum); | 9335 | if (hasBreakWithValue(breakLoopType)) { |
| 9265 | std::string len = getUnusedName("_len_"sv); | 9336 | str_list vs; |
| 9266 | addToScope(len); | 9337 | for (const auto& var : vars) { |
| 9267 | auto breakLoopType = getBreakLoopType(forEach->body, accum); | 9338 | if (!isDefined(var)) { |
| 9268 | _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(forEach); | 9339 | addToScope(var); |
| 9340 | vs.push_back(var); | ||
| 9341 | } | ||
| 9342 | } | ||
| 9343 | if (!vs.empty()) { | ||
| 9344 | _buf << indent() << "local "sv << join(vs, ", "sv) << nl(forEach); | ||
| 9345 | } | ||
| 9346 | } else { | ||
| 9347 | accum = getUnusedName("_accum_"sv); | ||
| 9348 | addToScope(accum); | ||
| 9349 | vars = {accum}; | ||
| 9350 | _buf << indent() << "local "sv << accum << " = { }"sv << nl(forEach); | ||
| 9351 | } | ||
| 9269 | out.emplace_back(clearBuf()); | 9352 | out.emplace_back(clearBuf()); |
| 9270 | _buf << indent() << "local "sv << len << " = 1"sv << nl(forEach); | ||
| 9271 | auto& lenAssign = out.emplace_back(clearBuf()); | ||
| 9272 | transformForEachHead(forEach->nameList, forEach->loopValue, out, true); | ||
| 9273 | if (hasBreakWithValue(breakLoopType)) { | 9353 | if (hasBreakWithValue(breakLoopType)) { |
| 9274 | lenAssign.clear(); | 9354 | transformForEachHead(forEach->nameList, forEach->loopValue, out, true); |
| 9275 | transformLoopBody(forEach->body, out, breakLoopType, ExpUsage::Common); | 9355 | transformLoopBody(forEach->body, out, breakLoopType, ExpUsage::Common); |
| 9276 | } else { | 9356 | } else { |
| 9357 | std::string len = getUnusedName("_len_"sv); | ||
| 9358 | addToScope(len); | ||
| 9359 | _buf << indent() << "local "sv << len << " = 1"sv << nl(forEach); | ||
| 9360 | auto& lenAssign = out.emplace_back(clearBuf()); | ||
| 9361 | transformForEachHead(forEach->nameList, forEach->loopValue, out, true); | ||
| 9277 | auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); | 9362 | auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); |
| 9278 | auto followStmt = toAst<Statement_t>(len + "+=1"s, forEach->body); | 9363 | auto followStmt = toAst<Statement_t>(len + "+=1"s, forEach->body); |
| 9279 | expList->followStmt = followStmt.get(); | 9364 | expList->followStmt = followStmt.get(); |
| @@ -9284,7 +9369,7 @@ private: | |||
| 9284 | } | 9369 | } |
| 9285 | popScope(); | 9370 | popScope(); |
| 9286 | out.push_back(indent() + "end"s + nl(forEach)); | 9371 | out.push_back(indent() + "end"s + nl(forEach)); |
| 9287 | return accum; | 9372 | return vars; |
| 9288 | } | 9373 | } |
| 9289 | 9374 | ||
| 9290 | void transformForEachClosure(ForEach_t* forEach, str_list& out) { | 9375 | void transformForEachClosure(ForEach_t* forEach, str_list& out) { |
| @@ -9300,8 +9385,10 @@ private: | |||
| 9300 | pushAnonVarArg(); | 9385 | pushAnonVarArg(); |
| 9301 | std::string& funcStart = temp.emplace_back(); | 9386 | std::string& funcStart = temp.emplace_back(); |
| 9302 | pushScope(); | 9387 | pushScope(); |
| 9303 | auto accum = transformForEachInner(forEach, temp); | 9388 | str_list vars; |
| 9304 | temp.push_back(indent() + "return "s + accum + nl(forEach)); | 9389 | auto breakLoopType = getBreakLoopType(forEach->body, true, vars); |
| 9390 | vars = transformForEachInner(forEach, temp, breakLoopType, std::move(vars)); | ||
| 9391 | temp.push_back(indent() + "return "s + join(vars, ", "sv) + nl(forEach)); | ||
| 9305 | popScope(); | 9392 | popScope(); |
| 9306 | funcStart = anonFuncStart() + nl(forEach); | 9393 | funcStart = anonFuncStart() + nl(forEach); |
| 9307 | temp.push_back(indent() + anonFuncEnd()); | 9394 | temp.push_back(indent() + anonFuncEnd()); |
| @@ -9311,29 +9398,45 @@ private: | |||
| 9311 | } | 9398 | } |
| 9312 | 9399 | ||
| 9313 | void transformForEachInPlace(ForEach_t* forEach, str_list& out, ExpList_t* assignExpList) { | 9400 | void transformForEachInPlace(ForEach_t* forEach, str_list& out, ExpList_t* assignExpList) { |
| 9314 | auto x = forEach; | ||
| 9315 | str_list temp; | 9401 | str_list temp; |
| 9316 | bool isScoped = !currentScope().lastStatement; | ||
| 9317 | if (assignExpList) { | 9402 | if (assignExpList) { |
| 9403 | auto vars = getAssignVars(assignExpList); | ||
| 9404 | bool extraVar = false; | ||
| 9405 | for (const auto& var : vars) { | ||
| 9406 | if (var.empty()) { | ||
| 9407 | vars.clear(); | ||
| 9408 | extraVar = true; | ||
| 9409 | break; | ||
| 9410 | } | ||
| 9411 | } | ||
| 9412 | auto breakLoopType = getBreakLoopType(forEach->body, true, vars); | ||
| 9413 | bool isScoped = true; | ||
| 9414 | if (currentScope().lastStatement) { | ||
| 9415 | isScoped = false; | ||
| 9416 | } else if (!extraVar && hasBreakWithValue(breakLoopType)) { | ||
| 9417 | isScoped = false; | ||
| 9418 | } | ||
| 9318 | if (isScoped) { | 9419 | if (isScoped) { |
| 9319 | _buf << indent() << "do"sv << nl(forEach); | 9420 | _buf << indent() << "do"sv << nl(forEach); |
| 9320 | pushScope(); | 9421 | pushScope(); |
| 9321 | } | 9422 | } |
| 9322 | auto accum = transformForEachInner(forEach, temp); | 9423 | vars = transformForEachInner(forEach, temp, breakLoopType, std::move(vars)); |
| 9323 | auto assign = x->new_ptr<Assign_t>(); | 9424 | if (extraVar || !hasBreakWithValue(breakLoopType)) { |
| 9324 | assign->values.push_back(toAst<Exp_t>(accum, x)); | 9425 | auto assign = toAst<Assign_t>('=' + join(vars, ","sv), assignExpList); |
| 9325 | auto assignment = x->new_ptr<ExpListAssign_t>(); | 9426 | auto assignment = assignExpList->new_ptr<ExpListAssign_t>(); |
| 9326 | assignment->expList.set(assignExpList); | 9427 | assignment->expList.set(assignExpList); |
| 9327 | assignment->action.set(assign); | 9428 | assignment->action.set(assign); |
| 9328 | transformAssignment(assignment, temp); | 9429 | transformAssignment(assignment, temp); |
| 9430 | } | ||
| 9329 | if (isScoped) { | 9431 | if (isScoped) { |
| 9330 | popScope(); | 9432 | popScope(); |
| 9331 | temp.push_back(indent() + "end"s + nl(forEach)); | 9433 | temp.push_back(indent() + "end"s + nl(forEach)); |
| 9332 | } | 9434 | } |
| 9333 | } else { | 9435 | } else { |
| 9334 | auto accum = transformForEachInner(forEach, temp); | 9436 | str_list vars; |
| 9335 | auto returnNode = newReturn(toAst<Exp_t>(accum, forEach)); | 9437 | auto breakLoopType = getBreakLoopType(forEach->body, true, vars); |
| 9336 | transformReturn(returnNode, temp); | 9438 | vars = transformForEachInner(forEach, temp, breakLoopType, std::move(vars)); |
| 9439 | temp.push_back(indent() + "return "s + join(vars, ", "sv) + nl(forEach)); | ||
| 9337 | } | 9440 | } |
| 9338 | out.push_back(join(temp)); | 9441 | out.push_back(join(temp)); |
| 9339 | } | 9442 | } |
| @@ -10274,7 +10377,8 @@ private: | |||
| 10274 | breakWithVar = getUnusedName("_val_"sv); | 10377 | breakWithVar = getUnusedName("_val_"sv); |
| 10275 | extraBreakVar = true; | 10378 | extraBreakVar = true; |
| 10276 | } | 10379 | } |
| 10277 | auto breakLoopType = getBreakLoopType(with->body, breakWithVar); | 10380 | str_list vars{breakWithVar}; |
| 10381 | auto breakLoopType = getBreakLoopType(with->body, true, vars); | ||
| 10278 | if (!hasBreakWithValue(breakLoopType)) { | 10382 | if (!hasBreakWithValue(breakLoopType)) { |
| 10279 | breakWithVar.clear(); | 10383 | breakWithVar.clear(); |
| 10280 | } | 10384 | } |
| @@ -10308,6 +10412,10 @@ private: | |||
| 10308 | } else { | 10412 | } else { |
| 10309 | bool transformed = false; | 10413 | bool transformed = false; |
| 10310 | if (!breakWithVar.empty()) { | 10414 | if (!breakWithVar.empty()) { |
| 10415 | if (extraBreakVar) { | ||
| 10416 | addToScope(breakWithVar); | ||
| 10417 | temp.push_back(indent() + "local "s + breakWithVar + nl(with)); | ||
| 10418 | } | ||
| 10311 | auto repeatNode = toAst<Repeat_t>("repeat\n\t--\nuntil true"s, x); | 10419 | auto repeatNode = toAst<Repeat_t>("repeat\n\t--\nuntil true"s, x); |
| 10312 | auto block = x->new_ptr<Block_t>(); | 10420 | auto block = x->new_ptr<Block_t>(); |
| 10313 | if (auto blk = with->body.as<Block_t>()) { | 10421 | if (auto blk = with->body.as<Block_t>()) { |
| @@ -10317,10 +10425,7 @@ private: | |||
| 10317 | block->statementOrComments.push_back(stmt); | 10425 | block->statementOrComments.push_back(stmt); |
| 10318 | } | 10426 | } |
| 10319 | repeatNode->body.set(block); | 10427 | repeatNode->body.set(block); |
| 10320 | auto sVal = x->new_ptr<SimpleValue_t>(); | 10428 | transformRepeat(repeatNode, temp); |
| 10321 | sVal->value.set(repeatNode); | ||
| 10322 | auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x); | ||
| 10323 | transformAssignment(asmt, temp); | ||
| 10324 | transformed = true; | 10429 | transformed = true; |
| 10325 | } else if (!extraScope && assignList) { | 10430 | } else if (!extraScope && assignList) { |
| 10326 | if (auto block = with->body.as<Block_t>()) { | 10431 | if (auto block = with->body.as<Block_t>()) { |
| @@ -10784,7 +10889,57 @@ private: | |||
| 10784 | temp.push_back(indent() + "do"s + nl(doNode)); | 10889 | temp.push_back(indent() + "do"s + nl(doNode)); |
| 10785 | pushScope(); | 10890 | pushScope(); |
| 10786 | } | 10891 | } |
| 10787 | transformBody(doNode->body, temp, usage, assignList); | 10892 | str_list breakVars; |
| 10893 | bool extraVar = false; | ||
| 10894 | switch (usage) { | ||
| 10895 | case ExpUsage::Closure: | ||
| 10896 | case ExpUsage::Return: { | ||
| 10897 | uint32_t breakLoopType = 0; | ||
| 10898 | std::tie(breakLoopType, breakVars) = getBreakLoopTypeAllowValues(doNode->body); | ||
| 10899 | if (hasBreakWithValue(breakLoopType)) { | ||
| 10900 | for (const auto& var : breakVars) addToScope(var); | ||
| 10901 | temp.push_back(indent() + "local "s + join(breakVars, ", "sv) + nl(doNode)); | ||
| 10902 | extraVar = true; | ||
| 10903 | } | ||
| 10904 | break; | ||
| 10905 | } | ||
| 10906 | case ExpUsage::Assignment: { | ||
| 10907 | auto vars = getAssignVars(assignList); | ||
| 10908 | for (const auto& var : vars) { | ||
| 10909 | if (var.empty()) { | ||
| 10910 | vars.clear(); | ||
| 10911 | extraVar = true; | ||
| 10912 | break; | ||
| 10913 | } | ||
| 10914 | } | ||
| 10915 | auto breakLoopType = getBreakLoopType(doNode->body, true, vars); | ||
| 10916 | if (hasBreakWithValue(breakLoopType)) { | ||
| 10917 | breakVars = std::move(vars); | ||
| 10918 | } | ||
| 10919 | break; | ||
| 10920 | } | ||
| 10921 | case ExpUsage::Common: { | ||
| 10922 | getBreakLoopTypeNoValues(doNode->body); | ||
| 10923 | break; | ||
| 10924 | } | ||
| 10925 | } | ||
| 10926 | if (breakVars.empty()) { | ||
| 10927 | transformBody(doNode->body, temp, usage, assignList); | ||
| 10928 | } else { | ||
| 10929 | auto x = doNode; | ||
| 10930 | auto repeatNode = toAst<Repeat_t>("repeat\n\t--\nuntil true"s, x); | ||
| 10931 | repeatNode->body.set(doNode->body->content); | ||
| 10932 | transformRepeat(repeatNode, temp); | ||
| 10933 | if (assignList && extraVar) { | ||
| 10934 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
| 10935 | assignment->expList.set(assignList); | ||
| 10936 | auto assign = toAst<Assign_t>('=' + join(breakVars, ","sv), x); | ||
| 10937 | assignment->action.set(assign); | ||
| 10938 | transformAssignment(assignment, temp); | ||
| 10939 | } else if (usage == ExpUsage::Closure || usage == ExpUsage::Return) { | ||
| 10940 | temp.push_back(indent() + "return "s + join(breakVars, ", "sv) + nl(doNode)); | ||
| 10941 | } | ||
| 10942 | } | ||
| 10788 | if (usage == ExpUsage::Closure) { | 10943 | if (usage == ExpUsage::Closure) { |
| 10789 | popScope(); | 10944 | popScope(); |
| 10790 | *funcStart = anonFuncStart() + nl(doNode); | 10945 | *funcStart = anonFuncStart() + nl(doNode); |
| @@ -11438,13 +11593,20 @@ private: | |||
| 11438 | pushScope(); | 11593 | pushScope(); |
| 11439 | } | 11594 | } |
| 11440 | } | 11595 | } |
| 11441 | auto accumVar = getUnusedName("_accum_"sv); | 11596 | std::string accumVar; |
| 11442 | addToScope(accumVar); | 11597 | auto [breakLoopType, vars] = getBreakLoopTypeAllowValues(whileNode->body); |
| 11598 | if (hasBreakWithValue(breakLoopType)) { | ||
| 11599 | for (const auto& var : vars) addToScope(var); | ||
| 11600 | _buf << indent() << "local "sv << join(vars, ", "sv) << nl(whileNode); | ||
| 11601 | } else { | ||
| 11602 | accumVar = getUnusedName("_accum_"sv); | ||
| 11603 | addToScope(accumVar); | ||
| 11604 | vars.push_back(accumVar); | ||
| 11605 | _buf << indent() << "local "sv << accumVar << " = { }"sv << nl(whileNode); | ||
| 11606 | } | ||
| 11607 | temp.emplace_back(clearBuf()); | ||
| 11443 | auto lenVar = getUnusedName("_len_"sv); | 11608 | auto lenVar = getUnusedName("_len_"sv); |
| 11444 | addToScope(lenVar); | 11609 | addToScope(lenVar); |
| 11445 | auto breakLoopType = getBreakLoopType(whileNode->body, accumVar); | ||
| 11446 | _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(whileNode); | ||
| 11447 | temp.emplace_back(clearBuf()); | ||
| 11448 | _buf << indent() << "local "s << lenVar << " = 1"s << nl(whileNode); | 11610 | _buf << indent() << "local "s << lenVar << " = 1"s << nl(whileNode); |
| 11449 | auto& lenAssign = temp.emplace_back(clearBuf()); | 11611 | auto& lenAssign = temp.emplace_back(clearBuf()); |
| 11450 | bool isUntil = _parser.toString(whileNode->type) == "until"sv; | 11612 | bool isUntil = _parser.toString(whileNode->type) == "until"sv; |
| @@ -11466,15 +11628,14 @@ private: | |||
| 11466 | popScope(); | 11628 | popScope(); |
| 11467 | temp.push_back(indent() + "end"s + nl(whileNode)); | 11629 | temp.push_back(indent() + "end"s + nl(whileNode)); |
| 11468 | if (expList) { | 11630 | if (expList) { |
| 11469 | auto assign = x->new_ptr<Assign_t>(); | 11631 | auto assign = toAst<Assign_t>('=' + join(vars, ","sv), expList); |
| 11470 | assign->values.push_back(toAst<Exp_t>(accumVar, x)); | 11632 | auto assignment = expList->new_ptr<ExpListAssign_t>(); |
| 11471 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
| 11472 | assignment->expList.set(expList); | 11633 | assignment->expList.set(expList); |
| 11473 | assignment->action.set(assign); | 11634 | assignment->action.set(assign); |
| 11474 | transformAssignment(assignment, temp); | 11635 | transformAssignment(assignment, temp); |
| 11475 | if (extraScope) popScope(); | 11636 | if (extraScope) popScope(); |
| 11476 | } else { | 11637 | } else { |
| 11477 | temp.push_back(indent() + "return "s + accumVar + nl(whileNode)); | 11638 | temp.push_back(indent() + "return "s + join(vars, ", "sv) + nl(whileNode)); |
| 11478 | } | 11639 | } |
| 11479 | if (expList && extraScope) { | 11640 | if (expList && extraScope) { |
| 11480 | temp.push_back(indent() + "end"s + nl(whileNode)); | 11641 | temp.push_back(indent() + "end"s + nl(whileNode)); |
| @@ -11494,13 +11655,20 @@ private: | |||
| 11494 | pushAnonVarArg(); | 11655 | pushAnonVarArg(); |
| 11495 | std::string& funcStart = temp.emplace_back(); | 11656 | std::string& funcStart = temp.emplace_back(); |
| 11496 | pushScope(); | 11657 | pushScope(); |
| 11497 | auto accumVar = getUnusedName("_accum_"sv); | 11658 | std::string accumVar; |
| 11498 | addToScope(accumVar); | 11659 | auto [breakLoopType, vars] = getBreakLoopTypeAllowValues(whileNode->body); |
| 11660 | if (hasBreakWithValue(breakLoopType)) { | ||
| 11661 | for (const auto& var : vars) addToScope(var); | ||
| 11662 | _buf << indent() << "local "sv << join(vars, ", "sv) << nl(whileNode); | ||
| 11663 | } else { | ||
| 11664 | accumVar = getUnusedName("_accum_"sv); | ||
| 11665 | addToScope(accumVar); | ||
| 11666 | vars.push_back(accumVar); | ||
| 11667 | _buf << indent() << "local "sv << accumVar << " = { }"sv << nl(whileNode); | ||
| 11668 | } | ||
| 11669 | temp.emplace_back(clearBuf()); | ||
| 11499 | auto lenVar = getUnusedName("_len_"sv); | 11670 | auto lenVar = getUnusedName("_len_"sv); |
| 11500 | addToScope(lenVar); | 11671 | addToScope(lenVar); |
| 11501 | auto breakLoopType = getBreakLoopType(whileNode->body, accumVar); | ||
| 11502 | _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(whileNode); | ||
| 11503 | temp.emplace_back(clearBuf()); | ||
| 11504 | auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nl(whileNode)); | 11672 | auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nl(whileNode)); |
| 11505 | bool isUntil = _parser.toString(whileNode->type) == "until"sv; | 11673 | bool isUntil = _parser.toString(whileNode->type) == "until"sv; |
| 11506 | auto condStr = transformCondExp(whileNode->condition, isUntil); | 11674 | auto condStr = transformCondExp(whileNode->condition, isUntil); |
| @@ -11520,7 +11688,7 @@ private: | |||
| 11520 | } | 11688 | } |
| 11521 | popScope(); | 11689 | popScope(); |
| 11522 | temp.push_back(indent() + "end"s + nl(whileNode)); | 11690 | temp.push_back(indent() + "end"s + nl(whileNode)); |
| 11523 | temp.push_back(indent() + "return "s + accumVar + nl(whileNode)); | 11691 | temp.push_back(indent() + "return "s + join(vars, ", "sv) + nl(whileNode)); |
| 11524 | popScope(); | 11692 | popScope(); |
| 11525 | funcStart = anonFuncStart() + nl(whileNode); | 11693 | funcStart = anonFuncStart() + nl(whileNode); |
| 11526 | temp.push_back(indent() + anonFuncEnd()); | 11694 | temp.push_back(indent() + anonFuncEnd()); |
| @@ -11560,7 +11728,7 @@ private: | |||
| 11560 | pushScope(); | 11728 | pushScope(); |
| 11561 | bool isUntil = _parser.toString(whileNode->type) == "until"sv; | 11729 | bool isUntil = _parser.toString(whileNode->type) == "until"sv; |
| 11562 | auto condStr = transformCondExp(whileNode->condition, isUntil); | 11730 | auto condStr = transformCondExp(whileNode->condition, isUntil); |
| 11563 | auto breakLoopType = getBreakLoopType(whileNode->body, Empty); | 11731 | auto breakLoopType = getBreakLoopTypeNoValues(whileNode->body); |
| 11564 | transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common); | 11732 | transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common); |
| 11565 | popScope(); | 11733 | popScope(); |
| 11566 | _buf << indent() << "while "sv << condStr << " do"sv << nl(whileNode); | 11734 | _buf << indent() << "while "sv << condStr << " do"sv << nl(whileNode); |
| @@ -11580,13 +11748,20 @@ private: | |||
| 11580 | pushScope(); | 11748 | pushScope(); |
| 11581 | } | 11749 | } |
| 11582 | } | 11750 | } |
| 11583 | auto accumVar = getUnusedName("_accum_"sv); | 11751 | std::string accumVar; |
| 11584 | addToScope(accumVar); | 11752 | auto [breakLoopType, vars] = getBreakLoopTypeAllowValues(repeatNode->body); |
| 11753 | if (hasBreakWithValue(breakLoopType)) { | ||
| 11754 | for (const auto& var : vars) addToScope(var); | ||
| 11755 | _buf << indent() << "local "sv << join(vars, ", "sv) << nl(repeatNode); | ||
| 11756 | } else { | ||
| 11757 | accumVar = getUnusedName("_accum_"sv); | ||
| 11758 | addToScope(accumVar); | ||
| 11759 | vars.push_back(accumVar); | ||
| 11760 | _buf << indent() << "local "sv << accumVar << " = { }"sv << nl(repeatNode); | ||
| 11761 | } | ||
| 11762 | temp.emplace_back(clearBuf()); | ||
| 11585 | auto lenVar = getUnusedName("_len_"sv); | 11763 | auto lenVar = getUnusedName("_len_"sv); |
| 11586 | addToScope(lenVar); | 11764 | addToScope(lenVar); |
| 11587 | auto breakLoopType = getBreakLoopType(repeatNode->body, accumVar); | ||
| 11588 | _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(repeatNode); | ||
| 11589 | temp.emplace_back(clearBuf()); | ||
| 11590 | _buf << indent() << "local "s << lenVar << " = 1"s << nl(repeatNode); | 11765 | _buf << indent() << "local "s << lenVar << " = 1"s << nl(repeatNode); |
| 11591 | auto& lenAssign = temp.emplace_back(clearBuf()); | 11766 | auto& lenAssign = temp.emplace_back(clearBuf()); |
| 11592 | auto condStr = transformCondExp(repeatNode->condition, false); | 11767 | auto condStr = transformCondExp(repeatNode->condition, false); |
| @@ -11607,15 +11782,14 @@ private: | |||
| 11607 | popScope(); | 11782 | popScope(); |
| 11608 | temp.push_back(indent() + "until "s + condStr + nl(repeatNode)); | 11783 | temp.push_back(indent() + "until "s + condStr + nl(repeatNode)); |
| 11609 | if (expList) { | 11784 | if (expList) { |
| 11610 | auto assign = x->new_ptr<Assign_t>(); | 11785 | auto assign = toAst<Assign_t>('=' + join(vars, ","sv), expList); |
| 11611 | assign->values.push_back(toAst<Exp_t>(accumVar, x)); | 11786 | auto assignment = expList->new_ptr<ExpListAssign_t>(); |
| 11612 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
| 11613 | assignment->expList.set(expList); | 11787 | assignment->expList.set(expList); |
| 11614 | assignment->action.set(assign); | 11788 | assignment->action.set(assign); |
| 11615 | transformAssignment(assignment, temp); | 11789 | transformAssignment(assignment, temp); |
| 11616 | if (extraScope) popScope(); | 11790 | if (extraScope) popScope(); |
| 11617 | } else { | 11791 | } else { |
| 11618 | temp.push_back(indent() + "return "s + accumVar + nl(repeatNode)); | 11792 | temp.push_back(indent() + "return "s + join(vars, ", "sv) + nl(repeatNode)); |
| 11619 | } | 11793 | } |
| 11620 | if (expList && extraScope) { | 11794 | if (expList && extraScope) { |
| 11621 | temp.push_back(indent() + "end"s + nl(repeatNode)); | 11795 | temp.push_back(indent() + "end"s + nl(repeatNode)); |
| @@ -11635,13 +11809,20 @@ private: | |||
| 11635 | pushAnonVarArg(); | 11809 | pushAnonVarArg(); |
| 11636 | std::string& funcStart = temp.emplace_back(); | 11810 | std::string& funcStart = temp.emplace_back(); |
| 11637 | pushScope(); | 11811 | pushScope(); |
| 11638 | auto accumVar = getUnusedName("_accum_"sv); | 11812 | std::string accumVar; |
| 11639 | addToScope(accumVar); | 11813 | auto [breakLoopType, vars] = getBreakLoopTypeAllowValues(repeatNode->body); |
| 11814 | if (hasBreakWithValue(breakLoopType)) { | ||
| 11815 | for (const auto& var : vars) addToScope(var); | ||
| 11816 | _buf << indent() << "local "sv << join(vars, ", "sv) << nl(repeatNode); | ||
| 11817 | } else { | ||
| 11818 | accumVar = getUnusedName("_accum_"sv); | ||
| 11819 | addToScope(accumVar); | ||
| 11820 | vars.push_back(accumVar); | ||
| 11821 | _buf << indent() << "local "sv << accumVar << " = { }"sv << nl(repeatNode); | ||
| 11822 | } | ||
| 11823 | temp.emplace_back(clearBuf()); | ||
| 11640 | auto lenVar = getUnusedName("_len_"sv); | 11824 | auto lenVar = getUnusedName("_len_"sv); |
| 11641 | addToScope(lenVar); | 11825 | addToScope(lenVar); |
| 11642 | auto breakLoopType = getBreakLoopType(repeatNode->body, accumVar); | ||
| 11643 | _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(repeatNode); | ||
| 11644 | temp.emplace_back(clearBuf()); | ||
| 11645 | auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nl(repeatNode)); | 11826 | auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nl(repeatNode)); |
| 11646 | auto condStr = transformCondExp(repeatNode->condition, false); | 11827 | auto condStr = transformCondExp(repeatNode->condition, false); |
| 11647 | temp.push_back(indent() + "repeat"s + nl(repeatNode)); | 11828 | temp.push_back(indent() + "repeat"s + nl(repeatNode)); |
| @@ -11660,7 +11841,7 @@ private: | |||
| 11660 | } | 11841 | } |
| 11661 | popScope(); | 11842 | popScope(); |
| 11662 | temp.push_back(indent() + "until "s + condStr + nl(repeatNode)); | 11843 | temp.push_back(indent() + "until "s + condStr + nl(repeatNode)); |
| 11663 | temp.push_back(indent() + "return "s + accumVar + nl(repeatNode)); | 11844 | temp.push_back(indent() + "return "s + join(vars, ", "sv) + nl(repeatNode)); |
| 11664 | popScope(); | 11845 | popScope(); |
| 11665 | funcStart = anonFuncStart() + nl(repeatNode); | 11846 | funcStart = anonFuncStart() + nl(repeatNode); |
| 11666 | temp.push_back(indent() + anonFuncEnd()); | 11847 | temp.push_back(indent() + anonFuncEnd()); |
| @@ -11975,9 +12156,9 @@ private: | |||
| 11975 | if (x->leftList.size() < x->assign->values.size()) { | 12156 | if (x->leftList.size() < x->assign->values.size()) { |
| 11976 | auto num = x->leftList.size(); | 12157 | auto num = x->leftList.size(); |
| 11977 | if (num > 1) { | 12158 | if (num > 1) { |
| 11978 | _buf << "no more than "sv << num << " right values expected, got "sv << x->assign->values.size(); | 12159 | _buf << "expected no more than "sv << num << " right values, got "sv << x->assign->values.size(); |
| 11979 | } else { | 12160 | } else { |
| 11980 | _buf << "only one right value expected, got "sv << x->assign->values.size(); | 12161 | _buf << "expected only one right value, got "sv << x->assign->values.size(); |
| 11981 | } | 12162 | } |
| 11982 | throw CompileError(clearBuf(), x->assign->values.front()); | 12163 | throw CompileError(clearBuf(), x->assign->values.front()); |
| 11983 | } | 12164 | } |
| @@ -12044,7 +12225,7 @@ private: | |||
| 12044 | auto value = singleValueFrom(assignA->values.back()); | 12225 | auto value = singleValueFrom(assignA->values.back()); |
| 12045 | if (!value) { | 12226 | if (!value) { |
| 12046 | if (listA->names.size() > assignA->values.size()) { | 12227 | if (listA->names.size() > assignA->values.size()) { |
| 12047 | _buf << listA->names.size() << " right values expected, got "sv << assignA->values.size(); | 12228 | _buf << "expected "sv << listA->names.size() << " right values, got "sv << assignA->values.size(); |
| 12048 | throw CompileError(clearBuf(), assignA->values.front()); | 12229 | throw CompileError(clearBuf(), assignA->values.front()); |
| 12049 | } else { | 12230 | } else { |
| 12050 | break; | 12231 | break; |
| @@ -12067,7 +12248,7 @@ private: | |||
| 12067 | if (listA->names.size() > assignA->values.size()) { | 12248 | if (listA->names.size() > assignA->values.size()) { |
| 12068 | auto chainValue = value->item.as<ChainValue_t>(); | 12249 | auto chainValue = value->item.as<ChainValue_t>(); |
| 12069 | if (!chainValue || !ast_is<Invoke_t, InvokeArgs_t>(chainValue->items.back())) { | 12250 | if (!chainValue || !ast_is<Invoke_t, InvokeArgs_t>(chainValue->items.back())) { |
| 12070 | _buf << listA->names.size() << " right values expected, got "sv << assignA->values.size(); | 12251 | _buf << "expected "sv << listA->names.size() << " right values, got "sv << assignA->values.size(); |
| 12071 | throw CompileError(clearBuf(), assignA->values.front()); | 12252 | throw CompileError(clearBuf(), assignA->values.front()); |
| 12072 | } | 12253 | } |
| 12073 | } | 12254 | } |
| @@ -12223,9 +12404,13 @@ private: | |||
| 12223 | throw CompileError(keyword + " is not inside a loop"s, breakLoop); | 12404 | throw CompileError(keyword + " is not inside a loop"s, breakLoop); |
| 12224 | } | 12405 | } |
| 12225 | if (isBreak) { | 12406 | if (isBreak) { |
| 12226 | if (breakLoop->value) { | 12407 | if (breakLoop->valueList) { |
| 12227 | auto exp = toAst<Exp_t>(breakLoop->varBWV, breakLoop->value); | 12408 | auto expList = toAst<ExpList_t>(join(breakLoop->vars, ","sv), breakLoop); |
| 12228 | auto assignment = assignmentFrom(exp, breakLoop->value, breakLoop); | 12409 | auto assignment = breakLoop->new_ptr<ExpListAssign_t>(); |
| 12410 | assignment->expList.set(expList); | ||
| 12411 | auto assign = breakLoop->new_ptr<Assign_t>(); | ||
| 12412 | assign->values.dup(breakLoop->valueList->exprs); | ||
| 12413 | assignment->action.set(assign); | ||
| 12229 | transformAssignment(assignment, out); | 12414 | transformAssignment(assignment, out); |
| 12230 | } | 12415 | } |
| 12231 | out.push_back(indent() + keyword + nl(breakLoop)); | 12416 | out.push_back(indent() + keyword + nl(breakLoop)); |
| @@ -12293,7 +12478,7 @@ private: | |||
| 12293 | auto x = chainAssign; | 12478 | auto x = chainAssign; |
| 12294 | auto value = chainAssign->assign->values.front(); | 12479 | auto value = chainAssign->assign->values.front(); |
| 12295 | if (chainAssign->assign->values.size() != 1) { | 12480 | if (chainAssign->assign->values.size() != 1) { |
| 12296 | throw CompileError("only one right value expected"sv, value); | 12481 | throw CompileError("expected only one right value"sv, value); |
| 12297 | } | 12482 | } |
| 12298 | str_list temp; | 12483 | str_list temp; |
| 12299 | bool constVal = false; | 12484 | bool constVal = false; |
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index 3d8e315..b52a452 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp | |||
| @@ -476,7 +476,7 @@ YueParser::YueParser() { | |||
| 476 | 476 | ||
| 477 | Break = key("break"); | 477 | Break = key("break"); |
| 478 | Continue = key("continue"); | 478 | Continue = key("continue"); |
| 479 | BreakLoop = (Break >> -(space >> Exp) | Continue) >> not_alpha_num; | 479 | BreakLoop = (Break >> -(space >> ExpList) | Continue) >> not_alpha_num; |
| 480 | 480 | ||
| 481 | Return = key("return") >> -(space >> (TableBlock | ExpList)); | 481 | Return = key("return") >> -(space >> (TableBlock | ExpList)); |
| 482 | 482 | ||
