First class block scope
- Make let, const, and class symbols be declared in a block scope. - Piggy back on existing catch symbol implementation to get block-aware mangling working - Make sure unused block-scoped declarations can be dropped - Don't eliminate a block if it has a block-scoped declaration - Remove silly empty anonymous blocks left over from drop_unused - AST_Toplevel now gets to call drop_unused too, since block-scoped variables aren't global! - Don't consider block declarations global
This commit is contained in:
committed by
Richard van Velzen
parent
6702cae918
commit
634f231b78
41
lib/scope.js
41
lib/scope.js
@@ -106,11 +106,15 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
var in_destructuring = null;
|
||||
var in_export;
|
||||
var tw = new TreeWalker(function(node, descend){
|
||||
if (options.screw_ie8 && node instanceof AST_Catch) {
|
||||
var create_a_block_scope =
|
||||
(options.screw_ie8 && node instanceof AST_Catch) ||
|
||||
((node instanceof AST_Block) && node.creates_block_scope());
|
||||
if (create_a_block_scope) {
|
||||
var save_scope = scope;
|
||||
scope = new AST_Scope(node);
|
||||
scope.init_scope_vars(nesting);
|
||||
scope.parent_scope = save_scope;
|
||||
scope.is_block_scope = true;
|
||||
descend();
|
||||
scope = save_scope;
|
||||
return true;
|
||||
@@ -174,7 +178,11 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
// scope when we encounter the AST_Defun node (which is
|
||||
// instanceof AST_Scope) but we get to the symbol a bit
|
||||
// later.
|
||||
(node.scope = defun.parent_scope).def_function(node, in_export);
|
||||
var parent_lambda = defun.parent_scope;
|
||||
while (parent_lambda.is_block_scope) {
|
||||
parent_lambda = parent_lambda.parent_scope;
|
||||
}
|
||||
(node.scope = parent_lambda).def_function(node, in_export);
|
||||
}
|
||||
else if (node instanceof AST_SymbolClass) {
|
||||
defun.def_variable(node, in_export);
|
||||
@@ -188,8 +196,9 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
(node.scope = defun.parent_scope).def_function(node, in_export);
|
||||
}
|
||||
else if (node instanceof AST_SymbolVar
|
||||
|| node instanceof AST_SymbolConst) {
|
||||
var def = defun.def_variable(node, in_export);
|
||||
|| node instanceof AST_SymbolConst
|
||||
|| node instanceof AST_SymbolLet) {
|
||||
var def = ((node instanceof AST_SymbolBlockDeclaration) ? scope : defun).def_variable(node, in_export);
|
||||
def.constant = node instanceof AST_SymbolConst;
|
||||
def.destructuring = in_destructuring;
|
||||
def.init = tw.parent().value;
|
||||
@@ -279,6 +288,14 @@ AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){
|
||||
this.nesting = nesting; // the nesting level of this scope (0 means toplevel)
|
||||
});
|
||||
|
||||
AST_Block.DEFMETHOD("creates_block_scope", function() {
|
||||
return (
|
||||
!(this instanceof AST_Lambda) &&
|
||||
!(this instanceof AST_Toplevel) &&
|
||||
!(this instanceof AST_Class)
|
||||
);
|
||||
});
|
||||
|
||||
AST_Lambda.DEFMETHOD("init_scope_vars", function(){
|
||||
AST_Scope.prototype.init_scope_vars.apply(this, arguments);
|
||||
this.uses_arguments = false;
|
||||
@@ -312,17 +329,10 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol, in_export){
|
||||
def = new SymbolDef(this, this.variables.size(), symbol);
|
||||
this.variables.set(symbol.name, def);
|
||||
def.object_destructuring_arg = symbol.object_destructuring_arg;
|
||||
def.global = !this.parent_scope;
|
||||
if (symbol instanceof AST_SymbolImport) {
|
||||
// Imports are not global
|
||||
def.global = false;
|
||||
// TODO The real fix comes with block scoping being first class in uglifyJS,
|
||||
// enabling import definitions to behave like module-level let declarations
|
||||
}
|
||||
if (!this.parent_scope && in_export) {
|
||||
def.global = false;
|
||||
if (in_export) {
|
||||
def.export = true;
|
||||
}
|
||||
def.global = !this.parent_scope && !(symbol instanceof AST_SymbolBlockDeclaration);
|
||||
} else {
|
||||
def = this.variables.get(symbol.name);
|
||||
def.orig.push(symbol);
|
||||
@@ -466,7 +476,10 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
||||
node.mangled_name = name;
|
||||
return true;
|
||||
}
|
||||
if (options.screw_ie8 && node instanceof AST_SymbolCatch) {
|
||||
var mangle_with_block_scope =
|
||||
(options.screw_ie8 && node instanceof AST_SymbolCatch) ||
|
||||
node instanceof AST_SymbolBlockDeclaration;
|
||||
if (mangle_with_block_scope) {
|
||||
to_mangle.push(node.definition());
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user