BinaryExpressionControlFlowReplacer.ts 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import { injectable, inject } from 'inversify';
  2. import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
  3. import * as ESTree from 'estree';
  4. import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory';
  5. import { TStatement } from '../../../types/node/TStatement';
  6. import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
  7. import { IOptions } from '../../../interfaces/options/IOptions';
  8. import { IStorage } from '../../../interfaces/storages/IStorage';
  9. import { CustomNodes } from '../../../enums/container/CustomNodes';
  10. import { AbstractControlFlowReplacer } from './AbstractControlFlowReplacer';
  11. import { Node } from '../../../node/Node';
  12. import { NodeUtils } from '../../../node/NodeUtils';
  13. import { RandomGeneratorUtils } from '../../../utils/RandomGeneratorUtils';
  14. @injectable()
  15. export class BinaryExpressionControlFlowReplacer extends AbstractControlFlowReplacer {
  16. /**
  17. * @type {number}
  18. */
  19. private static readonly useExistingOperatorKeyThreshold: number = 0.5;
  20. /**
  21. * @type {Map<string, Map<ESTree.BinaryOperator, string[]>>}
  22. */
  23. private readonly binaryOperatorsDataByControlFlowStorageId: Map <string, Map<ESTree.BinaryOperator, string[]>> = new Map();
  24. /**
  25. * @type {TCustomNodeFactory}
  26. */
  27. private readonly customNodeFactory: TCustomNodeFactory;
  28. /**
  29. * @param customNodeFactory
  30. * @param options
  31. */
  32. constructor (
  33. @inject(ServiceIdentifiers['Factory<ICustomNode>']) customNodeFactory: TCustomNodeFactory,
  34. @inject(ServiceIdentifiers.IOptions) options: IOptions
  35. ) {
  36. super(options);
  37. this.customNodeFactory = customNodeFactory;
  38. }
  39. /**
  40. * @param binaryOperatorsDataByControlFlowStorageId
  41. * @param controlFlowStorageId
  42. * @returns {Map<ESTree.BinaryOperator, string[]>}
  43. */
  44. private static getStorageKeysByBinaryOperatorForCurrentStorage (
  45. binaryOperatorsDataByControlFlowStorageId: Map<string, Map<ESTree.BinaryOperator, string[]>>,
  46. controlFlowStorageId: string
  47. ): Map<ESTree.BinaryOperator, string[]> {
  48. let storageKeysByBinaryOperator: Map<ESTree.BinaryOperator, string[]>;
  49. if (binaryOperatorsDataByControlFlowStorageId.has(controlFlowStorageId)) {
  50. storageKeysByBinaryOperator = <Map<ESTree.BinaryOperator, string[]>>binaryOperatorsDataByControlFlowStorageId
  51. .get(controlFlowStorageId);
  52. } else {
  53. storageKeysByBinaryOperator = new Map <ESTree.BinaryOperator, string[]> ();
  54. }
  55. return storageKeysByBinaryOperator;
  56. }
  57. /**
  58. * @param binaryExpressionNode
  59. * @param parentNode
  60. * @param controlFlowStorage
  61. * @returns {ESTree.Node}
  62. */
  63. public replace (
  64. binaryExpressionNode: ESTree.BinaryExpression,
  65. parentNode: ESTree.Node,
  66. controlFlowStorage: IStorage <ICustomNode>
  67. ): ESTree.Node {
  68. const controlFlowStorageId: string = controlFlowStorage.getStorageId();
  69. const controlFlowStorageCallCustomNode: ICustomNode = this.customNodeFactory(CustomNodes.ControlFlowStorageCallNode);
  70. const storageKeysByBinaryOperator: Map<ESTree.BinaryOperator, string[]> = BinaryExpressionControlFlowReplacer
  71. .getStorageKeysByBinaryOperatorForCurrentStorage(
  72. this.binaryOperatorsDataByControlFlowStorageId,
  73. controlFlowStorageId
  74. );
  75. let storageKeysForCurrentOperator: string[] | undefined = storageKeysByBinaryOperator.get(binaryExpressionNode.operator);
  76. let storageKey: string;
  77. if (
  78. RandomGeneratorUtils.getRandomFloat(0, 1) > BinaryExpressionControlFlowReplacer.useExistingOperatorKeyThreshold &&
  79. storageKeysForCurrentOperator &&
  80. storageKeysForCurrentOperator.length
  81. ) {
  82. storageKey = RandomGeneratorUtils.getRandomGenerator().pickone(storageKeysForCurrentOperator);
  83. } else {
  84. const binaryExpressionFunctionCustomNode: ICustomNode = this.customNodeFactory(CustomNodes.BinaryExpressionFunctionNode);
  85. binaryExpressionFunctionCustomNode.initialize(binaryExpressionNode.operator);
  86. storageKey = RandomGeneratorUtils.getRandomString(3);
  87. storageKeysByBinaryOperator.set(binaryExpressionNode.operator, [storageKey]);
  88. this.binaryOperatorsDataByControlFlowStorageId.set(controlFlowStorageId, storageKeysByBinaryOperator);
  89. controlFlowStorage.set(storageKey, binaryExpressionFunctionCustomNode);
  90. }
  91. controlFlowStorageCallCustomNode.initialize(
  92. controlFlowStorageId,
  93. storageKey,
  94. NodeUtils.convertStructureToCode([binaryExpressionNode.left]),
  95. NodeUtils.convertStructureToCode([binaryExpressionNode.right])
  96. );
  97. const statementNode: TStatement = controlFlowStorageCallCustomNode.getNode()[0];
  98. if (!statementNode || !Node.isExpressionStatementNode(statementNode)) {
  99. throw new Error(`\`controlFlowStorageCallNode.getNode()[0]\` should returns array with \`ExpressionStatement\` node`);
  100. }
  101. return statementNode.expression;
  102. }
  103. }