add support for break and continue in block binding

This commit is contained in:
Sebastian McKenzie
2014-10-03 10:50:53 +10:00
parent e6753bfab4
commit 5dabe50ed7
6 changed files with 89 additions and 13 deletions

View File

@@ -3,6 +3,8 @@ var util = require("../util");
var b = require("ast-types").builders;
var _ = require("lodash");
var funcTypes = ["FunctionDeclaration", "FunctionExpression"];
var isLet = function (node) {
if (node && node.type === "VariableDeclaration" && node.kind === "let") {
node.kind = "var";
@@ -22,9 +24,7 @@ var hasLet = function (nodes) {
};
exports.Program = function (node) {
if (hasLet(node.body)) {
node.body = buildNode(node.body);
}
if (hasLet(node.body)) node.body = buildNode(node.body);
};
exports.BlockStatement = function (node, parent) {
@@ -33,7 +33,31 @@ exports.BlockStatement = function (node, parent) {
// ignore if we're the body of a closure already
if (parent.type === "FunctionExpression") return;
node.body = buildNode(node.body);
var body = node.body;
node.body = buildNode(node.body, true);
var container = _.last(node.body);
traverse.replace(container, function (node) {
if (node.type === "ContinueStatement") {
return b.returnStatement(null);
}
}, funcTypes);
if (traverse.hasType(body, "BreakStatement", funcTypes)) {
var id = b.identifier("_break");
node.body.unshift(b.variableDeclaration("var", [
b.variableDeclarator(id, b.literal(false))
]));
traverse.replace(container, function (node) {
if (node.type === "BreakStatement") {
return b.returnStatement(b.assignmentExpression("=", id, b.literal(true)));
}
}, funcTypes);
node.body.push(b.ifStatement(id, b.breakStatement()));
}
};
exports.ForOfStatement =
@@ -45,7 +69,7 @@ exports.ForStatement = function (node) {
if (isLet(node.init)) return buildNode(node);
};
var buildNode = function (node) {
var buildNode = function (node, isBlock) {
var nodes = [];
// hoist normal variable declarations
@@ -55,9 +79,11 @@ var buildNode = function (node) {
if (node._ignoreBlockBindingHoist) return node;
if (node.type === "VariableDeclaration" && node.kind === "var") {
nodes.push(b.variableDeclaration("var", node.declarations.map(function (declar) {
var declars = node.declarations.map(function (declar) {
return b.variableDeclarator(declar.id, null);
})));
});
nodes.push(b.variableDeclaration("var", declars));
return node.declarations.map(function (declar) {
return util.template("assign", {
@@ -80,7 +106,8 @@ var buildNode = function (node) {
var block = b.blockStatement([]);
block.body = node;
var func = b.functionExpression(null, [], block, false)
var func = b.functionExpression(null, [], block, false);
var templateName = "function-call";
if (traverse.hasType(node, "ThisExpression")) {

View File

@@ -1,15 +1,17 @@
var VISITOR_KEYS = require("./visitor-keys");
var _ = require("lodash");
var traverse = module.exports = function (parent, callback) {
var traverse = module.exports = function (parent, callback, blacklistTypes) {
if (_.isArray(parent)) {
_.each(parent, function (node) {
traverse(node, callback);
traverse(node, callback, blacklistTypes);
});
return;
}
var keys = VISITOR_KEYS[parent.type] || [];
blacklistTypes = blacklistTypes || [];
_.each(keys, function (key) {
var nodes = parent[key];
@@ -20,6 +22,7 @@ var traverse = module.exports = function (parent, callback) {
// strict references in case the callback modified/replaced the node
if (blacklistTypes.indexOf(obj[key].type) >= 0) return;
var result = callback(obj[key], parent, obj, key);
if (result === false) return;
@@ -47,12 +50,15 @@ var traverse = module.exports = function (parent, callback) {
traverse.Delete = {};
traverse.hasType = function (tree, type) {
traverse.hasType = function (tree, type, blacklistTypes) {
if (tree.type === type) return true;
var has = false;
blacklistTypes = blacklistTypes || []
if (_.isArray(tree)) {
return !!_.find(tree, function (node) {
return traverse.hasType(node, type);
return traverse.hasType(node, type, blacklistTypes);
});
} else {
traverse(tree, function (node) {
@@ -60,7 +66,7 @@ traverse.hasType = function (tree, type) {
has = true;
return false;
}
});
}, blacklistTypes);
}
return has;
@@ -69,6 +75,7 @@ traverse.hasType = function (tree, type) {
traverse.replace = function (node, callback) {
traverse(node, function (node, parent, obj, key) {
var result = callback(node, parent);
if (result === false) return false;
if (result != null) obj[key] = result;
});
};

View File

@@ -0,0 +1,6 @@
var arr = [1, 2, 3];
for (let i in arr) {
let val = arr[i];
console.log(val * 2);
break;
}

View File

@@ -0,0 +1,16 @@
var arr = [
1,
2,
3
];
(function () {
for (var i in arr) {
var _break = false;
(function () {
var val = arr[i];
console.log(val * 2);
return _break = true;
}());
if (_break) break;
}
}());

View File

@@ -0,0 +1,6 @@
var arr = [1, 2, 3];
for (let i in arr) {
let val = arr[i];
console.log(val * 2);
continue;
}

View File

@@ -0,0 +1,14 @@
var arr = [
1,
2,
3
];
(function () {
for (var i in arr) {
(function () {
var val = arr[i];
console.log(val * 2);
return;
}());
}
}());