Compare commits

...

36 Commits

Author SHA1 Message Date
Sebastian McKenzie
bb17571e56 v3.5.0 2015-02-08 16:35:45 +11:00
Sebastian McKenzie
9161af58c0 fix linting errors 2015-02-08 16:32:08 +11:00
Sebastian McKenzie
e39f4e8025 update 3.5.0 changelog 2015-02-08 16:31:24 +11:00
Sebastian McKenzie
f5e9909e71 Merge pull request #716 from daliwali/master
Make `__esModule` property not enumerable
2015-02-08 16:30:26 +11:00
Sebastian McKenzie
46913fc55f add 3.5.0 changelog 2015-02-08 16:22:12 +11:00
Dali Zheng
d358a86e98 make __esModule property not enumerable 2015-02-07 21:19:11 -08:00
Sebastian McKenzie
055545980c update traceur test runner 2015-02-08 16:19:05 +11:00
Sebastian McKenzie
6fd7f9868e upgrade acorn-6to5 2015-02-08 16:18:54 +11:00
Sebastian McKenzie
e8184a9bc5 fix browser api location in browser test 2015-02-08 14:34:43 +11:00
Sebastian McKenzie
f74de3ef55 move destructuring and parameters.rest transformer to above blockScoping 2015-02-08 14:34:34 +11:00
Sebastian McKenzie
9624f8287d add checkNode to block scoped functions transformer 2015-02-08 14:34:10 +11:00
Sebastian McKenzie
e42d5a889e make destructuring in catch clauses block scoped and add support for non-variable destructuring in for-in/of heads 2015-02-08 14:33:55 +11:00
Sebastian McKenzie
4c8e6481b6 make default parameters iife invocation less serious 2015-02-08 09:54:24 +11:00
Sebastian McKenzie
0867df2691 fix ForOf block body not properly inheriting declarations 2015-02-08 09:50:12 +11:00
Sebastian McKenzie
b06f99ab30 add iife detection to non-identifier params in default parameters 2015-02-08 09:37:06 +11:00
Sebastian McKenzie
9afa3f6b58 add opts param to t.isReferencedIdentifier 2015-02-08 09:31:41 +11:00
Sebastian McKenzie
785cb4b72f allow optional transformer to be set via the whitelist 2015-02-08 09:31:30 +11:00
Sebastian McKenzie
dabe69856a add additional checks to transformers 2015-02-08 09:31:19 +11:00
Sebastian McKenzie
24e70802b5 fix block scoped tracking in functions - fixes #710 2015-02-08 09:31:04 +11:00
Sebastian McKenzie
c1ba55a52d Merge pull request #714 from RReverser/master
Added complete TCO (tail call optimization).
2015-02-08 08:55:19 +11:00
Ingvar Stepanyan
4c318166e1 Added complete TCO (tail call optimization).
Works across functions and generates simpler and faster code than #701.
Works even across files when used in conjunction with `runtime` option.

Closes #256.
2015-02-07 22:22:38 +02:00
Sebastian McKenzie
c0af67eca1 add support for super in object literals - fixes #411 2015-02-08 02:01:17 +11:00
Sebastian McKenzie
eb14f1da00 implement optional TDZ - fixes #563 2015-02-08 01:27:22 +11:00
Sebastian McKenzie
3361b81658 expose parentPath 2015-02-08 01:27:00 +11:00
Sebastian McKenzie
a15f218e9b dump code to esvalid errors 2015-02-08 01:26:46 +11:00
Sebastian McKenzie
067cf43f52 fix File::addHelper unknown helper error message 2015-02-08 00:01:26 +11:00
Sebastian McKenzie
689ce048e6 remove tail call exec test 2015-02-07 23:52:41 +11:00
Sebastian McKenzie
8a143bf957 use a template in tail call transformer - @RReverser 2015-02-07 23:52:35 +11:00
Sebastian McKenzie
9f7bcf585d remove dead TraversalContext code 2015-02-07 23:51:05 +11:00
Sebastian McKenzie
f9efd8a272 fix error message in File::addHelper 2015-02-07 23:50:56 +11:00
Sebastian McKenzie
8cd2326ff9 Merge branch 'master' of github.com:6to5/6to5 2015-02-07 23:37:51 +11:00
Sebastian McKenzie
eb1ae70bfa Merge pull request #701 from RReverser/master
Add tail recursion optimization.
2015-02-07 23:37:43 +11:00
Ingvar Stepanyan
24ef81908c Increase test timeout for Travis. 2015-02-07 14:34:23 +02:00
Ingvar Stepanyan
b53b41cef3 Provide placeholders for proper function length. 2015-02-07 14:26:03 +02:00
Sebastian McKenzie
ad245ed46a 3.4.1 2015-02-07 19:48:59 +11:00
Ingvar Stepanyan
5b2216b348 Add tail recursion optimization.
As per ES6, VMs should perform tail call optimization and prevent growth of call stack.
This adds tail call optimization for recursion case (when function has explicit name and calls itself in `return`).
Cross-function optimization is not currently performed as it's more complicated and requires value tracking.
2015-02-06 16:34:35 +02:00
93 changed files with 795 additions and 160 deletions

View File

@@ -6,6 +6,6 @@ charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.js]
[*.{js,json}]
indent_style = space
indent_size = 2

View File

@@ -11,6 +11,18 @@
_Note: Gaps between patch versions are faulty/broken releases._
## 3.5.0
* **Bug Fix**
* Destructuring patterns as the left operator in `ForInStatement`/`ForOfStatement`.
* **Polish**
* Make default parameter IIFE invocation smarter.
* Make `__esModule` flag non-enumerable. Thanks [@daliwali](https://github.com/daliwali)!
* **New Feature**
* Optional `es6.blockScopingTDZ` is now completely functional and handles all edgecases.
* `super` in object literals.
* Tail call optimisation. Thanks [@RReverser](https://github.com/RReverser)!
## 3.4.1
* **Bug Fix**

View File

@@ -54,7 +54,10 @@ File.helpers = [
"get",
"set",
"class-call-check",
"object-destructuring-empty"
"object-destructuring-empty",
"temporal-undefined",
"temporal-assert-defined",
"tail-call"
];
File.validOptions = [
@@ -297,7 +300,7 @@ File.prototype.isConsequenceExpressionStatement = function (node) {
File.prototype.addHelper = function (name) {
if (!contains(File.helpers, name)) {
throw new ReferenceError("unknown declaration " + name);
throw new ReferenceError("Unknown helper " + name);
}
var program = this.ast.program;

View File

@@ -8,13 +8,17 @@ var t = require("../../types");
* Description
*
* @param {Object} opts
* @param {Boolean} [inClass]
*/
function ReplaceSupers(opts) {
this.topLevelThisReference = null;
function ReplaceSupers(opts, inClass) {
this.topLevelThisReference = opts.topLevelThisReference;
this.methodNode = opts.methodNode;
this.className = opts.className;
this.superName = opts.superName;
this.isStatic = opts.isStatic;
this.hasSuper = false;
this.inClass = inClass;
this.isLoose = opts.isLoose;
this.scope = opts.scope;
this.file = opts.file;
@@ -28,19 +32,21 @@ function ReplaceSupers(opts) {
* _set(Object.getPrototypeOf(CLASS.prototype), "METHOD", "VALUE", this)
*
* @param {Node} property
* @param {boolean} isStatic
* @param {boolean} isComputed
* @param {Node} value
* @param {Boolean} isComputed
* @param {Node} thisExpression
*
* @returns {Node}
*/
ReplaceSupers.prototype.setSuperProperty = function (property, value, isStatic, isComputed, thisExpression) {
ReplaceSupers.prototype.setSuperProperty = function (property, value, isComputed, thisExpression) {
return t.callExpression(
this.file.addHelper("set"),
[
t.callExpression(
t.memberExpression(t.identifier("Object"), t.identifier("getPrototypeOf")),
[
isStatic ? this.className : t.memberExpression(this.className, t.identifier("prototype"))
this.isStatic ? this.className : t.memberExpression(this.className, t.identifier("prototype"))
]
),
isComputed ? property : t.literal(property.name),
@@ -58,20 +64,20 @@ ReplaceSupers.prototype.setSuperProperty = function (property, value, isStatic,
* _get(Object.getPrototypeOf(CLASS.prototype), "METHOD", this)
*
* @param {Node} property
* @param {boolean} isStatic
* @param {boolean} isComputed
* @param {Boolean} isComputed
* @param {Node} thisExpression
*
* @returns {Node}
*/
ReplaceSupers.prototype.getSuperProperty = function (property, isStatic, isComputed, thisExpression) {
ReplaceSupers.prototype.getSuperProperty = function (property, isComputed, thisExpression) {
return t.callExpression(
this.file.addHelper("get"),
[
t.callExpression(
t.memberExpression(t.identifier("Object"), t.identifier("getPrototypeOf")),
[
isStatic ? this.className : t.memberExpression(this.className, t.identifier("prototype"))
this.isStatic ? this.className : t.memberExpression(this.className, t.identifier("prototype"))
]
),
isComputed ? property : t.literal(property.name),
@@ -153,7 +159,8 @@ ReplaceSupers.prototype.getThisReference = function () {
* @returns {Object}
*/
ReplaceSupers.prototype.getLooseSuperProperty = function (methodNode, id, parent) {
ReplaceSupers.prototype.getLooseSuperProperty = function (id, parent) {
var methodNode = this.methodNode;
var methodName = methodNode.key;
var superName = this.superName || t.identifier("Function");
@@ -195,13 +202,15 @@ ReplaceSupers.prototype.getLooseSuperProperty = function (methodNode, id, parent
ReplaceSupers.prototype.looseHandle = function (getThisReference, node, parent) {
if (t.isIdentifier(node, { name: "super" })) {
return this.getLooseSuperProperty(this.methodNode, node, parent);
this.hasSuper = true;
return this.getLooseSuperProperty(node, parent);
} else if (t.isCallExpression(node)) {
var callee = node.callee;
if (!t.isMemberExpression(callee)) return;
if (callee.object.name !== "super") return;
// super.test(); -> ClassName.prototype.MethodName.call(this);
this.hasSuper = true;
t.appendToMemberExpression(callee, t.identifier("call"));
node.arguments.unshift(getThisReference());
}
@@ -237,7 +246,7 @@ ReplaceSupers.prototype.specHandle = function (getThisReference, node, parent) {
// bare `super` call is illegal inside non-constructors
// - https://esdiscuss.org/topic/super-call-in-methods
// - https://twitter.com/wycats/status/544553184396836864
if (methodNode.key.name !== "constructor") {
if (methodNode.key.name !== "constructor" || !this.inClass) {
var methodName = methodNode.key.name || "METHOD_NAME";
throw this.file.errorWithNode(node, "Direct super call is illegal in non-constructor, use super." + methodName + "() instead");
}
@@ -253,13 +262,16 @@ ReplaceSupers.prototype.specHandle = function (getThisReference, node, parent) {
computed = node.computed;
} else if (t.isAssignmentExpression(node) && isSuper(node.left.object, node.left) && methodNode.kind === "set") {
// super.name = "val"; -> _set(Object.getPrototypeOf(ClassName.prototype), "name", this);
return this.setSuperProperty(node.left.property, node.right, methodNode.static, node.left.computed, getThisReference());
this.hasSuper = true;
return this.setSuperProperty(node.left.property, node.right, node.left.computed, getThisReference());
}
if (!property) return;
this.hasSuper = true;
thisReference = getThisReference();
var superProperty = this.getSuperProperty(property, methodNode.static, computed, thisReference);
var superProperty = this.getSuperProperty(property, computed, thisReference);
if (args) {
if (args.length === 1 && t.isSpreadElement(args[0])) {
// super(...arguments);

View File

@@ -1 +1 @@
var VARIABLE_NAME = ARGUMENTS[ARGUMENT_KEY] === undefined ? DEFAULT_VALUE : ARGUMENTS[ARGUMENT_KEY];
let VARIABLE_NAME = ARGUMENTS[ARGUMENT_KEY] === undefined ? DEFAULT_VALUE : ARGUMENTS[ARGUMENT_KEY];

View File

@@ -1 +1,3 @@
exports.__esModule = true;
Object.defineProperty(exports, "__esModule", {
value: true
});

View File

@@ -0,0 +1,21 @@
(function () {
function Tail(func, args, context) {
this.func = func;
this.args = args;
this.context = context;
}
var isRunning = false;
return function (func, args, context) {
var result = new Tail(func, args, context);
if (!isRunning) {
isRunning = true;
do {
result = result.func.apply(result.context, result.args);
} while (result instanceof Tail);
isRunning = false;
}
return result;
};
})()

View File

@@ -0,0 +1,6 @@
(function (val, name, undef) {
if (val === undef) {
throw new ReferenceError(name + " is not defined - temporal dead zone");
}
return true;
})

View File

@@ -0,0 +1 @@
({})

View File

@@ -29,7 +29,7 @@ TransformerPass.prototype.canRun = function () {
// whitelist
var whitelist = opts.whitelist;
if (whitelist.length && !contains(whitelist, key)) return false;
if (whitelist.length) return contains(whitelist, key);
// optional
if (transformer.optional && !contains(opts.optional, key)) return false;

View File

@@ -12,22 +12,18 @@ var visitor = {
// declared node is different in this scope
if (scope.getBinding(node.name) !== declared) return;
var declaredLoc = declared.loc;
var referenceLoc = node.loc;
var assert = t.callExpression(
state.file.addHelper("temporal-assert-defined"),
[node, t.literal(node.name), state.file.addHelper("temporal-undefined")]
);
if (!declaredLoc || !referenceLoc) return;
this.skip();
// does this reference appear on a line before the declaration?
var before = referenceLoc.start.line < declaredLoc.start.line;
if (referenceLoc.start.line === declaredLoc.start.line) {
// this reference appears on the same line
// check it appears before the declaration
before = referenceLoc.start.col < declaredLoc.start.col;
}
if (before) {
throw state.file.errorWithNode(node, "Temporal dead zone - accessing a variable before it's initialized");
if (t.isAssignmentExpression(parent) || t.isUpdateExpression(parent)) {
if (parent._ignoreBlockScopingTDZ) return;
this.parentPath.replaceNode(t.sequenceExpression([assert, parent]));
} else {
return t.logicalExpression("&&", assert, node);
}
}
};

View File

@@ -17,7 +17,7 @@ var isLet = function (node, parent) {
if (node.kind !== "let") return false;
// https://github.com/6to5/6to5/issues/255
if (!t.isFor(parent) || t.isFor(parent) && parent.left !== node) {
if (isLetInitable(node, parent)) {
for (var i = 0; i < node.declarations.length; i++) {
var declar = node.declarations[i];
declar.init = declar.init || t.identifier("undefined");
@@ -29,6 +29,10 @@ var isLet = function (node, parent) {
return true;
};
var isLetInitable = function (node, parent) {
return !t.isFor(parent) || t.isFor(parent) && parent.left !== node;
};
var isVar = function (node, parent) {
return t.isVariableDeclaration(node, { kind: "var" }) && !isLet(node, parent);
};
@@ -39,8 +43,26 @@ var standardizeLets = function (declars) {
}
};
exports.VariableDeclaration = function (node, parent) {
isLet(node, parent);
exports.VariableDeclaration = function (node, parent, scope, file) {
if (!isLet(node, parent)) return;
if (isLetInitable(node) && file.transformers["es6.blockScopingTDZ"].canRun()) {
var nodes = [node];
for (var i = 0; i < node.declarations.length; i++) {
var decl = node.declarations[i];
if (decl.init) {
var assign = t.assignmentExpression("=", decl.id, decl.init);
assign._ignoreBlockScopingTDZ = true;
nodes.push(t.expressionStatement(assign));
}
decl.init = file.addHelper("temporal-undefined");
}
node._blockHoist = 2;
return nodes;
}
};
exports.Loop = function (node, parent, scope, file) {

View File

@@ -152,10 +152,11 @@ Class.prototype.buildBody = function () {
methodNode: node,
className: this.className,
superName: this.superName,
isStatic: node.static,
isLoose: this.isLoose,
scope: this.scope,
file: this.file
});
}, true);
replaceSupers.replace();
if (node.key.name === "constructor") {

View File

@@ -179,21 +179,40 @@ Destructuring.prototype.init = function (pattern, parentId) {
exports.ForInStatement =
exports.ForOfStatement = function (node, parent, scope, file) {
var declar = node.left;
if (!t.isVariableDeclaration(declar)) return;
var left = node.left;
var pattern = declar.declarations[0].id;
if (t.isPattern(left)) {
// for ({ length: k } in { abc: 3 });
var temp = scope.generateUidIdentifier("ref");
node.left = t.variableDeclaration("var", [
t.variableDeclarator(temp)
]);
t.ensureBlock(node);
node.body.body.unshift(t.variableDeclaration("var", [
t.variableDeclarator(left, temp)
]));
return;
}
if (!t.isVariableDeclaration(left)) return;
var pattern = left.declarations[0].id;
if (!t.isPattern(pattern)) return;
var key = scope.generateUidIdentifier("ref");
node.left = t.variableDeclaration(declar.kind, [
node.left = t.variableDeclaration(left.kind, [
t.variableDeclarator(key, null)
]);
var nodes = [];
var destructuring = new Destructuring({
kind: declar.kind,
kind: left.kind,
file: file,
scope: scope,
nodes: nodes
@@ -248,7 +267,7 @@ exports.CatchClause = function (node, parent, scope, file) {
var nodes = [];
var destructuring = new Destructuring({
kind: "var",
kind: "let",
file: file,
scope: scope,
nodes: nodes
@@ -256,6 +275,8 @@ exports.CatchClause = function (node, parent, scope, file) {
destructuring.init(pattern, ref);
node.body.body = nodes.concat(node.body.body);
return node;
};
exports.ExpressionStatement = function (node, parent, scope, file) {

View File

@@ -27,6 +27,7 @@ exports.ForOfStatement = function (node, parent, scope, file) {
// push the rest of the original loop body onto our new body
block.body = block.body.concat(node.body.body);
block._declarations = node.body._declarations;
// todo: find out why this is necessary? #538
loop._scopeInfo = node._scopeInfo;

View File

@@ -0,0 +1,34 @@
"use strict";
var ReplaceSupers = require("../../helpers/replace-supers");
var t = require("../../../types");
exports.check = function (node) {
return t.isIdentifier(node, { name: "super" });
};
exports.Property = function (node, parent, scope, file) {
if (!node.method) return;
var value = node.value;
var thisExpr = scope.generateUidIdentifier("this");
var replaceSupers = new ReplaceSupers({
topLevelThisReference: thisExpr,
methodNode: node,
className: thisExpr,
isStatic: true,
scope: scope,
file: file
});
replaceSupers.replace();
if (replaceSupers.hasSuper) {
value.body.body.unshift(
t.variableDeclaration("var", [
t.variableDeclarator(thisExpr, t.thisExpression())
])
);
}
};

View File

@@ -9,21 +9,23 @@ exports.check = function (node) {
var hasDefaults = function (node) {
for (var i = 0; i < node.params.length; i++) {
if (t.isAssignmentPattern(node.params[i])) return true;
if (!t.isIdentifier(node.params[i])) return true;
}
return false;
};
var iifeVisitor = {
enter: function (node, parent, scope, state) {
if (t.isReferencedIdentifier(node, parent) && state.scope.hasOwnReference(node.name)) {
state.iife = true;
this.stop();
}
if (!t.isReferencedIdentifier(node, parent)) return;
if (!state.scope.hasOwnBinding(node.name)) return;
if (state.scope.bindingEquals(node.name, node)) return;
state.iife = true;
this.stop();
}
};
exports.Function = function (node, parent, scope) {
exports.Function = function (node, parent, scope, file) {
if (!hasDefaults(node)) return;
t.ensureBlock(node);
@@ -37,11 +39,32 @@ exports.Function = function (node, parent, scope) {
var state = { iife: false, scope: scope };
var pushDefNode = function (left, right, i) {
var defNode = util.template("default-parameter", {
VARIABLE_NAME: left,
DEFAULT_VALUE: right,
ARGUMENT_KEY: t.literal(i),
ARGUMENTS: argsIdentifier
}, true);
file.checkNode(defNode);
defNode._blockHoist = node.params.length - i;
body.push(defNode);
};
for (var i = 0; i < node.params.length; i++) {
var param = node.params[i];
if (!t.isAssignmentPattern(param)) {
lastNonDefaultParam = +i + 1;
lastNonDefaultParam = i + 1;
if (!t.isIdentifier(param)) {
scope.traverse(param, iifeVisitor, state);
}
if (file.transformers["es6.blockScopingTDZ"].canRun()) {
pushDefNode(param, t.identifier("undefined"), i);
}
continue;
}
@@ -58,14 +81,7 @@ exports.Function = function (node, parent, scope) {
}
}
var defNode = util.template("default-parameter", {
VARIABLE_NAME: left,
DEFAULT_VALUE: right,
ARGUMENT_KEY: t.literal(+i),
ARGUMENTS: argsIdentifier
}, true);
defNode._blockHoist = node.params.length - i;
body.push(defNode);
pushDefNode(left, right, i);
}
// we need to cut off all trailing default parameters

View File

@@ -73,8 +73,8 @@ exports.CallExpression = function (node, parent, scope, file) {
} else {
nodes = build(args, file);
}
var first = nodes.shift();
var first = nodes.shift();
if (nodes.length) {
node.arguments.push(t.callExpression(t.memberExpression(first, t.identifier("concat")), nodes));
} else {

View File

@@ -0,0 +1,153 @@
"use strict";
var t = require("../../../types");
function returnBlock(expr) {
return t.blockStatement([t.returnStatement(expr)]);
}
function transformExpression(node, scope, state) {
if (!node) return;
return (function subTransform(node) {
switch (node.type) {
case "ConditionalExpression":
var callConsequent = subTransform(node.consequent);
var callAlternate = subTransform(node.alternate);
if (!callConsequent && !callAlternate) {
return;
}
// if ternary operator had tail recursion in value, convert to optimized if-statement
node.type = "IfStatement";
node.consequent = callConsequent ? t.toBlock(callConsequent) : returnBlock(node.consequent);
if (callAlternate) {
node.alternate = t.isIfStatement(callAlternate) ? callAlternate : t.toBlock(callAlternate);
} else {
node.alternate = returnBlock(node.alternate);
}
return [node];
case "LogicalExpression":
// only call in right-value of can be optimized
var callRight = subTransform(node.right);
if (!callRight) {
return;
}
var test = state.wrapSideEffect(node.left);
if (node.operator === "&&") {
test.expr = t.unaryExpression("!", test.expr);
}
return [t.ifStatement(test.expr, returnBlock(test.ref))].concat(callRight);
case "SequenceExpression":
var seq = node.expressions;
// only last element can be optimized
var lastCall = subTransform(seq[seq.length - 1]);
if (!lastCall) {
return;
}
// remove converted expression from sequence
// and convert to regular expression if needed
if (--seq.length === 1) {
node = seq[0];
}
return [t.expressionStatement(node)].concat(lastCall);
case "CallExpression":
var callee = node.callee, thisBinding;
var args = [callee];
// bind `this` to object in member expressions
if (t.isMemberExpression(callee)) {
var object = state.wrapSideEffect(callee.object);
callee.object = object.expr;
thisBinding = object.ref;
}
if (node.arguments.length > 0 || thisBinding) {
args.push(t.arrayExpression(node.arguments));
}
if (thisBinding) {
args.push(thisBinding);
}
return [t.returnStatement(t.callExpression(
state.getHelperRef(),
args
))];
}
})(node);
}
var functionChildrenVisitor = {
enter: function (node, parent, scope, state) {
if (t.isReturnStatement(node)) {
// prevent entrance by current visitor
this.skip();
// transform return argument into statement if
// it contains tail recursion
return transformExpression(node.argument, scope, state);
} else if (t.isFunction(node)) {
return this.skip();
} else if (t.isTryStatement(parent)) {
if (node === parent.block) {
return this.skip();
} else if (node === parent.finalizer) {
return;
} else {
if (parent.finalizer) {
this.skip();
}
return;
}
}
}
};
var functionVisitor = {
enter: function (node, parent, scope, state) {
// traverse all child nodes of this function and find `arguments` and `this`
scope.traverse(node, functionChildrenVisitor, state);
return this.skip();
}
};
exports.FunctionDeclaration =
exports.FunctionExpression = function (node, parent, scope, file) {
var tempId, helperRef;
var state = {
ownerId: node.id,
getHelperRef: function () {
return helperRef = helperRef || file.addHelper("tail-call");
},
wrapSideEffect: function (node) {
if (t.isIdentifier(node) || t.isLiteral(node)) {
return {expr: node, ref: node};
}
tempId = tempId || scope.generateUidIdentifier("temp");
return {
expr: t.assignmentExpression("=", tempId, node),
ref: tempId
};
}
};
// traverse the function and look for tail recursion
scope.traverse(node, functionVisitor, state);
if (tempId) {
t.ensureBlock(node).body.unshift(t.variableDeclaration("var", [
t.variableDeclarator(tempId)
]));
}
};

View File

@@ -28,6 +28,7 @@ module.exports = {
asyncToGenerator: require("./other/async-to-generator"),
bluebirdCoroutines: require("./other/bluebird-coroutines"),
"es6.objectSuper": require("./es6/object-super"),
"es7.objectRestSpread": require("./es7/object-rest-spread"),
"es7.exponentiationOperator": require("./es7/exponentiation-operator"),
"es6.spread": require("./es6/spread"),
@@ -46,6 +47,14 @@ module.exports = {
"es6.constants": require("./es6/constants"),
// needs to be before `es6.blockScoping` as default parameters have a TDZ
"es6.parameters.default": require("./es6/parameters.default"),
"es6.parameters.rest": require("./es6/parameters.rest"),
// needs to be before `es6.blockScoping` as let variables may be produced
"es6.destructuring": require("./es6/destructuring"),
// needs to be before `_aliasFunction` due to block scopes sometimes being wrapped in a
// closure
"es6.blockScoping": require("./es6/block-scoping"),
@@ -53,10 +62,7 @@ module.exports = {
// needs to be after `es6.blockScoping` due to needing `letReferences` set on blocks
"es6.blockScopingTDZ": require("./es6/block-scoping-tdz"),
"es6.parameters.default": require("./es6/parameters.default"),
"es6.parameters.rest": require("./es6/parameters.rest"),
"es6.destructuring": require("./es6/destructuring"),
"es6.tailCall": require("./es6/tail-call"),
regenerator: require("./other/regenerator"),

View File

@@ -2,7 +2,7 @@
var t = require("../../../types");
exports.BlockStatement = function (node, parent) {
exports.BlockStatement = function (node, parent, scope, file) {
if ((t.isFunction(parent) && parent.body === node) || t.isExportDeclaration(parent)) {
return;
}
@@ -22,5 +22,7 @@ exports.BlockStatement = function (node, parent) {
func.id = null;
node.body[i] = declar;
file.checkNode(declar);
}
};

View File

@@ -2,6 +2,8 @@
var t = require("../../../types");
exports.check = t.isFor;
exports.ForInStatement =
exports.ForOfStatement = function (node, parent, scope, file) {
var left = node.left;

View File

@@ -1,5 +1,9 @@
"use strict";
exports.check = function (node) {
return node.kind === "set";
};
exports.MethodDefinition =
exports.Property = function (node, parent, scope, file) {
if (node.kind === "set" && node.value.params.length !== 1) {

View File

@@ -8,42 +8,20 @@ var TraversalPath = require("./path");
var flatten = require("lodash/array/flatten");
var compact = require("lodash/array/compact");
function TraversalContext(scope, opts, state) {
function TraversalContext(scope, opts, state, parentPath) {
this.shouldFlatten = false;
this.parentPath = parentPath;
this.scope = scope;
this.state = state;
this.opts = opts;
this.reset();
}
TraversalContext.prototype.flatten = function () {
this.shouldFlatten = true;
};
TraversalContext.prototype.remove = function () {
this.shouldRemove = true;
this.shouldSkip = true;
};
TraversalContext.prototype.skip = function () {
this.shouldSkip = true;
};
TraversalContext.prototype.stop = function () {
this.shouldStop = true;
this.shouldSkip = true;
};
TraversalContext.prototype.reset = function () {
this.shouldRemove = false;
this.shouldSkip = false;
this.shouldStop = false;
};
TraversalContext.prototype.visitNode = function (node, obj, key) {
this.reset();
var iteration = new TraversalPath(this, node, obj, key);
return iteration.visit();
};

View File

@@ -29,11 +29,11 @@ function traverse(parent, opts, scope, state) {
}
}
traverse.node = function (node, opts, scope, state) {
traverse.node = function (node, opts, scope, state, parentPath) {
var keys = t.VISITOR_KEYS[node.type];
if (!keys) return;
var context = new TraversalContext(scope, opts, state);
var context = new TraversalContext(scope, opts, state, parentPath);
for (var i = 0; i < keys.length; i++) {
if (context.visit(node, keys[i])) {
return;

View File

@@ -14,16 +14,17 @@ function TraversalPath(context, parent, obj, key) {
this.shouldSkip = false;
this.shouldStop = false;
this.context = context;
this.state = this.context.state;
this.opts = this.context.opts;
this.parentPath = context.parentPath;
this.context = context;
this.state = this.context.state;
this.opts = this.context.opts;
this.key = key;
this.obj = obj;
this.parent = parent;
this.scope = TraversalPath.getScope(this.getNode(), parent, context.scope);
this.state = context.state;
this.parent = parent;
this.scope = TraversalPath.getScope(this.getNode(), parent, context.scope);
this.state = context.state;
}
TraversalPath.prototype.remove = function () {
@@ -70,7 +71,7 @@ TraversalPath.prototype.getNode = function () {
return this.obj[this.key];
};
TraversalPath.prototype.replaceNode = function (replacement, scope) {
TraversalPath.prototype.replaceNode = function (replacement) {
var isArray = Array.isArray(replacement);
// inherit comments from original node to the first replacement node
@@ -85,10 +86,10 @@ TraversalPath.prototype.replaceNode = function (replacement, scope) {
if (file) {
if (isArray) {
for (var i = 0; i < replacement.length; i++) {
file.checkNode(replacement[i], scope);
file.checkNode(replacement[i], this.scope);
}
} else {
file.checkNode(replacement, scope);
file.checkNode(replacement, this.scope);
}
}
@@ -144,10 +145,10 @@ TraversalPath.prototype.visit = function () {
// traverse over these replacement nodes we purposely don't call exitNode
// as the original node has been destroyed
for (var i = 0; i < node.length; i++) {
traverse.node(node[i], opts, this.scope, this.state);
traverse.node(node[i], opts, this.scope, this.state, this);
}
} else {
traverse.node(node, opts, this.scope, this.state);
traverse.node(node, opts, this.scope, this.state, this);
this.call("exit");
}

View File

@@ -320,11 +320,12 @@ Scope.prototype.crawl = function () {
for (i = 0; i < block.params.length; i++) {
this.register(block.params[i]);
}
this.traverse(block.body, blockVariableVisitor, this);
}
// Program, BlockStatement, Function - let variables
if (t.isBlockStatement(block) || t.isProgram(block) || t.isFunction(block)) {
if (t.isBlockStatement(block) || t.isProgram(block)) {
this.traverse(block, blockVariableVisitor, this);
}

View File

@@ -340,8 +340,8 @@ t.isReferenced = function (node, parent) {
* @returns {Boolean}
*/
t.isReferencedIdentifier = function (node, parent) {
return t.isIdentifier(node) && t.isReferenced(node, parent);
t.isReferencedIdentifier = function (node, parent, opts) {
return t.isIdentifier(node, opts) && t.isReferenced(node, parent);
};
/**
@@ -395,7 +395,7 @@ t.toIdentifier = function (name) {
t.ensureBlock = function (node, key) {
key = key || "body";
node[key] = t.toBlock(node[key], node);
return node[key] = t.toBlock(node[key], node);
};
/**

View File

@@ -1,7 +1,7 @@
{
"name": "6to5",
"description": "Turn ES6 code into readable vanilla ES5 with source maps",
"version": "3.4.1",
"version": "3.5.0",
"author": "Sebastian McKenzie <sebmck@gmail.com>",
"homepage": "https://6to5.org/",
"repository": "6to5/6to5",
@@ -33,7 +33,7 @@
"test": "make test"
},
"dependencies": {
"acorn-6to5": "0.11.1-25",
"acorn-6to5": "0.11.1-27",
"ast-types": "~0.6.1",
"chalk": "^0.5.1",
"chokidar": "0.12.6",

View File

@@ -1,7 +1,7 @@
{
"name": "6to5-runtime",
"description": "6to5 selfContained runtime",
"version": "3.4.0",
"version": "3.4.1",
"repository": "6to5/6to5",
"author": "Sebastian McKenzie <sebmck@gmail.com>"
}

View File

@@ -1,5 +1,5 @@
if (process.browser) {
require("../lib/6to5/browser");
require("../lib/6to5/api/browser");
require("./generation");
require("./transformation");
require("./traverse");

View File

@@ -19,14 +19,14 @@ var readFile = exports.readFile = function (filename) {
}
};
exports.esvalid = function (ast, loc) {
exports.esvalid = function (ast, code, loc) {
var errors = esvalid.errors(ast);
if (errors.length) {
var msg = [];
_.each(errors, function (err) {
msg.push(err.message + " - " + JSON.stringify(err.node));
});
throw new Error(loc + ": " + msg.join(". "));
throw new Error(loc + ": " + msg.join(". ") + "\n" + code);
}
};

View File

@@ -16,6 +16,14 @@ global.assertNoOwnProperties = function (obj) {
assert.equal(Object.getOwnPropertyNames(obj).length, 0);
};
global.assertHasOwnProperty = function () {
};
global.assertLacksOwnProperty = function () {
};
global.assertArrayEquals = assert.deepEqual;
global.assert = chai.assert;
global.chai = chai;
@@ -54,7 +62,7 @@ var run = function (task, done) {
var checkAst = function (result, opts) {
if (noCheckAst) return;
helper.esvalid(result.ast.program, opts.loc);
helper.esvalid(result.ast.program, result.code, opts.loc);
};
if (execCode) {
@@ -129,12 +137,7 @@ module.exports = function (suiteOpts, taskOpts, dynamicOpts) {
var runTest = function (done) {
var runTask = function () {
try {
run(task, done);
} catch (err) {
if (task.options.after) task.options.after();
throw err;
}
run(task, done);
};
_.extend(task.options, taskOpts);

View File

@@ -17,6 +17,6 @@ suite("api", function () {
var file = new File;
assert.throws(function () {
file.addHelper("foob");
}, /unknown declaration foob/);
}, /Unknown helper foob/);
});
});

View File

@@ -0,0 +1,3 @@
{
"blacklist": ["es6.tailCall"]
}

View File

@@ -0,0 +1,3 @@
a = 1;
let a = 2;

View File

@@ -0,0 +1,7 @@
function b() {
assert.equals(a, 1);
}
let a = 1;
b();

View File

@@ -0,0 +1,7 @@
function b() {
assert.equals(a, 1);
}
b();
let a = 1;

View File

@@ -0,0 +1,3 @@
a;
let a = 1;

View File

@@ -0,0 +1,3 @@
function foo(bar = bar2, bar2) {}
foo();

View File

@@ -0,0 +1,4 @@
{
"optional": "es6.blockScopingTDZ",
"throws": "is not defined - temporal dead zone"
}

View File

@@ -0,0 +1,3 @@
a++;
let a = 1;

View File

@@ -0,0 +1,3 @@
let a = 1;
a = 2;
assert.equal(a, 2);

View File

@@ -0,0 +1,7 @@
let a = 1;
function b() {
return a + 1;
}
assert.equal(b(), 2);

View File

@@ -0,0 +1,3 @@
function foo(bar, bar2 = bar) {}
foo();

View File

@@ -0,0 +1,3 @@
{
"optional": "es6.blockScopingTDZ"
}

View File

@@ -0,0 +1,3 @@
let a = 1;
a++;
assert.equal(a, 2);

View File

@@ -1,2 +0,0 @@
qux;
let qux = 456;

View File

@@ -1,4 +0,0 @@
{
"throws": "Temporal dead zone - accessing a variable before it's initialized",
"optional": ["es6.blockScopingTDZ"]
}

View File

@@ -1,3 +1,4 @@
{
"loose": ["es6.classes"]
"loose": ["es6.classes"],
"blacklist": ["es6.tailCall"]
}

View File

@@ -0,0 +1,3 @@
{
"blacklist": ["es6.tailCall"]
}

View File

@@ -0,0 +1,3 @@
{
"blacklist": ["es6.tailCall"]
}

View File

@@ -14,5 +14,7 @@ define(["exports", "foo"], function (exports, _foo) {
exports["default"] = _foo.foo;
exports["default"] = _foo.foo;
exports.bar = _foo.bar;
exports.__esModule = true;
Object.defineProperty(exports, "__esModule", {
value: true
});
});

View File

@@ -8,5 +8,7 @@ define(["exports"], function (exports) {
exports["default"] = foo;
exports["default"] = foo;
exports.bar = bar;
exports.__esModule = true;
Object.defineProperty(exports, "__esModule", {
value: true
});
});

View File

@@ -17,5 +17,7 @@ define(["exports"], function (exports) {
_classCallCheck(this, foo8);
};
exports.__esModule = true;
Object.defineProperty(exports, "__esModule", {
value: true
});
});

View File

@@ -12,5 +12,7 @@ define(["exports", "./evens"], function (exports, _evens) {
return !isEven(n);
};
})(isEven);
exports.__esModule = true;
Object.defineProperty(exports, "__esModule", {
value: true
});
});

View File

@@ -12,5 +12,7 @@ define(["exports", "foo", "foo-bar", "./directory/foo-bar"], function (exports,
var test2 = exports.test2 = 5;
exports["default"] = test;
exports.__esModule = true;
Object.defineProperty(exports, "__esModule", {
value: true
});
});

View File

@@ -10,5 +10,7 @@ define(["exports"], function (exports) {
test = 3;
test++;
})();
exports.__esModule = true;
Object.defineProperty(exports, "__esModule", {
value: true
});
});

View File

@@ -3,4 +3,6 @@
exports.Cachier = Cachier;
exports["default"] = new Cachier();
function Cachier(databaseName) {}
exports.__esModule = true;
Object.defineProperty(exports, "__esModule", {
value: true
});

View File

@@ -15,4 +15,6 @@ exports.bar = _foo.foo;
exports["default"] = _foo.foo;
exports["default"] = _foo.foo;
exports.bar = _foo.bar;
exports.__esModule = true;
Object.defineProperty(exports, "__esModule", {
value: true
});

View File

@@ -7,4 +7,6 @@ exports.bar = foo;
exports["default"] = foo;
exports["default"] = foo;
exports.bar = bar;
exports.__esModule = true;
Object.defineProperty(exports, "__esModule", {
value: true
});

View File

@@ -16,4 +16,6 @@ var foo8 = exports.foo8 = function foo8() {
_classCallCheck(this, foo8);
};
exports.__esModule = true;
Object.defineProperty(exports, "__esModule", {
value: true
});

View File

@@ -11,4 +11,6 @@ var isOdd = exports.isOdd = (function (isEven) {
return !isEven(n);
};
})(isEven);
exports.__esModule = true;
Object.defineProperty(exports, "__esModule", {
value: true
});

View File

@@ -18,4 +18,6 @@ var bar = require("foo4").bar;
var bar2 = require("foo5").foo;
exports.test = test;
var test = exports.test = 5;
exports.__esModule = true;
Object.defineProperty(exports, "__esModule", {
value: true
});

View File

@@ -9,4 +9,6 @@ test = exports.test += 1;
test = 3;
test++;
})();
exports.__esModule = true;
Object.defineProperty(exports, "__esModule", {
value: true
});

View File

@@ -0,0 +1,3 @@
{
"blacklist": ["es6.tailCall"]
}

View File

@@ -20,5 +20,7 @@
exports["default"] = _foo.foo;
exports["default"] = _foo.foo;
exports.bar = _foo.bar;
exports.__esModule = true;
Object.defineProperty(exports, "__esModule", {
value: true
});
});

View File

@@ -14,5 +14,7 @@
exports["default"] = foo;
exports["default"] = foo;
exports.bar = bar;
exports.__esModule = true;
Object.defineProperty(exports, "__esModule", {
value: true
});
});

View File

@@ -23,5 +23,7 @@
_classCallCheck(this, foo8);
};
exports.__esModule = true;
Object.defineProperty(exports, "__esModule", {
value: true
});
});

View File

@@ -18,5 +18,7 @@
return !isEven(n);
};
})(isEven);
exports.__esModule = true;
Object.defineProperty(exports, "__esModule", {
value: true
});
});

View File

@@ -18,5 +18,7 @@
var test2 = exports.test2 = 5;
exports["default"] = test;
exports.__esModule = true;
Object.defineProperty(exports, "__esModule", {
value: true
});
});

View File

@@ -16,5 +16,7 @@
test = 3;
test++;
})();
exports.__esModule = true;
Object.defineProperty(exports, "__esModule", {
value: true
});
});

View File

@@ -0,0 +1,15 @@
var a = {
name() {
return "Suyash";
}
};
var b = {
name() {
return super.name() + " Verma";
}
};
Object.setPrototypeOf(b, a);
assert.equal(b.name(), "Suyash Verma");

View File

@@ -0,0 +1,3 @@
{
"blacklist": ["es6.tailCall"]
}

View File

@@ -0,0 +1,3 @@
{
"blacklist": ["es6.tailCall"]
}

View File

@@ -0,0 +1,7 @@
(function f(n) {
if (n <= 0) {
console.log(this, arguments);
return "foo";
}
return Math.random() > 0.5 ? f.call(this, n - 1) : f.apply(this, [n - 1]);
})(1e6) === "foo";

View File

@@ -0,0 +1,13 @@
"use strict";
(function f(n) {
if (n <= 0) {
console.log(this, arguments);
return "foo";
}
if (Math.random() > 0.5) {
return to5Runtime.tailCall(f.call, [this, n - 1], f);
} else {
return to5Runtime.tailCall(f.apply, [this, [n - 1]], f);
}
})(1000000) === "foo";

View File

@@ -0,0 +1,7 @@
function f(n) {
return n <= 0 ? "foo" : g(n - 1);
}
function g(n) {
return n <= 0 ? "goo" : f(n - 1);
}

View File

@@ -0,0 +1,17 @@
"use strict";
function f(n) {
if (n <= 0) {
return "foo";
} else {
return to5Runtime.tailCall(g, [n - 1]);
}
}
function g(n) {
if (n <= 0) {
return "goo";
} else {
return to5Runtime.tailCall(f, [n - 1]);
}
}

View File

@@ -0,0 +1,3 @@
(function f(n) {
return n <= 0 ? "foo" : (doSmth(), getTrueValue() && (getFalseValue() || f(n - 1)));
})(1e6, true) === "foo";

View File

@@ -0,0 +1,18 @@
"use strict";
(function f(n) {
var _temp;
if (n <= 0) {
return "foo";
} else {
doSmth();
if (!(_temp = getTrueValue())) {
return _temp;
}
if (_temp = getFalseValue()) {
return _temp;
}
return to5Runtime.tailCall(f, [n - 1]);
}
})(1000000, true) === "foo";

View File

@@ -0,0 +1,4 @@
{
"runtime": true,
"blacklist": []
}

View File

@@ -0,0 +1,8 @@
(function f(n = getDefaultValue(), /* should be undefined after first pass */ m) {
if (n <= 0) {
return "foo";
}
// Should be clean (undefined) on each pass
var local;
return f(n - 1);
})(1e6, true) === "foo";

View File

@@ -0,0 +1,11 @@
"use strict";
(function f(_x, /* should be undefined after first pass */m) {
var n = arguments[0] === undefined ? getDefaultValue() : arguments[0];
if (n <= 0) {
return "foo";
}
// Should be clean (undefined) on each pass
var local;
return to5Runtime.tailCall(f, [n - 1]);
})(1000000, true) === "foo";

View File

@@ -0,0 +1,7 @@
function f() {
return getObj().method();
}
function g() {
return getFalseValue() || getValue();
}

View File

@@ -0,0 +1,14 @@
"use strict";
function f() {
var _temp;
return to5Runtime.tailCall((_temp = getObj()).method, [], _temp);
}
function g() {
var _temp;
if (_temp = getFalseValue()) {
return _temp;
}
return to5Runtime.tailCall(getValue);
}

View File

@@ -0,0 +1,39 @@
(function f(n) {
if (n <= 0) {
return "foo";
}
try {
return f(n - 1);
} catch (e) {}
})(1e6) === "foo";
(function f(n) {
if (n <= 0) {
return "foo";
}
try {
throw new Error();
} catch (e) {
return f(n - 1);
}
})(1e6) === "foo";
(function f(n) {
if (n <= 0) {
return "foo";
}
try {
throw new Error();
} catch (e) {
return f(n - 1);
} finally {}
})(1e6) === "foo";
(function f(n) {
if (n <= 0) {
return "foo";
}
try {} finally {
return f(n - 1);
}
})(1e6) === "foo";

View File

@@ -0,0 +1,41 @@
"use strict";
(function f(n) {
if (n <= 0) {
return "foo";
}
try {
return f(n - 1);
} catch (e) {}
})(1000000) === "foo";
(function f(n) {
if (n <= 0) {
return "foo";
}
try {
throw new Error();
} catch (e) {
return to5Runtime.tailCall(f, [n - 1]);
}
})(1000000) === "foo";
(function f(n) {
if (n <= 0) {
return "foo";
}
try {
throw new Error();
} catch (e) {
return f(n - 1);
} finally {}
})(1000000) === "foo";
(function f(n) {
if (n <= 0) {
return "foo";
}
try {} finally {
return to5Runtime.tailCall(f, [n - 1]);
}
})(1000000) === "foo";

View File

@@ -1,3 +1,4 @@
{
"experimental": true
"experimental": true,
"blacklist": ["es6.tailCall"]
}

View File

@@ -0,0 +1,3 @@
{
"blacklist": ["es6.tailCall"]
}

View File

@@ -0,0 +1,3 @@
{
"blacklist": ["useStrict", "es6.tailCall"]
}

View File

@@ -27,4 +27,6 @@ var foo = _to5Helpers.interopRequire(_someModule);
var bar = _to5Helpers.interopRequireWildcard(_someModule);
var myWord = exports.myWord = _core.Symbol("abc");
exports.__esModule = true;
Object.defineProperty(exports, "__esModule", {
value: true
});

View File

@@ -10,6 +10,18 @@ require("./_transformation-helper")({
loc: __dirname + "/../vendor/traceur/test/feature",
ignoreSuites: [
"Modules",
"Classes",
// these are the responsibility of regenerator
"AsyncFunctions",
"Yield",
// these are the responsibility of core-js
"StringExtras",
"ArrayExtras",
"Collections",
// these are all internal traceur tests or non-standard features
"ObjectMixin",
"Annotations",
@@ -24,9 +36,24 @@ require("./_transformation-helper")({
],
ignoreTasks: [
// core.js doesn't support due to a perf hit and having to override a lot
// of native methods
// these are the responsibility of core-js
"Symbol/GetOwnPropertySymbols",
"Spread/Type",
"Symbol/ObjectModel",
"Symbol/Object",
"Spread/NoIterator",
"Destructuring/Rest",
"Destructuring/Empty",
// traceur uses an old version of regexpu
"RegularExpression/Simple",
// class methods are still enumerable in traceur
"NumericLiteral/Simple",
"Classes/Method",
// Object.mixin didn't make it into ES6
"ObjectMixin",
// traceur doesn't name methods and has an incorrect test asserting that
// they have no names
@@ -38,20 +65,17 @@ require("./_transformation-helper")({
"Syntax/UseStrictLineContinuation",
// experimental es7 - the spec hasn't been finalized yet
// these both fail because of filter between blocks
// these both fail because of filters between blocks
"ArrayComprehension/Simple",
"GeneratorComprehension/Simple",
// yield has been added as a keyword in ES6 so this test is actually incorrect
"Yield/YieldIdentifier"
// yield has been added as a keyword in ES6
"Yield/YieldIdentifier",
"Syntax/StrictKeywords"
]
}, {
optional: ["typeofSymbol"],
experimental: true,
after: function () {
// StringExtras/StarsWith
delete Object.prototype[1];
}
optional: ["spec.typeofSymbol"],
experimental: true
}, function (opts, task) {
if (!_.contains(task.exec.loc, "module.js")) {
opts.blacklist = ["useStrict"];