import { injectable, inject } from 'inversify'; import { ServiceIdentifiers } from '../../container/ServiceIdentifiers'; import * as ESTree from 'estree'; import { TStatement } from '../../types/node/TStatement'; import { IOptions } from '../../interfaces/options/IOptions'; import { initializable } from '../../decorators/Initializable'; import { AbstractCustomNode } from '../AbstractCustomNode'; import { Nodes } from '../../node/Nodes'; import { NodeUtils } from '../../node/NodeUtils'; import { RandomGeneratorUtils } from '../../utils/RandomGeneratorUtils'; @injectable() export class BlockStatementControlFlowFlatteningNode extends AbstractCustomNode { /** * @type {ESTree.Statement[]} */ @initializable() private blockStatementBody: ESTree.Statement[]; /** * @type {number[]} */ @initializable() private originalKeysIndexesInShuffledArray: number[]; /** * @type {number[]} */ @initializable() private shuffledKeys: number[]; /** * @param options */ constructor ( @inject(ServiceIdentifiers.IOptions) options: IOptions ) { super(options); } /*** * @param blockStatementBody * @param shuffledKeys * @param originalKeysIndexesInShuffledArray */ public initialize ( blockStatementBody: ESTree.Statement[], shuffledKeys: number[], originalKeysIndexesInShuffledArray: number[] ): void { this.blockStatementBody = blockStatementBody; this.shuffledKeys = shuffledKeys; this.originalKeysIndexesInShuffledArray = originalKeysIndexesInShuffledArray; } /** * @returns {TStatement[]} */ protected getNodeStructure (): TStatement[] { const controllerIdentifierName: string = RandomGeneratorUtils.getRandomString(3); const indexIdentifierName: string = RandomGeneratorUtils.getRandomString(3); const structure: ESTree.BlockStatement = Nodes.getBlockStatementNode([ Nodes.getVariableDeclarationNode([ Nodes.getVariableDeclaratorNode( Nodes.getIdentifierNode(controllerIdentifierName), Nodes.getCallExpressionNode( Nodes.getMemberExpressionNode( Nodes.getLiteralNode( this.originalKeysIndexesInShuffledArray.join('|') ), Nodes.getIdentifierNode('split') ), [ Nodes.getLiteralNode('|') ] ) ), Nodes.getVariableDeclaratorNode( Nodes.getIdentifierNode(indexIdentifierName), Nodes.getLiteralNode(0) ) ]), Nodes.getWhileStatementNode( Nodes.getLiteralNode(true), Nodes.getBlockStatementNode([ Nodes.getSwitchStatementNode( Nodes.getMemberExpressionNode( Nodes.getIdentifierNode(controllerIdentifierName), Nodes.getUpdateExpressionNode( '++', Nodes.getIdentifierNode(indexIdentifierName) ), true ), this.shuffledKeys.map((key: number, index: number) => { return Nodes.getSwitchCaseNode( Nodes.getLiteralNode(String(index)), [ this.blockStatementBody[key], Nodes.getContinueStatement() ] ); }) ), Nodes.getBreakStatement() ]) ) ]); NodeUtils.parentize(structure); return [structure]; } }