Skip to content

Commit

Permalink
Merge pull request #4700 from webpack/bug/future-var-declaration
Browse files Browse the repository at this point in the history
add parser prewalking to capture scope
  • Loading branch information
sokra authored Apr 13, 2017
2 parents 98153f5 + e4b8833 commit e787452
Show file tree
Hide file tree
Showing 6 changed files with 340 additions and 41 deletions.
186 changes: 146 additions & 40 deletions lib/Parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -435,36 +435,40 @@ class Parser extends Tapable {
this.walkExpression(methodDefinition.value);
}

walkStatements(statements) {
for(let indexA = 0, lenA = statements.length; indexA < lenA; indexA++) {
const statementA = statements[indexA];
if(this.isHoistedStatement(statementA))
this.walkStatement(statementA);
}
for(let indexB = 0, lenB = statements.length; indexB < lenB; indexB++) {
const statementB = statements[indexB];
if(!this.isHoistedStatement(statementB))
this.walkStatement(statementB);
// Prewalking iterates the scope for variable declarations
prewalkStatements(statements) {
for(let index = 0, len = statements.length; index < len; index++) {
const statement = statements[index];
this.prewalkStatement(statement);
}
}

isHoistedStatement(statement) {
switch(statement.type) {
case "ImportDeclaration":
case "ExportAllDeclaration":
case "ExportNamedDeclaration":
return true;
// Walking iterates the statements and expressions and processes them
walkStatements(statements) {
for(let index = 0, len = statements.length; index < len; index++) {
const statement = statements[index];
this.walkStatement(statement);
}
return false;
}

prewalkStatement(statement) {
const handler = this["prewalk" + statement.type];
if(handler)
handler.call(this, statement);
}

walkStatement(statement) {
if(this.applyPluginsBailResult1("statement", statement) !== undefined) return;
if(this["walk" + statement.type])
this["walk" + statement.type](statement);
const handler = this["walk" + statement.type];
if(handler)
handler.call(this, statement);
}

// Real Statements
prewalkBlockStatement(statement) {
this.prewalkStatements(statement.body);
}

walkBlockStatement(statement) {
this.walkStatements(statement.body);
}
Expand All @@ -473,6 +477,12 @@ class Parser extends Tapable {
this.walkExpression(statement.expression);
}

prewalkIfStatement(statement) {
this.prewalkStatement(statement.consequent);
if(statement.alternate)
this.prewalkStatement(statement.alternate);
}

walkIfStatement(statement) {
const result = this.applyPluginsBailResult1("statement if", statement);
if(result === undefined) {
Expand All @@ -488,17 +498,29 @@ class Parser extends Tapable {
}
}

prewalkLabeledStatement(statement) {
this.prewalkStatement(statement.body);
}

walkLabeledStatement(statement) {
const result = this.applyPluginsBailResult1("label " + statement.label.name, statement);
if(result !== true)
this.walkStatement(statement.body);
}

prewalkWithStatement(statement) {
this.prewalkStatement(statement.body);
}

walkWithStatement(statement) {
this.walkExpression(statement.object);
this.walkStatement(statement.body);
}

prewalkSwitchStatement(statement) {
this.prewalkSwitchCases(statement.cases);
}

walkSwitchStatement(statement) {
this.walkExpression(statement.discriminant);
this.walkSwitchCases(statement.cases);
Expand All @@ -517,6 +539,10 @@ class Parser extends Tapable {
this.walkTerminatingStatement(statement);
}

prewalkTryStatement(statement) {
this.prewalkStatement(statement.block);
}

walkTryStatement(statement) {
if(this.scope.inTry) {
this.walkStatement(statement.block);
Expand All @@ -531,16 +557,32 @@ class Parser extends Tapable {
this.walkStatement(statement.finalizer);
}

prewalkWhileStatement(statement) {
this.prewalkStatement(statement.body);
}

walkWhileStatement(statement) {
this.walkExpression(statement.test);
this.walkStatement(statement.body);
}

prewalkDoWhileStatement(statement) {
this.prewalkStatement(statement.body);
}

walkDoWhileStatement(statement) {
this.walkStatement(statement.body);
this.walkExpression(statement.test);
}

prewalkForStatement(statement) {
if(statement.init) {
if(statement.init.type === "VariableDeclaration")
this.prewalkStatement(statement.init);
}
this.prewalkStatement(statement.body);
}

walkForStatement(statement) {
if(statement.init) {
if(statement.init.type === "VariableDeclaration")
Expand All @@ -555,6 +597,12 @@ class Parser extends Tapable {
this.walkStatement(statement.body);
}

prewalkForInStatement(statement) {
if(statement.left.type === "VariableDeclaration")
this.prewalkStatement(statement.left);
this.prewalkStatement(statement.body);
}

walkForInStatement(statement) {
if(statement.left.type === "VariableDeclaration")
this.walkStatement(statement.left);
Expand All @@ -564,6 +612,12 @@ class Parser extends Tapable {
this.walkStatement(statement.body);
}

prewalkForOfStatement(statement) {
if(statement.left.type === "VariableDeclaration")
this.prewalkStatement(statement.left);
this.prewalkStatement(statement.body);
}

walkForOfStatement(statement) {
if(statement.left.type === "VariableDeclaration")
this.walkStatement(statement.left);
Expand All @@ -574,11 +628,14 @@ class Parser extends Tapable {
}

// Declarations
walkFunctionDeclaration(statement) {
prewalkFunctionDeclaration(statement) {
if(statement.id) {
this.scope.renames["$" + statement.id.name] = undefined;
this.scope.definitions.push(statement.id.name);
}
}

walkFunctionDeclaration(statement) {
this.inScope(statement.params, function() {
if(statement.body.type === "BlockStatement")
this.walkStatement(statement.body);
Expand All @@ -587,7 +644,7 @@ class Parser extends Tapable {
}.bind(this));
}

walkImportDeclaration(statement) {
prewalkImportDeclaration(statement) {
const source = statement.source.value;
this.applyPluginsBailResult("import", statement, source);
statement.specifiers.forEach(function(specifier) {
Expand All @@ -608,7 +665,7 @@ class Parser extends Tapable {
}, this);
}

walkExportNamedDeclaration(statement) {
prewalkExportNamedDeclaration(statement) {
let source;
if(statement.source) {
source = statement.source.value;
Expand All @@ -622,7 +679,7 @@ class Parser extends Tapable {
} else {
if(!this.applyPluginsBailResult("export declaration", statement, statement.declaration)) {
const pos = this.scope.definitions.length;
this.walkStatement(statement.declaration);
this.prewalkStatement(statement.declaration);
const newDefs = this.scope.definitions.slice(pos);
for(let index = newDefs.length - 1; index >= 0; index--) {
const def = newDefs[index];
Expand All @@ -649,17 +706,29 @@ class Parser extends Tapable {
}
}

walkExportNamedDeclaration(statement) {
if(statement.declaration) {
this.walkStatement(statement.declaration);
}
}

prewalkExportDefaultDeclaration(statement) {
if(/Declaration$/.test(statement.declaration.type)) {
const pos = this.scope.definitions.length;
this.prewalkStatement(statement.declaration);
const newDefs = this.scope.definitions.slice(pos);
for(let index = 0, len = newDefs.length; index < len; index++) {
const def = newDefs[index];
this.applyPluginsBailResult("export specifier", statement, def, "default");
}
}
}

walkExportDefaultDeclaration(statement) {
this.applyPluginsBailResult1("export", statement);
if(/Declaration$/.test(statement.declaration.type)) {
if(!this.applyPluginsBailResult("export declaration", statement, statement.declaration)) {
const pos = this.scope.definitions.length;
this.walkStatement(statement.declaration);
const newDefs = this.scope.definitions.slice(pos);
for(let index = 0, len = newDefs.length; index < len; index++) {
const def = newDefs[index];
this.applyPluginsBailResult("export specifier", statement, def, "default");
}
}
} else {
this.walkExpression(statement.declaration);
Expand All @@ -669,25 +738,40 @@ class Parser extends Tapable {
}
}

walkExportAllDeclaration(statement) {
prewalkExportAllDeclaration(statement) {
const source = statement.source.value;
this.applyPluginsBailResult("export import", statement, source);
this.applyPluginsBailResult("export import specifier", statement, source, null, null, 0);
}

prewalkVariableDeclaration(statement) {
if(statement.declarations)
this.prewalkVariableDeclarators(statement.declarations);
}

walkVariableDeclaration(statement) {
if(statement.declarations)
this.walkVariableDeclarators(statement.declarations);
}

walkClassDeclaration(statement) {
prewalkClassDeclaration(statement) {
if(statement.id) {
this.scope.renames["$" + statement.id.name] = undefined;
this.scope.definitions.push(statement.id.name);
}
}

walkClassDeclaration(statement) {
this.walkClass(statement);
}

prewalkSwitchCases(switchCases) {
for(let index = 0, len = switchCases.length; index < len; index++) {
const switchCase = switchCases[index];
this.prewalkStatements(switchCase.consequent);
}
}

walkSwitchCases(switchCases) {
for(let index = 0, len = switchCases.length; index < len; index++) {
const switchCase = switchCases[index];
Expand All @@ -701,11 +785,12 @@ class Parser extends Tapable {

walkCatchClause(catchClause) {
this.inScope([catchClause.param], function() {
this.prewalkStatement(catchClause.body);
this.walkStatement(catchClause.body);
}.bind(this));
}

walkVariableDeclarators(declarators) {
prewalkVariableDeclarators(declarators) {
declarators.forEach(declarator => {
switch(declarator.type) {
case "VariableDeclarator":
Expand All @@ -719,7 +804,6 @@ class Parser extends Tapable {
if(idx >= 0) this.scope.definitions.splice(idx, 1);
}
} else {
this.walkPattern(declarator.id);
this.enterPattern(declarator.id, (name, decl) => {
if(!this.applyPluginsBailResult1("var-" + declarator.kind + " " + name, decl)) {
if(!this.applyPluginsBailResult1("var " + name, decl)) {
Expand All @@ -728,6 +812,21 @@ class Parser extends Tapable {
}
}
});
}
break;
}
}
});
}

walkVariableDeclarators(declarators) {
declarators.forEach(declarator => {
switch(declarator.type) {
case "VariableDeclarator":
{
const renameIdentifier = declarator.init && this.getRenameIdentifier(declarator.init);
if(!renameIdentifier || declarator.id.type !== "Identifier" || !this.applyPluginsBailResult1("can-rename " + renameIdentifier, declarator.init)) {
this.walkPattern(declarator.id);
if(declarator.init)
this.walkExpression(declarator.init);
}
Expand Down Expand Up @@ -812,19 +911,23 @@ class Parser extends Tapable {

walkFunctionExpression(expression) {
this.inScope(expression.params, function() {
if(expression.body.type === "BlockStatement")
if(expression.body.type === "BlockStatement") {
this.prewalkStatement(expression.body);
this.walkStatement(expression.body);
else
} else {
this.walkExpression(expression.body);
}
}.bind(this));
}

walkArrowFunctionExpression(expression) {
this.inScope(expression.params, function() {
if(expression.body.type === "BlockStatement")
if(expression.body.type === "BlockStatement") {
this.prewalkStatement(expression.body);
this.walkStatement(expression.body);
else
} else {
this.walkExpression(expression.body);
}
}.bind(this));
}

Expand Down Expand Up @@ -957,9 +1060,10 @@ class Parser extends Tapable {
if(!params[i] || params[i].type !== "Identifier") continue;
this.scope.renames["$" + params[i].name] = param;
}
if(functionExpression.body.type === "BlockStatement")
if(functionExpression.body.type === "BlockStatement") {
this.prewalkStatement(functionExpression.body);
this.walkStatement(functionExpression.body);
else
} else
this.walkExpression(functionExpression.body);
}.bind(this));
}
Expand Down Expand Up @@ -1236,8 +1340,10 @@ class Parser extends Tapable {
};
const state = this.state = initialState || {};
this.comments = comments;
if(this.applyPluginsBailResult("program", ast, comments) === undefined)
if(this.applyPluginsBailResult("program", ast, comments) === undefined) {
this.prewalkStatements(ast.body);
this.walkStatements(ast.body);
}
this.scope = oldScope;
this.state = oldState;
this.comments = oldComments;
Expand Down
Loading

0 comments on commit e787452

Please sign in to comment.