text: var parse = require('acorn').parse;
  
  var objectKeys = Object.keys || function (obj) {
      var keys = [];
      for (var key in obj) keys.push(key);
      return keys;
  };
  var forEach = function (xs, fn) {
      if (xs.forEach) return xs.forEach(fn);
      for (var i = 0; i < xs.length; i++) {
          fn.call(xs, xs[i], i, xs);
      }
  };
  
  var isArray = Array.isArray || function (xs) {
      return Object.prototype.toString.call(xs) === '[object Array]';
  };
  
  module.exports = function (src, opts, fn) {
      if (typeof opts === 'function') {
          fn = opts;
          opts = {};
      }
      if (typeof src === 'object') {
          opts = src;
          src = opts.source;
          delete opts.source;
      }
      src = src === undefined ? opts.source : src;
      if (typeof src !== 'string') src = String(src);
      var ast = parse(src, opts);
      
      var result = {
          chunks : src.split(''),
          toString : function () { return result.chunks.join('') },
          inspect : function () { return result.toString() }
      };
      var index = 0;
      
      (function walk (node, parent) {
          insertHelpers(node, parent, result.chunks);
          
          forEach(objectKeys(node), function (key) {
              if (key === 'parent') return;
              
              var child = node[key];
              if (isArray(child)) {
                  forEach(child, function (c) {
                      if (c && typeof c.type === 'string') {
                          walk(c, node);
                      }
                  });
              }
              else if (child && typeof child.type === 'string') {
                  walk(child, node);
              }
          });
          fn(node);
      })(ast, undefined);
      
      return result;
  };
   
  function insertHelpers (node, parent, chunks) {
      node.parent = parent;
      
      node.source = function () {
          return chunks.slice(node.start, node.end).join('');
      };
      
      if (node.update && typeof node.update === 'object') {
          var prev = node.update;
          forEach(objectKeys(prev), function (key) {
              update[key] = prev[key];
          });
          node.update = update;
      }
      else {
          node.update = update;
      }
      
      function update (s) {
          chunks[node.start] = s;
          for (var i = node.start + 1; i < node.end; i++) {
              chunks[i] = '';
          }
      }
  }
  