diff --git a/README.md b/README.md index 32ee0b7d76..e16e165208 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,10 @@ simply visit all statements and expressions and not produce a meaningful state. (An example of a use of state it to track scope at each point in the tree.) +**ancestor**`(node, visitors, base, state)` does a 'simple' walk over +a tree, building up an array of ancestor nodes (including the current node) +and passing the array to callbacks in the `state` parameter. + **recursive**`(node, state, functions, base)` does a 'recursive' walk, where the walker functions are responsible for continuing the walk on the child nodes of their target node. `state` is the start diff --git a/util/walk.js b/util/walk.js index 4c0d9a7f88..f8c697c8c4 100644 --- a/util/walk.js +++ b/util/walk.js @@ -32,6 +32,23 @@ c(node, state); }; + // An ancestor walk builds up an array of ancestor nodes (including + // the current node) and passes them to the callback as the state parameter. + exports.ancestor = function(node, visitors, base, state) { + if (!base) base = exports.base; + if (!state) state = []; + function c(node, st, override) { + var type = override || node.type, found = visitors[type]; + if (node != st[st.length - 1]) { + st = st.slice(); + st.push(node); + } + base[type](node, st, c); + if (found) found(node, st); + } + c(node, state); + }; + // A recursive walk is one where your functions override the default // walkers. They can modify and replace the state parameter that's // threaded through the walk, and can opt how and whether to walk