BlockStatementControlFlowFlatteningNode.ts 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. import { inject, injectable, } from 'inversify';
  2. import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
  3. import * as ESTree from 'estree';
  4. import { TIdentifierNamesGeneratorFactory } from '../../types/container/generators/TIdentifierNamesGeneratorFactory';
  5. import { TStatement } from '../../types/node/TStatement';
  6. import { ICustomCodeHelperFormatter } from '../../interfaces/custom-code-helpers/ICustomCodeHelperFormatter';
  7. import { IOptions } from '../../interfaces/options/IOptions';
  8. import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
  9. import { initializable } from '../../decorators/Initializable';
  10. import { AbstractCustomNode } from '../AbstractCustomNode';
  11. import { NodeFactory } from '../../node/NodeFactory';
  12. import { NodeGuards } from '../../node/NodeGuards';
  13. import { NodeUtils } from '../../node/NodeUtils';
  14. @injectable()
  15. export class BlockStatementControlFlowFlatteningNode extends AbstractCustomNode {
  16. /**
  17. * @type {ESTree.Statement[]}
  18. */
  19. @initializable()
  20. private blockStatementBody!: ESTree.Statement[];
  21. /**
  22. * @type {number[]}
  23. */
  24. @initializable()
  25. private originalKeysIndexesInShuffledArray!: number[];
  26. /**
  27. * @type {number[]}
  28. */
  29. @initializable()
  30. private shuffledKeys!: number[];
  31. /**
  32. * @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
  33. * @param {ICustomCodeHelperFormatter} customCodeHelperFormatter
  34. * @param {IRandomGenerator} randomGenerator
  35. * @param {IOptions} options
  36. */
  37. public constructor (
  38. @inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
  39. identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
  40. @inject(ServiceIdentifiers.ICustomCodeHelperFormatter) customCodeHelperFormatter: ICustomCodeHelperFormatter,
  41. @inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
  42. @inject(ServiceIdentifiers.IOptions) options: IOptions
  43. ) {
  44. super(
  45. identifierNamesGeneratorFactory,
  46. customCodeHelperFormatter,
  47. randomGenerator,
  48. options
  49. );
  50. }
  51. /**
  52. * @param {Statement[]} blockStatementBody
  53. * @param {number[]} shuffledKeys
  54. * @param {number[]} originalKeysIndexesInShuffledArray
  55. */
  56. public initialize (
  57. blockStatementBody: ESTree.Statement[],
  58. shuffledKeys: number[],
  59. originalKeysIndexesInShuffledArray: number[]
  60. ): void {
  61. this.blockStatementBody = blockStatementBody;
  62. this.shuffledKeys = shuffledKeys;
  63. this.originalKeysIndexesInShuffledArray = originalKeysIndexesInShuffledArray;
  64. }
  65. /**
  66. * @returns {TStatement[]}
  67. */
  68. protected getNodeStructure (): TStatement[] {
  69. const controllerIdentifierName: string = this.randomGenerator.getRandomString(6);
  70. const indexIdentifierName: string = this.randomGenerator.getRandomString(6);
  71. const structure: ESTree.BlockStatement = NodeFactory.blockStatementNode([
  72. NodeFactory.variableDeclarationNode(
  73. [
  74. NodeFactory.variableDeclaratorNode(
  75. NodeFactory.identifierNode(controllerIdentifierName),
  76. NodeFactory.callExpressionNode(
  77. NodeFactory.memberExpressionNode(
  78. NodeFactory.literalNode(
  79. this.originalKeysIndexesInShuffledArray.join('|')
  80. ),
  81. NodeFactory.identifierNode('split')
  82. ),
  83. [
  84. NodeFactory.literalNode('|')
  85. ]
  86. )
  87. )
  88. ],
  89. 'const'
  90. ),
  91. NodeFactory.variableDeclarationNode(
  92. [
  93. NodeFactory.variableDeclaratorNode(
  94. NodeFactory.identifierNode(indexIdentifierName),
  95. NodeFactory.literalNode(0)
  96. )
  97. ],
  98. 'let'
  99. ),
  100. NodeFactory.whileStatementNode(
  101. NodeFactory.literalNode(true),
  102. NodeFactory.blockStatementNode([
  103. NodeFactory.switchStatementNode(
  104. NodeFactory.memberExpressionNode(
  105. NodeFactory.identifierNode(controllerIdentifierName),
  106. NodeFactory.updateExpressionNode(
  107. '++',
  108. NodeFactory.identifierNode(indexIdentifierName)
  109. ),
  110. true
  111. ),
  112. this.shuffledKeys.map((key: number, index: number) => {
  113. const statement: ESTree.Statement = this.blockStatementBody[key];
  114. const consequent: ESTree.Statement[] = [statement];
  115. /**
  116. * We shouldn't add continue statement after return statement
  117. * to prevent `unreachable code after return statement` warnings
  118. */
  119. if (!NodeGuards.isReturnStatementNode(statement)) {
  120. consequent.push(NodeFactory.continueStatement());
  121. }
  122. return NodeFactory.switchCaseNode(
  123. NodeFactory.literalNode(String(index)),
  124. consequent
  125. );
  126. })
  127. ),
  128. NodeFactory.breakStatement()
  129. ])
  130. )
  131. ]);
  132. NodeUtils.parentizeAst(structure);
  133. return [structure];
  134. }
  135. }