UNPKG

decaffeinate-traverse

Version:
1,242 lines (1,095 loc) 28.9 kB
'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;