decaffeinate-traverse
Version:
Traverse programs parsed using decaffeinate-parser.
1,242 lines (1,095 loc) • 28.9 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var classCallCheck = function (instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
};
var createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
var get = function get(object, property, receiver) {
if (object === null) object = Function.prototype;
var desc = Object.getOwnPropertyDescriptor(object, property);
if (desc === undefined) {
var parent = Object.getPrototypeOf(object);
if (parent === null) {
return undefined;
} else {
return get(parent, property, receiver);
}
} else if ("value" in desc) {
return desc.value;
} else {
var getter = desc.get;
if (getter === undefined) {
return undefined;
}
return getter.call(receiver);
}
};
var inherits = function (subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
};
var possibleConstructorReturn = function (self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
};
/**
* Abstract subclass providing basic visitor support for visiting nodes in a
* decaffeinate-parser AST. For the real visitor, see `Visitor`.
*/
var BasicVisitor = function () {
function BasicVisitor() {
classCallCheck(this, BasicVisitor);
this._node = null;
this._parent = null;
this._break = false;
this._skip = false;
this._visiting = false;
}
createClass(BasicVisitor, [{
key: 'visit',
/**
* Visit a node and its descendants in a decaffeinate AST. Parent nodes are
* visited first, followed by their children in the order defined by
* individual visitor methods.
*/
value: function visit(node) {
if (this._visiting) {
throw new Error('Cannot visit() ' + node.type + ' while already inside a visit() call. ' + 'Call descend() instead?');
}
try {
this._visiting = true;
this.descend(node);
} finally {
this._node = null;
this._parent = null;
this._break = false;
this._visiting = false;
}
}
/**
* Descend into a node from a parent visitor method.
*/
}, {
key: 'descend',
value: function descend(node) {
if (this._break || this._skip) {
return;
}
if (!this._visiting) {
throw new Error('Cannot descend() into ' + node.type + ' because there was no call to ' + 'visit(). Call visit() instead?');
}
var parent = this._parent;
var current = this._node;
var skip = this._skip;
try {
this._parent = current;
this._node = node;
this._skip = false;
this.visitNode(node);
} finally {
this._parent = parent;
this._node = current;
this._skip = skip;
}
}
/**
* Override point for subclasses. Implementers of this method should delegate
* to the appropriate methods based on `node`.
*/
}, {
key: 'visitNode',
value: function visitNode(node) {
throw new Error('Cannot call unimplemented visitNode() with ' + node.type + '. Ensure ' + (this.constructor.name + ' implements visitNode() correctly.'));
}
/**
* Gets the parent node for the node currently being visited.
*/
}, {
key: 'parent',
value: function parent() {
return this._parent;
}
/**
* Prevents visiting any new nodes.
*/
}, {
key: 'break',
value: function _break() {
this._break = true;
}
/**
* Skips any descendants of the current node.
*/
}, {
key: 'skip',
value: function skip() {
this._skip = true;
}
}]);
return BasicVisitor;
}();
/**
* Implements the visitor pattern for decaffeinate-parser ASTs.
*/
var Visitor = function (_BasicVisitor) {
inherits(Visitor, _BasicVisitor);
function Visitor() {
classCallCheck(this, Visitor);
return possibleConstructorReturn(this, Object.getPrototypeOf(Visitor).apply(this, arguments));
}
createClass(Visitor, [{
key: 'visitNode',
value: function visitNode(node) {
switch (node.type) {
case 'ArrayInitialiser':
this.visitArrayInitialiser(node);
break;
case 'AssignOp':
this.visitAssignOp(node);
break;
case 'BitAndOp':
this.visitBitAndOp(node);
break;
case 'BitNotOp':
this.visitBitNotOp(node);
break;
case 'BitOrOp':
this.visitBitOrOp(node);
break;
case 'BitXorOp':
this.visitBitXorOp(node);
break;
case 'Block':
this.visitBlock(node);
break;
case 'Bool':
this.visitBool(node);
break;
case 'BoundFunction':
this.visitBoundFunction(node);
break;
case 'Break':
this.visitBreak(node);
break;
case 'ChainedComparisonOp':
this.visitChainedComparisonOp(node);
break;
case 'Class':
this.visitClass(node);
break;
case 'ClassProtoAssignOp':
this.visitClassProtoAssignOp(node);
break;
case 'CompoundAssignOp':
this.visitCompoundAssignOp(node);
break;
case 'Conditional':
this.visitConditional(node);
break;
case 'Constructor':
this.visitConstructor(node);
break;
case 'Continue':
this.visitContinue(node);
break;
case 'DefaultParam':
this.visitDefaultParam(node);
break;
case 'DeleteOp':
this.visitDeleteOp(node);
break;
case 'DivideOp':
this.visitDivideOp(node);
break;
case 'DoOp':
this.visitDoOp(node);
break;
case 'DynamicMemberAccessOp':
this.visitDynamicMemberAccessOp(node);
break;
case 'EQOp':
this.visitEQOp(node);
break;
case 'ExistsOp':
this.visitExistsOp(node);
break;
case 'ExpOp':
this.visitExpOp(node);
break;
case 'Expansion':
this.visitExpansion(node);
break;
case 'ExtendsOp':
this.visitExtendsOp(node);
break;
case 'Float':
this.visitFloat(node);
break;
case 'FloorDivideOp':
this.visitFloorDivideOp(node);
break;
case 'ForIn':
this.visitForIn(node);
break;
case 'ForOf':
this.visitForOf(node);
break;
case 'Function':
this.visitFunction(node);
break;
case 'FunctionApplication':
this.visitFunctionApplication(node);
break;
case 'GeneratorFunction':
this.visitGeneratorFunction(node);
break;
case 'GTEOp':
this.visitGTEOp(node);
break;
case 'GTOp':
this.visitGTOp(node);
break;
case 'Herestring':
this.visitHerestring(node);
break;
case 'Identifier':
this.visitIdentifier(node);
break;
case 'InOp':
this.visitInOp(node);
break;
case 'InstanceofOp':
this.visitInstanceofOp(node);
break;
case 'Int':
this.visitInt(node);
break;
case 'JavaScript':
this.visitJavaScript(node);
break;
case 'LTEOp':
this.visitLTEOp(node);
break;
case 'LTOp':
this.visitLTOp(node);
break;
case 'LeftShiftOp':
this.visitLeftShiftOp(node);
break;
case 'LogicalAndOp':
this.visitLogicalAndOp(node);
break;
case 'LogicalNotOp':
this.visitLogicalNotOp(node);
break;
case 'LogicalOrOp':
this.visitLogicalOrOp(node);
break;
case 'MemberAccessOp':
this.visitMemberAccessOp(node);
break;
case 'MultiplyOp':
this.visitMultiplyOp(node);
break;
case 'NEQOp':
this.visitNEQOp(node);
break;
case 'NewOp':
this.visitNewOp(node);
break;
case 'Null':
this.visitNull(node);
break;
case 'ObjectInitialiser':
this.visitObjectInitialiser(node);
break;
case 'ObjectInitialiserMember':
this.visitObjectInitialiserMember(node);
break;
case 'OfOp':
this.visitOfOp(node);
break;
case 'PlusOp':
this.visitPlusOp(node);
break;
case 'PostDecrementOp':
this.visitPostDecrementOp(node);
break;
case 'PostIncrementOp':
this.visitPostIncrementOp(node);
break;
case 'PreDecrementOp':
this.visitPreDecrementOp(node);
break;
case 'PreIncrementOp':
this.visitPreIncrementOp(node);
break;
case 'Program':
this.visitProgram(node);
break;
case 'ProtoMemberAccessOp':
this.visitProtoMemberAccessOp(node);
break;
case 'Range':
this.visitRange(node);
break;
case 'RegExp':
this.visitRegExp(node);
break;
case 'RemOp':
this.visitRemOp(node);
break;
case 'Rest':
this.visitRest(node);
break;
case 'Return':
this.visitReturn(node);
break;
case 'SeqOp':
this.visitSeqOp(node);
break;
case 'SignedRightShiftOp':
this.visitSignedRightShiftOp(node);
break;
case 'Slice':
this.visitSlice(node);
break;
case 'SoakedDynamicMemberAccessOp':
this.visitSoakedDynamicMemberAccessOp(node);
break;
case 'SoakedFunctionApplication':
this.visitSoakedFunctionApplication(node);
break;
case 'SoakedMemberAccessOp':
this.visitSoakedMemberAccessOp(node);
break;
case 'Spread':
this.visitSpread(node);
break;
case 'String':
this.visitString(node);
break;
case 'SubtractOp':
this.visitSubtractOp(node);
break;
case 'Super':
this.visitSuper(node);
break;
case 'Switch':
this.visitSwitch(node);
break;
case 'SwitchCase':
this.visitSwitchCase(node);
break;
case 'TemplateLiteral':
this.visitTemplateLiteral(node);
break;
case 'This':
this.visitThis(node);
break;
case 'Throw':
this.visitThrow(node);
break;
case 'Try':
this.visitTry(node);
break;
case 'TypeofOp':
this.visitTypeofOp(node);
break;
case 'UnaryExistsOp':
this.visitUnaryExistsOp(node);
break;
case 'UnaryNegateOp':
this.visitUnaryNegateOp(node);
break;
case 'UnaryPlusOp':
this.visitUnaryPlusOp(node);
break;
case 'Undefined':
this.visitUndefined(node);
break;
case 'UnsignedRightShiftOp':
this.visitUnsignedRightShiftOp(node);
break;
case 'While':
this.visitWhile(node);
break;
case 'Yield':
this.visitYield(node);
break;
case 'YieldFrom':
this.visitYieldFrom(node);
break;
default:
throw new Error('unexpected node type: ' + node.type);
}
}
}, {
key: 'visitArrayInitialiser',
value: function visitArrayInitialiser(node) {
var _this2 = this;
node.members.forEach(function (child) {
return _this2.descend(child);
});
}
}, {
key: 'visitAssignOp',
value: function visitAssignOp(node) {
this.descend(node.assignee);
this.descend(node.expression);
}
}, {
key: 'visitBitAndOp',
value: function visitBitAndOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitBitNotOp',
value: function visitBitNotOp(node) {
this.descend(node.expression);
}
}, {
key: 'visitBitOrOp',
value: function visitBitOrOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitBitXorOp',
value: function visitBitXorOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitBlock',
value: function visitBlock(node) {
var _this3 = this;
node.statements.forEach(function (child) {
return _this3.descend(child);
});
}
}, {
key: 'visitBool',
value: function visitBool(node) {
// no children
}
}, {
key: 'visitBoundFunction',
value: function visitBoundFunction(node) {
var _this4 = this;
node.parameters.forEach(function (child) {
return _this4.descend(child);
});
if (node.body) {
this.descend(node.body);
}
}
}, {
key: 'visitBreak',
value: function visitBreak(node) {
// no children
}
}, {
key: 'visitChainedComparisonOp',
value: function visitChainedComparisonOp(node) {
this.descend(node.expression);
}
}, {
key: 'visitClass',
value: function visitClass(node) {
if (node.nameAssignee) {
this.descend(node.nameAssignee);
}
if (node.parent) {
this.descend(node.parent);
}
if (node.body) {
this.descend(node.body);
}
}
}, {
key: 'visitClassProtoAssignOp',
value: function visitClassProtoAssignOp(node) {
this.descend(node.assignee);
this.descend(node.expression);
}
}, {
key: 'visitCompoundAssignOp',
value: function visitCompoundAssignOp(node) {
this.descend(node.assignee);
this.descend(node.expression);
}
}, {
key: 'visitConditional',
value: function visitConditional(node) {
this.descend(node.condition);
if (node.consequent) {
this.descend(node.consequent);
}
if (node.alternate) {
this.descend(node.alternate);
}
}
}, {
key: 'visitConstructor',
value: function visitConstructor(node) {
this.descend(node.assignee);
this.descend(node.expression);
}
}, {
key: 'visitContinue',
value: function visitContinue(node) {
// no children
}
}, {
key: 'visitDefaultParam',
value: function visitDefaultParam(node) {
this.descend(node.param);
this.descend(node.default);
}
}, {
key: 'visitDeleteOp',
value: function visitDeleteOp(node) {
this.descend(node.expression);
}
}, {
key: 'visitDivideOp',
value: function visitDivideOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitDoOp',
value: function visitDoOp(node) {
this.descend(node.expression);
}
}, {
key: 'visitDynamicMemberAccessOp',
value: function visitDynamicMemberAccessOp(node) {
this.descend(node.expression);
this.descend(node.indexingExpr);
}
}, {
key: 'visitEQOp',
value: function visitEQOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitExistsOp',
value: function visitExistsOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitExpOp',
value: function visitExpOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitExpansion',
value: function visitExpansion(node) {
// no children
}
}, {
key: 'visitExtendsOp',
value: function visitExtendsOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitFloat',
value: function visitFloat(node) {
// no children
}
}, {
key: 'visitFloorDivideOp',
value: function visitFloorDivideOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitForIn',
value: function visitForIn(node) {
if (node.keyAssignee) {
this.descend(node.keyAssignee);
}
if (node.valAssignee) {
this.descend(node.valAssignee);
}
this.descend(node.target);
if (node.step) {
this.descend(node.step);
}
if (node.filter) {
this.descend(node.filter);
}
this.descend(node.body);
}
}, {
key: 'visitForOf',
value: function visitForOf(node) {
this.descend(node.keyAssignee);
if (node.valAssignee) {
this.descend(node.valAssignee);
}
this.descend(node.target);
if (node.filter) {
this.descend(node.filter);
}
this.descend(node.body);
}
}, {
key: 'visitFunction',
value: function visitFunction(node) {
var _this5 = this;
node.parameters.forEach(function (child) {
return _this5.descend(child);
});
if (node.body) {
this.descend(node.body);
}
}
}, {
key: 'visitFunctionApplication',
value: function visitFunctionApplication(node) {
var _this6 = this;
this.descend(node.function);
node.arguments.forEach(function (child) {
return _this6.descend(child);
});
}
}, {
key: 'visitGeneratorFunction',
value: function visitGeneratorFunction(node) {
var _this7 = this;
node.parameters.forEach(function (child) {
return _this7.descend(child);
});
this.descend(node.body);
}
}, {
key: 'visitGTEOp',
value: function visitGTEOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitGTOp',
value: function visitGTOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitHerestring',
value: function visitHerestring(node) {
// no children
}
}, {
key: 'visitIdentifier',
value: function visitIdentifier(node) {
// no children
}
}, {
key: 'visitInOp',
value: function visitInOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitInstanceofOp',
value: function visitInstanceofOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitInt',
value: function visitInt(node) {
// no children
}
}, {
key: 'visitJavaScript',
value: function visitJavaScript(node) {
// no children
}
}, {
key: 'visitLTEOp',
value: function visitLTEOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitLTOp',
value: function visitLTOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitLeftShiftOp',
value: function visitLeftShiftOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitLogicalAndOp',
value: function visitLogicalAndOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitLogicalNotOp',
value: function visitLogicalNotOp(node) {
this.descend(node.expression);
}
}, {
key: 'visitLogicalOrOp',
value: function visitLogicalOrOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitMemberAccessOp',
value: function visitMemberAccessOp(node) {
this.descend(node.expression);
}
}, {
key: 'visitMultiplyOp',
value: function visitMultiplyOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitNEQOp',
value: function visitNEQOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitNewOp',
value: function visitNewOp(node) {
var _this8 = this;
this.descend(node.ctor);
node.arguments.forEach(function (child) {
return _this8.descend(child);
});
}
}, {
key: 'visitNull',
value: function visitNull(node) {
// no children
}
}, {
key: 'visitObjectInitialiser',
value: function visitObjectInitialiser(node) {
var _this9 = this;
node.members.forEach(function (child) {
return _this9.descend(child);
});
}
}, {
key: 'visitObjectInitialiserMember',
value: function visitObjectInitialiserMember(node) {
this.descend(node.key);
this.descend(node.expression);
}
}, {
key: 'visitOfOp',
value: function visitOfOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitPlusOp',
value: function visitPlusOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitPostDecrementOp',
value: function visitPostDecrementOp(node) {
this.descend(node.expression);
}
}, {
key: 'visitPostIncrementOp',
value: function visitPostIncrementOp(node) {
this.descend(node.expression);
}
}, {
key: 'visitPreDecrementOp',
value: function visitPreDecrementOp(node) {
this.descend(node.expression);
}
}, {
key: 'visitPreIncrementOp',
value: function visitPreIncrementOp(node) {
this.descend(node.expression);
}
}, {
key: 'visitProgram',
value: function visitProgram(node) {
if (node.body) {
this.descend(node.body);
}
}
}, {
key: 'visitProtoMemberAccessOp',
value: function visitProtoMemberAccessOp(node) {
this.descend(node.expression);
}
}, {
key: 'visitRange',
value: function visitRange(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitRegExp',
value: function visitRegExp(node) {
// no children
}
}, {
key: 'visitRemOp',
value: function visitRemOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitRest',
value: function visitRest(node) {
this.descend(node.expression);
}
}, {
key: 'visitReturn',
value: function visitReturn(node) {
if (node.expression) {
this.descend(node.expression);
}
}
}, {
key: 'visitSeqOp',
value: function visitSeqOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitSignedRightShiftOp',
value: function visitSignedRightShiftOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitSlice',
value: function visitSlice(node) {
this.descend(node.expression);
if (node.left) {
this.descend(node.left);
}
if (node.right) {
this.descend(node.right);
}
}
}, {
key: 'visitSoakedDynamicMemberAccessOp',
value: function visitSoakedDynamicMemberAccessOp(node) {
this.descend(node.expression);
this.descend(node.indexingExpr);
}
}, {
key: 'visitSoakedFunctionApplication',
value: function visitSoakedFunctionApplication(node) {
var _this10 = this;
this.descend(node.function);
node.arguments.forEach(function (child) {
return _this10.descend(child);
});
}
}, {
key: 'visitSoakedMemberAccessOp',
value: function visitSoakedMemberAccessOp(node) {
this.descend(node.expression);
}
}, {
key: 'visitSpread',
value: function visitSpread(node) {
this.descend(node.expression);
}
}, {
key: 'visitString',
value: function visitString(node) {
// no children
}
}, {
key: 'visitSubtractOp',
value: function visitSubtractOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitSuper',
value: function visitSuper(node) {
// no children
}
}, {
key: 'visitSwitch',
value: function visitSwitch(node) {
var _this11 = this;
if (node.expression) {
this.descend(node.expression);
}
node.cases.forEach(function (child) {
return _this11.descend(child);
});
if (node.alternate) {
this.descend(node.alternate);
}
}
}, {
key: 'visitSwitchCase',
value: function visitSwitchCase(node) {
var _this12 = this;
node.conditions.forEach(function (child) {
return _this12.descend(child);
});
this.descend(node.consequent);
}
}, {
key: 'visitTemplateLiteral',
value: function visitTemplateLiteral(node) {
var _this13 = this;
node.quasis.forEach(function (child) {
return _this13.descend(child);
});
node.expressions.forEach(function (child) {
return _this13.descend(child);
});
}
}, {
key: 'visitThis',
value: function visitThis(node) {
// no children
}
}, {
key: 'visitThrow',
value: function visitThrow(node) {
this.descend(node.expression);
}
}, {
key: 'visitTry',
value: function visitTry(node) {
this.descend(node.body);
if (node.catchAssignee) {
this.descend(node.catchAssignee);
}
if (node.catchBody) {
this.descend(node.catchBody);
}
if (node.finallyBody) {
this.descend(node.finallyBody);
}
}
}, {
key: 'visitTypeofOp',
value: function visitTypeofOp(node) {
this.descend(node.expression);
}
}, {
key: 'visitUnaryExistsOp',
value: function visitUnaryExistsOp(node) {
this.descend(node.expression);
}
}, {
key: 'visitUnaryNegateOp',
value: function visitUnaryNegateOp(node) {
this.descend(node.expression);
}
}, {
key: 'visitUnaryPlusOp',
value: function visitUnaryPlusOp(node) {
this.descend(node.expression);
}
}, {
key: 'visitUndefined',
value: function visitUndefined(node) {
// no children
}
}, {
key: 'visitUnsignedRightShiftOp',
value: function visitUnsignedRightShiftOp(node) {
this.descend(node.left);
this.descend(node.right);
}
}, {
key: 'visitWhile',
value: function visitWhile(node) {
this.descend(node.condition);
if (node.guard) {
this.descend(node.guard);
}
this.descend(node.body);
}
}, {
key: 'visitYield',
value: function visitYield(node) {
this.descend(node.expression);
}
}, {
key: 'visitYieldFrom',
value: function visitYieldFrom(node) {
this.descend(node.expression);
}
}]);
return Visitor;
}(BasicVisitor);
function traverse(node, iterator) {
var visitorClass = function (_Visitor) {
inherits(visitorClass, _Visitor);
function visitorClass() {
classCallCheck(this, visitorClass);
return possibleConstructorReturn(this, Object.getPrototypeOf(visitorClass).apply(this, arguments));
}
createClass(visitorClass, [{
key: 'visitNode',
value: function visitNode(node) {
var result = iterator(node, this.parent());
if (result !== false) {
get(Object.getPrototypeOf(visitorClass.prototype), 'visitNode', this).call(this, node);
}
}
}]);
return visitorClass;
}(Visitor);
new visitorClass().visit(node);
}
exports.Visitor = Visitor;
exports.traverse = traverse;