ensure that a scope is always passed to traverse and allow scopes to have access to file

This commit is contained in:
Sebastian McKenzie 2015-01-21 23:52:12 +11:00
parent 0b6d49e421
commit 3205c78f01
17 changed files with 39 additions and 26 deletions

View File

@ -262,7 +262,7 @@ File.prototype.transform = function (ast) {
var self = this;
this.ast = ast;
this.scope = new Scope(ast.program);
this.scope = new Scope(ast.program, null, this);
this.moduleFormatter = this.getModuleFormatter(this.opts.modules);
var astRun = function (key) {

View File

@ -13,11 +13,11 @@ var traverser = {
}
};
module.exports = function (node, callId) {
module.exports = function (node, callId, scope) {
node.async = false;
node.generator = true;
traverse(node, traverser);
traverse(node, traverser, scope);
var call = t.callExpression(callId, [node]);

View File

@ -12,15 +12,17 @@ var t = require("../../types");
* @param {Object} className
* @param {Object} superName
* @param {Boolean} isLoose
* @param {Scope} scope
* @param {File} file
*/
function ReplaceSupers(methodNode, className, superName, isLoose, file) {
function ReplaceSupers(methodNode, className, superName, isLoose, scope, file) {
this.topLevelThisReference = null;
this.methodNode = methodNode;
this.className = className;
this.superName = superName;
this.isLoose = isLoose;
this.scope = scope;
this.file = file;
}
@ -140,7 +142,7 @@ var traverser = {
ReplaceSupers.prototype.traverseLevel = function (node, topLevel) {
var state = { self: this, topLevel: topLevel };
traverse(node, traverser, null, state);
traverse(node, traverser, this.scope, state);
};
/**

View File

@ -29,7 +29,7 @@ var exportsTraverser = {
DefaultFormatter.prototype.getLocalExports = function () {
var localExports = {};
traverse(this.file.ast, exportsTraverser, null, localExports);
traverse(this.file.ast, exportsTraverser, this.file.scope, localExports);
return localExports;
};
@ -43,7 +43,7 @@ var importsTraverser = {
DefaultFormatter.prototype.getLocalImports = function () {
var localImports = {};
traverse(this.file.ast, importsTraverser, null, localImports);
traverse(this.file.ast, importsTraverser, this.file.scope, localImports);
return localImports;
};
@ -140,7 +140,7 @@ var remapTraverser = {
DefaultFormatter.prototype.remapAssignments = function () {
var state = { self: this };
traverse(this.file.ast, remapTraverser, null, state);
traverse(this.file.ast, remapTraverser, this.file.scope, state);
};
DefaultFormatter.prototype.getModuleName = function () {

View File

@ -18,7 +18,7 @@ function CommonJSFormatter(file) {
DefaultFormatter.apply(this, arguments);
var state = { hasNonDefaultExports: false };
traverse(file.ast, traverser, null, state);
traverse(file.ast, traverser, file.scope, state);
this.hasNonDefaultExports = state.hasNonDefaultExports;
}

View File

@ -83,6 +83,8 @@ var runnerSettersTraverser = {
};
SystemFormatter.prototype.buildRunnerSetters = function (block, hoistDeclarators) {
var scope = this.file.scope;
return t.arrayExpression(_.map(this.ids, function (uid, source) {
var state = {
source: source,
@ -90,7 +92,7 @@ SystemFormatter.prototype.buildRunnerSetters = function (block, hoistDeclarators
hoistDeclarators: hoistDeclarators
};
traverse(block, runnerSettersTraverser, null, state);
traverse(block, runnerSettersTraverser, scope, state);
return t.functionExpression(null, [uid], t.blockStatement(state.nodes));
}));
@ -171,7 +173,7 @@ SystemFormatter.prototype.transform = function (ast) {
var returnStatement = handlerBody.pop();
// hoist up all variable declarations
traverse(block, hoistVariablesTraverser, null, hoistDeclarators);
traverse(block, hoistVariablesTraverser, this.file.scope, hoistDeclarators);
if (hoistDeclarators.length) {
var hoistDeclar = t.variableDeclaration("var", hoistDeclarators);
@ -180,7 +182,7 @@ SystemFormatter.prototype.transform = function (ast) {
}
// hoist up function declarations for circular references
traverse(block, hoistFunctionsTraverser, null, handlerBody);
traverse(block, hoistFunctionsTraverser, this.file.scope, handlerBody);
handlerBody.push(returnStatement);

View File

@ -76,7 +76,7 @@ Transformer.prototype.transform = function (file) {
this.astRun(file, "before");
var state = { file: file, transformer: this.transformer };
traverse(file.ast, transformTraverser, null, state);
traverse(file.ast, transformTraverser, file.scope, state);
this.astRun(file, "after");
};

View File

@ -37,7 +37,7 @@ var functionTraverser = {
}
// traverse all child nodes of this function and find `arguments` and `this`
traverse(node, functionChildrenTraverser, null, state);
traverse(node, functionChildrenTraverser, scope, state);
return context.skip();
}
@ -58,7 +58,7 @@ var go = function (getBody, node, file, scope) {
// traverse the function and find all alias functions so we can alias
// `arguments` and `this` if necessary
traverse(node, functionTraverser, null, state);
traverse(node, functionTraverser, scope, state);
var body;

View File

@ -212,7 +212,7 @@ LetScoping.prototype.needsClosure = function () {
var call = t.callExpression(fn, params);
var ret = this.file.generateUidIdentifier("ret", this.scope);
var hasYield = traverse.hasType(fn.body, "YieldExpression", t.FUNCTION_TYPES);
var hasYield = traverse.hasType(fn.body, this.scope, "YieldExpression", t.FUNCTION_TYPES);
if (hasYield) {
fn.generator = true;
call = t.yieldExpression(call, true);

View File

@ -137,7 +137,7 @@ Class.prototype.buildBody = function () {
for (var i = 0; i < classBody.length; i++) {
var node = classBody[i];
if (t.isMethodDefinition(node)) {
var replaceSupers = new ReplaceSupers(node, this.className, this.superName, this.isLoose, this.file);
var replaceSupers = new ReplaceSupers(node, this.className, this.superName, this.isLoose, this.scope, this.file);
replaceSupers.replace();
if (node.key.name === "constructor") {

View File

@ -83,5 +83,5 @@ exports.ForStatement = function (node, parent, scope, context, file) {
if (!hasConstants) return;
var state = { check: check, getIds: getIds };
traverse(node, traverser, null, state);
traverse(node, traverser, scope, state);
};

View File

@ -36,7 +36,7 @@ var array = function (node, parent, scope, file) {
var block = container.callee.body;
var body = block.body;
if (traverse.hasType(node, "YieldExpression", t.FUNCTION_TYPES)) {
if (traverse.hasType(node, scope, "YieldExpression", t.FUNCTION_TYPES)) {
container.callee.generator = true;
container = t.yieldExpression(container, true);
}

View File

@ -10,5 +10,5 @@ exports.manipulateOptions = bluebirdCoroutines.manipulateOptions;
exports.Function = function (node, parent, scope, context, file) {
if (!node.async || node.generator) return;
return remapAsyncToGenerator(node, file.addHelper("async-to-generator"));
return remapAsyncToGenerator(node, file.addHelper("async-to-generator"), scope);
};

View File

@ -16,6 +16,7 @@ exports.Function = function (node, parent, scope, context, file) {
return remapAsyncToGenerator(
node,
t.memberExpression(file.addImport("bluebird"), t.identifier("coroutine"))
t.memberExpression(file.addImport("bluebird"), t.identifier("coroutine")),
scope
);
};

View File

@ -36,5 +36,5 @@ exports.MethodDefinition = function (node, parent, scope, context, file) {
file: file
};
traverse(value, traverser, null, state);
traverse(value, traverser, scope, state);
};

View File

@ -164,6 +164,12 @@ function traverse(parent, opts, scope, state) {
// falsy node
if (!parent) return;
if (!scope) {
if (parent.type !== "Program" && parent.type !== "File") {
throw new Error("Must pass a scope unless traversing a Program/File got a " + parent.type + " node");
}
}
if (!opts) opts = {};
if (!opts.enter) opts.enter = _.noop;
if (!opts.exit) opts.exit = _.noop;
@ -217,7 +223,7 @@ function hasBlacklistedType(node, parent, scope, context, state) {
}
}
traverse.hasType = function (tree, type, blacklistTypes) {
traverse.hasType = function (tree, scope, type, blacklistTypes) {
// the node we're searching in is blacklisted
if (_.contains(blacklistTypes, tree.type)) return false;
@ -232,7 +238,7 @@ traverse.hasType = function (tree, type, blacklistTypes) {
traverse(tree, {
blacklist: blacklistTypes,
enter: hasBlacklistedType
}, null, state);
}, scope, state);
return state.has;
};

View File

@ -14,11 +14,13 @@ var FOR_KEYS = ["left", "init"];
*
* @param {Node} block
* @param {Scope} [parent]
* @param {File} [file]
*/
function Scope(block, parent) {
function Scope(block, parent, file) {
this.parent = parent;
this.block = block;
this.file = parent ? parent.file : file;
var info = this.getInfo();
this.references = info.references;
@ -34,7 +36,7 @@ Scope.defaultDeclarations = _.flatten([
vars.reservedVars
].map(_.keys));
Scope.add = function (node, references) {
Scope.add = function (node, references, throwOnDuplicate) {
if (!node) return;
_.defaults(references, t.getIds(node, true));
};