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; var self = this;
this.ast = ast; this.ast = ast;
this.scope = new Scope(ast.program); this.scope = new Scope(ast.program, null, this);
this.moduleFormatter = this.getModuleFormatter(this.opts.modules); this.moduleFormatter = this.getModuleFormatter(this.opts.modules);
var astRun = function (key) { 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.async = false;
node.generator = true; node.generator = true;
traverse(node, traverser); traverse(node, traverser, scope);
var call = t.callExpression(callId, [node]); var call = t.callExpression(callId, [node]);

View File

@ -12,15 +12,17 @@ var t = require("../../types");
* @param {Object} className * @param {Object} className
* @param {Object} superName * @param {Object} superName
* @param {Boolean} isLoose * @param {Boolean} isLoose
* @param {Scope} scope
* @param {File} file * @param {File} file
*/ */
function ReplaceSupers(methodNode, className, superName, isLoose, file) { function ReplaceSupers(methodNode, className, superName, isLoose, scope, file) {
this.topLevelThisReference = null; this.topLevelThisReference = null;
this.methodNode = methodNode; this.methodNode = methodNode;
this.className = className; this.className = className;
this.superName = superName; this.superName = superName;
this.isLoose = isLoose; this.isLoose = isLoose;
this.scope = scope;
this.file = file; this.file = file;
} }
@ -140,7 +142,7 @@ var traverser = {
ReplaceSupers.prototype.traverseLevel = function (node, topLevel) { ReplaceSupers.prototype.traverseLevel = function (node, topLevel) {
var state = { self: this, topLevel: 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 () { DefaultFormatter.prototype.getLocalExports = function () {
var localExports = {}; var localExports = {};
traverse(this.file.ast, exportsTraverser, null, localExports); traverse(this.file.ast, exportsTraverser, this.file.scope, localExports);
return localExports; return localExports;
}; };
@ -43,7 +43,7 @@ var importsTraverser = {
DefaultFormatter.prototype.getLocalImports = function () { DefaultFormatter.prototype.getLocalImports = function () {
var localImports = {}; var localImports = {};
traverse(this.file.ast, importsTraverser, null, localImports); traverse(this.file.ast, importsTraverser, this.file.scope, localImports);
return localImports; return localImports;
}; };
@ -140,7 +140,7 @@ var remapTraverser = {
DefaultFormatter.prototype.remapAssignments = function () { DefaultFormatter.prototype.remapAssignments = function () {
var state = { self: this }; var state = { self: this };
traverse(this.file.ast, remapTraverser, null, state); traverse(this.file.ast, remapTraverser, this.file.scope, state);
}; };
DefaultFormatter.prototype.getModuleName = function () { DefaultFormatter.prototype.getModuleName = function () {

View File

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

View File

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

View File

@ -76,7 +76,7 @@ Transformer.prototype.transform = function (file) {
this.astRun(file, "before"); this.astRun(file, "before");
var state = { file: file, transformer: this.transformer }; var state = { file: file, transformer: this.transformer };
traverse(file.ast, transformTraverser, null, state); traverse(file.ast, transformTraverser, file.scope, state);
this.astRun(file, "after"); 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 all child nodes of this function and find `arguments` and `this`
traverse(node, functionChildrenTraverser, null, state); traverse(node, functionChildrenTraverser, scope, state);
return context.skip(); 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 // traverse the function and find all alias functions so we can alias
// `arguments` and `this` if necessary // `arguments` and `this` if necessary
traverse(node, functionTraverser, null, state); traverse(node, functionTraverser, scope, state);
var body; var body;

View File

@ -212,7 +212,7 @@ LetScoping.prototype.needsClosure = function () {
var call = t.callExpression(fn, params); var call = t.callExpression(fn, params);
var ret = this.file.generateUidIdentifier("ret", this.scope); 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) { if (hasYield) {
fn.generator = true; fn.generator = true;
call = t.yieldExpression(call, true); call = t.yieldExpression(call, true);

View File

@ -137,7 +137,7 @@ Class.prototype.buildBody = function () {
for (var i = 0; i < classBody.length; i++) { for (var i = 0; i < classBody.length; i++) {
var node = classBody[i]; var node = classBody[i];
if (t.isMethodDefinition(node)) { 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(); replaceSupers.replace();
if (node.key.name === "constructor") { if (node.key.name === "constructor") {

View File

@ -83,5 +83,5 @@ exports.ForStatement = function (node, parent, scope, context, file) {
if (!hasConstants) return; if (!hasConstants) return;
var state = { check: check, getIds: getIds }; 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 block = container.callee.body;
var body = block.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.callee.generator = true;
container = t.yieldExpression(container, true); container = t.yieldExpression(container, true);
} }

View File

@ -10,5 +10,5 @@ exports.manipulateOptions = bluebirdCoroutines.manipulateOptions;
exports.Function = function (node, parent, scope, context, file) { exports.Function = function (node, parent, scope, context, file) {
if (!node.async || node.generator) return; 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( return remapAsyncToGenerator(
node, 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 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 // falsy node
if (!parent) return; 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) opts = {};
if (!opts.enter) opts.enter = _.noop; if (!opts.enter) opts.enter = _.noop;
if (!opts.exit) opts.exit = _.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 // the node we're searching in is blacklisted
if (_.contains(blacklistTypes, tree.type)) return false; if (_.contains(blacklistTypes, tree.type)) return false;
@ -232,7 +238,7 @@ traverse.hasType = function (tree, type, blacklistTypes) {
traverse(tree, { traverse(tree, {
blacklist: blacklistTypes, blacklist: blacklistTypes,
enter: hasBlacklistedType enter: hasBlacklistedType
}, null, state); }, scope, state);
return state.has; return state.has;
}; };

View File

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