CallExpressionControlFlowReplacer.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import { inject, injectable, } from 'inversify';
  2. import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
  3. import * as ESTree from 'estree';
  4. import { TControlFlowCustomNodeFactory } from '../../../types/container/custom-nodes/TControlFlowCustomNodeFactory';
  5. import { TControlFlowStorage } from '../../../types/storages/TControlFlowStorage';
  6. import { TInitialData } from '../../../types/TInitialData';
  7. import { TStatement } from '../../../types/node/TStatement';
  8. import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
  9. import { IOptions } from '../../../interfaces/options/IOptions';
  10. import { IRandomGenerator } from '../../../interfaces/utils/IRandomGenerator';
  11. import { ControlFlowCustomNode } from '../../../enums/custom-nodes/ControlFlowCustomNode';
  12. import { AbstractControlFlowReplacer } from './AbstractControlFlowReplacer';
  13. import { CallExpressionFunctionNode } from '../../../custom-nodes/control-flow-flattening-nodes/CallExpressionFunctionNode';
  14. import { CallExpressionControlFlowStorageCallNode } from '../../../custom-nodes/control-flow-flattening-nodes/control-flow-storage-nodes/CallExpressionControlFlowStorageCallNode';
  15. import { NodeGuards } from '../../../node/NodeGuards';
  16. @injectable()
  17. export class CallExpressionControlFlowReplacer extends AbstractControlFlowReplacer {
  18. /**
  19. * @type {number}
  20. */
  21. private static readonly usingExistingIdentifierChance: number = 0.5;
  22. /**
  23. * @param {TControlFlowCustomNodeFactory} controlFlowCustomNodeFactory
  24. * @param {IRandomGenerator} randomGenerator
  25. * @param {IOptions} options
  26. */
  27. constructor (
  28. @inject(ServiceIdentifiers.Factory__IControlFlowCustomNode)
  29. controlFlowCustomNodeFactory: TControlFlowCustomNodeFactory,
  30. @inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
  31. @inject(ServiceIdentifiers.IOptions) options: IOptions
  32. ) {
  33. super(controlFlowCustomNodeFactory, randomGenerator, options);
  34. }
  35. /**
  36. * @param {CallExpression} callExpressionNode
  37. * @param {NodeGuards} parentNode
  38. * @param {TControlFlowStorage} controlFlowStorage
  39. * @returns {NodeGuards}
  40. */
  41. public replace (
  42. callExpressionNode: ESTree.CallExpression,
  43. parentNode: ESTree.Node,
  44. controlFlowStorage: TControlFlowStorage
  45. ): ESTree.Node {
  46. const callee: ESTree.Expression = <ESTree.Expression>callExpressionNode.callee;
  47. if (!NodeGuards.isIdentifierNode(callee)) {
  48. return callExpressionNode;
  49. }
  50. const replacerId: string = String(callExpressionNode.arguments.length);
  51. const callExpressionFunctionCustomNode: ICustomNode<TInitialData<CallExpressionFunctionNode>> =
  52. this.controlFlowCustomNodeFactory(ControlFlowCustomNode.CallExpressionFunctionNode);
  53. const expressionArguments: (ESTree.Expression | ESTree.SpreadElement)[] = callExpressionNode.arguments;
  54. callExpressionFunctionCustomNode.initialize(expressionArguments);
  55. const storageKey: string = this.insertCustomNodeToControlFlowStorage(
  56. callExpressionFunctionCustomNode,
  57. controlFlowStorage,
  58. replacerId,
  59. CallExpressionControlFlowReplacer.usingExistingIdentifierChance
  60. );
  61. return this.getControlFlowStorageCallNode(
  62. controlFlowStorage.getStorageId(),
  63. storageKey,
  64. callee,
  65. expressionArguments
  66. );
  67. }
  68. /**
  69. * @param {string} controlFlowStorageId
  70. * @param {string} storageKey
  71. * @param {Expression} callee
  72. * @param {(Expression | SpreadElement)[]} expressionArguments
  73. * @returns {NodeGuards}
  74. */
  75. protected getControlFlowStorageCallNode (
  76. controlFlowStorageId: string,
  77. storageKey: string,
  78. callee: ESTree.Expression,
  79. expressionArguments: (ESTree.Expression | ESTree.SpreadElement)[]
  80. ): ESTree.Node {
  81. const controlFlowStorageCallCustomNode: ICustomNode<TInitialData<CallExpressionControlFlowStorageCallNode>> =
  82. this.controlFlowCustomNodeFactory(ControlFlowCustomNode.CallExpressionControlFlowStorageCallNode);
  83. controlFlowStorageCallCustomNode.initialize(controlFlowStorageId, storageKey, callee, expressionArguments);
  84. const statementNode: TStatement = controlFlowStorageCallCustomNode.getNode()[0];
  85. if (!statementNode || !NodeGuards.isExpressionStatementNode(statementNode)) {
  86. throw new Error(`\`controlFlowStorageCallCustomNode.getNode()[0]\` should returns array with \`ExpressionStatement\` node`);
  87. }
  88. return statementNode.expression;
  89. }
  90. }