diff --git a/lib/6to5/transformation/transformers/generators/emit.js b/lib/6to5/transformation/transformers/generators/emit.js index 62a0a5a4ed..221bc435b8 100644 --- a/lib/6to5/transformation/transformers/generators/emit.js +++ b/lib/6to5/transformation/transformers/generators/emit.js @@ -8,57 +8,50 @@ * the same directory. */ -var assert = require("assert"); -var types = require("ast-types"); -var b = types.builders; -var n = types.namedTypes; -var leap = require("./leap"); -var meta = require("./meta"); +exports.Emitter = Emitter; + var runtimeProperty = require("./util").runtimeProperty; +var assert = require("assert"); +var types = require("ast-types"); +var leap = require("./leap"); +var meta = require("./meta"); +var _ = require("lodash"); + var runtimeKeysMethod = runtimeProperty("keys"); -var hasOwn = Object.prototype.hasOwnProperty; +var b = types.builders; +var n = types.namedTypes; function Emitter(contextId) { assert.ok(this instanceof Emitter); n.Identifier.assert(contextId); - Object.defineProperties(this, { - // In order to make sure the context object does not collide with - // anything in the local scope, we might have to rename it, so we - // refer to it symbolically instead of just assuming that it will be - // called "context". - contextId: { value: contextId }, + // In order to make sure the context object does not collide with + // anything in the local scope, we might have to rename it, so we + // refer to it symbolically instead of just assuming that it will be + // called "context". + this.contextId = contextId; - // An append-only list of Statements that grows each time this.emit is - // called. - listing: { value: [] }, + // An append-only list of Statements that grows each time this.emit is + // called. + this.listing = []; - // A sparse array whose keys correspond to locations in this.listing - // that have been marked as branch/jump targets. - marked: { value: [true] }, + // A sparse array whose keys correspond to locations in this.listing + // that have been marked as branch/jump targets. + this.marked = [true]; - // The last location will be marked when this.getDispatchLoop is - // called. - finalLoc: { value: loc() }, + // The last location will be marked when this.getDispatchLoop is + // called. + this.finalLoc = loc(); - // A list of all leap.TryEntry statements emitted. - tryEntries: { value: [] } - }); + // A list of all leap.TryEntry statements emitted. + this.tryEntries = []; - // The .leapManager property needs to be defined by a separate - // defineProperties call so that .finalLoc will be visible to the - // leap.LeapManager constructor. - Object.defineProperties(this, { - // Each time we evaluate the body of a loop, we tell this.leapManager - // to enter a nested loop context that determines the meaning of break - // and continue statements therein. - leapManager: { value: new leap.LeapManager(this) } - }); + // Each time we evaluate the body of a loop, we tell this.leapManager + // to enter a nested loop context that determines the meaning of break + // and continue statements therein. + this.leapManager = new leap.LeapManager(this); } -var Ep = Emitter.prototype; -exports.Emitter = Emitter; - // Offsets into this.listing that could be used as targets for branches or // jumps are represented as numeric Literal nodes. This representation has // the amazingly convenient benefit of allowing the exact value of the @@ -70,7 +63,7 @@ function loc() { // Sets the exact value of the given location to the offset of the next // Statement emitted. -Ep.mark = function(loc) { +Emitter.prototype.mark = function(loc) { n.Literal.assert(loc); var index = this.listing.length; if (loc.value === -1) { @@ -84,29 +77,28 @@ Ep.mark = function(loc) { return loc; }; -Ep.emit = function(node) { - if (n.Expression.check(node)) - node = b.expressionStatement(node); +Emitter.prototype.emit = function(node) { + if (n.Expression.check(node)) node = b.expressionStatement(node); n.Statement.assert(node); this.listing.push(node); }; // Shorthand for emitting assignment statements. This will come in handy // for assignments to temporary variables. -Ep.emitAssign = function(lhs, rhs) { +Emitter.prototype.emitAssign = function(lhs, rhs) { this.emit(this.assign(lhs, rhs)); return lhs; }; // Shorthand for an assignment statement. -Ep.assign = function(lhs, rhs) { +Emitter.prototype.assign = function(lhs, rhs) { return b.expressionStatement( b.assignmentExpression("=", lhs, rhs)); }; // Convenience function for generating expressions like context.next, // context.sent, and context.rval. -Ep.contextProperty = function(name, computed) { +Emitter.prototype.contextProperty = function(name, computed) { return b.memberExpression( this.contextId, computed ? b.literal(name) : b.identifier(name), @@ -124,7 +116,7 @@ var volatileContextPropertyNames = { // A "volatile" context property is a MemberExpression like context.sent // that should probably be stored in a temporary variable when there's a // possibility the property will get overwritten. -Ep.isVolatileContextProperty = function(expr) { +Emitter.prototype.isVolatileContextProperty = function(expr) { if (n.MemberExpression.check(expr)) { if (expr.computed) { // If it's a computed property such as context[couldBeAnything], @@ -135,8 +127,7 @@ Ep.isVolatileContextProperty = function(expr) { if (n.Identifier.check(expr.object) && n.Identifier.check(expr.property) && expr.object.name === this.contextId.name && - hasOwn.call(volatileContextPropertyNames, - expr.property.name)) { + _.has(volatileContextPropertyNames, expr.property.name)) { return true; } } @@ -145,7 +136,7 @@ Ep.isVolatileContextProperty = function(expr) { }; // Shorthand for setting context.rval and jumping to `context.stop()`. -Ep.stop = function(rval) { +Emitter.prototype.stop = function(rval) { if (rval) { this.setReturnValue(rval); } @@ -153,7 +144,7 @@ Ep.stop = function(rval) { this.jump(this.finalLoc); }; -Ep.setReturnValue = function(valuePath) { +Emitter.prototype.setReturnValue = function(valuePath) { n.Expression.assert(valuePath.value); this.emitAssign( @@ -162,7 +153,7 @@ Ep.setReturnValue = function(valuePath) { ); }; -Ep.clearPendingException = function(tryLoc, assignee) { +Emitter.prototype.clearPendingException = function(tryLoc, assignee) { n.Literal.assert(tryLoc); var catchCall = b.callExpression( @@ -179,13 +170,13 @@ Ep.clearPendingException = function(tryLoc, assignee) { // Emits code for an unconditional jump to the given location, even if the // exact value of the location is not yet known. -Ep.jump = function(toLoc) { +Emitter.prototype.jump = function(toLoc) { this.emitAssign(this.contextProperty("next"), toLoc); this.emit(b.breakStatement()); }; // Conditional jump. -Ep.jumpIf = function(test, toLoc) { +Emitter.prototype.jumpIf = function(test, toLoc) { n.Expression.assert(test); n.Literal.assert(toLoc); @@ -199,13 +190,12 @@ Ep.jumpIf = function(test, toLoc) { }; // Conditional jump, with the condition negated. -Ep.jumpIfNot = function(test, toLoc) { +Emitter.prototype.jumpIfNot = function(test, toLoc) { n.Expression.assert(test); n.Literal.assert(toLoc); var negatedTest; - if (n.UnaryExpression.check(test) && - test.operator === "!") { + if (n.UnaryExpression.check(test) && test.operator === "!") { // Avoid double negation. negatedTest = test.argument; } else { @@ -227,13 +217,13 @@ Ep.jumpIfNot = function(test, toLoc) { // other local variables, and since we just increment `nextTempId` // monotonically, uniqueness is assured. var nextTempId = 0; -Ep.makeTempVar = function() { +Emitter.prototype.makeTempVar = function() { return this.contextProperty("t" + nextTempId++); }; -Ep.getContextFunction = function(id) { +Emitter.prototype.getContextFunction = function(id) { var node = b.functionExpression( - id || null/*Anonymous*/, + id || null, [this.contextId], b.blockStatement([this.getDispatchLoop()]), false, // Not a generator anymore! @@ -254,7 +244,7 @@ Ep.getContextFunction = function(id) { // // Each marked location in this.listing will correspond to one generated // case statement. -Ep.getDispatchLoop = function() { +Emitter.prototype.getDispatchLoop = function() { var self = this; var cases = []; var current; @@ -265,9 +255,7 @@ Ep.getDispatchLoop = function() { self.listing.forEach(function(stmt, i) { if (self.marked.hasOwnProperty(i)) { - cases.push(b.switchCase( - b.literal(i), - current = [])); + cases.push(b.switchCase(b.literal(i), current = [])); alreadyEnded = false; } @@ -318,7 +306,7 @@ function isSwitchCaseEnder(stmt) { n.ThrowStatement.check(stmt); } -Ep.getTryEntryList = function() { +Emitter.prototype.getTryEntryList = function() { if (this.tryEntries.length === 0) { // To avoid adding a needless [] to the majority of runtime.wrap // argument lists, force the caller to handle this case specially. @@ -358,7 +346,7 @@ Ep.getTryEntryList = function() { // No destructive modification of AST nodes. -Ep.explode = function(path, ignoreResult) { +Emitter.prototype.explode = function(path, ignoreResult) { assert.ok(path instanceof types.NodePath); var node = path.value; @@ -377,10 +365,7 @@ Ep.explode = function(path, ignoreResult) { switch (node.type) { case "Program": - return path.get("body").map( - self.explodeStatement, - self - ); + return path.get("body").map(self.explodeStatement, self); case "VariableDeclarator": throw getDeclError(node); @@ -390,13 +375,10 @@ Ep.explode = function(path, ignoreResult) { case "Property": case "SwitchCase": case "CatchClause": - throw new Error( - node.type + " nodes should be handled by their parents"); + throw new Error(node.type + " nodes should be handled by their parents"); default: - throw new Error( - "unknown Node of type " + - JSON.stringify(node.type)); + throw new Error("unknown Node of type " + JSON.stringify(node.type)); } }; @@ -407,7 +389,7 @@ function getDeclError(node) { JSON.stringify(node)); } -Ep.explodeStatement = function(path, labelId) { +Emitter.prototype.explodeStatement = function(path, labelId) { assert.ok(path instanceof types.NodePath); var stmt = path.value; @@ -768,18 +750,15 @@ Ep.explodeStatement = function(path, labelId) { break; default: - throw new Error( - "unknown Statement of type " + - JSON.stringify(stmt.type)); + throw new Error("unknown Statement of type " + JSON.stringify(stmt.type)); } }; -Ep.emitAbruptCompletion = function(record) { +Emitter.prototype.emitAbruptCompletion = function(record) { if (!isValidCompletion(record)) { assert.ok( false, - "invalid completion record: " + - JSON.stringify(record) + "invalid completion record: " + JSON.stringify(record) ); } @@ -790,12 +769,10 @@ Ep.emitAbruptCompletion = function(record) { var abruptArgs = [b.literal(record.type)]; - if (record.type === "break" || - record.type === "continue") { + if (record.type === "break" || record.type === "continue") { n.Literal.assert(record.target); abruptArgs[1] = record.target; - } else if (record.type === "return" || - record.type === "throw") { + } else if (record.type === "return" || record.type === "throw") { if (record.value) { n.Expression.assert(record.value); abruptArgs[1] = record.value; @@ -816,15 +793,15 @@ function isValidCompletion(record) { var type = record.type; if (type === "normal") { - return !hasOwn.call(record, "target"); + return !_.has(record, "target"); } if (type === "break" || type === "continue") { - return !hasOwn.call(record, "value") && n.Literal.check(record.target); + return !_.has(record, "value") && n.Literal.check(record.target); } if (type === "return" || type === "throw") { - return hasOwn.call(record, "value") && !hasOwn.call(record, "target"); + return _.has(record, "value") && !_.has(record, "target"); } return false; @@ -840,7 +817,7 @@ function isValidCompletion(record) { // statements). There's no logical harm in marking such locations as jump // targets, but minimizing the number of switch cases keeps the generated // code shorter. -Ep.getUnmarkedCurrentLoc = function() { +Emitter.prototype.getUnmarkedCurrentLoc = function() { return b.literal(this.listing.length); }; @@ -854,7 +831,7 @@ Ep.getUnmarkedCurrentLoc = function() { // would know the location of the current instruction with complete // precision at all times, but we don't have that luxury here, as it would // be costly and verbose to set context.prev before every statement. -Ep.updateContextPrevLoc = function(loc) { +Emitter.prototype.updateContextPrevLoc = function(loc) { if (loc) { n.Literal.assert(loc); @@ -877,7 +854,7 @@ Ep.updateContextPrevLoc = function(loc) { this.emitAssign(this.contextProperty("prev"), loc); }; -Ep.explodeExpression = function(path, ignoreResult) { +Emitter.prototype.explodeExpression = function(path, ignoreResult) { assert.ok(path instanceof types.NodePath); var expr = path.value; diff --git a/lib/6to5/transformation/transformers/generators/hoist.js b/lib/6to5/transformation/transformers/generators/hoist.js index d83daccc34..6235ef4951 100644 --- a/lib/6to5/transformation/transformers/generators/hoist.js +++ b/lib/6to5/transformation/transformers/generators/hoist.js @@ -9,10 +9,11 @@ */ var assert = require("assert"); -var types = require("ast-types"); +var types = require("ast-types"); +var _ = require("lodash"); + var n = types.namedTypes; var b = types.builders; -var hasOwn = Object.prototype.hasOwnProperty; // The hoist function takes a FunctionExpression or FunctionDeclaration // and replaces any Declaration nodes in its body with assignments, then @@ -139,7 +140,7 @@ exports.hoist = function(funPath) { var declarations = []; Object.keys(vars).forEach(function(name) { - if (!hasOwn.call(paramNames, name)) { + if (!_.has(paramNames, name)) { declarations.push(b.variableDeclarator(vars[name], null)); } }); diff --git a/lib/6to5/transformation/transformers/generators/leap.js b/lib/6to5/transformation/transformers/generators/leap.js index bc6f100915..b6704d8ce2 100644 --- a/lib/6to5/transformation/transformers/generators/leap.js +++ b/lib/6to5/transformation/transformers/generators/leap.js @@ -8,10 +8,20 @@ * the same directory. */ +exports.FunctionEntry = FunctionEntry; +exports.FinallyEntry = FinallyEntry; +exports.SwitchEntry = SwitchEntry; +exports.LeapManager = LeapManager; +exports.CatchEntry = CatchEntry; +exports.LoopEntry = LoopEntry; +exports.TryEntry = TryEntry; + var assert = require("assert"); -var types = require("ast-types"); -var n = types.namedTypes; -var inherits = require("util").inherits; +var types = require("ast-types"); +var util = require("util"); + +var inherits = util.inherits; +var n = types.namedTypes; function Entry() { assert.ok(this instanceof Entry); @@ -22,13 +32,10 @@ function FunctionEntry(returnLoc) { n.Literal.assert(returnLoc); - Object.defineProperties(this, { - returnLoc: { value: returnLoc } - }); + this.returnLoc = returnLoc; } inherits(FunctionEntry, Entry); -exports.FunctionEntry = FunctionEntry; function LoopEntry(breakLoc, continueLoc, label) { Entry.call(this); @@ -42,28 +49,22 @@ function LoopEntry(breakLoc, continueLoc, label) { label = null; } - Object.defineProperties(this, { - breakLoc: { value: breakLoc }, - continueLoc: { value: continueLoc }, - label: { value: label } - }); + this.breakLoc = breakLoc; + this.continueLoc = continueLoc; + this.label = label; } inherits(LoopEntry, Entry); -exports.LoopEntry = LoopEntry; function SwitchEntry(breakLoc) { Entry.call(this); n.Literal.assert(breakLoc); - Object.defineProperties(this, { - breakLoc: { value: breakLoc } - }); + this.breakLoc = breakLoc; } inherits(SwitchEntry, Entry); -exports.SwitchEntry = SwitchEntry; function TryEntry(firstLoc, catchEntry, finallyEntry) { Entry.call(this); @@ -85,15 +86,12 @@ function TryEntry(firstLoc, catchEntry, finallyEntry) { // Have to have one or the other (or both). assert.ok(catchEntry || finallyEntry); - Object.defineProperties(this, { - firstLoc: { value: firstLoc }, - catchEntry: { value: catchEntry }, - finallyEntry: { value: finallyEntry } - }); + this.firstLoc = firstLoc; + this.catchEntry = catchEntry; + this.finallyEntry = finallyEntry; } inherits(TryEntry, Entry); -exports.TryEntry = TryEntry; function CatchEntry(firstLoc, paramId) { Entry.call(this); @@ -101,27 +99,21 @@ function CatchEntry(firstLoc, paramId) { n.Literal.assert(firstLoc); n.Identifier.assert(paramId); - Object.defineProperties(this, { - firstLoc: { value: firstLoc }, - paramId: { value: paramId } - }); + this.firstLoc = firstLoc; + this.paramId = paramId; } inherits(CatchEntry, Entry); -exports.CatchEntry = CatchEntry; function FinallyEntry(firstLoc) { Entry.call(this); n.Literal.assert(firstLoc); - Object.defineProperties(this, { - firstLoc: { value: firstLoc } - }); + this.firstLoc = firstLoc; } inherits(FinallyEntry, Entry); -exports.FinallyEntry = FinallyEntry; function LeapManager(emitter) { assert.ok(this instanceof LeapManager); @@ -129,18 +121,11 @@ function LeapManager(emitter) { var Emitter = require("./emit").Emitter; assert.ok(emitter instanceof Emitter); - Object.defineProperties(this, { - emitter: { value: emitter }, - entryStack: { - value: [new FunctionEntry(emitter.finalLoc)] - } - }); + this.emitter = emitter; + this.entryStack = [new FunctionEntry(emitter.finalLoc)]; } -var LMp = LeapManager.prototype; -exports.LeapManager = LeapManager; - -LMp.withEntry = function(entry, callback) { +LeapManager.prototype.withEntry = function(entry, callback) { assert.ok(entry instanceof Entry); this.entryStack.push(entry); try { @@ -151,7 +136,7 @@ LMp.withEntry = function(entry, callback) { } }; -LMp._findLeapLocation = function(property, label) { +LeapManager.prototype._findLeapLocation = function(property, label) { for (var i = this.entryStack.length - 1; i >= 0; --i) { var entry = this.entryStack[i]; var loc = entry[property]; @@ -170,10 +155,10 @@ LMp._findLeapLocation = function(property, label) { return null; }; -LMp.getBreakLoc = function(label) { +LeapManager.prototype.getBreakLoc = function(label) { return this._findLeapLocation("breakLoc", label); }; -LMp.getContinueLoc = function(label) { +LeapManager.prototype.getContinueLoc = function(label) { return this._findLeapLocation("continueLoc", label); }; diff --git a/lib/6to5/transformation/transformers/generators/meta.js b/lib/6to5/transformation/transformers/generators/meta.js index 08e32ba697..515f81a8b4 100644 --- a/lib/6to5/transformation/transformers/generators/meta.js +++ b/lib/6to5/transformation/transformers/generators/meta.js @@ -9,11 +9,12 @@ */ var assert = require("assert"); -var types = require("ast-types"); -var m = require("private").makeAccessor(); +var types = require("ast-types"); +var m = require("private").makeAccessor(); +var _ = require("lodash"); + var isArray = types.builtInTypes.array; -var n = types.namedTypes; -var hasOwn = Object.prototype.hasOwnProperty; +var n = types.namedTypes; function makePredicate(propertyName, knownTypes) { function onlyChildren(node) { @@ -45,16 +46,13 @@ function makePredicate(propertyName, knownTypes) { n.Node.assert(node); var meta = m(node); - if (hasOwn.call(meta, propertyName)) - return meta[propertyName]; + if (_.has(meta, propertyName)) return meta[propertyName]; // Certain types are "opaque," which means they have no side // effects or leaps and we don't care about their subexpressions. - if (hasOwn.call(opaqueTypes, node.type)) - return meta[propertyName] = false; + if (_.has(opaqueTypes, node.type)) return meta[propertyName] = false; - if (hasOwn.call(knownTypes, node.type)) - return meta[propertyName] = true; + if (_.has(knownTypes, node.type)) return meta[propertyName] = true; return meta[propertyName] = onlyChildren(node); } @@ -91,7 +89,7 @@ var leapTypes = { // All leap types are also side effect types. for (var type in leapTypes) { - if (hasOwn.call(leapTypes, type)) { + if (_.has(leapTypes, type)) { sideEffectTypes[type] = leapTypes[type]; } } diff --git a/lib/6to5/transformation/transformers/generators/runtime.js b/lib/6to5/transformation/transformers/generators/runtime.js index 47a0e949b6..12330ec166 100644 --- a/lib/6to5/transformation/transformers/generators/runtime.js +++ b/lib/6to5/transformation/transformers/generators/runtime.js @@ -12,9 +12,9 @@ if (typeof global.regeneratorRuntime === "object") { return; } -var hasOwn = Object.prototype.hasOwnProperty; var iteratorSymbol = typeof Symbol === "function" && Symbol.iterator || "@@iterator"; var runtime = global.regeneratorRuntime = exports; +var hasOwn = Object.prototype.hasOwnProperty; var wrap = runtime.wrap = function wrap(innerFn, outerFn, self, tryList) { return new Generator(innerFn, outerFn, self || null, tryList || []); @@ -412,8 +412,7 @@ Context.prototype = { throw record.arg; } - if (record.type === "break" || - record.type === "continue") { + if (record.type === "break" || record.type === "continue") { this.next = record.arg; } else if (record.type === "return") { this.rval = record.arg; diff --git a/lib/6to5/transformation/transformers/generators/util.js b/lib/6to5/transformation/transformers/generators/util.js index e9c3bc673e..a6b5dc165f 100644 --- a/lib/6to5/transformation/transformers/generators/util.js +++ b/lib/6to5/transformation/transformers/generators/util.js @@ -8,30 +8,11 @@ * the same directory. */ -var b = require("ast-types").builders; -var hasOwn = Object.prototype.hasOwnProperty; +var t = require("../../../types"); -exports.defaults = function(obj) { - var len = arguments.length; - var extension; - - for (var i = 1; i < len; ++i) { - if ((extension = arguments[i])) { - for (var key in extension) { - if (hasOwn.call(extension, key) && !hasOwn.call(obj, key)) { - obj[key] = extension[key]; - } - } - } - } - - return obj; -}; - -exports.runtimeProperty = function(name) { - return b.memberExpression( - b.identifier("regeneratorRuntime"), - b.identifier(name), - false +exports.runtimeProperty = function (name) { + return t.memberExpression( + t.identifier("regeneratorRuntime"), + t.identifier(name) ); }; diff --git a/lib/6to5/transformation/transformers/generators/visit.js b/lib/6to5/transformation/transformers/generators/visit.js index b3e260ac88..b71f4c2083 100644 --- a/lib/6to5/transformation/transformers/generators/visit.js +++ b/lib/6to5/transformation/transformers/generators/visit.js @@ -200,8 +200,7 @@ function shouldNotHoistAbove(stmtPath) { for (var i = 0; i < value.declarations.length; ++i) { var decl = value.declarations[i]; if (n.CallExpression.check(decl.init) && - types.astNodesAreEquivalent(decl.init.callee, - runtimeMarkMethod)) { + types.astNodesAreEquivalent(decl.init.callee, runtimeMarkMethod)) { return true; } }