uglify-js
Advanced tools
Comparing version 3.11.2 to 3.11.3
103
lib/ast.js
@@ -206,2 +206,6 @@ /*********************************************************************** | ||
var AST_EmptyStatement = DEFNODE("EmptyStatement", null, { | ||
$documentation: "The empty statement (empty block or simply a semicolon)" | ||
}, AST_Statement); | ||
function must_be_expression(node, prop) { | ||
@@ -230,31 +234,5 @@ if (!(node[prop] instanceof AST_Node)) throw new Error(prop + " must be AST_Node"); | ||
function walk_body(node, visitor) { | ||
node.body.forEach(function(node) { | ||
node.walk(visitor); | ||
}); | ||
} | ||
var AST_Block = DEFNODE("Block", "body", { | ||
$documentation: "A body of statements (usually braced)", | ||
$propdoc: { | ||
body: "[AST_Statement*] an array of statements" | ||
}, | ||
walk: function(visitor) { | ||
var node = this; | ||
visitor.visit(node, function() { | ||
walk_body(node, visitor); | ||
}); | ||
}, | ||
_validate: function() { | ||
this.body.forEach(function(node) { | ||
if (!(node instanceof AST_Statement)) throw new Error("body must be AST_Statement[]"); | ||
if (node instanceof AST_Function) throw new Error("body cannot contain AST_Function"); | ||
}); | ||
}, | ||
}, AST_Statement); | ||
var AST_BlockScope = DEFNODE("BlockScope", "cname enclosed functions make_def parent_scope variables", { | ||
var AST_BlockScope = DEFNODE("BlockScope", "enclosed functions make_def parent_scope variables", { | ||
$documentation: "Base class for all statements introducing a lexical scope", | ||
$propdoc: { | ||
cname: "[integer/S] current index for mangling variables (used internally by the mangler)", | ||
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes", | ||
@@ -283,12 +261,33 @@ functions: "[Object/S] like `variables`, but only lists function declarations", | ||
}, | ||
}, AST_Block); | ||
}, AST_Statement); | ||
function walk_body(node, visitor) { | ||
node.body.forEach(function(node) { | ||
node.walk(visitor); | ||
}); | ||
} | ||
var AST_Block = DEFNODE("Block", "body", { | ||
$documentation: "A body of statements (usually braced)", | ||
$propdoc: { | ||
body: "[AST_Statement*] an array of statements" | ||
}, | ||
walk: function(visitor) { | ||
var node = this; | ||
visitor.visit(node, function() { | ||
walk_body(node, visitor); | ||
}); | ||
}, | ||
_validate: function() { | ||
this.body.forEach(function(node) { | ||
if (!(node instanceof AST_Statement)) throw new Error("body must be AST_Statement[]"); | ||
if (node instanceof AST_Function) throw new Error("body cannot contain AST_Function"); | ||
}); | ||
}, | ||
}, AST_BlockScope); | ||
var AST_BlockStatement = DEFNODE("BlockStatement", null, { | ||
$documentation: "A block statement", | ||
}, AST_BlockScope); | ||
}, AST_Block); | ||
var AST_EmptyStatement = DEFNODE("EmptyStatement", null, { | ||
$documentation: "The empty statement (empty block or simply a semicolon)" | ||
}, AST_Statement); | ||
var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", { | ||
@@ -303,3 +302,3 @@ $documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`", | ||
}, | ||
}, AST_Statement); | ||
}, AST_BlockScope); | ||
@@ -458,3 +457,3 @@ var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", { | ||
resolve: return_this, | ||
}, AST_BlockScope); | ||
}, AST_Block); | ||
@@ -707,3 +706,3 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", { | ||
}, | ||
}, AST_BlockScope); | ||
}, AST_Block); | ||
@@ -727,7 +726,7 @@ var AST_Catch = DEFNODE("Catch", "argname", { | ||
}, | ||
}, AST_BlockScope); | ||
}, AST_Block); | ||
var AST_Finally = DEFNODE("Finally", null, { | ||
$documentation: "A `finally` node; only makes sense as part of a `try` statement" | ||
}, AST_BlockScope); | ||
}, AST_Block); | ||
@@ -748,5 +747,19 @@ /* -----[ VAR ]----- */ | ||
}); | ||
} | ||
}, | ||
_validate: function() { | ||
if (this.definitions.length < 1) throw new Error("must have at least one definition"); | ||
}, | ||
}, AST_Statement); | ||
var AST_Const = DEFNODE("Const", null, { | ||
$documentation: "A `const` statement", | ||
_validate: function() { | ||
this.definitions.forEach(function(node) { | ||
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]"); | ||
if (!(node.name instanceof AST_SymbolConst)) throw new Error("name must be AST_SymbolConst"); | ||
must_be_expression(node, "value"); | ||
}); | ||
}, | ||
}, AST_Definitions); | ||
var AST_Var = DEFNODE("Var", null, { | ||
@@ -757,2 +770,4 @@ $documentation: "A `var` statement", | ||
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]"); | ||
if (!(node.name instanceof AST_SymbolVar)) throw new Error("name must be AST_SymbolVar"); | ||
if (node.value != null) must_be_expression(node, "value"); | ||
}); | ||
@@ -775,6 +790,2 @@ }, | ||
}, | ||
_validate: function() { | ||
if (!(this.name instanceof AST_SymbolVar)) throw new Error("name must be AST_SymbolVar"); | ||
if (this.value != null) must_be_expression(this, "value"); | ||
}, | ||
}); | ||
@@ -1045,2 +1056,3 @@ | ||
var AST_Symbol = DEFNODE("Symbol", "scope name thedef", { | ||
$documentation: "Base class for all symbols", | ||
$propdoc: { | ||
@@ -1051,3 +1063,2 @@ name: "[string] name of this symbol", | ||
}, | ||
$documentation: "Base class for all symbols", | ||
_validate: function() { | ||
@@ -1066,2 +1077,6 @@ if (typeof this.name != "string") throw new Error("name must be string"); | ||
var AST_SymbolConst = DEFNODE("SymbolConst", null, { | ||
$documentation: "Symbol defining a constant", | ||
}, AST_SymbolDeclaration); | ||
var AST_SymbolVar = DEFNODE("SymbolVar", null, { | ||
@@ -1068,0 +1083,0 @@ $documentation: "Symbol defining a variable", |
@@ -838,6 +838,2 @@ /*********************************************************************** | ||
AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output) { | ||
force_statement(this.body, output); | ||
}); | ||
DEFPRINT(AST_Statement, function(output) { | ||
@@ -901,3 +897,3 @@ this.body.print(output); | ||
output.space(); | ||
self._do_print_body(output); | ||
force_statement(self.body, output); | ||
}); | ||
@@ -932,3 +928,3 @@ DEFPRINT(AST_For, function(output) { | ||
output.space(); | ||
self._do_print_body(output); | ||
force_statement(self.body, output); | ||
}); | ||
@@ -947,3 +943,3 @@ DEFPRINT(AST_ForIn, function(output) { | ||
output.space(); | ||
self._do_print_body(output); | ||
force_statement(self.body, output); | ||
}); | ||
@@ -958,3 +954,3 @@ DEFPRINT(AST_With, function(output) { | ||
output.space(); | ||
self._do_print_body(output); | ||
force_statement(self.body, output); | ||
}); | ||
@@ -1002,3 +998,3 @@ | ||
var b = self.body; | ||
if (output.option("braces") | ||
if (output.option("braces") && !(b instanceof AST_Const) | ||
|| output.option("ie8") && b instanceof AST_Do) | ||
@@ -1045,3 +1041,3 @@ return make_block(b, output); | ||
} else { | ||
self._do_print_body(output); | ||
force_statement(self.body, output); | ||
} | ||
@@ -1124,13 +1120,17 @@ }); | ||
DEFPRINT(AST_Var, function(output) { | ||
var self = this; | ||
output.print("var"); | ||
output.space(); | ||
self.definitions.forEach(function(def, i) { | ||
if (i) output.comma(); | ||
def.print(output); | ||
}); | ||
var p = output.parent(); | ||
if (p && p.init !== self || !(p instanceof AST_For || p instanceof AST_ForIn)) output.semicolon(); | ||
}); | ||
function print_definitinos(type) { | ||
return function(output) { | ||
var self = this; | ||
output.print(type); | ||
output.space(); | ||
self.definitions.forEach(function(def, i) { | ||
if (i) output.comma(); | ||
def.print(output); | ||
}); | ||
var p = output.parent(); | ||
if (p && p.init !== self || !(p instanceof AST_For || p instanceof AST_ForIn)) output.semicolon(); | ||
}; | ||
} | ||
DEFPRINT(AST_Const, print_definitinos("const")); | ||
DEFPRINT(AST_Var, print_definitinos("var")); | ||
@@ -1392,9 +1392,8 @@ function parenthesize_for_noin(node, output, noin) { | ||
function force_statement(stat, output) { | ||
if (output.option("braces")) { | ||
if (output.option("braces") && !(stat instanceof AST_Const)) { | ||
make_block(stat, output); | ||
} else if (!stat || stat instanceof AST_EmptyStatement) { | ||
output.force_semicolon(); | ||
} else { | ||
if (!stat || stat instanceof AST_EmptyStatement) | ||
output.force_semicolon(); | ||
else | ||
stat.print(output); | ||
stat.print(output); | ||
} | ||
@@ -1401,0 +1400,0 @@ } |
@@ -835,2 +835,8 @@ /*********************************************************************** | ||
case "const": | ||
next(); | ||
var node = const_(); | ||
semicolon(); | ||
return node; | ||
case "continue": | ||
@@ -992,3 +998,5 @@ next(); | ||
if (!is("punc", ";")) { | ||
init = is("keyword", "var") | ||
init = is("keyword", "const") | ||
? (next(), const_(true)) | ||
: is("keyword", "var") | ||
? (next(), var_(true)) | ||
@@ -1166,9 +1174,18 @@ : expression(true, true); | ||
function vardefs(no_in) { | ||
function vardefs(type, no_in, must_init) { | ||
var a = []; | ||
for (;;) { | ||
var start = S.token; | ||
var name = as_symbol(type); | ||
var value = null; | ||
if (is("operator", "=")) { | ||
next(); | ||
value = expression(false, no_in); | ||
} else if (must_init) { | ||
croak("Missing initializer in declaration"); | ||
} | ||
a.push(new AST_VarDef({ | ||
start : S.token, | ||
name : as_symbol(AST_SymbolVar), | ||
value : is("operator", "=") ? (next(), expression(false, no_in)) : null, | ||
start : start, | ||
name : name, | ||
value : value, | ||
end : prev() | ||
@@ -1183,6 +1200,14 @@ })); | ||
var const_ = function(no_in) { | ||
return new AST_Const({ | ||
start : prev(), | ||
definitions : vardefs(AST_SymbolConst, no_in, true), | ||
end : prev() | ||
}); | ||
}; | ||
var var_ = function(no_in) { | ||
return new AST_Var({ | ||
start : prev(), | ||
definitions : vardefs(no_in), | ||
definitions : vardefs(AST_SymbolVar, no_in), | ||
end : prev() | ||
@@ -1189,0 +1214,0 @@ }); |
@@ -71,4 +71,4 @@ /*********************************************************************** | ||
} else if (!this.mangled_name && !this.unmangleable(options)) { | ||
var def; | ||
if (def = this.redefined()) { | ||
var def = this.redefined(); | ||
if (def) { | ||
this.mangled_name = def.mangled_name || def.name; | ||
@@ -84,3 +84,11 @@ } else { | ||
redefined: function() { | ||
return this.defun && this.defun.variables.get(this.name); | ||
var scope = this.defun; | ||
if (!scope) return; | ||
var name = this.name; | ||
var def = scope.variables.get(name) | ||
|| scope instanceof AST_Toplevel && scope.globals.get(name) | ||
|| this.orig[0] instanceof AST_SymbolConst && find_if(function(def) { | ||
return def.name == name; | ||
}, scope.enclosed); | ||
if (def && def !== this) return def.redefined() || def; | ||
}, | ||
@@ -119,2 +127,7 @@ unmangleable: function(options) { | ||
} | ||
if (node instanceof AST_SwitchBranch) { | ||
node.init_vars(scope); | ||
descend(); | ||
return true; | ||
} | ||
if (node instanceof AST_Try) { | ||
@@ -128,6 +141,2 @@ walk_scope(function() { | ||
} | ||
if (node instanceof AST_BlockScope) { | ||
walk_scope(descend); | ||
return true; | ||
} | ||
if (node instanceof AST_With) { | ||
@@ -140,4 +149,9 @@ var s = scope; | ||
} while (s = s.parent_scope); | ||
return; | ||
walk_scope(descend); | ||
return true; | ||
} | ||
if (node instanceof AST_BlockScope) { | ||
walk_scope(descend); | ||
return true; | ||
} | ||
if (node instanceof AST_Symbol) { | ||
@@ -152,2 +166,4 @@ node.scope = scope; | ||
scope.def_variable(node).defun = defun; | ||
} else if (node instanceof AST_SymbolConst) { | ||
scope.def_variable(node).defun = defun; | ||
} else if (node instanceof AST_SymbolDefun) { | ||
@@ -225,3 +241,3 @@ defun.def_function(node, tw.parent()); | ||
} | ||
// ensure mangling works if catch reuses a scope variable | ||
// ensure mangling works if `catch` reuses a scope variable | ||
if (node instanceof AST_SymbolCatch) { | ||
@@ -235,2 +251,8 @@ var def = node.definition().redefined(); | ||
} | ||
// ensure compression works if `const` reuses a scope variable | ||
if (node instanceof AST_SymbolConst) { | ||
var redef = node.definition().redefined(); | ||
if (redef) redef.const_redefs = true; | ||
return true; | ||
} | ||
}); | ||
@@ -266,4 +288,4 @@ self.walk(tw); | ||
if (new_def) { | ||
var redef; | ||
while (redef = new_def.redefined()) new_def = redef; | ||
var redef = new_def.redefined(); | ||
if (redef) new_def = redef; | ||
} else { | ||
@@ -302,3 +324,2 @@ new_def = self.globals.get(name); | ||
function init_block_vars(scope, parent) { | ||
scope.cname = -1; // the current index for mangling functions/variables | ||
scope.enclosed = []; // variables from this or outer scope(s) that are referenced from this or inner scopes | ||
@@ -381,4 +402,5 @@ scope.parent_scope = parent; // the parent scope (null if this is the top level) | ||
if (!names) { | ||
scope.cname = -1; | ||
scope.cname_holes = []; | ||
scope.names_in_use = names = Object.create(null); | ||
scope.cname_holes = []; | ||
var cache = options.cache && options.cache.props; | ||
@@ -481,3 +503,7 @@ scope.enclosed.forEach(function(def) { | ||
} | ||
if (node instanceof AST_Scope) { | ||
if (node instanceof AST_BlockScope) { | ||
var to_mangle = []; | ||
node.variables.each(function(def) { | ||
if (!defer_redef(def)) to_mangle.push(def); | ||
}); | ||
descend(); | ||
@@ -492,5 +518,3 @@ if (options.cache && node instanceof AST_Toplevel) { | ||
} | ||
node.variables.each(function(def) { | ||
if (!defer_redef(def)) mangle(def); | ||
}); | ||
to_mangle.forEach(mangle); | ||
return true; | ||
@@ -506,9 +530,2 @@ } | ||
} | ||
if (!options.ie8 && node instanceof AST_Catch && node.argname) { | ||
var def = node.argname.definition(); | ||
var redef = defer_redef(def, node.argname); | ||
descend(); | ||
if (!redef) mangle(def); | ||
return true; | ||
} | ||
}); | ||
@@ -528,3 +545,4 @@ this.walk(tw); | ||
def.references.forEach(reference); | ||
if (node) reference(node); | ||
var node = def.orig[0]; | ||
if (node instanceof AST_SymbolCatch || node instanceof AST_SymbolConst) reference(node); | ||
return true; | ||
@@ -531,0 +549,0 @@ |
@@ -6,3 +6,3 @@ { | ||
"license": "BSD-2-Clause", | ||
"version": "3.11.2", | ||
"version": "3.11.3", | ||
"engines": { | ||
@@ -9,0 +9,0 @@ "node": ">=0.8.0" |
Sorry, the diff of this file is too big to display
918538
23848