UNPKG

@specs-feup/clava

Version:

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

99 lines (88 loc) 2.78 kB
import { EmptyStmt, Joinpoint, 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: Loop, stepLabelSuffix: number | string) { // 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: Joinpoint): Generator<Joinpoint> { if ($jp.astName === "ContinueStmt") { yield $jp; return; } if ($jp instanceof Loop) { return; } for (const $child of $jp.children) { yield* findLocalContinue($child); } };