@specs-feup/clava
Version:
A C/C++ source-to-source compiler written in Typescript
83 lines • 2.81 kB
JavaScript
import { EmptyStmt, Loop } from "../../Joinpoints.js";
import ClavaJoinPoints from "../ClavaJoinPoints.js";
/**
* Replaces for loop with an equivalent construct based on a while loop:
* ```c
* for (init; cond; step) {
* //...
* continue;
* //...
* //...
* }
* ```
* becomes
* ```c
* {
* init;
* while (cond) {
* // ...
* goto __for_loop_step_${step_label_suffix};
* // ...
* // ...
* __for_loop_step_${step_label_suffix}:
* step;
* }
* }
* ```
* @param $forStmt - For-loop joinpoint
* @param stepLabelSuffix - Suffix to attach to the for loop step label, added in case there are `continue` statements to account for
* @returns The newly created replacement joinpoint
*/
export default function ForToWhileStmt($forStmt, stepLabelSuffix) {
// replace continues with gotos to the step statement for the new loop body
const localContinues = [...findLocalContinue($forStmt.body)];
let loopStepStatements;
const initStmt = $forStmt.init ?? ClavaJoinPoints.emptyStmt();
const condStmt = ($forStmt.cond === undefined || $forStmt.cond instanceof EmptyStmt)
? ClavaJoinPoints.exprStmt(ClavaJoinPoints.integerLiteral(1))
: $forStmt.cond;
const stepStmt = $forStmt.step ?? ClavaJoinPoints.emptyStmt();
const scopeNodes = $forStmt.scopeNodes;
$forStmt.init?.replaceWith(ClavaJoinPoints.emptyStmt());
$forStmt.cond?.replaceWith(ClavaJoinPoints.emptyStmt());
$forStmt.step?.replaceWith(ClavaJoinPoints.emptyStmt());
for (const $node of scopeNodes) {
$node.detach();
}
if (localContinues.length > 0) {
const $labelDecl = ClavaJoinPoints.labelDecl(`__for_loop_step_${stepLabelSuffix}`);
loopStepStatements = [ClavaJoinPoints.labelStmt($labelDecl), stepStmt];
for (const $continue of localContinues) {
$continue.replaceWith(ClavaJoinPoints.gotoStmt($labelDecl));
}
}
else {
loopStepStatements = [stepStmt];
}
const $scope = ClavaJoinPoints.scope(initStmt, ClavaJoinPoints.whileStmt(condStmt, ClavaJoinPoints.scope(...scopeNodes, ...loopStepStatements)));
$forStmt.replaceWith($scope);
return $scope;
}
/**
* find local continue statements in a loop: that is, recursively traverse the tree and return continue statements,
* while ignoring sub-trees starting from an inner loop
*
* TODO: optimization - ignore sub-trees that will for sure not contain ContinueStmt nodes
*
* @param $jp -
* @returns
*/
function* findLocalContinue($jp) {
if ($jp.astName === "ContinueStmt") {
yield $jp;
return;
}
if ($jp instanceof Loop) {
return;
}
for (const $child of $jp.children) {
yield* findLocalContinue($child);
}
}
;
//# sourceMappingURL=ForToWhileStmt.js.map