UNPKG

@specs-feup/clava

Version:

A C/C++ source-to-source compiler written in Typescript

83 lines 2.81 kB
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