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