Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f67866147 | ||
|
|
645d5a348b | ||
|
|
cf120c7cea | ||
|
|
8d30902ba9 | ||
|
|
02459cddf9 | ||
|
|
1b579779be | ||
|
|
b18b70f63b | ||
|
|
641406d491 | ||
|
|
134ef0b1eb | ||
|
|
db87dcf13e | ||
|
|
aecbabc587 | ||
|
|
fd6544b340 | ||
|
|
f6a83f7944 | ||
|
|
35283e5dd1 | ||
|
|
7a51c17ff0 | ||
|
|
aff842f2f9 | ||
|
|
0bedd031da | ||
|
|
caa92aea5d | ||
|
|
383163afa6 | ||
|
|
8a83c8dd46 | ||
|
|
2a612fd472 | ||
|
|
b9798a01a8 | ||
|
|
6dbacb5e3f | ||
|
|
e5f80afc53 | ||
|
|
42e34c870a |
22
README.md
22
README.md
@@ -135,6 +135,10 @@ a double dash to prevent input files being used as option arguments:
|
|||||||
--toplevel Compress and/or mangle variables in top level scope.
|
--toplevel Compress and/or mangle variables in top level scope.
|
||||||
--verbose Print diagnostic messages.
|
--verbose Print diagnostic messages.
|
||||||
--warn Print warning messages.
|
--warn Print warning messages.
|
||||||
|
--webkit Support non-standard Safari/Webkit.
|
||||||
|
Equivalent to setting `webkit: true` in `minify()`
|
||||||
|
for `mangle` and `output` options.
|
||||||
|
By default UglifyJS will not try to be Safari-proof.
|
||||||
--wrap <name> Embed everything in a big function, making the
|
--wrap <name> Embed everything in a big function, making the
|
||||||
“exports” and “global” variables available. You
|
“exports” and “global” variables available. You
|
||||||
need to pass an argument to this option to
|
need to pass an argument to this option to
|
||||||
@@ -519,6 +523,9 @@ if (result.error) throw result.error;
|
|||||||
- `warnings` (default `false`) — pass `true` to return compressor warnings
|
- `warnings` (default `false`) — pass `true` to return compressor warnings
|
||||||
in `result.warnings`. Use the value `"verbose"` for more detailed warnings.
|
in `result.warnings`. Use the value `"verbose"` for more detailed warnings.
|
||||||
|
|
||||||
|
- `webkit` (default `false`) -- enable workarounds for Safari/WebKit bugs.
|
||||||
|
PhantomJS users should set this option to `true`.
|
||||||
|
|
||||||
## Minify options structure
|
## Minify options structure
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
@@ -868,6 +875,8 @@ can pass additional arguments that control the code output:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- `galio` (default `false`) -- enable workarounds for ANT Galio bugs
|
||||||
|
|
||||||
- `indent_level` (default `4`)
|
- `indent_level` (default `4`)
|
||||||
|
|
||||||
- `indent_start` (default `0`) -- prefix all lines by that many spaces
|
- `indent_start` (default `0`) -- prefix all lines by that many spaces
|
||||||
@@ -906,8 +915,7 @@ can pass additional arguments that control the code output:
|
|||||||
|
|
||||||
- `shebang` (default `true`) -- preserve shebang `#!` in preamble (bash scripts)
|
- `shebang` (default `true`) -- preserve shebang `#!` in preamble (bash scripts)
|
||||||
|
|
||||||
- `webkit` (default `false`) -- enable workarounds for WebKit bugs.
|
- `v8` (default `false`) -- enable workarounds for Chrome & Node.js bugs
|
||||||
PhantomJS users should set this option to `true`.
|
|
||||||
|
|
||||||
- `width` (default `80`) -- only takes effect when beautification is on, this
|
- `width` (default `80`) -- only takes effect when beautification is on, this
|
||||||
specifies an (orientative) line width that the beautifier will try to
|
specifies an (orientative) line width that the beautifier will try to
|
||||||
@@ -1138,7 +1146,7 @@ To enable fast minify mode with the API use:
|
|||||||
UglifyJS.minify(code, { compress: false, mangle: true });
|
UglifyJS.minify(code, { compress: false, mangle: true });
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Source maps and debugging
|
### Source maps and debugging
|
||||||
|
|
||||||
Various `compress` transforms that simplify, rearrange, inline and remove code
|
Various `compress` transforms that simplify, rearrange, inline and remove code
|
||||||
are known to have an adverse effect on debugging with source maps. This is
|
are known to have an adverse effect on debugging with source maps. This is
|
||||||
@@ -1150,6 +1158,10 @@ disable the Uglify `compress` option and just use `mangle`.
|
|||||||
|
|
||||||
To allow for better optimizations, the compiler makes various assumptions:
|
To allow for better optimizations, the compiler makes various assumptions:
|
||||||
|
|
||||||
|
- The code does not rely on preserving its runtime performance characteristics.
|
||||||
|
Typically uglified code will run faster due to less instructions and easier
|
||||||
|
inlining, but may be slower on rare occasions for a specific platform, e.g.
|
||||||
|
see [`reduce_funcs`](#compress-options).
|
||||||
- `.toString()` and `.valueOf()` don't have side effects, and for built-in
|
- `.toString()` and `.valueOf()` don't have side effects, and for built-in
|
||||||
objects they have not been overridden.
|
objects they have not been overridden.
|
||||||
- `undefined`, `NaN` and `Infinity` have not been externally redefined.
|
- `undefined`, `NaN` and `Infinity` have not been externally redefined.
|
||||||
@@ -1177,3 +1189,7 @@ To allow for better optimizations, the compiler makes various assumptions:
|
|||||||
top.B = "PASS";
|
top.B = "PASS";
|
||||||
console.log(B);
|
console.log(B);
|
||||||
```
|
```
|
||||||
|
- Use of `arguments` alongside destructuring as function parameters, e.g.
|
||||||
|
`function({}, arguments) {}` will result in `SyntaxError` in earlier versions
|
||||||
|
of Chrome and Node.js - UglifyJS may modify the input which in turn may
|
||||||
|
suppress those errors.
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ function process_option(name, no_value) {
|
|||||||
" --validate Perform validation during AST manipulations.",
|
" --validate Perform validation during AST manipulations.",
|
||||||
" --verbose Print diagnostic messages.",
|
" --verbose Print diagnostic messages.",
|
||||||
" --warn Print warning messages.",
|
" --warn Print warning messages.",
|
||||||
|
" --webkit Support non-standard Safari/Webkit.",
|
||||||
" --wrap <name> Embed everything as a function with “exports” corresponding to “name” globally.",
|
" --wrap <name> Embed everything as a function with “exports” corresponding to “name” globally.",
|
||||||
" --reduce-test Reduce a standalone test case (assumes cloned repository).",
|
" --reduce-test Reduce a standalone test case (assumes cloned repository).",
|
||||||
].join("\n"));
|
].join("\n"));
|
||||||
@@ -142,6 +143,7 @@ function process_option(name, no_value) {
|
|||||||
case "timings":
|
case "timings":
|
||||||
case "toplevel":
|
case "toplevel":
|
||||||
case "validate":
|
case "validate":
|
||||||
|
case "webkit":
|
||||||
options[name] = true;
|
options[name] = true;
|
||||||
break;
|
break;
|
||||||
case "keep-fnames":
|
case "keep-fnames":
|
||||||
|
|||||||
123
lib/ast.js
123
lib/ast.js
@@ -414,8 +414,12 @@ var AST_ForIn = DEFNODE("ForIn", "init object", {
|
|||||||
_validate: function() {
|
_validate: function() {
|
||||||
if (this.init instanceof AST_Definitions) {
|
if (this.init instanceof AST_Definitions) {
|
||||||
if (this.init.definitions.length != 1) throw new Error("init must have single declaration");
|
if (this.init.definitions.length != 1) throw new Error("init must have single declaration");
|
||||||
} else if (!(this.init instanceof AST_PropAccess || this.init instanceof AST_SymbolRef)) {
|
} else {
|
||||||
throw new Error("init must be assignable");
|
validate_destructured(this.init, function(node) {
|
||||||
|
if (!(node instanceof AST_PropAccess || node instanceof AST_SymbolRef)) {
|
||||||
|
throw new Error("init must be assignable: " + node.TYPE);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
must_be_expression(this, "object");
|
must_be_expression(this, "object");
|
||||||
},
|
},
|
||||||
@@ -496,12 +500,24 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
|||||||
}
|
}
|
||||||
}, AST_Scope);
|
}, AST_Scope);
|
||||||
|
|
||||||
var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments length_read", {
|
var AST_Lambda = DEFNODE("Lambda", "name argnames length_read uses_arguments", {
|
||||||
$documentation: "Base class for functions",
|
$documentation: "Base class for functions",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
name: "[AST_SymbolDeclaration?] the name of this function",
|
name: "[AST_SymbolDeclaration?] the name of this function",
|
||||||
argnames: "[AST_SymbolFunarg*] array of function arguments",
|
argnames: "[(AST_Destructured|AST_SymbolFunarg)*] array of function arguments and/or destructured literals",
|
||||||
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array"
|
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array",
|
||||||
|
},
|
||||||
|
each_argname: function(visit) {
|
||||||
|
var tw = new TreeWalker(function(node) {
|
||||||
|
if (node instanceof AST_DestructuredKeyVal) {
|
||||||
|
node.value.walk(tw);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_SymbolFunarg) visit(node);
|
||||||
|
});
|
||||||
|
this.argnames.forEach(function(argname) {
|
||||||
|
argname.walk(tw);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
walk: function(visitor) {
|
walk: function(visitor) {
|
||||||
var node = this;
|
var node = this;
|
||||||
@@ -515,7 +531,9 @@ var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments length_read", {
|
|||||||
},
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
this.argnames.forEach(function(node) {
|
this.argnames.forEach(function(node) {
|
||||||
if (!(node instanceof AST_SymbolFunarg)) throw new Error("argnames must be AST_SymbolFunarg[]");
|
validate_destructured(node, function(node) {
|
||||||
|
if (!(node instanceof AST_SymbolFunarg)) throw new Error("argnames must be AST_SymbolFunarg[]");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}, AST_Scope);
|
}, AST_Scope);
|
||||||
@@ -748,8 +766,10 @@ var AST_Const = DEFNODE("Const", null, {
|
|||||||
_validate: function() {
|
_validate: function() {
|
||||||
this.definitions.forEach(function(node) {
|
this.definitions.forEach(function(node) {
|
||||||
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
|
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");
|
validate_destructured(node.name, function(node) {
|
||||||
must_be_expression(node, "value");
|
if (!(node instanceof AST_SymbolConst)) throw new Error("name must be AST_SymbolConst");
|
||||||
|
});
|
||||||
|
if (node.value != null) must_be_expression(node, "value");
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}, AST_Definitions);
|
}, AST_Definitions);
|
||||||
@@ -759,7 +779,9 @@ var AST_Let = DEFNODE("Let", null, {
|
|||||||
_validate: function() {
|
_validate: function() {
|
||||||
this.definitions.forEach(function(node) {
|
this.definitions.forEach(function(node) {
|
||||||
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
|
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
|
||||||
if (!(node.name instanceof AST_SymbolLet)) throw new Error("name must be AST_SymbolLet");
|
validate_destructured(node.name, function(node) {
|
||||||
|
if (!(node instanceof AST_SymbolLet)) throw new Error("name must be AST_SymbolLet");
|
||||||
|
});
|
||||||
if (node.value != null) must_be_expression(node, "value");
|
if (node.value != null) must_be_expression(node, "value");
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -770,7 +792,9 @@ var AST_Var = DEFNODE("Var", null, {
|
|||||||
_validate: function() {
|
_validate: function() {
|
||||||
this.definitions.forEach(function(node) {
|
this.definitions.forEach(function(node) {
|
||||||
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
|
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");
|
validate_destructured(node.name, function(node) {
|
||||||
|
if (!(node instanceof AST_SymbolVar)) throw new Error("name must be AST_SymbolVar");
|
||||||
|
});
|
||||||
if (node.value != null) must_be_expression(node, "value");
|
if (node.value != null) must_be_expression(node, "value");
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -969,6 +993,14 @@ var AST_Assign = DEFNODE("Assign", null, {
|
|||||||
$documentation: "An assignment expression — `a = b + 5`",
|
$documentation: "An assignment expression — `a = b + 5`",
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
if (this.operator.indexOf("=") < 0) throw new Error('operator must contain "="');
|
if (this.operator.indexOf("=") < 0) throw new Error('operator must contain "="');
|
||||||
|
if (this.left instanceof AST_Destructured) {
|
||||||
|
if (this.operator != "=") throw new Error("invalid destructuring operator: " + this.operator);
|
||||||
|
validate_destructured(this.left, function(node) {
|
||||||
|
if (!(node instanceof AST_PropAccess || node instanceof AST_SymbolRef)) {
|
||||||
|
throw new Error("left must be assignable: " + node.TYPE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}, AST_Binary);
|
}, AST_Binary);
|
||||||
|
|
||||||
@@ -992,6 +1024,77 @@ var AST_Array = DEFNODE("Array", "elements", {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var AST_Destructured = DEFNODE("Destructured", null, {
|
||||||
|
$documentation: "Base class for destructured literal",
|
||||||
|
});
|
||||||
|
|
||||||
|
function validate_destructured(node, check) {
|
||||||
|
if (node instanceof AST_DestructuredArray) return node.elements.forEach(function(node) {
|
||||||
|
if (!(node instanceof AST_Hole)) validate_destructured(node, check);
|
||||||
|
});
|
||||||
|
if (node instanceof AST_DestructuredObject) return node.properties.forEach(function(prop) {
|
||||||
|
validate_destructured(prop.value, check);
|
||||||
|
});
|
||||||
|
check(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
var AST_DestructuredArray = DEFNODE("DestructuredArray", "elements", {
|
||||||
|
$documentation: "A destructured array literal",
|
||||||
|
$propdoc: {
|
||||||
|
elements: "[AST_Node*] array of elements",
|
||||||
|
},
|
||||||
|
walk: function(visitor) {
|
||||||
|
var node = this;
|
||||||
|
visitor.visit(node, function() {
|
||||||
|
node.elements.forEach(function(element) {
|
||||||
|
element.walk(visitor);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}, AST_Destructured);
|
||||||
|
|
||||||
|
var AST_DestructuredKeyVal = DEFNODE("DestructuredKeyVal", "key value", {
|
||||||
|
$documentation: "A key: value destructured property",
|
||||||
|
$propdoc: {
|
||||||
|
key: "[string|AST_Node] property name. For computed property this is an AST_Node.",
|
||||||
|
value: "[AST_Node] property value",
|
||||||
|
},
|
||||||
|
walk: function(visitor) {
|
||||||
|
var node = this;
|
||||||
|
visitor.visit(node, function() {
|
||||||
|
if (node.key instanceof AST_Node) node.key.walk(visitor);
|
||||||
|
node.value.walk(visitor);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_validate: function() {
|
||||||
|
if (typeof this.key != "string") {
|
||||||
|
if (!(this.key instanceof AST_Node)) throw new Error("key must be string or AST_Node");
|
||||||
|
must_be_expression(this, "key");
|
||||||
|
}
|
||||||
|
must_be_expression(this, "value");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
var AST_DestructuredObject = DEFNODE("DestructuredObject", "properties", {
|
||||||
|
$documentation: "A destructured object literal",
|
||||||
|
$propdoc: {
|
||||||
|
properties: "[AST_DestructuredKeyVal*] array of properties",
|
||||||
|
},
|
||||||
|
walk: function(visitor) {
|
||||||
|
var node = this;
|
||||||
|
visitor.visit(node, function() {
|
||||||
|
node.properties.forEach(function(prop) {
|
||||||
|
prop.walk(visitor);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_validate: function() {
|
||||||
|
this.properties.forEach(function(node) {
|
||||||
|
if (!(node instanceof AST_DestructuredKeyVal)) throw new Error("properties must be AST_DestructuredKeyVal[]");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}, AST_Destructured);
|
||||||
|
|
||||||
var AST_Object = DEFNODE("Object", "properties", {
|
var AST_Object = DEFNODE("Object", "properties", {
|
||||||
$documentation: "An object literal",
|
$documentation: "An object literal",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
|
|||||||
1034
lib/compress.js
1034
lib/compress.js
File diff suppressed because it is too large
Load Diff
@@ -89,6 +89,7 @@ function minify(files, options) {
|
|||||||
toplevel: false,
|
toplevel: false,
|
||||||
validate: false,
|
validate: false,
|
||||||
warnings: false,
|
warnings: false,
|
||||||
|
webkit: false,
|
||||||
wrap: false,
|
wrap: false,
|
||||||
}, true);
|
}, true);
|
||||||
if (options.validate) AST_Node.enable_validation();
|
if (options.validate) AST_Node.enable_validation();
|
||||||
@@ -101,6 +102,7 @@ function minify(files, options) {
|
|||||||
set_shorthand("ie8", options, [ "compress", "mangle", "output" ]);
|
set_shorthand("ie8", options, [ "compress", "mangle", "output" ]);
|
||||||
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
|
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
|
||||||
set_shorthand("toplevel", options, [ "compress", "mangle" ]);
|
set_shorthand("toplevel", options, [ "compress", "mangle" ]);
|
||||||
|
set_shorthand("webkit", options, [ "mangle", "output" ]);
|
||||||
var quoted_props;
|
var quoted_props;
|
||||||
if (options.mangle) {
|
if (options.mangle) {
|
||||||
options.mangle = defaults(options.mangle, {
|
options.mangle = defaults(options.mangle, {
|
||||||
@@ -111,6 +113,7 @@ function minify(files, options) {
|
|||||||
properties: false,
|
properties: false,
|
||||||
reserved: [],
|
reserved: [],
|
||||||
toplevel: false,
|
toplevel: false,
|
||||||
|
webkit: false,
|
||||||
}, true);
|
}, true);
|
||||||
if (options.mangle.properties) {
|
if (options.mangle.properties) {
|
||||||
if (typeof options.mangle.properties != "object") {
|
if (typeof options.mangle.properties != "object") {
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ function OutputStream(options) {
|
|||||||
beautify : false,
|
beautify : false,
|
||||||
braces : false,
|
braces : false,
|
||||||
comments : false,
|
comments : false,
|
||||||
|
galio : false,
|
||||||
ie8 : false,
|
ie8 : false,
|
||||||
indent_level : 4,
|
indent_level : 4,
|
||||||
indent_start : 0,
|
indent_start : 0,
|
||||||
@@ -69,6 +70,7 @@ function OutputStream(options) {
|
|||||||
semicolons : true,
|
semicolons : true,
|
||||||
shebang : true,
|
shebang : true,
|
||||||
source_map : null,
|
source_map : null,
|
||||||
|
v8 : false,
|
||||||
webkit : false,
|
webkit : false,
|
||||||
width : 80,
|
width : 80,
|
||||||
wrap_iife : false,
|
wrap_iife : false,
|
||||||
@@ -499,11 +501,11 @@ function OutputStream(options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (/comment[134]/.test(c.type)) {
|
if (/comment[134]/.test(c.type)) {
|
||||||
print("//" + c.value.replace(/[@#]__PURE__/g, ' ') + "\n");
|
print("//" + c.value.replace(/[@#]__PURE__/g, " ") + "\n");
|
||||||
indent();
|
indent();
|
||||||
last_nlb = true;
|
last_nlb = true;
|
||||||
} else if (c.type == "comment2") {
|
} else if (c.type == "comment2") {
|
||||||
print("/*" + c.value.replace(/[@#]__PURE__/g, ' ') + "*/");
|
print("/*" + c.value.replace(/[@#]__PURE__/g, " ") + "*/");
|
||||||
last_nlb = false;
|
last_nlb = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -557,10 +559,10 @@ function OutputStream(options) {
|
|||||||
space();
|
space();
|
||||||
}
|
}
|
||||||
if (/comment[134]/.test(c.type)) {
|
if (/comment[134]/.test(c.type)) {
|
||||||
print("//" + c.value.replace(/[@#]__PURE__/g, ' '));
|
print("//" + c.value.replace(/[@#]__PURE__/g, " "));
|
||||||
need_newline_indented = true;
|
need_newline_indented = true;
|
||||||
} else if (c.type == "comment2") {
|
} else if (c.type == "comment2") {
|
||||||
print("/*" + c.value.replace(/[@#]__PURE__/g, ' ') + "*/");
|
print("/*" + c.value.replace(/[@#]__PURE__/g, " ") + "*/");
|
||||||
need_space = true;
|
need_space = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -610,7 +612,7 @@ function OutputStream(options) {
|
|||||||
},
|
},
|
||||||
parent : function(n) {
|
parent : function(n) {
|
||||||
return stack[stack.length - 2 - (n || 0)];
|
return stack[stack.length - 2 - (n || 0)];
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -652,13 +654,7 @@ function OutputStream(options) {
|
|||||||
/* -----[ PARENTHESES ]----- */
|
/* -----[ PARENTHESES ]----- */
|
||||||
|
|
||||||
function PARENS(nodetype, func) {
|
function PARENS(nodetype, func) {
|
||||||
if (Array.isArray(nodetype)) {
|
nodetype.DEFMETHOD("needs_parens", func);
|
||||||
nodetype.forEach(function(nodetype) {
|
|
||||||
PARENS(nodetype, func);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
nodetype.DEFMETHOD("needs_parens", func);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PARENS(AST_Node, return_false);
|
PARENS(AST_Node, return_false);
|
||||||
@@ -667,11 +663,11 @@ function OutputStream(options) {
|
|||||||
// the first token to appear in a statement.
|
// the first token to appear in a statement.
|
||||||
PARENS(AST_Function, function(output) {
|
PARENS(AST_Function, function(output) {
|
||||||
if (!output.has_parens() && first_in_statement(output)) return true;
|
if (!output.has_parens() && first_in_statement(output)) return true;
|
||||||
if (output.option('webkit')) {
|
if (output.option("webkit")) {
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
if (p instanceof AST_PropAccess && p.expression === this) return true;
|
if (p instanceof AST_PropAccess && p.expression === this) return true;
|
||||||
}
|
}
|
||||||
if (output.option('wrap_iife')) {
|
if (output.option("wrap_iife")) {
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
if (p instanceof AST_Call && p.expression === this) return true;
|
if (p instanceof AST_Call && p.expression === this) return true;
|
||||||
}
|
}
|
||||||
@@ -679,9 +675,10 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
// same goes for an object literal, because otherwise it would be
|
// same goes for an object literal, because otherwise it would be
|
||||||
// interpreted as a block of code.
|
// interpreted as a block of code.
|
||||||
PARENS(AST_Object, function(output) {
|
function needs_parens_obj(output) {
|
||||||
return !output.has_parens() && first_in_statement(output);
|
return !output.has_parens() && first_in_statement(output);
|
||||||
});
|
}
|
||||||
|
PARENS(AST_Object, needs_parens_obj);
|
||||||
|
|
||||||
PARENS(AST_Unary, function(output) {
|
PARENS(AST_Unary, function(output) {
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
@@ -701,6 +698,7 @@ function OutputStream(options) {
|
|||||||
|| p instanceof AST_Conditional
|
|| p instanceof AST_Conditional
|
||||||
// { [(1, 2)]: 3 }[2] ==> 3
|
// { [(1, 2)]: 3 }[2] ==> 3
|
||||||
// { foo: (1, 2) }.foo ==> 2
|
// { foo: (1, 2) }.foo ==> 2
|
||||||
|
|| p instanceof AST_DestructuredKeyVal
|
||||||
|| p instanceof AST_ObjectProperty
|
|| p instanceof AST_ObjectProperty
|
||||||
// (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|
// (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|
||||||
|| p instanceof AST_PropAccess && p.expression === this
|
|| p instanceof AST_PropAccess && p.expression === this
|
||||||
@@ -747,7 +745,7 @@ function OutputStream(options) {
|
|||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
if (p instanceof AST_New) return p.expression === this;
|
if (p instanceof AST_New) return p.expression === this;
|
||||||
// https://bugs.webkit.org/show_bug.cgi?id=123506
|
// https://bugs.webkit.org/show_bug.cgi?id=123506
|
||||||
if (output.option('webkit')) {
|
if (output.option("webkit")) {
|
||||||
var g = output.parent(1);
|
var g = output.parent(1);
|
||||||
return this.expression instanceof AST_Function
|
return this.expression instanceof AST_Function
|
||||||
&& p instanceof AST_PropAccess
|
&& p instanceof AST_PropAccess
|
||||||
@@ -770,24 +768,36 @@ function OutputStream(options) {
|
|||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
if (p instanceof AST_PropAccess && p.expression === this) {
|
if (p instanceof AST_PropAccess && p.expression === this) {
|
||||||
var value = this.value;
|
var value = this.value;
|
||||||
// https://github.com/mishoo/UglifyJS/issues/115
|
// https://github.com/mishoo/UglifyJS/issues/115
|
||||||
// https://github.com/mishoo/UglifyJS/pull/1009
|
return value < 0
|
||||||
return value < 0 || /^0/.test(make_num(value));
|
// https://github.com/mishoo/UglifyJS/pull/1009
|
||||||
|
|| output.option("galio") && /^0/.test(make_num(value));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
PARENS([ AST_Assign, AST_Conditional ], function(output) {
|
function needs_parens_assign_cond(self, output) {
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
// 1 + (a = 2) + 3 → 6, side effect setting a = 2
|
// 1 + (a = 2) + 3 → 6, side effect setting a = 2
|
||||||
if (p instanceof AST_Binary) return !(p instanceof AST_Assign);
|
if (p instanceof AST_Binary) return !(p instanceof AST_Assign);
|
||||||
// (a = func)() —or— new (a = Object)()
|
// (a = func)() —or— new (a = Object)()
|
||||||
if (p instanceof AST_Call) return p.expression === this;
|
if (p instanceof AST_Call) return p.expression === self;
|
||||||
// (a = foo) ? bar : baz
|
// (a = foo) ? bar : baz
|
||||||
if (p instanceof AST_Conditional) return p.condition === this;
|
if (p instanceof AST_Conditional) return p.condition === self;
|
||||||
// (a = foo)["prop"] —or— (a = foo).prop
|
// (a = foo)["prop"] —or— (a = foo).prop
|
||||||
if (p instanceof AST_PropAccess) return p.expression === this;
|
if (p instanceof AST_PropAccess) return p.expression === self;
|
||||||
// !(a = false) → true
|
// !(a = false) → true
|
||||||
if (p instanceof AST_Unary) return true;
|
if (p instanceof AST_Unary) return true;
|
||||||
|
}
|
||||||
|
PARENS(AST_Assign, function(output) {
|
||||||
|
if (needs_parens_assign_cond(this, output)) return true;
|
||||||
|
// v8 parser bug => workaround
|
||||||
|
// f([1], [a] = []) => f([1], ([a] = []))
|
||||||
|
if (output.option("v8")) return this.left instanceof AST_Destructured;
|
||||||
|
// ({ p: a } = o);
|
||||||
|
if (this.left instanceof AST_DestructuredObject) return needs_parens_obj(output);
|
||||||
|
});
|
||||||
|
PARENS(AST_Conditional, function(output) {
|
||||||
|
return needs_parens_assign_cond(this, output);
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ PRINTERS ]----- */
|
/* -----[ PRINTERS ]----- */
|
||||||
@@ -1274,6 +1284,38 @@ function OutputStream(options) {
|
|||||||
output.space();
|
output.space();
|
||||||
} : noop);
|
} : noop);
|
||||||
});
|
});
|
||||||
|
DEFPRINT(AST_DestructuredArray, function(output) {
|
||||||
|
var a = this.elements, len = a.length;
|
||||||
|
output.with_square(len > 0 ? function() {
|
||||||
|
output.space();
|
||||||
|
a.forEach(function(exp, i) {
|
||||||
|
if (i) output.comma();
|
||||||
|
exp.print(output);
|
||||||
|
// If the final element is a hole, we need to make sure it
|
||||||
|
// doesn't look like a trailing comma, by inserting an actual
|
||||||
|
// trailing comma.
|
||||||
|
if (i === len - 1 && exp instanceof AST_Hole)
|
||||||
|
output.comma();
|
||||||
|
});
|
||||||
|
output.space();
|
||||||
|
} : noop);
|
||||||
|
});
|
||||||
|
DEFPRINT(AST_DestructuredKeyVal, print_key_value);
|
||||||
|
DEFPRINT(AST_DestructuredObject, function(output) {
|
||||||
|
var props = this.properties;
|
||||||
|
if (props.length > 0) output.with_block(function() {
|
||||||
|
props.forEach(function(prop, i) {
|
||||||
|
if (i) {
|
||||||
|
output.print(",");
|
||||||
|
output.newline();
|
||||||
|
}
|
||||||
|
output.indent();
|
||||||
|
prop.print(output);
|
||||||
|
});
|
||||||
|
output.newline();
|
||||||
|
});
|
||||||
|
else print_braced_empty(this, output);
|
||||||
|
});
|
||||||
DEFPRINT(AST_Object, function(output) {
|
DEFPRINT(AST_Object, function(output) {
|
||||||
var props = this.properties;
|
var props = this.properties;
|
||||||
if (props.length > 0) output.with_block(function() {
|
if (props.length > 0) output.with_block(function() {
|
||||||
@@ -1314,12 +1356,13 @@ function OutputStream(options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFPRINT(AST_ObjectKeyVal, function(output) {
|
function print_key_value(output) {
|
||||||
var self = this;
|
var self = this;
|
||||||
print_property_key(self, output);
|
print_property_key(self, output);
|
||||||
output.colon();
|
output.colon();
|
||||||
self.value.print(output);
|
self.value.print(output);
|
||||||
});
|
}
|
||||||
|
DEFPRINT(AST_ObjectKeyVal, print_key_value);
|
||||||
function print_accessor(type) {
|
function print_accessor(type) {
|
||||||
return function(output) {
|
return function(output) {
|
||||||
var self = this;
|
var self = this;
|
||||||
@@ -1483,6 +1526,7 @@ function OutputStream(options) {
|
|||||||
AST_Constant,
|
AST_Constant,
|
||||||
AST_Debugger,
|
AST_Debugger,
|
||||||
AST_Definitions,
|
AST_Definitions,
|
||||||
|
AST_Destructured,
|
||||||
AST_Finally,
|
AST_Finally,
|
||||||
AST_Jump,
|
AST_Jump,
|
||||||
AST_Lambda,
|
AST_Lambda,
|
||||||
@@ -1497,7 +1541,7 @@ function OutputStream(options) {
|
|||||||
output.add_mapping(this.start);
|
output.add_mapping(this.start);
|
||||||
});
|
});
|
||||||
|
|
||||||
DEFMAP([ AST_ObjectProperty ], function(output) {
|
DEFMAP([ AST_DestructuredKeyVal, AST_ObjectProperty ], function(output) {
|
||||||
if (typeof this.key == "string") output.add_mapping(this.start, this.key);
|
if (typeof this.key == "string") output.add_mapping(this.start, this.key);
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|||||||
103
lib/parse.js
103
lib/parse.js
@@ -973,14 +973,16 @@ function parse($TEXT, options) {
|
|||||||
if (!is("punc", ";")) {
|
if (!is("punc", ";")) {
|
||||||
init = is("keyword", "const")
|
init = is("keyword", "const")
|
||||||
? (next(), const_(true))
|
? (next(), const_(true))
|
||||||
|
: is("keyword", "let")
|
||||||
|
? (next(), let_(true))
|
||||||
: is("keyword", "var")
|
: is("keyword", "var")
|
||||||
? (next(), var_(true))
|
? (next(), var_(true))
|
||||||
: expression(true, true);
|
: expression(true, true);
|
||||||
if (is("operator", "in")) {
|
if (is("operator", "in")) {
|
||||||
if (init instanceof AST_Var) {
|
if (init instanceof AST_Definitions) {
|
||||||
if (init.definitions.length > 1)
|
if (init.definitions.length > 1)
|
||||||
croak("Only one variable declaration allowed in for..in loop", init.start.line, init.start.col, init.start.pos);
|
croak("Only one variable declaration allowed in for..in loop", init.start.line, init.start.col, init.start.pos);
|
||||||
} else if (!is_assignable(init)) {
|
} else if (!(is_assignable(init) || (init = to_destructured(init)) instanceof AST_Destructured)) {
|
||||||
croak("Invalid left-hand side in for..in loop", init.start.line, init.start.col, init.start.pos);
|
croak("Invalid left-hand side in for..in loop", init.start.line, init.start.col, init.start.pos);
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
@@ -1025,7 +1027,7 @@ function parse($TEXT, options) {
|
|||||||
var argnames = [];
|
var argnames = [];
|
||||||
for (var first = true; !is("punc", ")");) {
|
for (var first = true; !is("punc", ")");) {
|
||||||
if (first) first = false; else expect(",");
|
if (first) first = false; else expect(",");
|
||||||
argnames.push(as_symbol(AST_SymbolFunarg));
|
argnames.push(maybe_destructured(AST_SymbolFunarg));
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
var loop = S.in_loop;
|
var loop = S.in_loop;
|
||||||
@@ -1146,16 +1148,16 @@ function parse($TEXT, options) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function vardefs(type, no_in, must_init) {
|
function vardefs(type, no_in) {
|
||||||
var a = [];
|
var a = [];
|
||||||
for (;;) {
|
for (;;) {
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
var name = as_symbol(type);
|
var name = maybe_destructured(type);
|
||||||
var value = null;
|
var value = null;
|
||||||
if (is("operator", "=")) {
|
if (is("operator", "=")) {
|
||||||
next();
|
next();
|
||||||
value = expression(false, no_in);
|
value = expression(false, no_in);
|
||||||
} else if (must_init) {
|
} else if (!no_in && (type === AST_SymbolConst || name instanceof AST_Destructured)) {
|
||||||
croak("Missing initializer in declaration");
|
croak("Missing initializer in declaration");
|
||||||
}
|
}
|
||||||
a.push(new AST_VarDef({
|
a.push(new AST_VarDef({
|
||||||
@@ -1174,7 +1176,7 @@ function parse($TEXT, options) {
|
|||||||
var const_ = function(no_in) {
|
var const_ = function(no_in) {
|
||||||
return new AST_Const({
|
return new AST_Const({
|
||||||
start : prev(),
|
start : prev(),
|
||||||
definitions : vardefs(AST_SymbolConst, no_in, true),
|
definitions : vardefs(AST_SymbolConst, no_in),
|
||||||
end : prev()
|
end : prev()
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -1306,7 +1308,8 @@ function parse($TEXT, options) {
|
|||||||
unexpected();
|
unexpected();
|
||||||
};
|
};
|
||||||
|
|
||||||
function expr_list(closing, allow_trailing_comma, allow_empty) {
|
function expr_list(closing, allow_trailing_comma, allow_empty, parser) {
|
||||||
|
if (!parser) parser = expression;
|
||||||
var first = true, a = [];
|
var first = true, a = [];
|
||||||
while (!is("punc", closing)) {
|
while (!is("punc", closing)) {
|
||||||
if (first) first = false; else expect(",");
|
if (first) first = false; else expect(",");
|
||||||
@@ -1314,7 +1317,7 @@ function parse($TEXT, options) {
|
|||||||
if (is("punc", ",") && allow_empty) {
|
if (is("punc", ",") && allow_empty) {
|
||||||
a.push(new AST_Hole({ start: S.token, end: S.token }));
|
a.push(new AST_Hole({ start: S.token, end: S.token }));
|
||||||
} else {
|
} else {
|
||||||
a.push(expression(false));
|
a.push(parser());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
@@ -1449,6 +1452,54 @@ function parse($TEXT, options) {
|
|||||||
return sym;
|
return sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function maybe_destructured(type) {
|
||||||
|
var start = S.token;
|
||||||
|
if (is("punc", "[")) {
|
||||||
|
next();
|
||||||
|
return new AST_DestructuredArray({
|
||||||
|
start: start,
|
||||||
|
elements: expr_list("]", !options.strict, true, function() {
|
||||||
|
return maybe_destructured(type);
|
||||||
|
}),
|
||||||
|
end: prev(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (is("punc", "{")) {
|
||||||
|
next();
|
||||||
|
var first = true, a = [];
|
||||||
|
while (!is("punc", "}")) {
|
||||||
|
if (first) first = false; else expect(",");
|
||||||
|
// allow trailing comma
|
||||||
|
if (!options.strict && is("punc", "}")) break;
|
||||||
|
var key_start = S.token;
|
||||||
|
var key = as_property_key();
|
||||||
|
if (!is("punc", ":") && key_start.type == "name") {
|
||||||
|
a.push(new AST_DestructuredKeyVal({
|
||||||
|
start: key_start,
|
||||||
|
key: key,
|
||||||
|
value: _make_symbol(type, key_start),
|
||||||
|
end: prev(),
|
||||||
|
}));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
expect(":");
|
||||||
|
a.push(new AST_DestructuredKeyVal({
|
||||||
|
start: key_start,
|
||||||
|
key: key,
|
||||||
|
value: maybe_destructured(type),
|
||||||
|
end: prev(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
return new AST_DestructuredObject({
|
||||||
|
start: start,
|
||||||
|
properties: a,
|
||||||
|
end: prev(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return as_symbol(type);
|
||||||
|
}
|
||||||
|
|
||||||
function mark_pure(call) {
|
function mark_pure(call) {
|
||||||
var start = call.start;
|
var start = call.start;
|
||||||
var comments = start.comments_before;
|
var comments = start.comments_before;
|
||||||
@@ -1578,11 +1629,43 @@ function parse($TEXT, options) {
|
|||||||
return expr instanceof AST_PropAccess || expr instanceof AST_SymbolRef;
|
return expr instanceof AST_PropAccess || expr instanceof AST_SymbolRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function to_destructured(node) {
|
||||||
|
if (node instanceof AST_Array) {
|
||||||
|
var elements = node.elements.map(to_destructured);
|
||||||
|
return all(elements, function(node) {
|
||||||
|
return node instanceof AST_Destructured || node instanceof AST_Hole || is_assignable(node);
|
||||||
|
}) ? new AST_DestructuredArray({
|
||||||
|
start: node.start,
|
||||||
|
elements: elements,
|
||||||
|
end: node.end,
|
||||||
|
}) : node;
|
||||||
|
}
|
||||||
|
if (!(node instanceof AST_Object)) return node;
|
||||||
|
var props = [];
|
||||||
|
for (var i = 0; i < node.properties.length; i++) {
|
||||||
|
var prop = node.properties[i];
|
||||||
|
if (!(prop instanceof AST_ObjectKeyVal)) return node;
|
||||||
|
var value = to_destructured(prop.value);
|
||||||
|
if (!(value instanceof AST_Destructured || is_assignable(value))) return node;
|
||||||
|
props.push(new AST_DestructuredKeyVal({
|
||||||
|
start: prop.start,
|
||||||
|
key: prop.key,
|
||||||
|
value: value,
|
||||||
|
end: prop.end,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return new AST_DestructuredObject({
|
||||||
|
start: node.start,
|
||||||
|
properties: props,
|
||||||
|
end: node.end,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var maybe_assign = function(no_in) {
|
var maybe_assign = function(no_in) {
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
var left = maybe_conditional(no_in), val = S.token.value;
|
var left = maybe_conditional(no_in), val = S.token.value;
|
||||||
if (is("operator") && ASSIGNMENT[val]) {
|
if (is("operator") && ASSIGNMENT[val]) {
|
||||||
if (is_assignable(left)) {
|
if (is_assignable(left) || val == "=" && (left = to_destructured(left)) instanceof AST_Destructured) {
|
||||||
next();
|
next();
|
||||||
return new AST_Assign({
|
return new AST_Assign({
|
||||||
start : start,
|
start : start,
|
||||||
|
|||||||
67
lib/scope.js
67
lib/scope.js
@@ -72,7 +72,7 @@ SymbolDef.prototype = {
|
|||||||
if (def) {
|
if (def) {
|
||||||
this.mangled_name = def.mangled_name || def.name;
|
this.mangled_name = def.mangled_name || def.name;
|
||||||
} else {
|
} else {
|
||||||
this.mangled_name = next_mangled_name(this.scope, options, this);
|
this.mangled_name = next_mangled_name(this, options);
|
||||||
}
|
}
|
||||||
if (this.global && cache) {
|
if (this.global && cache) {
|
||||||
cache.set(this.name, this.mangled_name);
|
cache.set(this.name, this.mangled_name);
|
||||||
@@ -204,7 +204,17 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
|
|
||||||
// pass 2: find back references and eval
|
// pass 2: find back references and eval
|
||||||
self.globals = new Dictionary();
|
self.globals = new Dictionary();
|
||||||
|
var in_arg = [];
|
||||||
var tw = new TreeWalker(function(node) {
|
var tw = new TreeWalker(function(node) {
|
||||||
|
if (node instanceof AST_Lambda) {
|
||||||
|
in_arg.push(node);
|
||||||
|
node.argnames.forEach(function(argname) {
|
||||||
|
argname.walk(tw);
|
||||||
|
});
|
||||||
|
in_arg.pop();
|
||||||
|
walk_body(node, tw);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (node instanceof AST_LoopControl) {
|
if (node instanceof AST_LoopControl) {
|
||||||
if (node.label) node.label.thedef.references.push(node);
|
if (node.label) node.label.thedef.references.push(node);
|
||||||
return true;
|
return true;
|
||||||
@@ -212,10 +222,24 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
var name = node.name;
|
var name = node.name;
|
||||||
var sym = node.scope.find_variable(name);
|
var sym = node.scope.find_variable(name);
|
||||||
|
for (var i = in_arg.length; i > 0 && sym;) {
|
||||||
|
i = in_arg.lastIndexOf(sym.scope, i - 1);
|
||||||
|
if (i < 0) break;
|
||||||
|
var decl = sym.orig[0];
|
||||||
|
if (decl instanceof AST_SymbolFunarg || decl instanceof AST_SymbolLambda) {
|
||||||
|
node.in_arg = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sym = sym.scope.parent_scope.find_variable(name);
|
||||||
|
}
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
sym = self.def_global(node);
|
sym = self.def_global(node);
|
||||||
} else if (name == "arguments" && sym.scope instanceof AST_Lambda) {
|
} else if (name == "arguments" && sym.scope instanceof AST_Lambda) {
|
||||||
sym.scope.uses_arguments = true;
|
if (!(tw.parent() instanceof AST_PropAccess)) {
|
||||||
|
sym.scope.uses_arguments = "d";
|
||||||
|
} else if (!sym.scope.uses_arguments) {
|
||||||
|
sym.scope.uses_arguments = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (name == "eval") {
|
if (name == "eval") {
|
||||||
var parent = tw.parent();
|
var parent = tw.parent();
|
||||||
@@ -408,7 +432,8 @@ function names_in_use(scope, options) {
|
|||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
function next_mangled_name(scope, options, def) {
|
function next_mangled_name(def, options) {
|
||||||
|
var scope = def.scope;
|
||||||
var in_use = names_in_use(scope, options);
|
var in_use = names_in_use(scope, options);
|
||||||
var holes = scope.cname_holes;
|
var holes = scope.cname_holes;
|
||||||
var names = Object.create(null);
|
var names = Object.create(null);
|
||||||
@@ -461,6 +486,7 @@ function _default_mangler_options(options) {
|
|||||||
keep_fnames : false,
|
keep_fnames : false,
|
||||||
reserved : [],
|
reserved : [],
|
||||||
toplevel : false,
|
toplevel : false,
|
||||||
|
webkit : false,
|
||||||
});
|
});
|
||||||
if (!Array.isArray(options.reserved)) options.reserved = [];
|
if (!Array.isArray(options.reserved)) options.reserved = [];
|
||||||
// Never mangle arguments
|
// Never mangle arguments
|
||||||
@@ -495,9 +521,24 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_BlockScope) {
|
if (node instanceof AST_BlockScope) {
|
||||||
var to_mangle = [];
|
if (options.webkit && node instanceof AST_IterationStatement && node.init instanceof AST_Let) {
|
||||||
|
node.init.definitions.forEach(function(defn) {
|
||||||
|
defn.name.match_symbol(function(sym) {
|
||||||
|
if (!(sym instanceof AST_SymbolLet)) return;
|
||||||
|
var def = sym.definition();
|
||||||
|
var scope = sym.scope.parent_scope;
|
||||||
|
var redef = scope.def_variable(sym);
|
||||||
|
sym.thedef = def;
|
||||||
|
scope.to_mangle.push(redef);
|
||||||
|
def.redefined = function() {
|
||||||
|
return redef;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
node.to_mangle = [];
|
||||||
node.variables.each(function(def) {
|
node.variables.each(function(def) {
|
||||||
if (!defer_redef(def)) to_mangle.push(def);
|
if (!defer_redef(def)) node.to_mangle.push(def);
|
||||||
});
|
});
|
||||||
descend();
|
descend();
|
||||||
if (options.cache && node instanceof AST_Toplevel) {
|
if (options.cache && node instanceof AST_Toplevel) {
|
||||||
@@ -508,7 +549,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|||||||
sym.scope = node;
|
sym.scope = node;
|
||||||
sym.reference(options);
|
sym.reference(options);
|
||||||
}
|
}
|
||||||
to_mangle.forEach(mangle);
|
node.to_mangle.forEach(mangle);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Label) {
|
if (node instanceof AST_Label) {
|
||||||
@@ -528,13 +569,19 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|||||||
def.mangle(options);
|
def.mangle(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
function defer_redef(def, node) {
|
function defer_redef(def) {
|
||||||
|
var sym = def.orig[0];
|
||||||
var redef = def.redefined();
|
var redef = def.redefined();
|
||||||
if (!redef) return false;
|
if (!redef) {
|
||||||
|
if (!(sym instanceof AST_SymbolConst)) return false;
|
||||||
|
var scope = def.scope.resolve();
|
||||||
|
if (def.scope === scope) return false;
|
||||||
|
redef = scope.def_variable(sym);
|
||||||
|
scope.to_mangle.push(redef);
|
||||||
|
}
|
||||||
redefined.push(def);
|
redefined.push(def);
|
||||||
def.references.forEach(reference);
|
def.references.forEach(reference);
|
||||||
var node = def.orig[0];
|
if (sym instanceof AST_SymbolCatch || sym instanceof AST_SymbolConst) reference(sym);
|
||||||
if (node instanceof AST_SymbolCatch || node instanceof AST_SymbolConst) reference(node);
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
function reference(sym) {
|
function reference(sym) {
|
||||||
|
|||||||
@@ -160,6 +160,16 @@ TreeTransformer.prototype = new TreeWalker;
|
|||||||
DEF(AST_Array, function(self, tw) {
|
DEF(AST_Array, function(self, tw) {
|
||||||
self.elements = do_list(self.elements, tw);
|
self.elements = do_list(self.elements, tw);
|
||||||
});
|
});
|
||||||
|
DEF(AST_DestructuredArray, function(self, tw) {
|
||||||
|
self.elements = do_list(self.elements, tw);
|
||||||
|
});
|
||||||
|
DEF(AST_DestructuredKeyVal, function(self, tw) {
|
||||||
|
if (self.key instanceof AST_Node) self.key = self.key.transform(tw);
|
||||||
|
self.value = self.value.transform(tw);
|
||||||
|
});
|
||||||
|
DEF(AST_DestructuredObject, function(self, tw) {
|
||||||
|
self.properties = do_list(self.properties, tw);
|
||||||
|
});
|
||||||
DEF(AST_Object, function(self, tw) {
|
DEF(AST_Object, function(self, tw) {
|
||||||
self.properties = do_list(self.properties, tw);
|
self.properties = do_list(self.properties, tw);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"version": "3.11.6",
|
"version": "3.12.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ function make_code(ast, options) {
|
|||||||
|
|
||||||
function parse_test(file) {
|
function parse_test(file) {
|
||||||
var script = fs.readFileSync(file, "utf8");
|
var script = fs.readFileSync(file, "utf8");
|
||||||
// TODO try/catch can be removed after fixing https://github.com/mishoo/UglifyJS/issues/348
|
|
||||||
try {
|
try {
|
||||||
var ast = U.parse(script, {
|
var ast = U.parse(script, {
|
||||||
filename: file
|
filename: file
|
||||||
|
|||||||
@@ -807,3 +807,47 @@ issue_4200: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "undefined"
|
expect_stdout: "undefined"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4291_1: {
|
||||||
|
options = {
|
||||||
|
arguments: true,
|
||||||
|
keep_fargs: "strict",
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function() {
|
||||||
|
arguments[0] = "PASS";
|
||||||
|
return arguments;
|
||||||
|
}()[0]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
arguments[0] = "PASS";
|
||||||
|
return arguments;
|
||||||
|
}()[0]);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4291_2: {
|
||||||
|
options = {
|
||||||
|
arguments: true,
|
||||||
|
keep_fargs: "strict",
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = function() {
|
||||||
|
if (arguments[0])
|
||||||
|
arguments[1] = "PASS";
|
||||||
|
return arguments;
|
||||||
|
}(42);
|
||||||
|
console.log(a[1], a[0], a.length);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = function(argument_0) {
|
||||||
|
if (argument_0)
|
||||||
|
arguments[1] = "PASS";
|
||||||
|
return arguments;
|
||||||
|
}(42);
|
||||||
|
console.log(a[1], a[0], a.length);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS 42 1"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,45 @@
|
|||||||
|
mangle_block: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = "PASS";
|
||||||
|
{
|
||||||
|
const a = "FAIL";
|
||||||
|
}
|
||||||
|
console.log(o);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = "PASS";
|
||||||
|
{
|
||||||
|
const a = "FAIL";
|
||||||
|
}
|
||||||
|
console.log(o);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
mangle_block_toplevel: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = "PASS";
|
||||||
|
{
|
||||||
|
const a = "FAIL";
|
||||||
|
}
|
||||||
|
console.log(o);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = "PASS";
|
||||||
|
{
|
||||||
|
const c = "FAIL";
|
||||||
|
}
|
||||||
|
console.log(o);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
mangle_catch_1: {
|
mangle_catch_1: {
|
||||||
mangle = {}
|
mangle = {}
|
||||||
input: {
|
input: {
|
||||||
@@ -11,8 +53,8 @@ mangle_catch_1: {
|
|||||||
expect: {
|
expect: {
|
||||||
try {
|
try {
|
||||||
throw "eeeee";
|
throw "eeeee";
|
||||||
} catch (e) {
|
} catch (o) {
|
||||||
const o = typeof d;
|
const e = typeof d;
|
||||||
}
|
}
|
||||||
console.log(typeof a, typeof b);
|
console.log(typeof a, typeof b);
|
||||||
}
|
}
|
||||||
@@ -57,6 +99,23 @@ retain_block: {
|
|||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retain_catch: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {} catch (a) {
|
||||||
|
const a = "aa";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {} catch (a) {
|
||||||
|
const a = "aa";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
if_dead_branch: {
|
if_dead_branch: {
|
||||||
options = {
|
options = {
|
||||||
conditionals: true,
|
conditionals: true,
|
||||||
@@ -1225,3 +1284,66 @@ issue_4274_2: {
|
|||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4290_1: {
|
||||||
|
options = {
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
const a = 0;
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
const a = 0;
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4305_1: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
const arguments = function() {
|
||||||
|
while (console.log("PASS"));
|
||||||
|
};
|
||||||
|
arguments();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
const arguments = function() {
|
||||||
|
while (console.log("PASS"));
|
||||||
|
};
|
||||||
|
arguments();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4305_2: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function(a) {
|
||||||
|
const a = function() {
|
||||||
|
while (console.log("aaaaa"));
|
||||||
|
};
|
||||||
|
a();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function(a) {
|
||||||
|
const a = function() {
|
||||||
|
while (console.log("aaaaa"));
|
||||||
|
};
|
||||||
|
a();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|||||||
1649
test/compress/destructured.js
Normal file
1649
test/compress/destructured.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -521,7 +521,7 @@ issue_2531_2: {
|
|||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
inline: true,
|
inline: true,
|
||||||
passes: 3,
|
passes: 2,
|
||||||
reduce_funcs: true,
|
reduce_funcs: true,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
@@ -556,9 +556,10 @@ issue_2531_3: {
|
|||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
inline: true,
|
inline: true,
|
||||||
passes: 3,
|
passes: 2,
|
||||||
reduce_funcs: true,
|
reduce_funcs: true,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
|
sequences: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
toplevel: true,
|
toplevel: true,
|
||||||
unused: true,
|
unused: true,
|
||||||
|
|||||||
@@ -297,6 +297,33 @@ name_collision_3: {
|
|||||||
expect_stdout: "true 4 6"
|
expect_stdout: "true 4 6"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
name_collision_4: {
|
||||||
|
options = {
|
||||||
|
hoist_props: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function() {
|
||||||
|
var o = {
|
||||||
|
p: 0,
|
||||||
|
q: "PASS",
|
||||||
|
};
|
||||||
|
return function(o_p) {
|
||||||
|
if (!o.p) return o_p;
|
||||||
|
}(o.q);
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
var o_p$0 = 0, o_q = "PASS";
|
||||||
|
return function(o_p) {
|
||||||
|
if (!o_p$0) return o_p;
|
||||||
|
}(o_q);
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
contains_this_1: {
|
contains_this_1: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
|
|||||||
@@ -20,6 +20,26 @@ retain_block: {
|
|||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retain_catch: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
try {} catch (a) {
|
||||||
|
let a = "aa";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
try {} catch (a) {
|
||||||
|
let a = "aa";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
if_dead_branch: {
|
if_dead_branch: {
|
||||||
options = {
|
options = {
|
||||||
conditionals: true,
|
conditionals: true,
|
||||||
@@ -1006,3 +1026,205 @@ issue_4274_2: {
|
|||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4276_1: {
|
||||||
|
options = {
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
try {
|
||||||
|
let a = b, b;
|
||||||
|
console.log("FAIL");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
try {
|
||||||
|
let a = b, b;
|
||||||
|
console.log("FAIL");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4276_2: {
|
||||||
|
options = {
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
try {
|
||||||
|
let a = f(), b;
|
||||||
|
console.log("FAIL");
|
||||||
|
function f() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
try {
|
||||||
|
let a = f(), b;
|
||||||
|
console.log("FAIL");
|
||||||
|
function f() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4290_1: {
|
||||||
|
options = {
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
let a;
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
let a;
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4290_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
try {
|
||||||
|
console.log(function(a) {
|
||||||
|
a = c;
|
||||||
|
let c;
|
||||||
|
return a;
|
||||||
|
}());
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
try {
|
||||||
|
console.log(function(a) {
|
||||||
|
a = c;
|
||||||
|
let c;
|
||||||
|
return a;
|
||||||
|
}());
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4305_1: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
let arguments = function() {
|
||||||
|
while (console.log("PASS"));
|
||||||
|
};
|
||||||
|
arguments();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
let arguments = function() {
|
||||||
|
while (console.log("PASS"));
|
||||||
|
};
|
||||||
|
arguments();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4305_2: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
(function(a) {
|
||||||
|
let a = function() {
|
||||||
|
while (console.log("aaaaa"));
|
||||||
|
};
|
||||||
|
a();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
(function(a) {
|
||||||
|
let a = function() {
|
||||||
|
while (console.log("aaaaa"));
|
||||||
|
};
|
||||||
|
a();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_1753: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: false,
|
||||||
|
webkit: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
let l = null;
|
||||||
|
for (let i = 0; i < 1; i++)
|
||||||
|
console.log(i);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
let l = null;
|
||||||
|
for (let i = 0; i < 1; i++)
|
||||||
|
console.log(i);
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_1753_toplevel: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
webkit: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
let l = null;
|
||||||
|
for (let i = 0; i < 1; i++)
|
||||||
|
console.log(i);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
let l = null;
|
||||||
|
for (let e = 0; e < 1; e++)
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,49 +1,100 @@
|
|||||||
hex_numbers_in_parentheses_for_prototype_functions: {
|
parentheses_for_prototype_functions: {
|
||||||
beautify = {
|
beautify = {
|
||||||
beautify: true,
|
beautify: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
function f() {
|
(function() {
|
||||||
(-2);
|
console.log((-2));
|
||||||
(-2).toFixed(0);
|
console.log((-2).toFixed(0));
|
||||||
|
|
||||||
(2);
|
console.log((2));
|
||||||
(2).toFixed(0);
|
console.log((2).toFixed(0));
|
||||||
|
|
||||||
(0.2);
|
console.log((0.2));
|
||||||
(0.2).toFixed(0);
|
console.log((0.2).toFixed(0));
|
||||||
|
|
||||||
(2.34e20);
|
console.log((2.34e20));
|
||||||
(2.34e20).toFixed(0);
|
console.log((2.34e20).toFixed(0));
|
||||||
|
|
||||||
(0.00000002);
|
console.log((0.00000002));
|
||||||
(0.00000002).toFixed(0);
|
console.log((0.00000002).toFixed(0));
|
||||||
|
|
||||||
(1000000000000000128);
|
console.log((1000000000000000128));
|
||||||
(1000000000000000128).toFixed(0);
|
console.log((1000000000000000128).toFixed(0));
|
||||||
|
|
||||||
(-1000000000000000128);
|
console.log((-1000000000000000128));
|
||||||
(-1000000000000000128).toFixed(0);
|
console.log((-1000000000000000128).toFixed(0));
|
||||||
}
|
})();
|
||||||
}
|
}
|
||||||
expect_exact: [
|
expect_exact: [
|
||||||
"function f() {",
|
"(function() {",
|
||||||
" -2;",
|
" console.log(-2);",
|
||||||
" (-2).toFixed(0);",
|
" console.log((-2).toFixed(0));",
|
||||||
" 2;",
|
" console.log(2);",
|
||||||
" 2..toFixed(0);",
|
" console.log(2..toFixed(0));",
|
||||||
" .2;",
|
" console.log(.2);",
|
||||||
" .2.toFixed(0);",
|
" console.log(.2.toFixed(0));",
|
||||||
" 234e18;",
|
" console.log(234e18);",
|
||||||
" 234e18.toFixed(0);",
|
" console.log(234e18.toFixed(0));",
|
||||||
" 2e-8;",
|
" console.log(2e-8);",
|
||||||
" 2e-8.toFixed(0);",
|
" console.log(2e-8.toFixed(0));",
|
||||||
" 0xde0b6b3a7640080;",
|
" console.log(0xde0b6b3a7640080);",
|
||||||
" (0xde0b6b3a7640080).toFixed(0);",
|
" console.log(0xde0b6b3a7640080.toFixed(0));",
|
||||||
" -0xde0b6b3a7640080;",
|
" console.log(-0xde0b6b3a7640080);",
|
||||||
" (-0xde0b6b3a7640080).toFixed(0);",
|
" console.log((-0xde0b6b3a7640080).toFixed(0));",
|
||||||
"}",
|
"})();",
|
||||||
]
|
]
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
parentheses_for_prototype_functions_galio: {
|
||||||
|
beautify = {
|
||||||
|
beautify: true,
|
||||||
|
galio: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
console.log((-2));
|
||||||
|
console.log((-2).toFixed(0));
|
||||||
|
|
||||||
|
console.log((2));
|
||||||
|
console.log((2).toFixed(0));
|
||||||
|
|
||||||
|
console.log((0.2));
|
||||||
|
console.log((0.2).toFixed(0));
|
||||||
|
|
||||||
|
console.log((2.34e20));
|
||||||
|
console.log((2.34e20).toFixed(0));
|
||||||
|
|
||||||
|
console.log((0.00000002));
|
||||||
|
console.log((0.00000002).toFixed(0));
|
||||||
|
|
||||||
|
console.log((1000000000000000128));
|
||||||
|
console.log((1000000000000000128).toFixed(0));
|
||||||
|
|
||||||
|
console.log((-1000000000000000128));
|
||||||
|
console.log((-1000000000000000128).toFixed(0));
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_exact: [
|
||||||
|
"(function() {",
|
||||||
|
" console.log(-2);",
|
||||||
|
" console.log((-2).toFixed(0));",
|
||||||
|
" console.log(2);",
|
||||||
|
" console.log(2..toFixed(0));",
|
||||||
|
" console.log(.2);",
|
||||||
|
" console.log(.2.toFixed(0));",
|
||||||
|
" console.log(234e18);",
|
||||||
|
" console.log(234e18.toFixed(0));",
|
||||||
|
" console.log(2e-8);",
|
||||||
|
" console.log(2e-8.toFixed(0));",
|
||||||
|
" console.log(0xde0b6b3a7640080);",
|
||||||
|
" console.log((0xde0b6b3a7640080).toFixed(0));",
|
||||||
|
" console.log(-0xde0b6b3a7640080);",
|
||||||
|
" console.log((-0xde0b6b3a7640080).toFixed(0));",
|
||||||
|
"})();",
|
||||||
|
]
|
||||||
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
comparisons: {
|
comparisons: {
|
||||||
|
|||||||
@@ -234,3 +234,178 @@ issue_4191_let: {
|
|||||||
expect_stdout: "function undefined"
|
expect_stdout: "function undefined"
|
||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forin_const_1: {
|
||||||
|
options = {
|
||||||
|
join_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
const o = {
|
||||||
|
foo: 42,
|
||||||
|
bar: "PASS",
|
||||||
|
};
|
||||||
|
for (const k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
foo: 42,
|
||||||
|
bar: "PASS",
|
||||||
|
};
|
||||||
|
for (const k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
forin_const_2: {
|
||||||
|
options = {
|
||||||
|
join_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
const o = {
|
||||||
|
p: 42,
|
||||||
|
q: "PASS",
|
||||||
|
};
|
||||||
|
for (const [ k ] in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
p: 42,
|
||||||
|
q: "PASS",
|
||||||
|
}, k;
|
||||||
|
for ([ k ] in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"p 42",
|
||||||
|
"q PASS",
|
||||||
|
]
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
forin_let_1: {
|
||||||
|
options = {
|
||||||
|
join_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
let o = {
|
||||||
|
foo: 42,
|
||||||
|
bar: "PASS",
|
||||||
|
};
|
||||||
|
for (let k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
var o = {
|
||||||
|
foo: 42,
|
||||||
|
bar: "PASS",
|
||||||
|
}, k;
|
||||||
|
for (k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo 42",
|
||||||
|
"bar PASS",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
forin_let_2: {
|
||||||
|
options = {
|
||||||
|
join_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
let o = {
|
||||||
|
p: 42,
|
||||||
|
q: "PASS",
|
||||||
|
};
|
||||||
|
for (let [ k ] in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
p: 42,
|
||||||
|
q: "PASS",
|
||||||
|
}, k;
|
||||||
|
for ([ k ] in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"p 42",
|
||||||
|
"q PASS",
|
||||||
|
]
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4290_1_const: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
const a = 0;
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
const a = 0;
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4290_1_let: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
let a = 0;
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
let a = 0;
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
drop_forin_let: {
|
||||||
|
options = {
|
||||||
|
loops: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
for (let a in console.log("PASS"));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
|
|
||||||
// quick ignores
|
// quick ignores
|
||||||
if (node instanceof U.AST_Accessor) return;
|
if (node instanceof U.AST_Accessor) return;
|
||||||
|
if (node instanceof U.AST_Destructured) return;
|
||||||
if (node instanceof U.AST_Directive) return;
|
if (node instanceof U.AST_Directive) return;
|
||||||
if (!in_list && node instanceof U.AST_EmptyStatement) return;
|
if (!in_list && node instanceof U.AST_EmptyStatement) return;
|
||||||
if (node instanceof U.AST_Label) return;
|
if (node instanceof U.AST_Label) return;
|
||||||
@@ -114,6 +115,8 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
|
|
||||||
// ignore lvalues
|
// ignore lvalues
|
||||||
if (parent instanceof U.AST_Assign && parent.left === node) return;
|
if (parent instanceof U.AST_Assign && parent.left === node) return;
|
||||||
|
if (parent instanceof U.AST_DestructuredArray) return;
|
||||||
|
if (parent instanceof U.AST_DestructuredKeyVal && parent.value === node) return;
|
||||||
if (parent instanceof U.AST_Unary && parent.expression === node) switch (parent.operator) {
|
if (parent instanceof U.AST_Unary && parent.expression === node) switch (parent.operator) {
|
||||||
case "++":
|
case "++":
|
||||||
case "--":
|
case "--":
|
||||||
@@ -250,13 +253,23 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (node instanceof U.AST_ForIn) {
|
else if (node instanceof U.AST_ForIn) {
|
||||||
var expr = [
|
var expr;
|
||||||
node.init,
|
switch ((node.start._permute * steps | 0) % 3) {
|
||||||
node.object,
|
case 0:
|
||||||
node.body,
|
if (!(node.init instanceof U.AST_Definitions
|
||||||
][ (node.start._permute * steps | 0) % 3 ];
|
&& node.init.definitions[0].name instanceof U.AST_Destructured)) {
|
||||||
|
expr = node.init;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
expr = node.object;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (!has_loopcontrol(node.body, node, parent)) expr = node.body;
|
||||||
|
break;
|
||||||
|
}
|
||||||
node.start._permute += step;
|
node.start._permute += step;
|
||||||
if (expr && (expr !== node.body || !has_loopcontrol(expr, node, parent))) {
|
if (expr) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
return to_statement(expr);
|
return to_statement(expr);
|
||||||
}
|
}
|
||||||
@@ -389,6 +402,13 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
return List.skip;
|
return List.skip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// skip element/property from (destructured) array/object
|
||||||
|
if (parent instanceof U.AST_Array || parent instanceof U.AST_Destructured || parent instanceof AST_Object) {
|
||||||
|
node.start._permute++;
|
||||||
|
CHANGED = true;
|
||||||
|
return List.skip;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace this node
|
// replace this node
|
||||||
|
|||||||
@@ -377,6 +377,118 @@ function createArgs(recurmax, stmtDepth, canThrow) {
|
|||||||
return args.join(", ");
|
return args.join(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createAssignmentPairs(recurmax, noComma, stmtDepth, canThrow, varNames, maybe, dontStore) {
|
||||||
|
var avoid = [];
|
||||||
|
var len = unique_vars.length;
|
||||||
|
var pairs = createPairs(recurmax);
|
||||||
|
unique_vars.length = len;
|
||||||
|
return pairs;
|
||||||
|
|
||||||
|
function createAssignmentValue(recurmax) {
|
||||||
|
var current = VAR_NAMES;
|
||||||
|
VAR_NAMES = (varNames || VAR_NAMES).slice();
|
||||||
|
var value = varNames && rng(2) ? createValue() : createExpression(recurmax, noComma, stmtDepth, canThrow);
|
||||||
|
VAR_NAMES = current;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createKey(recurmax, keys) {
|
||||||
|
var save = VAR_NAMES;
|
||||||
|
VAR_NAMES = VAR_NAMES.filter(function(name) {
|
||||||
|
return avoid.indexOf(name) < 0;
|
||||||
|
});
|
||||||
|
var len = VAR_NAMES.length;
|
||||||
|
var key;
|
||||||
|
do {
|
||||||
|
key = createObjectKey(recurmax, stmtDepth, canThrow);
|
||||||
|
} while (keys.indexOf(key) >= 0);
|
||||||
|
VAR_NAMES = save.concat(VAR_NAMES.slice(len));
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createPairs(recurmax) {
|
||||||
|
var names = [], values = [];
|
||||||
|
var m = rng(4), n = rng(4);
|
||||||
|
if (!varNames) m = Math.max(m, n, 1);
|
||||||
|
for (var i = Math.max(m, n); --i >= 0;) {
|
||||||
|
if (i < m && i < n) {
|
||||||
|
createDestructured(recurmax, names, values);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (i < m) {
|
||||||
|
unique_vars.push("a", "b", "c", "undefined", "NaN", "Infinity");
|
||||||
|
var name = createVarName(maybe, dontStore);
|
||||||
|
unique_vars.length -= 6;
|
||||||
|
avoid.push(name);
|
||||||
|
unique_vars.push(name);
|
||||||
|
names.unshift(name);
|
||||||
|
}
|
||||||
|
if (i < n) {
|
||||||
|
values.unshift(createAssignmentValue(recurmax));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
names: names,
|
||||||
|
values: values,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDestructured(recurmax, names, values) {
|
||||||
|
switch (rng(20)) {
|
||||||
|
case 0:
|
||||||
|
if (--recurmax < 0) {
|
||||||
|
names.unshift("[]");
|
||||||
|
values.unshift('""');
|
||||||
|
} else {
|
||||||
|
var pairs = createPairs(recurmax);
|
||||||
|
while (!rng(10)) {
|
||||||
|
var index = rng(pairs.names.length + 1);
|
||||||
|
pairs.names.splice(index, 0, "");
|
||||||
|
pairs.values.splice(index, 0, rng(2) ? createAssignmentValue(recurmax) : "");
|
||||||
|
}
|
||||||
|
names.unshift("[ " + pairs.names.join(", ") + " ]");
|
||||||
|
values.unshift("[ " + pairs.values.join(", ") + " ]");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (--recurmax < 0) {
|
||||||
|
names.unshift("{}");
|
||||||
|
values.unshift('""');
|
||||||
|
} else {
|
||||||
|
var pairs = createPairs(recurmax);
|
||||||
|
var keys = [];
|
||||||
|
pairs.names.forEach(function(name, index) {
|
||||||
|
if (/^[[{]/.test(name)) {
|
||||||
|
var key;
|
||||||
|
do {
|
||||||
|
key = KEYS[rng(KEYS.length)];
|
||||||
|
} while (keys.indexOf(key) >= 0);
|
||||||
|
keys[index] = key;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
names.unshift("{ " + pairs.names.map(function(name, index) {
|
||||||
|
var key = index in keys ? keys[index] : rng(10) && createKey(recurmax, keys);
|
||||||
|
return key ? key + ": " + name : name;
|
||||||
|
}).join(", ") + " }");
|
||||||
|
values.unshift("{ " + pairs.values.map(function(value, index) {
|
||||||
|
var key = index in keys ? keys[index] : createKey(recurmax, keys);
|
||||||
|
return key + ": " + value;
|
||||||
|
}).join(", ") + " }");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
unique_vars.push("a", "b", "c", "undefined", "NaN", "Infinity");
|
||||||
|
var name = createVarName(maybe, dontStore);
|
||||||
|
unique_vars.length -= 6;
|
||||||
|
avoid.push(name);
|
||||||
|
unique_vars.push(name);
|
||||||
|
names.unshift(name);
|
||||||
|
values.unshift(createAssignmentValue(recurmax));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function filterDirective(s) {
|
function filterDirective(s) {
|
||||||
if (!generate_directive && !s[1] && /\("/.test(s[2])) s[2] = ";" + s[2];
|
if (!generate_directive && !s[1] && /\("/.test(s[2])) s[2] = ";" + s[2];
|
||||||
return s;
|
return s;
|
||||||
@@ -415,11 +527,37 @@ function createBlockVariables(recurmax, stmtDepth, canThrow, fn) {
|
|||||||
return names.indexOf(name) < 0;
|
return names.indexOf(name) < 0;
|
||||||
});
|
});
|
||||||
var len = VAR_NAMES.length;
|
var len = VAR_NAMES.length;
|
||||||
var s = type + " " + names.map(function(name) {
|
var s = type + " ";
|
||||||
var value = createExpression(recurmax, NO_COMMA, stmtDepth, canThrow);
|
switch (rng(10)) {
|
||||||
VAR_NAMES.push(name);
|
case 0:
|
||||||
return name + " = " + value;
|
while (!rng(10)) names.splice(rng(names.length + 1), 0, "");
|
||||||
}).join(", ") + ";";
|
s += "[ " + names.join(", ") + " ] = [ " + names.map(function() {
|
||||||
|
return rng(10) ? createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) : "";
|
||||||
|
}).join(", ") + " ];";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
var keys = [];
|
||||||
|
s += "{ " + names.map(function(name, i) {
|
||||||
|
var key = createObjectKey(recurmax, stmtDepth, canThrow);
|
||||||
|
if (!/\[/.test(key)) keys[i] = key;
|
||||||
|
return key + ": " + name;
|
||||||
|
}).join(", ") + "} = { " + names.map(function(name, i) {
|
||||||
|
var key = i in keys ? keys[i] : createObjectKey(recurmax, stmtDepth, canThrow);
|
||||||
|
return key + ": " + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow);
|
||||||
|
}).join(", ") + "};";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
s += names.map(function(name, i) {
|
||||||
|
if (type == "let" && !rng(10)) {
|
||||||
|
VAR_NAMES.push(name);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
var value = createExpression(recurmax, NO_COMMA, stmtDepth, canThrow);
|
||||||
|
VAR_NAMES.push(name);
|
||||||
|
return name + " = " + value;
|
||||||
|
}).join(", ") + ";";
|
||||||
|
break;
|
||||||
|
}
|
||||||
VAR_NAMES = save.concat(VAR_NAMES.slice(len));
|
VAR_NAMES = save.concat(VAR_NAMES.slice(len));
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@@ -429,9 +567,9 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
|||||||
if (--recurmax < 0) { return ";"; }
|
if (--recurmax < 0) { return ";"; }
|
||||||
if (!STMT_COUNT_FROM_GLOBAL) stmtDepth = 0;
|
if (!STMT_COUNT_FROM_GLOBAL) stmtDepth = 0;
|
||||||
var s = [];
|
var s = [];
|
||||||
var name;
|
var name, args;
|
||||||
|
var varNames = VAR_NAMES.slice();
|
||||||
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||||
var namesLenBefore = VAR_NAMES.length;
|
|
||||||
if (allowDefun || rng(5) > 0) {
|
if (allowDefun || rng(5) > 0) {
|
||||||
name = "f" + funcs++;
|
name = "f" + funcs++;
|
||||||
} else {
|
} else {
|
||||||
@@ -439,7 +577,16 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
|||||||
name = createVarName(MANDATORY, !allowDefun);
|
name = createVarName(MANDATORY, !allowDefun);
|
||||||
unique_vars.length -= 3;
|
unique_vars.length -= 3;
|
||||||
}
|
}
|
||||||
s.push("function " + name + "(" + createParams() + "){", strictMode());
|
var params;
|
||||||
|
if ((!allowDefun || !(name in called)) && rng(2)) {
|
||||||
|
called[name] = false;
|
||||||
|
var pairs = createAssignmentPairs(recurmax, COMMA_OK, stmtDepth, canThrow, varNames, MANDATORY);
|
||||||
|
params = pairs.names.join(", ");
|
||||||
|
args = pairs.values.join(", ");
|
||||||
|
} else {
|
||||||
|
params = createParams();
|
||||||
|
}
|
||||||
|
s.push("function " + name + "(" + params + "){", strictMode());
|
||||||
s.push(defns());
|
s.push(defns());
|
||||||
if (rng(5) === 0) {
|
if (rng(5) === 0) {
|
||||||
// functions with functions. lower the recursion to prevent a mess.
|
// functions with functions. lower the recursion to prevent a mess.
|
||||||
@@ -450,17 +597,16 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
|||||||
}
|
}
|
||||||
s.push("}", "");
|
s.push("}", "");
|
||||||
s = filterDirective(s).join("\n");
|
s = filterDirective(s).join("\n");
|
||||||
|
|
||||||
VAR_NAMES.length = namesLenBefore;
|
|
||||||
});
|
});
|
||||||
|
VAR_NAMES = varNames;
|
||||||
|
|
||||||
if (!allowDefun) {
|
if (!allowDefun) {
|
||||||
// avoid "function statements" (decl inside statements)
|
// avoid "function statements" (decl inside statements)
|
||||||
s = "var " + createVarName(MANDATORY) + " = " + s;
|
s = "var " + createVarName(MANDATORY) + " = " + s;
|
||||||
s += "(" + createArgs(recurmax, stmtDepth, canThrow) + ")";
|
s += "(" + (args || createArgs(recurmax, stmtDepth, canThrow)) + ")";
|
||||||
} else if (!(name in called) || rng(3) > 0) {
|
} else if (!(name in called) || args || rng(3)) {
|
||||||
s += "var " + createVarName(MANDATORY) + " = " + name;
|
s += "var " + createVarName(MANDATORY) + " = " + name;
|
||||||
s += "(" + createArgs(recurmax, stmtDepth, canThrow) + ")";
|
s += "(" + (args || createArgs(recurmax, stmtDepth, canThrow)) + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
return s + ";";
|
return s + ";";
|
||||||
@@ -561,8 +707,9 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
|||||||
return [
|
return [
|
||||||
"{var expr" + loop + " = " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "; ",
|
"{var expr" + loop + " = " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "; ",
|
||||||
label.target + " for (",
|
label.target + " for (",
|
||||||
/^key/.test(key) ? "var " : "",
|
!/^key/.test(key) ? rng(10) ? "" : "var " : rng(10) ? "var " : rng(2) ? "let " : "const ",
|
||||||
key + " in expr" + loop + ") {",
|
rng(10) ? key : rng(5) ? "[ " + key + " ]" : "{ length: " + key + " }",
|
||||||
|
" in expr" + loop + ") {",
|
||||||
rng(5) > 1 ? "c = 1 + c; var " + createVarName(MANDATORY) + " = expr" + loop + "[" + key + "]; " : "",
|
rng(5) > 1 ? "c = 1 + c; var " + createVarName(MANDATORY) + " = expr" + loop + "[" + key + "]; " : "",
|
||||||
createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth),
|
createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth),
|
||||||
"}}",
|
"}}",
|
||||||
@@ -576,7 +723,12 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
|||||||
// note: default does not _need_ to be last
|
// note: default does not _need_ to be last
|
||||||
return "switch (" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") { " + createSwitchParts(recurmax, 4, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + "}";
|
return "switch (" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") { " + createSwitchParts(recurmax, 4, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + "}";
|
||||||
case STMT_VAR:
|
case STMT_VAR:
|
||||||
switch (rng(3)) {
|
if (!rng(20)) {
|
||||||
|
var pairs = createAssignmentPairs(recurmax, NO_COMMA, stmtDepth, canThrow, null, MANDATORY);
|
||||||
|
return "var " + pairs.names.map(function(name, index) {
|
||||||
|
return index in pairs.values ? name + " = " + pairs.values[index] : name;
|
||||||
|
}).join(", ") + ";";
|
||||||
|
} else switch (rng(3)) {
|
||||||
case 0:
|
case 0:
|
||||||
unique_vars.push("c");
|
unique_vars.push("c");
|
||||||
var name = createVarName(MANDATORY);
|
var name = createVarName(MANDATORY);
|
||||||
@@ -719,7 +871,28 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
case p++:
|
case p++:
|
||||||
return getVarName();
|
return getVarName();
|
||||||
case p++:
|
case p++:
|
||||||
return getVarName(NO_CONST) + createAssignment() + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
switch (rng(20)) {
|
||||||
|
case 0:
|
||||||
|
return [
|
||||||
|
"[ ",
|
||||||
|
new Array(rng(3)).join(","),
|
||||||
|
getVarName(NO_CONST),
|
||||||
|
new Array(rng(3)).join(","),
|
||||||
|
" ] = ",
|
||||||
|
createArrayLiteral(recurmax, stmtDepth, canThrow),
|
||||||
|
].join("");
|
||||||
|
case 1:
|
||||||
|
return [
|
||||||
|
"{ ",
|
||||||
|
rng(2) ? "" : createObjectKey(recurmax, stmtDepth, canThrow) + ": ",
|
||||||
|
getVarName(NO_CONST),
|
||||||
|
" } = ",
|
||||||
|
createExpression(recurmax, COMMA_OK, stmtDepth, canThrow),
|
||||||
|
" || {}",
|
||||||
|
].join("");
|
||||||
|
default:
|
||||||
|
return getVarName(NO_CONST) + createAssignment() + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
||||||
|
}
|
||||||
case p++:
|
case p++:
|
||||||
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
||||||
case p++:
|
case p++:
|
||||||
@@ -864,7 +1037,10 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
case p++:
|
case p++:
|
||||||
case p++:
|
case p++:
|
||||||
case p++:
|
case p++:
|
||||||
var name = rng(3) == 0 ? getVarName() : "f" + rng(funcs + 2);
|
var name;
|
||||||
|
do {
|
||||||
|
name = rng(3) == 0 ? getVarName() : "f" + rng(funcs + 2);
|
||||||
|
} while (name in called && !called[name]);
|
||||||
called[name] = true;
|
called[name] = true;
|
||||||
return "typeof " + name + ' == "function" && --_calls_ >= 0 && ' + name + "(" + createArgs(recurmax, stmtDepth, canThrow) + ")";
|
return "typeof " + name + ' == "function" && --_calls_ >= 0 && ' + name + "(" + createArgs(recurmax, stmtDepth, canThrow) + ")";
|
||||||
}
|
}
|
||||||
@@ -1002,13 +1178,77 @@ function _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
return "(" + assignee + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
return "(" + assignee + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
||||||
case 3:
|
case 3:
|
||||||
assignee = getVarName();
|
assignee = getVarName();
|
||||||
expr = "(" + assignee + "[" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow)
|
switch (rng(20)) {
|
||||||
+ "]" + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
case 0:
|
||||||
|
expr = [
|
||||||
|
"([ ",
|
||||||
|
assignee,
|
||||||
|
"[", createExpression(recurmax, COMMA_OK, stmtDepth, canThrow), "]",
|
||||||
|
" ] = [ ",
|
||||||
|
_createBinaryExpr(recurmax, noComma, stmtDepth, canThrow),
|
||||||
|
" ])",
|
||||||
|
].join("");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
var key1 = createObjectKey(recurmax, stmtDepth, canThrow);
|
||||||
|
var key2 = /^\[/.test(key1) ? createObjectKey(recurmax, stmtDepth, canThrow) : key1;
|
||||||
|
expr = [
|
||||||
|
"({ ",
|
||||||
|
key1, ": ", assignee,
|
||||||
|
"[", createExpression(recurmax, COMMA_OK, stmtDepth, canThrow), "]",
|
||||||
|
" } = { ",
|
||||||
|
key2, ": ", _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow),
|
||||||
|
" })",
|
||||||
|
].join("");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
expr = [
|
||||||
|
"(",
|
||||||
|
assignee,
|
||||||
|
"[", createExpression(recurmax, COMMA_OK, stmtDepth, canThrow), "]",
|
||||||
|
createAssignment(),
|
||||||
|
_createBinaryExpr(recurmax, noComma, stmtDepth, canThrow),
|
||||||
|
")",
|
||||||
|
].join("");
|
||||||
|
break;
|
||||||
|
}
|
||||||
return canThrow && rng(10) == 0 ? expr : "(" + assignee + " && " + expr + ")";
|
return canThrow && rng(10) == 0 ? expr : "(" + assignee + " && " + expr + ")";
|
||||||
case 4:
|
case 4:
|
||||||
assignee = getVarName();
|
assignee = getVarName();
|
||||||
expr = "(" + assignee + "." + getDotKey(true) + createAssignment()
|
switch (rng(20)) {
|
||||||
+ _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
case 0:
|
||||||
|
expr = [
|
||||||
|
"([ ",
|
||||||
|
assignee,
|
||||||
|
".", getDotKey(true),
|
||||||
|
" ] = [ ",
|
||||||
|
_createBinaryExpr(recurmax, noComma, stmtDepth, canThrow),
|
||||||
|
" ])",
|
||||||
|
].join("");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
var key1 = createObjectKey(recurmax, stmtDepth, canThrow);
|
||||||
|
var key2 = /^\[/.test(key1) ? createObjectKey(recurmax, stmtDepth, canThrow) : key1;
|
||||||
|
expr = [
|
||||||
|
"({ ",
|
||||||
|
key1, ": ", assignee,
|
||||||
|
".", getDotKey(true),
|
||||||
|
" } = { ",
|
||||||
|
key2, ": ", _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow),
|
||||||
|
" })",
|
||||||
|
].join("");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
expr = [
|
||||||
|
"(",
|
||||||
|
assignee,
|
||||||
|
".", getDotKey(true),
|
||||||
|
createAssignment(),
|
||||||
|
_createBinaryExpr(recurmax, noComma, stmtDepth, canThrow),
|
||||||
|
")",
|
||||||
|
].join("");
|
||||||
|
break;
|
||||||
|
}
|
||||||
return canThrow && rng(10) == 0 ? expr : "(" + assignee + " && " + expr + ")";
|
return canThrow && rng(10) == 0 ? expr : "(" + assignee + " && " + expr + ")";
|
||||||
default:
|
default:
|
||||||
return _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow);
|
return _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow);
|
||||||
@@ -1351,7 +1591,14 @@ function patch_try_catch(orig, toplevel) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var minify_options = require("./options.json").map(JSON.stringify);
|
var minify_options = require("./options.json");
|
||||||
|
if (typeof sandbox.run_code("console.log([ 1 ], {} = 2);") != "string") {
|
||||||
|
minify_options.forEach(function(o) {
|
||||||
|
if (!("output" in o)) o.output = {};
|
||||||
|
o.output.v8 = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
minify_options = minify_options.map(JSON.stringify);
|
||||||
var original_code, original_result, errored;
|
var original_code, original_result, errored;
|
||||||
var uglify_code, uglify_result, ok;
|
var uglify_code, uglify_result, ok;
|
||||||
for (var round = 1; round <= num_iterations; round++) {
|
for (var round = 1; round <= num_iterations; round++) {
|
||||||
|
|||||||
Reference in New Issue
Block a user