Merge branch 'master' of github.com:6to5/6to5 into amd-module-id

Conflicts:
	lib/6to5/file.js
	lib/6to5/transformation/modules/umd.js
This commit is contained in:
Lars Kappert 2014-11-19 08:39:02 +01:00
commit a37f2093bc
48 changed files with 983 additions and 655 deletions

View File

@ -1,10 +1,17 @@
# 1.12.21
* Fix unneccesary let scoping replacement.
* Add `commonInterop` module formatter. Thanks [@Naddiseo](https://github.com/Naddiseo).
* Fix `return` outside of function body bug. Thanks [@brentburg](https://github.com/brentburg).
* Add more flexible option types.
# 1.12.20
* Append `sourceMappingURL` when using `bin/6to5` and output sourcemaps.
# 1.12.19
* Add `comments` option and `--remove-comments` flag. Thanks @[webpro](htps://github.com/webpro)!
* Add `comments` option and `--remove-comments` flag. Thanks [@webpro](htps://github.com/webpro).
* Embed `regenerator`.
# 1.12.18
@ -13,7 +20,7 @@
# 1.12.17
* Add `moduleName`, `sourceRoot` and `filenameRelative` options - thanks @[darvelo](https://github.com/darvelo)!
* Add `moduleName`, `sourceRoot` and `filenameRelative` options. Thanks [@darvelo](https://github.com/darvelo).
* Traversal optimisations.
# 1.12.16

View File

@ -115,10 +115,12 @@ to5.transformFile("filename.js", options, function (err, result) {
sourceFileName: "filename",
// The root from which all sources are relative
// Default: `moduleRoot` option.
sourceRoot: "assets/scripts",
// Optional prefix for the AMD module formatter that will be prepend to the
// filename on module definitions
// Default: `sourceRoot` option.
moduleRoot: "my-app",
// Optionally replace all 6to5 helper declarations with a referenece to this

View File

@ -19,7 +19,7 @@ function File(opts) {
}
File.declarations = ["extends", "class-props", "slice", "apply-constructor",
"tagged-template-literal"];
"tagged-template-literal", "interop-require"];
File.normaliseOptions = function (opts) {
opts = _.cloneDeep(opts || {});
@ -39,6 +39,17 @@ File.normaliseOptions = function (opts) {
// normalise windows path separators to unix
opts.filename = opts.filename.replace(/\\/g, "/");
opts.blacklist = util.arrayify(opts.blacklist);
opts.whitelist = util.arrayify(opts.whitelist);
_.defaults(opts, {
moduleRoot: opts.sourceRoot
});
_.defaults(opts, {
sourceRoot: opts.moduleRoot
});
_.defaults(opts, {
filenameRelative: opts.filename
});
@ -58,8 +69,8 @@ File.normaliseOptions = function (opts) {
return opts;
};
File.prototype.getModuleFormatter = function (type, opts) {
var ModuleFormatter = transform.moduleFormatters[type];
File.prototype.getModuleFormatter = function (type) {
var ModuleFormatter = _.isFunction(type) ? type : transform.moduleFormatters[type];
if (!ModuleFormatter) {
var loc = util.resolve(type);

View File

@ -165,6 +165,8 @@ CodeGenerator.prototype.print = function (node, parent, opts) {
};
CodeGenerator.prototype.printJoin = function (print, nodes, opts) {
if (!nodes || !nodes.length) return;
opts = opts || {};
var self = this;

View File

@ -78,7 +78,7 @@ exports.Literal = function (node) {
val = JSON.stringify(val);
// escape unicode characters
val = val.replace(/[\u007f-\uffff]/g, function(c) {
val = val.replace(/[\u007f-\uffff]/g, function (c) {
return "\\u" + ("0000" + c.charCodeAt(0).toString(16)).slice(-4);
});

View File

@ -17,6 +17,9 @@ exports.polyfill = function () {
exports.canCompile = util.canCompile;
// do not use this - this is for use by official maintained 6to5 plugins
exports._util = util;
exports.transform = transform;
exports.transformFile = function (filename, opts, callback) {

View File

@ -1,6 +1,7 @@
require("./polyfill");
var sourceMapSupport = require("source-map-support");
var util = require("./util");
var to5 = require("./index");
var _ = require("lodash");
@ -71,7 +72,8 @@ var loader = function (m, filename) {
var result = to5.transformFileSync(filename, {
whitelist: whitelist,
blacklist: blacklist,
sourceMap: true
sourceMap: true,
modules: "commonInterop"
});
maps[filename] = result.map;
@ -100,11 +102,11 @@ module.exports = function (opts) {
if (_.isRegExp(opts)) opts = { ignore: opts };
if (opts.ignoreRegex != null) opts.ignore = opts.ignoreRegex;
if (opts.only != null) onlyRegex = opts.only;
if (opts.ignore != null) ignoreRegex = opts.ignore;
if (opts.only != null) onlyRegex = util.regexify(opts.only);
if (opts.ignore != null) ignoreRegex = util.regexify(opts.ignore);
if (opts.extensions) hookExtensions(opts.extensions);
if (opts.extensions) hookExtensions(util.arrayify(opts.extensions));
if (opts.blacklist) blacklist = opts.blacklist;
if (opts.whitelist) whitelist = opts.whitelist;
if (opts.blacklist) blacklist = util.arrayify(opts.blacklist);
if (opts.whitelist) whitelist = util.arrayify(opts.whitelist);
};

View File

@ -0,0 +1,3 @@
(function (obj) {
return obj && (obj["default"] || obj);
})

View File

@ -0,0 +1,29 @@
module.exports = CommonJSInteropFormatter;
var CommonJSFormatter = require("./common");
var util = require("../../util");
var t = require("../../types");
function CommonJSInteropFormatter(file) {
this.file = file;
}
util.inherits(CommonJSInteropFormatter, CommonJSFormatter);
CommonJSInteropFormatter.prototype.importSpecifier = function (specifier, node, nodes) {
var variableName = t.getSpecifierName(specifier);
// import foo from "foo";
if (specifier.default) {
nodes.push(t.variableDeclaration("var", [
t.variableDeclarator(variableName,
t.callExpression(this.file.addDeclaration("interop-require"), [util.template("require", {
MODULE_NAME: node.source.raw
})])
)
]));
return;
}
CommonJSFormatter.prototype.importSpecifier.apply(this, arguments);
};

View File

@ -5,10 +5,8 @@ var util = require("../../util");
var t = require("../../types");
var _ = require("lodash");
function UMDFormatter(file, opts) {
this.file = file;
this.ids = {};
this.insertModuleId = opts.amdModuleId;
function UMDFormatter() {
AMDFormatter.apply(this, arguments);
}
util.inherits(UMDFormatter, AMDFormatter);

View File

@ -20,10 +20,11 @@ transform._ensureTransformerNames = function (type, keys) {
transform.transformers = {};
transform.moduleFormatters = {
common: require("./modules/common"),
ignore: require("./modules/ignore"),
amd: require("./modules/amd"),
umd: require("./modules/umd")
common: require("./modules/common"),
commonInterop: require("./modules/common-interop"),
ignore: require("./modules/ignore"),
amd: require("./modules/amd"),
umd: require("./modules/umd")
};
_.each({

View File

@ -0,0 +1,204 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* https://raw.github.com/facebook/regenerator/master/LICENSE file. An
* additional grant of patent rights can be found in the PATENTS file in
* the same directory.
*/
var assert = require("assert");
var loc = require("../util").loc;
var t = require("../../../../types");
exports.ParenthesizedExpression = function (expr, path, explodeViaTempVar, finish) {
return finish(this.explodeExpression(path.get("expression")));
};
exports.MemberExpression = function (expr, path, explodeViaTempVar, finish) {
return finish(t.memberExpression(
this.explodeExpression(path.get("object")),
expr.computed ? explodeViaTempVar(null, path.get("property")) : expr.property,
expr.computed
));
};
exports.CallExpression = function (expr, path, explodeViaTempVar, finish) {
var oldCalleePath = path.get("callee");
var newCallee = this.explodeExpression(oldCalleePath);
// If the callee was not previously a MemberExpression, then the
// CallExpression was "unqualified," meaning its `this` object should
// be the global object. If the exploded expression has become a
// MemberExpression, then we need to force it to be unqualified by
// using the (0, object.property)(...) trick; otherwise, it will
// receive the object of the MemberExpression as its `this` object.
if (!t.isMemberExpression(oldCalleePath.node) && t.isMemberExpression(newCallee)) {
newCallee = t.sequenceExpression([
t.literal(0),
newCallee
]);
}
return finish(t.callExpression(
newCallee,
path.get("arguments").map(function (argPath) {
return explodeViaTempVar(null, argPath);
})
));
};
exports.NewExpression = function (expr, path, explodeViaTempVar, finish) {
return finish(t.newExpression(
explodeViaTempVar(null, path.get("callee")),
path.get("arguments").map(function (argPath) {
return explodeViaTempVar(null, argPath);
})
));
};
exports.ObjectExpression = function (expr, path, explodeViaTempVar, finish) {
return finish(t.objectExpression(
path.get("properties").map(function (propPath) {
return t.property(
propPath.value.kind,
propPath.value.key,
explodeViaTempVar(null, propPath.get("value"))
);
})
));
};
exports.ArrayExpression = function (expr, path, explodeViaTempVar, finish) {
return finish(t.arrayExpression(
path.get("elements").map(function (elemPath) {
return explodeViaTempVar(null, elemPath);
})
));
};
exports.SequenceExpression = function (expr, path, explodeViaTempVar, finish, ignoreResult) {
var lastIndex = expr.expressions.length - 1;
var self = this;
var result;
path.get("expressions").each(function (exprPath) {
if (exprPath.name === lastIndex) {
result = self.explodeExpression(exprPath, ignoreResult);
} else {
self.explodeExpression(exprPath, true);
}
});
return result;
};
exports.LogicalExpression = function (expr, path, explodeViaTempVar, finish, ignoreResult) {
var after = loc();
var result;
if (!ignoreResult) {
result = this.makeTempVar();
}
var left = explodeViaTempVar(result, path.get("left"));
if (expr.operator === "&&") {
this.jumpIfNot(left, after);
} else {
assert.strictEqual(expr.operator, "||");
this.jumpIf(left, after);
}
explodeViaTempVar(result, path.get("right"), ignoreResult);
this.mark(after);
return result;
};
exports.ConditionalExpression = function (expr, path, explodeViaTempVar, finish, ignoreResult) {
var elseLoc = loc();
var after = loc();
var test = this.explodeExpression(path.get("test"));
var result;
this.jumpIfNot(test, elseLoc);
if (!ignoreResult) {
result = this.makeTempVar();
}
explodeViaTempVar(result, path.get("consequent"), ignoreResult);
this.jump(after);
this.mark(elseLoc);
explodeViaTempVar(result, path.get("alternate"), ignoreResult);
this.mark(after);
return result;
};
exports.UnaryExpression = function (expr, path, explodeViaTempVar, finish) {
return finish(t.unaryExpression(
expr.operator,
// Can't (and don't need to) break up the syntax of the argument.
// Think about delete a[b].
this.explodeExpression(path.get("argument")),
!!expr.prefix
));
};
exports.BinaryExpression = function (expr, path, explodeViaTempVar, finish) {
return finish(t.binaryExpression(
expr.operator,
explodeViaTempVar(null, path.get("left")),
explodeViaTempVar(null, path.get("right"))
));
};
exports.AssignmentExpression = function (expr, path, explodeViaTempVar, finish) {
return finish(t.assignmentExpression(
expr.operator,
this.explodeExpression(path.get("left")),
this.explodeExpression(path.get("right"))
));
};
exports.UpdateExpression = function (expr, path, explodeViaTempVar, finish) {
return finish(t.updateExpression(
expr.operator,
this.explodeExpression(path.get("argument")),
expr.prefix
));
};
exports.YieldExpression = function (expr, path) {
var after = loc();
var arg = expr.argument && this.explodeExpression(path.get("argument"));
var result;
if (arg && expr.delegate) {
result = this.makeTempVar();
this.emit(t.returnStatement(t.callExpression(
this.contextProperty("delegateYield"), [
arg,
t.literal(result.property.name),
after
]
)));
this.mark(after);
return result;
}
this.emitAssign(this.contextProperty("next"), after);
this.emit(t.returnStatement(arg || null));
this.mark(after);
return this.contextProperty("sent");
};

View File

@ -0,0 +1,334 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* https://raw.github.com/facebook/regenerator/master/LICENSE file. An
* additional grant of patent rights can be found in the PATENTS file in
* the same directory.
*/
var assert = require("assert");
var types = require("ast-types");
var leap = require("../leap");
var util = require("../util");
var t = require("../../../../types");
var runtimeKeysMethod = util.runtimeProperty("keys");
var loc = util.loc;
exports.ExpressionStatement = function (path) {
this.explodeExpression(path.get("expression"), true);
};
exports.LabeledStatement = function (path, stmt) {
this.explodeStatement(path.get("body"), stmt.label);
};
exports.WhileStatement = function (path, stmt, labelId) {
var before = loc();
var after = loc();
this.mark(before);
this.jumpIfNot(this.explodeExpression(path.get("test")), after);
this.leapManager.withEntry(
new leap.LoopEntry(after, before, labelId),
function () { this.explodeStatement(path.get("body")); }
);
this.jump(before);
this.mark(after);
};
exports.DoWhileStatement = function (path, stmt, labelId) {
var first = loc();
var test = loc();
var after = loc();
this.mark(first);
this.leapManager.withEntry(
new leap.LoopEntry(after, test, labelId),
function () { this.explode(path.get("body")); }
);
this.mark(test);
this.jumpIf(this.explodeExpression(path.get("test")), first);
this.mark(after);
};
exports.ForStatement = function (path, stmt, labelId) {
var head = loc();
var update = loc();
var after = loc();
if (stmt.init) {
// We pass true here to indicate that if stmt.init is an expression
// then we do not care about its result.
this.explode(path.get("init"), true);
}
this.mark(head);
if (stmt.test) {
this.jumpIfNot(this.explodeExpression(path.get("test")), after);
} else {
// No test means continue unconditionally.
}
this.leapManager.withEntry(
new leap.LoopEntry(after, update, labelId),
function () { this.explodeStatement(path.get("body")); }
);
this.mark(update);
if (stmt.update) {
// We pass true here to indicate that if stmt.update is an
// expression then we do not care about its result.
this.explode(path.get("update"), true);
}
this.jump(head);
this.mark(after);
};
exports.ForInStatement = function (path, stmt, labelId) {
t.assertIdentifier(stmt.left);
var head = loc();
var after = loc();
var keyIterNextFn = this.makeTempVar();
this.emitAssign(
keyIterNextFn,
t.callExpression(
runtimeKeysMethod,
[this.explodeExpression(path.get("right"))]
)
);
this.mark(head);
var keyInfoTmpVar = this.makeTempVar();
this.jumpIf(
t.memberExpression(
t.assignmentExpression(
"=",
keyInfoTmpVar,
t.callExpression(keyIterNextFn, [])
),
t.identifier("done"),
false
),
after
);
this.emitAssign(
stmt.left,
t.memberExpression(
keyInfoTmpVar,
t.identifier("value"),
false
)
);
this.leapManager.withEntry(
new leap.LoopEntry(after, head, labelId),
function () { this.explodeStatement(path.get("body")); }
);
this.jump(head);
this.mark(after);
};
exports.BreakStatement = function (path, stmt) {
this.emitAbruptCompletion({
type: "break",
target: this.leapManager.getBreakLoc(stmt.label)
});
};
exports.ContinueStatement = function (path, stmt) {
this.emitAbruptCompletion({
type: "continue",
target: this.leapManager.getContinueLoc(stmt.label)
});
};
exports.SwitchStatement = function (path, stmt) {
// Always save the discriminant into a temporary variable in case the
// test expressions overwrite values like context.sent.
var disc = this.emitAssign(
this.makeTempVar(),
this.explodeExpression(path.get("discriminant"))
);
var after = loc();
var defaultLoc = loc();
var condition = defaultLoc;
var caseLocs = [];
var self = this;
// If there are no cases, .cases might be undefined.
var cases = stmt.cases || [];
for (var i = cases.length - 1; i >= 0; --i) {
var c = cases[i];
t.assertSwitchCase(c);
if (c.test) {
condition = t.conditionalExpression(
t.binaryExpression("===", disc, c.test),
caseLocs[i] = loc(),
condition
);
} else {
caseLocs[i] = defaultLoc;
}
}
this.jump(this.explodeExpression(
new types.NodePath(condition, path, "discriminant")
));
this.leapManager.withEntry(
new leap.SwitchEntry(after),
function () {
path.get("cases").each(function (casePath) {
var i = casePath.name;
self.mark(caseLocs[i]);
casePath.get("consequent").each(
self.explodeStatement,
self
);
});
}
);
this.mark(after);
if (defaultLoc.value === -1) {
this.mark(defaultLoc);
assert.strictEqual(after.value, defaultLoc.value);
}
};
exports.IfStatement = function (path, stmt) {
var elseLoc = stmt.alternate && loc();
var after = loc();
this.jumpIfNot(
this.explodeExpression(path.get("test")),
elseLoc || after
);
this.explodeStatement(path.get("consequent"));
if (elseLoc) {
this.jump(after);
this.mark(elseLoc);
this.explodeStatement(path.get("alternate"));
}
this.mark(after);
};
exports.ReturnStatement = function (path) {
this.emitAbruptCompletion({
type: "return",
value: this.explodeExpression(path.get("argument"))
});
};
exports.TryStatement = function (path, stmt) {
var after = loc();
var self = this;
var handler = stmt.handler;
if (!handler && stmt.handlers) {
handler = stmt.handlers[0] || null;
}
var catchLoc = handler && loc();
var catchEntry = catchLoc && new leap.CatchEntry(
catchLoc,
handler.param
);
var finallyLoc = stmt.finalizer && loc();
var finallyEntry = finallyLoc && new leap.FinallyEntry(finallyLoc);
var tryEntry = new leap.TryEntry(
this.getUnmarkedCurrentLoc(),
catchEntry,
finallyEntry
);
this.tryEntries.push(tryEntry);
this.updateContextPrevLoc(tryEntry.firstLoc);
this.leapManager.withEntry(tryEntry, function () {
this.explodeStatement(path.get("block"));
if (catchLoc) {
if (finallyLoc) {
// If we have both a catch block and a finally block, then
// because we emit the catch block first, we need to jump over
// it to the finally block.
this.jump(finallyLoc);
} else {
// If there is no finally block, then we need to jump over the
// catch block to the fall-through location.
this.jump(after);
}
this.updateContextPrevLoc(self.mark(catchLoc));
var bodyPath = path.get("handler", "body");
var safeParam = this.makeTempVar();
this.clearPendingException(tryEntry.firstLoc, safeParam);
var catchScope = bodyPath.scope;
var catchParamName = handler.param.name;
t.assertCatchClause(catchScope.node);
assert.strictEqual(catchScope.lookup(catchParamName), catchScope);
types.visit(bodyPath, {
visitIdentifier: function (path) {
if (path.value.name === catchParamName &&
path.scope.lookup(catchParamName) === catchScope) {
return safeParam;
}
this.traverse(path);
}
});
this.leapManager.withEntry(catchEntry, function () {
this.explodeStatement(bodyPath);
});
}
if (finallyLoc) {
this.updateContextPrevLoc(this.mark(finallyLoc));
this.leapManager.withEntry(finallyEntry, function () {
this.explodeStatement(path.get("finalizer"));
});
this.emit(t.callExpression(
this.contextProperty("finish"),
[finallyEntry.firstLoc]
));
}
});
this.mark(after);
};
exports.ThrowStatement = function (path) {
this.emit(t.throwStatement(
this.explodeExpression(path.get("argument"))
));
};

View File

@ -10,20 +10,22 @@
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 t = require("../../../types");
var _ = require("lodash");
var explodeExpressions = require("./explode-expressions");
var explodeStatements = require("./explode-statements");
var assert = require("assert");
var types = require("ast-types");
var leap = require("../leap");
var meta = require("../meta");
var util = require("../util");
var t = require("../../../../types");
var _ = require("lodash");
var runtimeKeysMethod = runtimeProperty("keys");
var n = types.namedTypes;
var loc = util.loc;
var n = types.namedTypes;
function Emitter(contextId) {
assert.ok(this instanceof Emitter);
n.Identifier.assert(contextId);
t.assertIdentifier(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
@ -52,19 +54,10 @@ function Emitter(contextId) {
this.leapManager = new leap.LeapManager(this);
}
// 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
// location to be determined at any time, even after generating code that
// refers to the location.
function loc() {
return t.literal(-1);
}
// Sets the exact value of the given location to the offset of the next
// Statement emitted.
Emitter.prototype.mark = function(loc) {
n.Literal.assert(loc);
Emitter.prototype.mark = function (loc) {
t.assertLiteral(loc);
var index = this.listing.length;
if (loc.value === -1) {
loc.value = index;
@ -77,28 +70,28 @@ Emitter.prototype.mark = function(loc) {
return loc;
};
Emitter.prototype.emit = function(node) {
Emitter.prototype.emit = function (node) {
if (t.isExpression(node)) node = t.expressionStatement(node);
n.Statement.assert(node);
t.assertStatement(node);
this.listing.push(node);
};
// Shorthand for emitting assignment statements. This will come in handy
// for assignments to temporary variables.
Emitter.prototype.emitAssign = function(lhs, rhs) {
Emitter.prototype.emitAssign = function (lhs, rhs) {
this.emit(this.assign(lhs, rhs));
return lhs;
};
// Shorthand for an assignment statement.
Emitter.prototype.assign = function(lhs, rhs) {
Emitter.prototype.assign = function (lhs, rhs) {
return t.expressionStatement(
t.assignmentExpression("=", lhs, rhs));
};
// Convenience function for generating expressions like context.next,
// context.sent, and context.rval.
Emitter.prototype.contextProperty = function(name, computed) {
Emitter.prototype.contextProperty = function (name, computed) {
return t.memberExpression(
this.contextId,
computed ? t.literal(name) : t.identifier(name),
@ -116,7 +109,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.
Emitter.prototype.isVolatileContextProperty = function(expr) {
Emitter.prototype.isVolatileContextProperty = function (expr) {
if (t.isMemberExpression(expr)) {
if (expr.computed) {
// If it's a computed property such as context[couldBeAnything],
@ -136,7 +129,7 @@ Emitter.prototype.isVolatileContextProperty = function(expr) {
};
// Shorthand for setting context.rval and jumping to `context.stop()`.
Emitter.prototype.stop = function(rval) {
Emitter.prototype.stop = function (rval) {
if (rval) {
this.setReturnValue(rval);
}
@ -144,8 +137,8 @@ Emitter.prototype.stop = function(rval) {
this.jump(this.finalLoc);
};
Emitter.prototype.setReturnValue = function(valuePath) {
n.Expression.assert(valuePath.value);
Emitter.prototype.setReturnValue = function (valuePath) {
t.assertExpression(valuePath.value);
this.emitAssign(
this.contextProperty("rval"),
@ -153,8 +146,8 @@ Emitter.prototype.setReturnValue = function(valuePath) {
);
};
Emitter.prototype.clearPendingException = function(tryLoc, assignee) {
n.Literal.assert(tryLoc);
Emitter.prototype.clearPendingException = function (tryLoc, assignee) {
t.assertLiteral(tryLoc);
var catchCall = t.callExpression(
this.contextProperty("catch", true),
@ -170,15 +163,15 @@ Emitter.prototype.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.
Emitter.prototype.jump = function(toLoc) {
Emitter.prototype.jump = function (toLoc) {
this.emitAssign(this.contextProperty("next"), toLoc);
this.emit(t.breakStatement());
};
// Conditional jump.
Emitter.prototype.jumpIf = function(test, toLoc) {
n.Expression.assert(test);
n.Literal.assert(toLoc);
Emitter.prototype.jumpIf = function (test, toLoc) {
t.assertExpression(test);
t.assertLiteral(toLoc);
this.emit(t.ifStatement(
test,
@ -190,9 +183,9 @@ Emitter.prototype.jumpIf = function(test, toLoc) {
};
// Conditional jump, with the condition negated.
Emitter.prototype.jumpIfNot = function(test, toLoc) {
n.Expression.assert(test);
n.Literal.assert(toLoc);
Emitter.prototype.jumpIfNot = function (test, toLoc) {
t.assertExpression(test);
t.assertLiteral(toLoc);
var negatedTest;
if (t.isUnaryExpression(test) && test.operator === "!") {
@ -217,11 +210,11 @@ Emitter.prototype.jumpIfNot = function(test, toLoc) {
// other local variables, and since we just increment `nextTempId`
// monotonically, uniqueness is assured.
var nextTempId = 0;
Emitter.prototype.makeTempVar = function() {
Emitter.prototype.makeTempVar = function () {
return this.contextProperty("t" + nextTempId++);
};
Emitter.prototype.getContextFunction = function(id) {
Emitter.prototype.getContextFunction = function (id) {
var node = t.functionExpression(
id || null,
[this.contextId],
@ -244,7 +237,7 @@ Emitter.prototype.getContextFunction = function(id) {
//
// Each marked location in this.listing will correspond to one generated
// case statement.
Emitter.prototype.getDispatchLoop = function() {
Emitter.prototype.getDispatchLoop = function () {
var self = this;
var cases = [];
var current;
@ -253,7 +246,7 @@ Emitter.prototype.getDispatchLoop = function() {
// case, we can skip the rest of the statements until the next case.
var alreadyEnded = false;
self.listing.forEach(function(stmt, i) {
self.listing.forEach(function (stmt, i) {
if (self.marked.hasOwnProperty(i)) {
cases.push(t.switchCase(t.literal(i), current = []));
alreadyEnded = false;
@ -306,7 +299,7 @@ function isSwitchCaseEnder(stmt) {
t.isThrowStatement(stmt);
}
Emitter.prototype.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.
@ -316,7 +309,7 @@ Emitter.prototype.getTryEntryList = function() {
var lastLocValue = 0;
return t.arrayExpression(
this.tryEntries.map(function(tryEntry) {
this.tryEntries.map(function (tryEntry) {
var thisLocValue = tryEntry.firstLoc.value;
assert.ok(thisLocValue >= lastLocValue, "try entries out of order");
lastLocValue = thisLocValue;
@ -346,13 +339,13 @@ Emitter.prototype.getTryEntryList = function() {
// No destructive modification of AST nodes.
Emitter.prototype.explode = function(path, ignoreResult) {
Emitter.prototype.explode = function (path, ignoreResult) {
assert.ok(path instanceof types.NodePath);
var node = path.value;
var self = this;
n.Node.assert(node);
n.Node.check(node);
if (t.isStatement(node))
return self.explodeStatement(path);
@ -389,17 +382,16 @@ function getDeclError(node) {
JSON.stringify(node));
}
Emitter.prototype.explodeStatement = function(path, labelId) {
Emitter.prototype.explodeStatement = function (path, labelId) {
assert.ok(path instanceof types.NodePath);
var stmt = path.value;
var self = this;
var after, head;
n.Statement.assert(stmt);
t.assertStatement(stmt);
if (labelId) {
n.Identifier.assert(labelId);
t.assertIdentifier(labelId);
} else {
labelId = null;
}
@ -423,338 +415,15 @@ Emitter.prototype.explodeStatement = function(path, labelId) {
return;
}
switch (stmt.type) {
case "ExpressionStatement":
self.explodeExpression(path.get("expression"), true);
break;
case "LabeledStatement":
self.explodeStatement(path.get("body"), stmt.label);
break;
case "WhileStatement":
var before = loc();
after = loc();
self.mark(before);
self.jumpIfNot(self.explodeExpression(path.get("test")), after);
self.leapManager.withEntry(
new leap.LoopEntry(after, before, labelId),
function() { self.explodeStatement(path.get("body")); }
);
self.jump(before);
self.mark(after);
break;
case "DoWhileStatement":
var first = loc();
var test = loc();
after = loc();
self.mark(first);
self.leapManager.withEntry(
new leap.LoopEntry(after, test, labelId),
function() { self.explode(path.get("body")); }
);
self.mark(test);
self.jumpIf(self.explodeExpression(path.get("test")), first);
self.mark(after);
break;
case "ForStatement":
head = loc();
var update = loc();
after = loc();
if (stmt.init) {
// We pass true here to indicate that if stmt.init is an expression
// then we do not care about its result.
self.explode(path.get("init"), true);
}
self.mark(head);
if (stmt.test) {
self.jumpIfNot(self.explodeExpression(path.get("test")), after);
} else {
// No test means continue unconditionally.
}
self.leapManager.withEntry(
new leap.LoopEntry(after, update, labelId),
function() { self.explodeStatement(path.get("body")); }
);
self.mark(update);
if (stmt.update) {
// We pass true here to indicate that if stmt.update is an
// expression then we do not care about its result.
self.explode(path.get("update"), true);
}
self.jump(head);
self.mark(after);
break;
case "ForInStatement":
n.Identifier.assert(stmt.left);
head = loc();
after = loc();
var keyIterNextFn = self.makeTempVar();
self.emitAssign(
keyIterNextFn,
t.callExpression(
runtimeKeysMethod,
[self.explodeExpression(path.get("right"))]
)
);
self.mark(head);
var keyInfoTmpVar = self.makeTempVar();
self.jumpIf(
t.memberExpression(
t.assignmentExpression(
"=",
keyInfoTmpVar,
t.callExpression(keyIterNextFn, [])
),
t.identifier("done"),
false
),
after
);
self.emitAssign(
stmt.left,
t.memberExpression(
keyInfoTmpVar,
t.identifier("value"),
false
)
);
self.leapManager.withEntry(
new leap.LoopEntry(after, head, labelId),
function() { self.explodeStatement(path.get("body")); }
);
self.jump(head);
self.mark(after);
break;
case "BreakStatement":
self.emitAbruptCompletion({
type: "break",
target: self.leapManager.getBreakLoc(stmt.label)
});
break;
case "ContinueStatement":
self.emitAbruptCompletion({
type: "continue",
target: self.leapManager.getContinueLoc(stmt.label)
});
break;
case "SwitchStatement":
// Always save the discriminant into a temporary variable in case the
// test expressions overwrite values like context.sent.
var disc = self.emitAssign(
self.makeTempVar(),
self.explodeExpression(path.get("discriminant"))
);
after = loc();
var defaultLoc = loc();
var condition = defaultLoc;
var caseLocs = [];
// If there are no cases, .cases might be undefined.
var cases = stmt.cases || [];
for (var i = cases.length - 1; i >= 0; --i) {
var c = cases[i];
n.SwitchCase.assert(c);
if (c.test) {
condition = t.conditionalExpression(
t.binaryExpression("===", disc, c.test),
caseLocs[i] = loc(),
condition
);
} else {
caseLocs[i] = defaultLoc;
}
}
self.jump(self.explodeExpression(
new types.NodePath(condition, path, "discriminant")
));
self.leapManager.withEntry(
new leap.SwitchEntry(after),
function() {
path.get("cases").each(function(casePath) {
var i = casePath.name;
self.mark(caseLocs[i]);
casePath.get("consequent").each(
self.explodeStatement,
self
);
});
}
);
self.mark(after);
if (defaultLoc.value === -1) {
self.mark(defaultLoc);
assert.strictEqual(after.value, defaultLoc.value);
}
break;
case "IfStatement":
var elseLoc = stmt.alternate && loc();
after = loc();
self.jumpIfNot(
self.explodeExpression(path.get("test")),
elseLoc || after
);
self.explodeStatement(path.get("consequent"));
if (elseLoc) {
self.jump(after);
self.mark(elseLoc);
self.explodeStatement(path.get("alternate"));
}
self.mark(after);
break;
case "ReturnStatement":
self.emitAbruptCompletion({
type: "return",
value: self.explodeExpression(path.get("argument"))
});
break;
case "TryStatement":
after = loc();
var handler = stmt.handler;
if (!handler && stmt.handlers) {
handler = stmt.handlers[0] || null;
}
var catchLoc = handler && loc();
var catchEntry = catchLoc && new leap.CatchEntry(
catchLoc,
handler.param
);
var finallyLoc = stmt.finalizer && loc();
var finallyEntry = finallyLoc && new leap.FinallyEntry(finallyLoc);
var tryEntry = new leap.TryEntry(
self.getUnmarkedCurrentLoc(),
catchEntry,
finallyEntry
);
self.tryEntries.push(tryEntry);
self.updateContextPrevLoc(tryEntry.firstLoc);
self.leapManager.withEntry(tryEntry, function() {
self.explodeStatement(path.get("block"));
if (catchLoc) {
if (finallyLoc) {
// If we have both a catch block and a finally block, then
// because we emit the catch block first, we need to jump over
// it to the finally block.
self.jump(finallyLoc);
} else {
// If there is no finally block, then we need to jump over the
// catch block to the fall-through location.
self.jump(after);
}
self.updateContextPrevLoc(self.mark(catchLoc));
var bodyPath = path.get("handler", "body");
var safeParam = self.makeTempVar();
self.clearPendingException(tryEntry.firstLoc, safeParam);
var catchScope = bodyPath.scope;
var catchParamName = handler.param.name;
n.CatchClause.assert(catchScope.node);
assert.strictEqual(catchScope.lookup(catchParamName), catchScope);
types.visit(bodyPath, {
visitIdentifier: function(path) {
if (path.value.name === catchParamName &&
path.scope.lookup(catchParamName) === catchScope) {
return safeParam;
}
this.traverse(path);
}
});
self.leapManager.withEntry(catchEntry, function() {
self.explodeStatement(bodyPath);
});
}
if (finallyLoc) {
self.updateContextPrevLoc(self.mark(finallyLoc));
self.leapManager.withEntry(finallyEntry, function() {
self.explodeStatement(path.get("finalizer"));
});
self.emit(t.callExpression(
self.contextProperty("finish"),
[finallyEntry.firstLoc]
));
}
});
self.mark(after);
break;
case "ThrowStatement":
self.emit(t.throwStatement(
self.explodeExpression(path.get("argument"))
));
break;
default:
var fn = explodeStatements[stmt.type];
if (fn) {
fn.call(this, path, stmt, labelId);
} else {
throw new Error("unknown Statement of type " + JSON.stringify(stmt.type));
}
};
Emitter.prototype.emitAbruptCompletion = function(record) {
Emitter.prototype.emitAbruptCompletion = function (record) {
if (!isValidCompletion(record)) {
assert.ok(
false,
@ -770,11 +439,11 @@ Emitter.prototype.emitAbruptCompletion = function(record) {
var abruptArgs = [t.literal(record.type)];
if (record.type === "break" || record.type === "continue") {
n.Literal.assert(record.target);
t.assertLiteral(record.target);
abruptArgs[1] = record.target;
} else if (record.type === "return" || record.type === "throw") {
if (record.value) {
n.Expression.assert(record.value);
t.assertExpression(record.value);
abruptArgs[1] = record.value;
}
}
@ -797,7 +466,7 @@ function isValidCompletion(record) {
}
if (type === "break" || type === "continue") {
return !_.has(record, "value") && t.isLiteral(record.target);;
return !_.has(record, "value") && t.isLiteral(record.target);
}
if (type === "return" || type === "throw") {
@ -807,7 +476,6 @@ function isValidCompletion(record) {
return false;
}
// Not all offsets into emitter.listing are potential jump targets. For
// example, execution typically falls into the beginning of a try block
// without jumping directly there. This method returns the current offset
@ -817,7 +485,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.
Emitter.prototype.getUnmarkedCurrentLoc = function() {
Emitter.prototype.getUnmarkedCurrentLoc = function () {
return t.literal(this.listing.length);
};
@ -831,9 +499,9 @@ Emitter.prototype.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.
Emitter.prototype.updateContextPrevLoc = function(loc) {
Emitter.prototype.updateContextPrevLoc = function (loc) {
if (loc) {
n.Literal.assert(loc);
t.assertLiteral(loc);
if (loc.value === -1) {
// If an uninitialized location literal was passed in, set its value
@ -854,21 +522,20 @@ Emitter.prototype.updateContextPrevLoc = function(loc) {
this.emitAssign(this.contextProperty("prev"), loc);
};
Emitter.prototype.explodeExpression = function(path, ignoreResult) {
Emitter.prototype.explodeExpression = function (path, ignoreResult) {
assert.ok(path instanceof types.NodePath);
var expr = path.value;
if (expr) {
n.Expression.assert(expr);
t.assertExpression(expr);
} else {
return expr;
}
var self = this;
var result, after; // Used optionally by several cases below.
function finish(expr) {
n.Expression.assert(expr);
t.assertExpression(expr);
if (ignoreResult) {
self.emit(expr);
} else {
@ -935,180 +602,10 @@ Emitter.prototype.explodeExpression = function(path, ignoreResult) {
// emitting the expression with all its side effects, and we should not
// return a result.
switch (expr.type) {
case "ParenthesizedExpression":
return finish(self.explodeExpression(path.get("expression")));
case "MemberExpression":
return finish(t.memberExpression(
self.explodeExpression(path.get("object")),
expr.computed ? explodeViaTempVar(null, path.get("property")) : expr.property,
expr.computed
));
case "CallExpression":
var oldCalleePath = path.get("callee");
var newCallee = self.explodeExpression(oldCalleePath);
// If the callee was not previously a MemberExpression, then the
// CallExpression was "unqualified," meaning its `this` object should
// be the global object. If the exploded expression has become a
// MemberExpression, then we need to force it to be unqualified by
// using the (0, object.property)(...) trick; otherwise, it will
// receive the object of the MemberExpression as its `this` object.
if (!t.isMemberExpression(oldCalleePath.node) && t.isMemberExpression(newCallee)) {
newCallee = t.sequenceExpression([
t.literal(0),
newCallee
]);
}
return finish(t.callExpression(
newCallee,
path.get("arguments").map(function(argPath) {
return explodeViaTempVar(null, argPath);
})
));
case "NewExpression":
return finish(t.newExpression(
explodeViaTempVar(null, path.get("callee")),
path.get("arguments").map(function(argPath) {
return explodeViaTempVar(null, argPath);
})
));
case "ObjectExpression":
return finish(t.objectExpression(
path.get("properties").map(function(propPath) {
return t.property(
propPath.value.kind,
propPath.value.key,
explodeViaTempVar(null, propPath.get("value"))
);
})
));
case "ArrayExpression":
return finish(t.arrayExpression(
path.get("elements").map(function(elemPath) {
return explodeViaTempVar(null, elemPath);
})
));
case "SequenceExpression":
var lastIndex = expr.expressions.length - 1;
path.get("expressions").each(function(exprPath) {
if (exprPath.name === lastIndex) {
result = self.explodeExpression(exprPath, ignoreResult);
} else {
self.explodeExpression(exprPath, true);
}
});
return result;
case "LogicalExpression":
after = loc();
if (!ignoreResult) {
result = self.makeTempVar();
}
var left = explodeViaTempVar(result, path.get("left"));
if (expr.operator === "&&") {
self.jumpIfNot(left, after);
} else {
assert.strictEqual(expr.operator, "||");
self.jumpIf(left, after);
}
explodeViaTempVar(result, path.get("right"), ignoreResult);
self.mark(after);
return result;
case "ConditionalExpression":
var elseLoc = loc();
after = loc();
var test = self.explodeExpression(path.get("test"));
self.jumpIfNot(test, elseLoc);
if (!ignoreResult) {
result = self.makeTempVar();
}
explodeViaTempVar(result, path.get("consequent"), ignoreResult);
self.jump(after);
self.mark(elseLoc);
explodeViaTempVar(result, path.get("alternate"), ignoreResult);
self.mark(after);
return result;
case "UnaryExpression":
return finish(t.unaryExpression(
expr.operator,
// Can't (and don't need to) break up the syntax of the argument.
// Think about delete a[b].
self.explodeExpression(path.get("argument")),
!!expr.prefix
));
case "BinaryExpression":
return finish(t.binaryExpression(
expr.operator,
explodeViaTempVar(null, path.get("left")),
explodeViaTempVar(null, path.get("right"))
));
case "AssignmentExpression":
return finish(t.assignmentExpression(
expr.operator,
self.explodeExpression(path.get("left")),
self.explodeExpression(path.get("right"))
));
case "UpdateExpression":
return finish(t.updateExpression(
expr.operator,
self.explodeExpression(path.get("argument")),
expr.prefix
));
case "YieldExpression":
after = loc();
var arg = expr.argument && self.explodeExpression(path.get("argument"));
if (arg && expr.delegate) {
result = self.makeTempVar();
self.emit(t.returnStatement(t.callExpression(
self.contextProperty("delegateYield"), [
arg,
t.literal(result.property.name),
after
]
)));
self.mark(after);
return result;
}
self.emitAssign(self.contextProperty("next"), after);
self.emit(t.returnStatement(arg || null));
self.mark(after);
return self.contextProperty("sent");
default:
var fn = explodeExpressions[expr.type];
if (fn) {
return fn.call(this, expr, path, explodeViaTempVar, finish, ignoreResult);
} else {
throw new Error("unknown Expression of type " + JSON.stringify(expr.type));
}
};

View File

@ -13,23 +13,21 @@ var types = require("ast-types");
var t = require("../../../types");
var _ = require("lodash");
var n = types.namedTypes;
// The hoist function takes a FunctionExpression or FunctionDeclaration
// and replaces any Declaration nodes in its body with assignments, then
// returns a VariableDeclaration containing just the names of the removed
// declarations.
exports.hoist = function(funPath) {
exports.hoist = function (funPath) {
assert.ok(funPath instanceof types.NodePath);
n.Function.assert(funPath.value);
t.assertFunction(funPath.value);
var vars = {};
function varDeclToExpr(vdec, includeIdentifiers) {
n.VariableDeclaration.assert(vdec);
t.assertVariableDeclaration(vdec);
var exprs = [];
vdec.declarations.forEach(function(dec) {
vdec.declarations.forEach(function (dec) {
vars[dec.id.name] = dec.id;
if (dec.init) {
@ -51,7 +49,7 @@ exports.hoist = function(funPath) {
}
types.visit(funPath.get("body"), {
visitVariableDeclaration: function(path) {
visitVariableDeclaration: function (path) {
var expr = varDeclToExpr(path.value, false);
if (expr === null) {
path.replace();
@ -66,7 +64,7 @@ exports.hoist = function(funPath) {
return false;
},
visitForStatement: function(path) {
visitForStatement: function (path) {
var init = path.value.init;
if (t.isVariableDeclaration(init)) {
path.get("init").replace(varDeclToExpr(init, false));
@ -74,7 +72,7 @@ exports.hoist = function(funPath) {
this.traverse(path);
},
visitForInStatement: function(path) {
visitForInStatement: function (path) {
var left = path.value.left;
if (t.isVariableDeclaration(left)) {
path.get("left").replace(varDeclToExpr(left, true));
@ -82,7 +80,7 @@ exports.hoist = function(funPath) {
this.traverse(path);
},
visitFunctionDeclaration: function(path) {
visitFunctionDeclaration: function (path) {
var node = path.value;
vars[node.id.name] = node.id;
@ -120,14 +118,14 @@ exports.hoist = function(funPath) {
return false;
},
visitFunctionExpression: function() {
visitFunctionExpression: function () {
// Don't descend into nested function expressions.
return false;
}
});
var paramNames = {};
funPath.get("params").each(function(paramPath) {
funPath.get("params").each(function (paramPath) {
var param = paramPath.value;
if (t.isIdentifier(param)) {
paramNames[param.name] = param;
@ -139,7 +137,7 @@ exports.hoist = function(funPath) {
var declarations = [];
Object.keys(vars).forEach(function(name) {
Object.keys(vars).forEach(function (name) {
if (!_.has(paramNames, name)) {
declarations.push(t.variableDeclarator(vars[name], null));
}

View File

@ -17,11 +17,10 @@ exports.LoopEntry = LoopEntry;
exports.TryEntry = TryEntry;
var assert = require("assert");
var types = require("ast-types");
var util = require("util");
var t = require("../../../types");
var inherits = util.inherits;
var n = types.namedTypes;
function Entry() {
assert.ok(this instanceof Entry);
@ -30,7 +29,7 @@ function Entry() {
function FunctionEntry(returnLoc) {
Entry.call(this);
n.Literal.assert(returnLoc);
t.assertLiteral(returnLoc);
this.returnLoc = returnLoc;
}
@ -40,11 +39,11 @@ inherits(FunctionEntry, Entry);
function LoopEntry(breakLoc, continueLoc, label) {
Entry.call(this);
n.Literal.assert(breakLoc);
n.Literal.assert(continueLoc);
t.assertLiteral(breakLoc);
t.assertLiteral(continueLoc);
if (label) {
n.Identifier.assert(label);
t.assertIdentifier(label);
} else {
label = null;
}
@ -59,7 +58,7 @@ inherits(LoopEntry, Entry);
function SwitchEntry(breakLoc) {
Entry.call(this);
n.Literal.assert(breakLoc);
t.assertLiteral(breakLoc);
this.breakLoc = breakLoc;
}
@ -69,7 +68,7 @@ inherits(SwitchEntry, Entry);
function TryEntry(firstLoc, catchEntry, finallyEntry) {
Entry.call(this);
n.Literal.assert(firstLoc);
t.assertLiteral(firstLoc);
if (catchEntry) {
assert.ok(catchEntry instanceof CatchEntry);
@ -96,8 +95,8 @@ inherits(TryEntry, Entry);
function CatchEntry(firstLoc, paramId) {
Entry.call(this);
n.Literal.assert(firstLoc);
n.Identifier.assert(paramId);
t.assertLiteral(firstLoc);
t.assertIdentifier(paramId);
this.firstLoc = firstLoc;
this.paramId = paramId;
@ -108,7 +107,7 @@ inherits(CatchEntry, Entry);
function FinallyEntry(firstLoc) {
Entry.call(this);
n.Literal.assert(firstLoc);
t.assertLiteral(firstLoc);
this.firstLoc = firstLoc;
}
@ -125,7 +124,7 @@ function LeapManager(emitter) {
this.entryStack = [new FunctionEntry(emitter.finalLoc)];
}
LeapManager.prototype.withEntry = function(entry, callback) {
LeapManager.prototype.withEntry = function (entry, callback) {
assert.ok(entry instanceof Entry);
this.entryStack.push(entry);
try {
@ -136,7 +135,7 @@ LeapManager.prototype.withEntry = function(entry, callback) {
}
};
LeapManager.prototype._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];
@ -155,10 +154,10 @@ LeapManager.prototype._findLeapLocation = function(property, label) {
return null;
};
LeapManager.prototype.getBreakLoc = function(label) {
LeapManager.prototype.getBreakLoc = function (label) {
return this._findLeapLocation("breakLoc", label);
};
LeapManager.prototype.getContinueLoc = function(label) {
LeapManager.prototype.getContinueLoc = function (label) {
return this._findLeapLocation("continueLoc", label);
};

View File

@ -11,7 +11,6 @@
var assert = require("assert");
var types = require("ast-types");
var m = require("private").makeAccessor();
var t = require("../../../types");
var _ = require("lodash");
var isArray = types.builtInTypes.array;
@ -19,7 +18,7 @@ var n = types.namedTypes;
function makePredicate(propertyName, knownTypes) {
function onlyChildren(node) {
n.Node.assert(node);
n.Node.check(node);
// Assume no side effects until we find out otherwise.
var result = false;
@ -36,7 +35,7 @@ function makePredicate(propertyName, knownTypes) {
return result;
}
types.eachField(node, function(name, child) {
types.eachField(node, function (name, child) {
check(child);
});
@ -44,7 +43,7 @@ function makePredicate(propertyName, knownTypes) {
}
function predicate(node) {
n.Node.assert(node);
n.Node.check(node);
var meta = m(node);
if (_.has(meta, propertyName)) return meta[propertyName];

View File

@ -38,19 +38,19 @@ var GFName = "GeneratorFunction";
if (GF.name !== GFName) GF.name = GFName;
if (GF.name !== GFName) throw new Error(GFName + " renamed?");
runtime.isGeneratorFunction = function(genFun) {
runtime.isGeneratorFunction = function (genFun) {
var ctor = genFun && genFun.constructor;
return ctor ? GF.name === ctor.name : false;
};
runtime.mark = function(genFun) {
runtime.mark = function (genFun) {
genFun.__proto__ = GFp;
genFun.prototype = Object.create(Gp);
return genFun;
};
runtime.async = function(innerFn, outerFn, self, tryList) {
return new Promise(function(resolve, reject) {
runtime.async = function (innerFn, outerFn, self, tryList) {
return new Promise(function (resolve, reject) {
var generator = wrap(innerFn, outerFn, self, tryList);
var callNext = step.bind(generator.next);
var callThrow = step.bind(generator["throw"]);
@ -202,11 +202,11 @@ function Generator(innerFn, outerFn, self, tryList) {
return generator;
}
Gp[iteratorSymbol] = function() {
Gp[iteratorSymbol] = function () {
return this;
};
Gp.toString = function() {
Gp.toString = function () {
return "[object Generator]";
};
@ -240,7 +240,7 @@ function Context(tryList) {
this.reset();
}
runtime.keys = function(object) {
runtime.keys = function (object) {
var keys = [];
for (var key in object) {
keys.push(key);
@ -293,7 +293,7 @@ runtime.values = values;
Context.prototype = {
constructor: Context,
reset: function() {
reset: function () {
this.prev = 0;
this.next = 0;
this.sent = undefined;
@ -311,7 +311,7 @@ Context.prototype = {
}
},
stop: function() {
stop: function () {
this.done = true;
var rootEntry = this.tryEntries[0];
@ -323,7 +323,7 @@ Context.prototype = {
return this.rval;
},
dispatchException: function(exception) {
dispatchException: function (exception) {
if (this.done) {
throw exception;
}
@ -375,7 +375,7 @@ Context.prototype = {
}
},
_findFinallyEntry: function(finallyLoc) {
_findFinallyEntry: function (finallyLoc) {
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
var entry = this.tryEntries[i];
if (entry.tryLoc <= this.prev &&
@ -387,7 +387,7 @@ Context.prototype = {
}
},
abrupt: function(type, arg) {
abrupt: function (type, arg) {
var entry = this._findFinallyEntry();
var record = entry ? entry.completion : {};
@ -403,7 +403,7 @@ Context.prototype = {
return ContinueSentinel;
},
complete: function(record) {
complete: function (record) {
if (record.type === "throw") {
throw record.arg;
}
@ -418,12 +418,12 @@ Context.prototype = {
return ContinueSentinel;
},
finish: function(finallyLoc) {
finish: function (finallyLoc) {
var entry = this._findFinallyEntry(finallyLoc);
return this.complete(entry.completion);
},
"catch": function(tryLoc) {
"catch": function (tryLoc) {
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
var entry = this.tryEntries[i];
if (entry.tryLoc === tryLoc) {
@ -442,7 +442,7 @@ Context.prototype = {
throw new Error("illegal catch attempt");
},
delegateYield: function(iterable, resultName, nextLoc) {
delegateYield: function (iterable, resultName, nextLoc) {
this.delegate = {
iterator: values(iterable),
resultName: resultName,

View File

@ -16,3 +16,13 @@ exports.runtimeProperty = function (name) {
t.identifier(name)
);
};
// 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
// location to be determined at any time, even after generating code that
// refers to the location.
exports.loc = function () {
return t.literal(-1);
};

View File

@ -14,8 +14,6 @@ var hoist = require("./hoist").hoist;
var types = require("ast-types");
var t = require("../../../types");
var n = types.namedTypes;
var runtimeAsyncMethod = runtimeProperty("async");
var runtimeWrapMethod = runtimeProperty("wrap");
var runtimeMarkMethod = runtimeProperty("mark");
@ -25,7 +23,7 @@ exports.transform = function transform(node) {
};
var visitor = types.PathVisitor.fromMethodsObject({
visitFunction: function(path) {
visitFunction: function (path) {
// Calling this.traverse(path) first makes for a post-order traversal.
this.traverse(path);
@ -179,7 +177,7 @@ var visitor = types.PathVisitor.fromMethodsObject({
bodyPath.push(varDecl);
} else {
n.FunctionExpression.assert(node);
t.assertFunctionExpression(node);
return t.callExpression(runtimeMarkMethod, [node]);
}
}
@ -187,7 +185,7 @@ var visitor = types.PathVisitor.fromMethodsObject({
function shouldNotHoistAbove(stmtPath) {
var value = stmtPath.value;
n.Statement.assert(value);
t.assertStatement(value);
// If the first statement is a "use strict" declaration, make sure to
// insert hoisted declarations afterwards.
@ -210,11 +208,11 @@ function shouldNotHoistAbove(stmtPath) {
}
var awaitVisitor = types.PathVisitor.fromMethodsObject({
visitFunction: function() {
visitFunction: function () {
return false; // Don't descend into nested function scopes.
},
visitAwaitExpression: function(path) {
visitAwaitExpression: function (path) {
// Convert await expressions to yield expressions.
return t.yieldExpression(path.value.argument, false);
}

View File

@ -88,6 +88,9 @@ LetScoping.prototype.run = function () {
this.info = this.getInfo();
// remap all let references that exist in upper scopes to their uid
this.remap();
// this is a block within a `Function` so we can safely leave it be
if (t.isFunction(this.parent)) return this.noClosure();
@ -138,23 +141,29 @@ LetScoping.prototype.run = function () {
};
/**
* There are no let references accessed within a closure so we can just traverse
* through this block and replace all references that exist in a higher scope to
* their uids.
* There are no let references accessed within a closure so we can just turn the
* lets into vars.
*/
LetScoping.prototype.noClosure = function () {
var replacements = this.info.duplicates;
var declarators = this.info.declarators;
var block = this.block;
standardiseLets(this.info.declarators);
};
standardiseLets(declarators);
/**
* Traverse through block and replace all references that exist in a higher
* scope to their uids.
*/
LetScoping.prototype.remap = function () {
var replacements = this.info.duplicates;
var block = this.block;
if (_.isEmpty(replacements)) return;
var replace = function (node, parent) {
var replace = function (node, parent, scope) {
if (!t.isIdentifier(node)) return;
if (!t.isReferenced(node, parent)) return;
if (scope && scope.hasOwn(node.name)) return;
node.name = replacements[node.name] || node.name;
};
@ -260,7 +269,7 @@ LetScoping.prototype.checkFor = function () {
return false;
}
if (forParent && !node.label) {
if (forParent && node && !node.label) {
if (t.isBreakStatement(node)) {
has.hasBreak = true;
replace = t.returnStatement(t.literal("break"));

View File

@ -2,14 +2,25 @@ var _ = require("lodash");
var t = exports;
var addAssert = function (type, is) {
t["assert" + type] = function (node, opts) {
opts = opts || {};
if (!is(node, opts)) {
throw new Error("Expected type " + JSON.stringify(type) + " with option " + JSON.stringify(opts));
}
};
};
//
t.VISITOR_KEYS = require("./visitor-keys");
_.each(t.VISITOR_KEYS, function (keys, type) {
t["is" + type] = function (node, opts) {
var is = t["is" + type] = function (node, opts) {
return node && node.type === type && t.shallowEqual(node, opts);
};
addAssert(type, is);
});
//
@ -43,17 +54,21 @@ _.each(t.ALIAS_KEYS, function (aliases, type) {
_.each(_aliases, function (types, type) {
t[type.toUpperCase() + "_TYPES"] = types;
t["is" + type] = function (node, opts) {
var is = t["is" + type] = function (node, opts) {
return node && _.contains(types, node.type) && t.shallowEqual(node, opts);
};
addAssert(type, is);
});
//
t.isExpression = function (node) {
return !t.isDeclaration(node);
return !t.isStatement(node);
};
addAssert("Expression", t.isExpression);
//
t.shallowEqual = function (actual, expected) {

View File

@ -37,6 +37,21 @@ exports.list = function (val) {
return val ? val.split(",") : [];
};
exports.regexify = function (val) {
if (!val) return new RegExp;
if (_.isArray(val)) val = val.join("|");
if (_.isString(val)) return new RegExp(val || "");
if (_.isRegExp(val)) return val;
throw new TypeError("illegal type for regexify");
};
exports.arrayify = function (val) {
if (!val) return [];
if (_.isString(val)) return exports.list(val);
if (_.isArray(val)) return val;
throw new TypeError("illegal type for arrayify");
};
exports.getUid = function (parent, file) {
var node;

View File

@ -1,7 +1,7 @@
{
"name": "6to5",
"description": "Turn ES6 code into readable vanilla ES5 with source maps",
"version": "1.12.20",
"version": "1.12.21",
"author": "Sebastian McKenzie <sebmck@gmail.com>",
"homepage": "https://github.com/6to5/6to5",
"repository": {
@ -37,17 +37,17 @@
"dependencies": {
"ast-types": "~0.6.0",
"commander": "2.5.0",
"fs-readdir-recursive": "0.0.2",
"fs-readdir-recursive": "0.1.0",
"lodash": "2.4.1",
"mkdirp": "0.5.0",
"es6-shim": "0.20.2",
"es6-symbol": "0.1.1",
"regexpu": "0.3.0",
"source-map": "0.1.40",
"chokidar": "0.10.5",
"chokidar": "0.11.0",
"source-map-support": "0.2.8",
"esutils": "1.1.4",
"acorn-6to5": "https://github.com/6to5/acorn-6to5/archive/74d8e9bed20ba302d3504f53d0b1c649968959e1.tar.gz",
"acorn-6to5": "0.9.1-2",
"estraverse": "^1.7.0",
"private": "^0.1.6"
},

View File

@ -2,5 +2,12 @@ let x = 1;
{
let x = 2;
assert.equal(x, 2);
{
let x = 3;
assert.equal(x, 3);
x++;
assert.equal(x, 4);
}
}
assert.equal(x, 1);

View File

@ -0,0 +1,8 @@
export default 42;
export default {};
export default [];
export default foo;
export default function () {}
export default class {}
export default function foo () {}
export default class Foo {}

View File

@ -0,0 +1,13 @@
"use strict";
exports["default"] = 42;
exports["default"] = {};
exports["default"] = [];
exports["default"] = foo;
exports["default"] = function () {};
exports["default"] = function () {};
function foo() {}
exports["default"] = foo;
var Foo = function Foo() {};
exports["default"] = Foo;

View File

@ -0,0 +1,6 @@
export * from "foo";
export {foo} from "foo";
export {foo, bar} from "foo";
export {foo as bar} from "foo";
export {foo as default} from "foo";
export {foo as default, bar} from "foo";

View File

@ -0,0 +1,15 @@
"use strict";
(function (obj) {
for (var i in obj) {
exports[i] = obj[i];
}
})(require("foo"));
exports.foo = require("foo").foo;
exports.foo = require("foo").foo;
exports.bar = require("foo").bar;
exports.bar = require("foo").foo;
exports["default"] = require("foo").foo;
exports["default"] = require("foo").foo;
exports.bar = require("foo").bar;

View File

@ -0,0 +1,5 @@
export {foo};
export {foo, bar};
export {foo as bar};
export {foo as default};
export {foo as default, bar};

View File

@ -0,0 +1,9 @@
"use strict";
exports.foo = foo;
exports.foo = foo;
exports.bar = bar;
exports.bar = foo;
exports["default"] = foo;
exports["default"] = foo;
exports.bar = bar;

View File

@ -0,0 +1,8 @@
export var foo = 1;
export var foo2 = function () {};
export var foo3;
export let foo4 = 2;
export let foo5;
export const foo6 = 3;
export function foo7 () {}
export class foo8 {}

View File

@ -0,0 +1,13 @@
"use strict";
exports.foo7 = foo7;
var foo = exports.foo = 1;
var foo2 = exports.foo2 = function () {};
var foo3;
var foo4 = exports.foo4 = 2;
var foo5;
var foo6 = exports.foo6 = 3;
function foo7() {}
var foo8 = function foo8() {};
exports.foo8 = foo8;

View File

@ -0,0 +1,11 @@
import { isEven } from "./evens";
export function nextOdd(n) {
return isEven(n) ? n + 1 : n + 2;
}
export var isOdd = (function (isEven) {
return function (n) {
return !isEven(n);
};
})(isEven);

View File

@ -0,0 +1,13 @@
"use strict";
exports.nextOdd = nextOdd;
var isEven = require("./evens").isEven;
function nextOdd(n) {
return isEven(n) ? n + 1 : n + 2;
}
var isOdd = exports.isOdd = (function (isEven) {
return function (n) {
return !isEven(n);
};
})(isEven);

View File

@ -0,0 +1,2 @@
import foo from "foo";
import {default as foo} from "foo";

View File

@ -0,0 +1,9 @@
"use strict";
var _interopRequire = function (obj) {
return obj && (obj["default"] || obj);
};
var foo = _interopRequire(require("foo"));
var foo = require("foo")["default"];

View File

@ -0,0 +1 @@
import * as foo from "foo";

View File

@ -0,0 +1,3 @@
"use strict";
var foo = require("foo");

View File

@ -0,0 +1 @@
import foo, {baz as xyz} from "foo";

View File

@ -0,0 +1,9 @@
"use strict";
var _interopRequire = function (obj) {
return obj && (obj["default"] || obj);
};
var foo = _interopRequire(require("foo"));
var xyz = require("foo").baz;

View File

@ -0,0 +1,4 @@
import {bar} from "foo";
import {bar, baz} from "foo";
import {bar as baz} from "foo";
import {bar as baz, xyz} from "foo";

View File

@ -0,0 +1,8 @@
"use strict";
var bar = require("foo").bar;
var bar = require("foo").bar;
var baz = require("foo").baz;
var baz = require("foo").bar;
var baz = require("foo").bar;
var xyz = require("foo").xyz;

View File

@ -0,0 +1,3 @@
import "foo";
import "foo-bar";
import "./directory/foo-bar";

View File

@ -0,0 +1,7 @@
"use strict";
require("foo");
require("foo-bar");
require("./directory/foo-bar");

View File

@ -0,0 +1,3 @@
{
"modules": "commonInterop"
}

View File

@ -0,0 +1,12 @@
import "foo";
import "foo-bar";
import "./directory/foo-bar";
import foo from "foo";
import * as foo from "foo";
import {bar} from "foo";
import {foo as bar} from "foo";
export {test};
export var test = 5;
export default test;

View File

@ -0,0 +1,22 @@
"use strict";
var _interopRequire = function (obj) {
return obj && (obj["default"] || obj);
};
require("foo");
require("foo-bar");
require("./directory/foo-bar");
var foo = _interopRequire(require("foo"));
var foo = require("foo");
var bar = require("foo").bar;
var bar = require("foo").foo;
exports.test = test;
var test = exports.test = 5;
exports["default"] = test;