walk.es.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. // AST walker module for Mozilla Parser API compatible trees
  2. // A simple walk is one where you simply specify callbacks to be
  3. // called on specific nodes. The last two arguments are optional. A
  4. // simple use would be
  5. //
  6. // walk.simple(myTree, {
  7. // Expression: function(node) { ... }
  8. // });
  9. //
  10. // to do something with all expressions. All Parser API node types
  11. // can be used to identify node types, as well as Expression,
  12. // Statement, and ScopeBody, which denote categories of nodes.
  13. //
  14. // The base argument can be used to pass a custom (recursive)
  15. // walker, and state can be used to give this walked an initial
  16. // state.
  17. function simple(node, visitors, base, state, override) {
  18. if (!base) base = exports.base
  19. ;(function c(node, st, override) {
  20. var type = override || node.type, found = visitors[type]
  21. base[type](node, st, c)
  22. if (found) found(node, st)
  23. })(node, state, override)
  24. }
  25. // An ancestor walk keeps an array of ancestor nodes (including the
  26. // current node) and passes them to the callback as third parameter
  27. // (and also as state parameter when no other state is present).
  28. function ancestor(node, visitors, base, state) {
  29. if (!base) base = exports.base
  30. var ancestors = []
  31. ;(function c(node, st, override) {
  32. var type = override || node.type, found = visitors[type]
  33. var isNew = node != ancestors[ancestors.length - 1]
  34. if (isNew) ancestors.push(node)
  35. base[type](node, st, c)
  36. if (found) found(node, st || ancestors, ancestors)
  37. if (isNew) ancestors.pop()
  38. })(node, state)
  39. }
  40. // A recursive walk is one where your functions override the default
  41. // walkers. They can modify and replace the state parameter that's
  42. // threaded through the walk, and can opt how and whether to walk
  43. // their child nodes (by calling their third argument on these
  44. // nodes).
  45. function recursive(node, state, funcs, base, override) {
  46. var visitor = funcs ? exports.make(funcs, base) : base
  47. ;(function c(node, st, override) {
  48. visitor[override || node.type](node, st, c)
  49. })(node, state, override)
  50. }
  51. function makeTest(test) {
  52. if (typeof test == "string")
  53. return function (type) { return type == test; }
  54. else if (!test)
  55. return function () { return true; }
  56. else
  57. return test
  58. }
  59. var Found = function Found(node, state) { this.node = node; this.state = state };
  60. // Find a node with a given start, end, and type (all are optional,
  61. // null can be used as wildcard). Returns a {node, state} object, or
  62. // undefined when it doesn't find a matching node.
  63. function findNodeAt(node, start, end, test, base, state) {
  64. test = makeTest(test)
  65. if (!base) base = exports.base
  66. try {
  67. ;(function c(node, st, override) {
  68. var type = override || node.type
  69. if ((start == null || node.start <= start) &&
  70. (end == null || node.end >= end))
  71. base[type](node, st, c)
  72. if ((start == null || node.start == start) &&
  73. (end == null || node.end == end) &&
  74. test(type, node))
  75. throw new Found(node, st)
  76. })(node, state)
  77. } catch (e) {
  78. if (e instanceof Found) return e
  79. throw e
  80. }
  81. }
  82. // Find the innermost node of a given type that contains the given
  83. // position. Interface similar to findNodeAt.
  84. function findNodeAround(node, pos, test, base, state) {
  85. test = makeTest(test)
  86. if (!base) base = exports.base
  87. try {
  88. ;(function c(node, st, override) {
  89. var type = override || node.type
  90. if (node.start > pos || node.end < pos) return
  91. base[type](node, st, c)
  92. if (test(type, node)) throw new Found(node, st)
  93. })(node, state)
  94. } catch (e) {
  95. if (e instanceof Found) return e
  96. throw e
  97. }
  98. }
  99. // Find the outermost matching node after a given position.
  100. function findNodeAfter(node, pos, test, base, state) {
  101. test = makeTest(test)
  102. if (!base) base = exports.base
  103. try {
  104. ;(function c(node, st, override) {
  105. if (node.end < pos) return
  106. var type = override || node.type
  107. if (node.start >= pos && test(type, node)) throw new Found(node, st)
  108. base[type](node, st, c)
  109. })(node, state)
  110. } catch (e) {
  111. if (e instanceof Found) return e
  112. throw e
  113. }
  114. }
  115. // Find the outermost matching node before a given position.
  116. function findNodeBefore(node, pos, test, base, state) {
  117. test = makeTest(test)
  118. if (!base) base = exports.base
  119. var max
  120. ;(function c(node, st, override) {
  121. if (node.start > pos) return
  122. var type = override || node.type
  123. if (node.end <= pos && (!max || max.node.end < node.end) && test(type, node))
  124. max = new Found(node, st)
  125. base[type](node, st, c)
  126. })(node, state)
  127. return max
  128. }
  129. // Fallback to an Object.create polyfill for older environments.
  130. var create = Object.create || function(proto) {
  131. function Ctor() {}
  132. Ctor.prototype = proto
  133. return new Ctor
  134. }
  135. // Used to create a custom walker. Will fill in all missing node
  136. // type properties with the defaults.
  137. function make(funcs, base) {
  138. if (!base) base = exports.base
  139. var visitor = create(base)
  140. for (var type in funcs) visitor[type] = funcs[type]
  141. return visitor
  142. }
  143. function skipThrough(node, st, c) { c(node, st) }
  144. function ignore(_node, _st, _c) {}
  145. // Node walkers.
  146. var base = {}
  147. base.Program = base.BlockStatement = function (node, st, c) {
  148. for (var i = 0; i < node.body.length; ++i)
  149. c(node.body[i], st, "Statement")
  150. }
  151. base.Statement = skipThrough
  152. base.EmptyStatement = ignore
  153. base.ExpressionStatement = base.ParenthesizedExpression =
  154. function (node, st, c) { return c(node.expression, st, "Expression"); }
  155. base.IfStatement = function (node, st, c) {
  156. c(node.test, st, "Expression")
  157. c(node.consequent, st, "Statement")
  158. if (node.alternate) c(node.alternate, st, "Statement")
  159. }
  160. base.LabeledStatement = function (node, st, c) { return c(node.body, st, "Statement"); }
  161. base.BreakStatement = base.ContinueStatement = ignore
  162. base.WithStatement = function (node, st, c) {
  163. c(node.object, st, "Expression")
  164. c(node.body, st, "Statement")
  165. }
  166. base.SwitchStatement = function (node, st, c) {
  167. c(node.discriminant, st, "Expression")
  168. for (var i = 0; i < node.cases.length; ++i) {
  169. var cs = node.cases[i]
  170. if (cs.test) c(cs.test, st, "Expression")
  171. for (var j = 0; j < cs.consequent.length; ++j)
  172. c(cs.consequent[j], st, "Statement")
  173. }
  174. }
  175. base.ReturnStatement = base.YieldExpression = base.AwaitExpression = function (node, st, c) {
  176. if (node.argument) c(node.argument, st, "Expression")
  177. }
  178. base.ThrowStatement = base.SpreadElement =
  179. function (node, st, c) { return c(node.argument, st, "Expression"); }
  180. base.TryStatement = function (node, st, c) {
  181. c(node.block, st, "Statement")
  182. if (node.handler) c(node.handler, st)
  183. if (node.finalizer) c(node.finalizer, st, "Statement")
  184. }
  185. base.CatchClause = function (node, st, c) {
  186. c(node.param, st, "Pattern")
  187. c(node.body, st, "ScopeBody")
  188. }
  189. base.WhileStatement = base.DoWhileStatement = function (node, st, c) {
  190. c(node.test, st, "Expression")
  191. c(node.body, st, "Statement")
  192. }
  193. base.ForStatement = function (node, st, c) {
  194. if (node.init) c(node.init, st, "ForInit")
  195. if (node.test) c(node.test, st, "Expression")
  196. if (node.update) c(node.update, st, "Expression")
  197. c(node.body, st, "Statement")
  198. }
  199. base.ForInStatement = base.ForOfStatement = function (node, st, c) {
  200. c(node.left, st, "ForInit")
  201. c(node.right, st, "Expression")
  202. c(node.body, st, "Statement")
  203. }
  204. base.ForInit = function (node, st, c) {
  205. if (node.type == "VariableDeclaration") c(node, st)
  206. else c(node, st, "Expression")
  207. }
  208. base.DebuggerStatement = ignore
  209. base.FunctionDeclaration = function (node, st, c) { return c(node, st, "Function"); }
  210. base.VariableDeclaration = function (node, st, c) {
  211. for (var i = 0; i < node.declarations.length; ++i)
  212. c(node.declarations[i], st)
  213. }
  214. base.VariableDeclarator = function (node, st, c) {
  215. c(node.id, st, "Pattern")
  216. if (node.init) c(node.init, st, "Expression")
  217. }
  218. base.Function = function (node, st, c) {
  219. if (node.id) c(node.id, st, "Pattern")
  220. for (var i = 0; i < node.params.length; i++)
  221. c(node.params[i], st, "Pattern")
  222. c(node.body, st, node.expression ? "ScopeExpression" : "ScopeBody")
  223. }
  224. // FIXME drop these node types in next major version
  225. // (They are awkward, and in ES6 every block can be a scope.)
  226. base.ScopeBody = function (node, st, c) { return c(node, st, "Statement"); }
  227. base.ScopeExpression = function (node, st, c) { return c(node, st, "Expression"); }
  228. base.Pattern = function (node, st, c) {
  229. if (node.type == "Identifier")
  230. c(node, st, "VariablePattern")
  231. else if (node.type == "MemberExpression")
  232. c(node, st, "MemberPattern")
  233. else
  234. c(node, st)
  235. }
  236. base.VariablePattern = ignore
  237. base.MemberPattern = skipThrough
  238. base.RestElement = function (node, st, c) { return c(node.argument, st, "Pattern"); }
  239. base.ArrayPattern = function (node, st, c) {
  240. for (var i = 0; i < node.elements.length; ++i) {
  241. var elt = node.elements[i]
  242. if (elt) c(elt, st, "Pattern")
  243. }
  244. }
  245. base.ObjectPattern = function (node, st, c) {
  246. for (var i = 0; i < node.properties.length; ++i)
  247. c(node.properties[i].value, st, "Pattern")
  248. }
  249. base.Expression = skipThrough
  250. base.ThisExpression = base.Super = base.MetaProperty = ignore
  251. base.ArrayExpression = function (node, st, c) {
  252. for (var i = 0; i < node.elements.length; ++i) {
  253. var elt = node.elements[i]
  254. if (elt) c(elt, st, "Expression")
  255. }
  256. }
  257. base.ObjectExpression = function (node, st, c) {
  258. for (var i = 0; i < node.properties.length; ++i)
  259. c(node.properties[i], st)
  260. }
  261. base.FunctionExpression = base.ArrowFunctionExpression = base.FunctionDeclaration
  262. base.SequenceExpression = base.TemplateLiteral = function (node, st, c) {
  263. for (var i = 0; i < node.expressions.length; ++i)
  264. c(node.expressions[i], st, "Expression")
  265. }
  266. base.UnaryExpression = base.UpdateExpression = function (node, st, c) {
  267. c(node.argument, st, "Expression")
  268. }
  269. base.BinaryExpression = base.LogicalExpression = function (node, st, c) {
  270. c(node.left, st, "Expression")
  271. c(node.right, st, "Expression")
  272. }
  273. base.AssignmentExpression = base.AssignmentPattern = function (node, st, c) {
  274. c(node.left, st, "Pattern")
  275. c(node.right, st, "Expression")
  276. }
  277. base.ConditionalExpression = function (node, st, c) {
  278. c(node.test, st, "Expression")
  279. c(node.consequent, st, "Expression")
  280. c(node.alternate, st, "Expression")
  281. }
  282. base.NewExpression = base.CallExpression = function (node, st, c) {
  283. c(node.callee, st, "Expression")
  284. if (node.arguments) for (var i = 0; i < node.arguments.length; ++i)
  285. c(node.arguments[i], st, "Expression")
  286. }
  287. base.MemberExpression = function (node, st, c) {
  288. c(node.object, st, "Expression")
  289. if (node.computed) c(node.property, st, "Expression")
  290. }
  291. base.ExportNamedDeclaration = base.ExportDefaultDeclaration = function (node, st, c) {
  292. if (node.declaration)
  293. c(node.declaration, st, node.type == "ExportNamedDeclaration" || node.declaration.id ? "Statement" : "Expression")
  294. if (node.source) c(node.source, st, "Expression")
  295. }
  296. base.ExportAllDeclaration = function (node, st, c) {
  297. c(node.source, st, "Expression")
  298. }
  299. base.ImportDeclaration = function (node, st, c) {
  300. for (var i = 0; i < node.specifiers.length; i++)
  301. c(node.specifiers[i], st)
  302. c(node.source, st, "Expression")
  303. }
  304. base.ImportSpecifier = base.ImportDefaultSpecifier = base.ImportNamespaceSpecifier = base.Identifier = base.Literal = ignore
  305. base.TaggedTemplateExpression = function (node, st, c) {
  306. c(node.tag, st, "Expression")
  307. c(node.quasi, st)
  308. }
  309. base.ClassDeclaration = base.ClassExpression = function (node, st, c) { return c(node, st, "Class"); }
  310. base.Class = function (node, st, c) {
  311. if (node.id) c(node.id, st, "Pattern")
  312. if (node.superClass) c(node.superClass, st, "Expression")
  313. for (var i = 0; i < node.body.body.length; i++)
  314. c(node.body.body[i], st)
  315. }
  316. base.MethodDefinition = base.Property = function (node, st, c) {
  317. if (node.computed) c(node.key, st, "Expression")
  318. c(node.value, st, "Expression")
  319. }
  320. export { simple, ancestor, recursive, findNodeAt, findNodeAround, findNodeAfter, findNodeBefore, make, base };