Ohm-Management - Projektarbeit B-ME
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

debug-helpers.js 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /**
  2. * @fileoverview Helpers to debug for code path analysis.
  3. * @author Toru Nagashima
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Requirements
  8. //------------------------------------------------------------------------------
  9. const debug = require("debug")("eslint:code-path");
  10. //------------------------------------------------------------------------------
  11. // Helpers
  12. //------------------------------------------------------------------------------
  13. /**
  14. * Gets id of a given segment.
  15. * @param {CodePathSegment} segment - A segment to get.
  16. * @returns {string} Id of the segment.
  17. */
  18. /* istanbul ignore next */
  19. function getId(segment) { // eslint-disable-line require-jsdoc
  20. return segment.id + (segment.reachable ? "" : "!");
  21. }
  22. //------------------------------------------------------------------------------
  23. // Public Interface
  24. //------------------------------------------------------------------------------
  25. module.exports = {
  26. /**
  27. * A flag that debug dumping is enabled or not.
  28. * @type {boolean}
  29. */
  30. enabled: debug.enabled,
  31. /**
  32. * Dumps given objects.
  33. *
  34. * @param {...any} args - objects to dump.
  35. * @returns {void}
  36. */
  37. dump: debug,
  38. /**
  39. * Dumps the current analyzing state.
  40. *
  41. * @param {ASTNode} node - A node to dump.
  42. * @param {CodePathState} state - A state to dump.
  43. * @param {boolean} leaving - A flag whether or not it's leaving
  44. * @returns {void}
  45. */
  46. dumpState: !debug.enabled ? debug : /* istanbul ignore next */ function(node, state, leaving) {
  47. for (let i = 0; i < state.currentSegments.length; ++i) {
  48. const segInternal = state.currentSegments[i].internal;
  49. if (leaving) {
  50. segInternal.exitNodes.push(node);
  51. } else {
  52. segInternal.nodes.push(node);
  53. }
  54. }
  55. debug([
  56. `${state.currentSegments.map(getId).join(",")})`,
  57. `${node.type}${leaving ? ":exit" : ""}`
  58. ].join(" "));
  59. },
  60. /**
  61. * Dumps a DOT code of a given code path.
  62. * The DOT code can be visialized with Graphvis.
  63. *
  64. * @param {CodePath} codePath - A code path to dump.
  65. * @returns {void}
  66. * @see http://www.graphviz.org
  67. * @see http://www.webgraphviz.com
  68. */
  69. dumpDot: !debug.enabled ? debug : /* istanbul ignore next */ function(codePath) {
  70. let text =
  71. "\n" +
  72. "digraph {\n" +
  73. "node[shape=box,style=\"rounded,filled\",fillcolor=white];\n" +
  74. "initial[label=\"\",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];\n";
  75. if (codePath.returnedSegments.length > 0) {
  76. text += "final[label=\"\",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];\n";
  77. }
  78. if (codePath.thrownSegments.length > 0) {
  79. text += "thrown[label=\"✘\",shape=circle,width=0.3,height=0.3,fixedsize];\n";
  80. }
  81. const traceMap = Object.create(null);
  82. const arrows = this.makeDotArrows(codePath, traceMap);
  83. for (const id in traceMap) { // eslint-disable-line guard-for-in
  84. const segment = traceMap[id];
  85. text += `${id}[`;
  86. if (segment.reachable) {
  87. text += "label=\"";
  88. } else {
  89. text += "style=\"rounded,dashed,filled\",fillcolor=\"#FF9800\",label=\"<<unreachable>>\\n";
  90. }
  91. if (segment.internal.nodes.length > 0 || segment.internal.exitNodes.length > 0) {
  92. text += [].concat(
  93. segment.internal.nodes.map(node => {
  94. switch (node.type) {
  95. case "Identifier": return `${node.type} (${node.name})`;
  96. case "Literal": return `${node.type} (${node.value})`;
  97. default: return node.type;
  98. }
  99. }),
  100. segment.internal.exitNodes.map(node => {
  101. switch (node.type) {
  102. case "Identifier": return `${node.type}:exit (${node.name})`;
  103. case "Literal": return `${node.type}:exit (${node.value})`;
  104. default: return `${node.type}:exit`;
  105. }
  106. })
  107. ).join("\\n");
  108. } else {
  109. text += "????";
  110. }
  111. text += "\"];\n";
  112. }
  113. text += `${arrows}\n`;
  114. text += "}";
  115. debug("DOT", text);
  116. },
  117. /**
  118. * Makes a DOT code of a given code path.
  119. * The DOT code can be visialized with Graphvis.
  120. *
  121. * @param {CodePath} codePath - A code path to make DOT.
  122. * @param {Object} traceMap - Optional. A map to check whether or not segments had been done.
  123. * @returns {string} A DOT code of the code path.
  124. */
  125. makeDotArrows(codePath, traceMap) {
  126. const stack = [[codePath.initialSegment, 0]];
  127. const done = traceMap || Object.create(null);
  128. let lastId = codePath.initialSegment.id;
  129. let text = `initial->${codePath.initialSegment.id}`;
  130. while (stack.length > 0) {
  131. const item = stack.pop();
  132. const segment = item[0];
  133. const index = item[1];
  134. if (done[segment.id] && index === 0) {
  135. continue;
  136. }
  137. done[segment.id] = segment;
  138. const nextSegment = segment.allNextSegments[index];
  139. if (!nextSegment) {
  140. continue;
  141. }
  142. if (lastId === segment.id) {
  143. text += `->${nextSegment.id}`;
  144. } else {
  145. text += `;\n${segment.id}->${nextSegment.id}`;
  146. }
  147. lastId = nextSegment.id;
  148. stack.unshift([segment, 1 + index]);
  149. stack.push([nextSegment, 0]);
  150. }
  151. codePath.returnedSegments.forEach(finalSegment => {
  152. if (lastId === finalSegment.id) {
  153. text += "->final";
  154. } else {
  155. text += `;\n${finalSegment.id}->final`;
  156. }
  157. lastId = null;
  158. });
  159. codePath.thrownSegments.forEach(finalSegment => {
  160. if (lastId === finalSegment.id) {
  161. text += "->thrown";
  162. } else {
  163. text += `;\n${finalSegment.id}->thrown`;
  164. }
  165. lastId = null;
  166. });
  167. return `${text};`;
  168. }
  169. };