| 1431 | } |
| 1432 | |
| 1433 | ExpressionPtr replaceGeneratorFor ( ExprFor * expr, const FunctionPtr & func ) { |
| 1434 | auto begin_loop_label = func->totalGenLabel ++; |
| 1435 | auto mid_loop_label = func->totalGenLabel ++; |
| 1436 | auto end_loop_label = func->totalGenLabel ++; |
| 1437 | ExprFor * forCopy = nullptr; |
| 1438 | ExprBlock * bodyBlock = nullptr; |
| 1439 | const bool hasFinally = expr->body->rtti_isBlock() && |
| 1440 | !static_cast<ExprBlock*>(expr->body)->finalList.empty(); |
| 1441 | string breakFlag, returnFlag, returnValueName; |
| 1442 | bool hasReturn = false; |
| 1443 | if ( hasFinally ) { |
| 1444 | breakFlag = "__broke_for_" + to_string(expr->at.line) + "_" + to_string(expr->at.column); |
| 1445 | hasReturn = bodyHasTopLevelReturn(expr->body); |
| 1446 | if ( hasReturn ) { |
| 1447 | returnFlag = "__returning_for_" + to_string(expr->at.line) + "_" + to_string(expr->at.column); |
| 1448 | returnValueName = "__return_value_for_" + to_string(expr->at.line) + "_" + to_string(expr->at.column); |
| 1449 | } |
| 1450 | } |
| 1451 | if ( expr->body->rtti_isBlock() ) { |
| 1452 | forCopy = static_cast<ExprFor*>(expr->clone()); |
| 1453 | bodyBlock = static_cast<ExprBlock*>(forCopy->body); |
| 1454 | giveBlockVariablesUniqueNames(forCopy); |
| 1455 | if ( hasFinally ) { |
| 1456 | // break -> set flag, goto mid (finally runs, flag check -> end, iterator_close runs) |
| 1457 | // continue -> mid (finally runs, advances iterator, re-checks) |
| 1458 | // return -> spill value, set flag, goto mid (finally runs, then real return) |
| 1459 | replaceBreakContinueAndReturn(bodyBlock, mid_loop_label, mid_loop_label, breakFlag, |
| 1460 | mid_loop_label, returnFlag, returnValueName); |
| 1461 | } else { |
| 1462 | replaceBreakAndContinue(bodyBlock, end_loop_label, mid_loop_label); |
| 1463 | } |
| 1464 | expr = forCopy; |
| 1465 | } |
| 1466 | auto blk = new ExprBlock(); |
| 1467 | blk->at = expr->at; |
| 1468 | blk->isCollapseable = true; |
| 1469 | auto gtel = new ExprGoto(expr->at, end_loop_label); |
| 1470 | auto btel = new ExprBlock(); |
| 1471 | btel->at = expr->at; |
| 1472 | btel->list.push_back(gtel); |
| 1473 | // names |
| 1474 | string loopVar = "_loop_at_" + to_string(expr->at.line) + "_" + to_string(expr->at.column); |
| 1475 | vector<string> srcNames, pVarNames; |
| 1476 | for ( size_t si=0, sis=expr->sources.size(); si!=sis; ++si ) { |
| 1477 | srcNames.push_back("_source_" + to_string(si) + "_at_" + to_string(expr->at.line) + "_" + to_string(expr->at.column)); |
| 1478 | pVarNames.push_back("_pvar_" + to_string(si) + "_at_" + to_string(expr->at.line) + "_" + to_string(expr->at.column)); |
| 1479 | } |
| 1480 | auto leqt = new ExprLet(); |
| 1481 | leqt->at = expr->at; |
| 1482 | leqt->atInit = expr->at; |
| 1483 | leqt->visibility = expr->visibility; |
| 1484 | auto lvar = new Variable(); |
| 1485 | lvar->generated = true; |
| 1486 | lvar->at = expr->at; |
| 1487 | lvar->name = loopVar; |
| 1488 | lvar->type = new TypeDecl(Type::tBool); |
| 1489 | lvar->init = new ExprConstBool(expr->at, true); |
| 1490 | leqt->variables.push_back(lvar); |
no test coverage detected