1
0

walk.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. // AST walker module for Mozilla Parser API compatible trees
  2. (function(exports) {
  3. "use strict";
  4. // A simple walk is one where you simply specify callbacks to be
  5. // called on specific nodes. The last two arguments are optional. A
  6. // simple use would be
  7. //
  8. // walk.simple(myTree, {
  9. // Expression: function(node) { ... }
  10. // });
  11. //
  12. // to do something with all expressions. All Parser API node types
  13. // can be used to identify node types, as well as Expression,
  14. // Statement, and ScopeBody, which denote categories of nodes.
  15. //
  16. // The base argument can be used to pass a custom (recursive)
  17. // walker, and state can be used to give this walked an initial
  18. // state.
  19. exports.simple = function(node, visitors, base, state) {
  20. if (!base) base = exports;
  21. function c(node, st, override) {
  22. var type = override || node.type, found = visitors[type];
  23. if (found) found(node, st);
  24. base[type](node, st, c);
  25. }
  26. c(node, state);
  27. };
  28. // A recursive walk is one where your functions override the default
  29. // walkers. They can modify and replace the state parameter that's
  30. // threaded through the walk, and can opt how and whether to walk
  31. // their child nodes (by calling their third argument on these
  32. // nodes).
  33. exports.recursive = function(node, state, funcs, base) {
  34. var visitor = exports.make(funcs, base);
  35. function c(node, st, override) {
  36. visitor[override || node.type](node, st, c);
  37. }
  38. c(node, state);
  39. };
  40. // Used to create a custom walker. Will fill in all missing node
  41. // type properties with the defaults.
  42. exports.make = function(funcs, base) {
  43. if (!base) base = exports;
  44. var visitor = {};
  45. for (var type in base)
  46. visitor[type] = funcs.hasOwnProperty(type) ? funcs[type] : base[type];
  47. return visitor;
  48. };
  49. function skipThrough(node, st, c) { c(node, st); }
  50. function ignore(node, st, c) {}
  51. // Node walkers.
  52. exports.Program = exports.BlockStatement = function(node, st, c) {
  53. for (var i = 0; i < node.body.length; ++i)
  54. c(node.body[i], st, "Statement");
  55. };
  56. exports.Statement = skipThrough;
  57. exports.EmptyStatement = ignore;
  58. exports.ExpressionStatement = function(node, st, c) {
  59. c(node.expression, st, "Expression");
  60. };
  61. exports.IfStatement = function(node, st, c) {
  62. c(node.test, st, "Expression");
  63. c(node.consequent, st, "Statement");
  64. if (node.alternate) c(node.alternate, st, "Statement");
  65. };
  66. exports.LabeledStatement = function(node, st, c) {
  67. c(node.body, st, "Statement");
  68. };
  69. exports.BreakStatement = exports.ContinueStatement = ignore;
  70. exports.WithStatement = function(node, st, c) {
  71. c(node.object, st, "Expression");
  72. c(node.body, st, "Statement");
  73. };
  74. exports.SwitchStatement = function(node, st, c) {
  75. c(node.discriminant, st, "Expression");
  76. for (var i = 0; i < node.cases.length; ++i) {
  77. var cs = node.cases[i];
  78. if (cs.test) c(cs.test, st, "Expression");
  79. for (var j = 0; j < cs.consequent.length; ++j)
  80. c(cs.consequent[j], st, "Statement");
  81. }
  82. };
  83. exports.ReturnStatement = function(node, st, c) {
  84. if (node.argument) c(node.argument, st, "Expression");
  85. };
  86. exports.ThrowStatement = function(node, st, c) {
  87. c(node.argument, st, "Expression");
  88. };
  89. exports.TryStatement = function(node, st, c) {
  90. c(node.block, st, "Statement");
  91. for (var i = 0; i < node.handlers.length; ++i)
  92. c(node.handlers[i].body, st, "ScopeBody");
  93. if (node.finalizer) c(node.finalizer, st, "Statement");
  94. };
  95. exports.WhileStatement = function(node, st, c) {
  96. c(node.test, st, "Expression");
  97. c(node.body, st, "Statement");
  98. };
  99. exports.DoWhileStatement = exports.WhileStatement;
  100. exports.ForStatement = function(node, st, c) {
  101. if (node.init) c(node.init, st, "ForInit");
  102. if (node.test) c(node.test, st, "Expression");
  103. if (node.update) c(node.update, st, "Expression");
  104. c(node.body, st, "Statement");
  105. };
  106. exports.ForInStatement = function(node, st, c) {
  107. c(node.left, st, "ForInit");
  108. c(node.right, st, "Expression");
  109. c(node.body, st, "Statement");
  110. };
  111. exports.ForInit = function(node, st, c) {
  112. if (node.type == "VariableDeclaration") c(node, st);
  113. else c(node, st, "Expression");
  114. };
  115. exports.DebuggerStatement = ignore;
  116. exports.FunctionDeclaration = function(node, st, c) {
  117. c(node, st, "Function");
  118. };
  119. exports.VariableDeclaration = function(node, st, c) {
  120. for (var i = 0; i < node.declarations.length; ++i) {
  121. var decl = node.declarations[i];
  122. if (decl.init) c(decl.init, st, "Expression");
  123. }
  124. };
  125. exports.Function = function(node, st, c) {
  126. c(node.body, st, "ScopeBody");
  127. };
  128. exports.ScopeBody = function(node, st, c) {
  129. c(node, st, "Statement");
  130. };
  131. exports.Expression = skipThrough;
  132. exports.ThisExpression = ignore;
  133. exports.ArrayExpression = function(node, st, c) {
  134. for (var i = 0; i < node.elements.length; ++i) {
  135. var elt = node.elements[i];
  136. if (elt) c(elt, st, "Expression");
  137. }
  138. };
  139. exports.ObjectExpression = function(node, st, c) {
  140. for (var i = 0; i < node.properties.length; ++i)
  141. c(node.properties[i].value, st, "Expression");
  142. };
  143. exports.FunctionExpression = exports.FunctionDeclaration;
  144. exports.SequenceExpression = function(node, st, c) {
  145. for (var i = 0; i < node.expressions.length; ++i)
  146. c(node.expressions[i], st, "Expression");
  147. };
  148. exports.UnaryExpression = exports.UpdateExpression = function(node, st, c) {
  149. c(node.argument, st, "Expression");
  150. };
  151. exports.BinaryExpression = exports.AssignmentExpression = exports.LogicalExpression = function(node, st, c) {
  152. c(node.left, st, "Expression");
  153. c(node.right, st, "Expression");
  154. };
  155. exports.ConditionalExpression = function(node, st, c) {
  156. c(node.test, st, "Expression");
  157. c(node.consequent, st, "Expression");
  158. c(node.alternate, st, "Expression");
  159. };
  160. exports.NewExpression = exports.CallExpression = function(node, st, c) {
  161. c(node.callee, st, "Expression");
  162. if (node.arguments) for (var i = 0; i < node.arguments.length; ++i)
  163. c(node.arguments[i], st, "Expression");
  164. };
  165. exports.MemberExpression = function(node, st, c) {
  166. c(node.object, st, "Expression");
  167. if (node.computed) c(node.property, st, "Expression");
  168. };
  169. exports.Identifier = exports.Literal = ignore;
  170. // A custom walker that keeps track of the scope chain and the
  171. // variables defined in it.
  172. function makeScope(prev) {
  173. return {vars: Object.create(null), prev: prev};
  174. }
  175. exports.scopeVisitor = exports.make({
  176. Function: function(node, scope, c) {
  177. var inner = makeScope(scope);
  178. for (var i = 0; i < node.params.length; ++i)
  179. inner.vars[node.params[i].name] = {type: "argument", node: node.params[i]};
  180. if (node.id) {
  181. var decl = node.type == "FunctionDeclaration";
  182. (decl ? scope : inner).vars[node.id.name] =
  183. {type: decl ? "function" : "function name", node: node.id};
  184. }
  185. c(node.body, inner, "ScopeBody");
  186. },
  187. TryStatement: function(node, scope, c) {
  188. c(node.block, scope, "Statement");
  189. for (var i = 0; i < node.handlers.length; ++i) {
  190. var handler = node.handlers[i], inner = makeScope(scope);
  191. inner.vars[handler.param.name] = {type: "catch clause", node: handler.param};
  192. c(handler.body, inner, "ScopeBody");
  193. }
  194. if (node.finalizer) c(node.finalizer, scope, "Statement");
  195. },
  196. VariableDeclaration: function(node, scope, c) {
  197. for (var i = 0; i < node.declarations.length; ++i) {
  198. var decl = node.declarations[i];
  199. scope.vars[decl.id.name] = {type: "var", node: decl.id};
  200. if (decl.init) c(decl.init, scope, "Expression");
  201. }
  202. }
  203. });
  204. })(typeof exports == "undefined" ? acorn.walk = {} : exports);