aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/yuescript/yue_ast.cpp4
-rw-r--r--src/yuescript/yue_ast.h6
-rw-r--r--src/yuescript/yue_compiler.cpp413
-rw-r--r--src/yuescript/yue_parser.cpp2
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}
203std::string BreakLoop_t::to_string(void* ud) const { 203std::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
915AST_NODE(BreakLoop) 915AST_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;
920AST_END(BreakLoop) 920AST_END(BreakLoop)
921 921
922AST_NODE(PipeBody) 922AST_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
81const std::string_view version = "0.32.9"sv; 81const std::string_view version = "0.33.0"sv;
82const std::string_view extension = "yue"sv; 82const std::string_view extension = "yue"sv;
83 83
84class CompileError : public std::logic_error { 84class 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