instrument2.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // sample on how to use the parser and walker API to instrument some code
  2. var jsp = require("uglify-js").parser;
  3. var pro = require("uglify-js").uglify;
  4. function instrument(code) {
  5. var ast = jsp.parse(code, false, true); // true for the third arg specifies that we want
  6. // to have start/end tokens embedded in the
  7. // statements
  8. var w = pro.ast_walker();
  9. function trace (line, comment) {
  10. var code = pro.gen_code(line, { beautify: true });
  11. var data = line[0]
  12. var args = []
  13. if (!comment) comment = ""
  14. if (typeof data === "object") {
  15. code = code.split(/\n/).shift()
  16. args = [ [ "string", data.toString() ],
  17. [ "string", code ],
  18. [ "num", data.start.line ],
  19. [ "num", data.start.col ],
  20. [ "num", data.end.line ],
  21. [ "num", data.end.col ]]
  22. } else {
  23. args = [ [ "string", data ],
  24. [ "string", code ]]
  25. }
  26. return [ "call", [ "name", "trace" ], args ];
  27. }
  28. // we're gonna need this to push elements that we're currently looking at, to avoid
  29. // endless recursion.
  30. var analyzing = [];
  31. function do_stat() {
  32. var ret;
  33. if (this[0].start && analyzing.indexOf(this) < 0) {
  34. // without the `analyzing' hack, w.walk(this) would re-enter here leading
  35. // to infinite recursion
  36. analyzing.push(this);
  37. ret = [ "splice",
  38. [ [ "stat", trace(this) ],
  39. w.walk(this) ]];
  40. analyzing.pop(this);
  41. }
  42. return ret;
  43. }
  44. function do_cond(c, t, f) {
  45. return [ this[0], w.walk(c),
  46. ["seq", trace(t), w.walk(t) ],
  47. ["seq", trace(f), w.walk(f) ]];
  48. }
  49. function do_binary(c, l, r) {
  50. if (c !== "&&" && c !== "||") {
  51. return [this[0], c, w.walk(l), w.walk(r)];
  52. }
  53. return [ this[0], c,
  54. ["seq", trace(l), w.walk(l) ],
  55. ["seq", trace(r), w.walk(r) ]];
  56. }
  57. var new_ast = w.with_walkers({
  58. "stat" : do_stat,
  59. "label" : do_stat,
  60. "break" : do_stat,
  61. "continue" : do_stat,
  62. "debugger" : do_stat,
  63. "var" : do_stat,
  64. "const" : do_stat,
  65. "return" : do_stat,
  66. "throw" : do_stat,
  67. "try" : do_stat,
  68. "defun" : do_stat,
  69. "if" : do_stat,
  70. "while" : do_stat,
  71. "do" : do_stat,
  72. "for" : do_stat,
  73. "for-in" : do_stat,
  74. "switch" : do_stat,
  75. "with" : do_stat,
  76. "conditional" : do_cond,
  77. "binary" : do_binary
  78. }, function(){
  79. return w.walk(ast);
  80. });
  81. return pro.gen_code(new_ast, { beautify: true });
  82. }
  83. ////// test code follows.
  84. var code = instrument(test.toString());
  85. console.log(code);
  86. function test() {
  87. // simple stats
  88. a = 5;
  89. c += a + b;
  90. "foo";
  91. // var
  92. var foo = 5;
  93. const bar = 6, baz = 7;
  94. // switch block. note we can't track case lines the same way.
  95. switch ("foo") {
  96. case "foo":
  97. return 1;
  98. case "bar":
  99. return 2;
  100. }
  101. // for/for in
  102. for (var i = 0; i < 5; ++i) {
  103. console.log("Hello " + i);
  104. }
  105. for (var i in [ 1, 2, 3]) {
  106. console.log(i);
  107. }
  108. for (var i = 0; i < 5; ++i)
  109. console.log("foo");
  110. for (var i = 0; i < 5; ++i) {
  111. console.log("foo");
  112. }
  113. var k = plurp() ? 1 : 0;
  114. var x = a ? doX(y) && goZoo("zoo")
  115. : b ? blerg({ x: y })
  116. : null;
  117. var x = X || Y;
  118. }