Implement a PathVisitor abstraction and use it to power recast.visit

I can (and will) go into detail about the key features of this new traversal abstraction, but an example from the tests is worth at least a few hundred words:
```js
var objProp = b.memberExpression(
    b.identifier("object"),
    b.identifier("property"),
    false
);

var idNames = [];

recast.visit(objProp, {
    visitMemberExpression: function(path) {
        this.traverse(path.get("object"), {
            visitIdentifier: function(path) {
                idNames.push("*" + path.value.name + "*");
                return false;
            }
        });

        path.get("object", "name").replace("asdfasdf");
        path.get("property", "name").replace("zxcvzxcv");

        this.traverse(path.get("property"));
    },

    visitIdentifier: function(path) {
        idNames.push(path.value.name);
        return false;
    }
});

assert.deepEqual(idNames, ["*object*", "zxcvzxcv"]);
```

cc @thedekel