implement temporal dead zone for default parameters - fixes #169
This commit is contained in:
@@ -1,21 +1,70 @@
|
||||
var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
var traverse = require("../../traverse");
|
||||
var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
exports.Function = function (node) {
|
||||
exports.Function = function (node, parent, file, scope) {
|
||||
if (!node.defaults || !node.defaults.length) return;
|
||||
t.ensureBlock(node);
|
||||
|
||||
var ids = node.params.map(function (param) {
|
||||
return t.getIds(param);
|
||||
});
|
||||
|
||||
var closure = false;
|
||||
|
||||
_.each(node.defaults, function (def, i) {
|
||||
if (!def) return;
|
||||
|
||||
var param = node.params[i];
|
||||
|
||||
node.body.body.unshift(util.template("if-undefined-set-to", {
|
||||
VARIABLE: param,
|
||||
DEFAULT: def
|
||||
// temporal dead zone check - here we prevent accessing of params that
|
||||
// are to the right - ie. uninitialized parameters
|
||||
_.each(ids.slice(i), function (ids, i) {
|
||||
var check = function (node, parent) {
|
||||
if (!t.isIdentifier(node) || !t.isReferenced(node, parent)) return;
|
||||
|
||||
if (_.contains(ids, node.name)) {
|
||||
throw file.errorWithNode(node, "Temporal dead zone - accessing a variable before it's initialized");
|
||||
}
|
||||
|
||||
if (scope.has(node.name)) {
|
||||
closure = true;
|
||||
}
|
||||
};
|
||||
|
||||
check(def, node);
|
||||
traverse(def, check);
|
||||
});
|
||||
|
||||
// we're accessing a variable that's already defined within this function
|
||||
var has = scope.get(param.name);
|
||||
if (has && !_.contains(node.params, has)) {
|
||||
closure = true;
|
||||
}
|
||||
});
|
||||
|
||||
var body = [];
|
||||
|
||||
_.each(node.defaults, function (def, i) {
|
||||
if (!def) return;
|
||||
|
||||
body.push(util.template("if-undefined-set-to", {
|
||||
VARIABLE: node.params[i],
|
||||
DEFAULT: def
|
||||
}, true));
|
||||
});
|
||||
|
||||
if (closure) {
|
||||
var container = t.functionExpression(null, [], node.body, node.generator);
|
||||
container._aliasFunction = true;
|
||||
|
||||
body.push(t.returnStatement(t.callExpression(container, [])));
|
||||
|
||||
node.body = t.blockStatement(body);
|
||||
} else {
|
||||
node.body.body = body.concat(node.body.body);
|
||||
}
|
||||
|
||||
node.defaults = [];
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user