Compare commits
55 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 | ||
|
|
e390e7e124 | ||
|
|
6fd5b5b371 | ||
|
|
fba27bfb71 | ||
|
|
41310e6404 | ||
|
|
91fc1c82b5 | ||
|
|
810cd40356 | ||
|
|
1cbd07e789 | ||
|
|
b82de04775 | ||
|
|
4bbeb09f7c | ||
|
|
c2f6fd5fde | ||
|
|
af4ea3ff69 | ||
|
|
e7643248a3 | ||
|
|
68091dbf69 | ||
|
|
cbf7269296 | ||
|
|
d8563caba7 | ||
|
|
2e0ad40fe6 | ||
|
|
5d12abc41b | ||
|
|
79e5c3f564 | ||
|
|
607f87c5cd | ||
|
|
b2775746a7 | ||
|
|
e478da24c7 | ||
|
|
c5df8355ba | ||
|
|
ff38d2471f | ||
|
|
8e86d05c32 | ||
|
|
9e40abeded | ||
|
|
23ca7d675f | ||
|
|
fd8c0212b8 | ||
|
|
256950c2c0 | ||
|
|
8ecaa40c6e | ||
|
|
96bf7fceab |
25
README.md
25
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.
|
||||
--verbose Print diagnostic 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
|
||||
“exports” and “global” variables available. You
|
||||
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
|
||||
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
|
||||
|
||||
```javascript
|
||||
@@ -784,6 +791,9 @@ to be `false` and all symbol names will be omitted.
|
||||
- `unused` (default: `true`) -- drop unreferenced functions and variables (simple
|
||||
direct variable assignments do not count as references unless set to `"keep_assign"`)
|
||||
|
||||
- `varify` (default: `true`) -- convert block-scoped declaractions into `var`
|
||||
whenever safe to do so
|
||||
|
||||
## Mangle options
|
||||
|
||||
- `eval` (default `false`) -- Pass `true` to mangle names visible in scopes
|
||||
@@ -865,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_start` (default `0`) -- prefix all lines by that many spaces
|
||||
@@ -903,8 +915,7 @@ can pass additional arguments that control the code output:
|
||||
|
||||
- `shebang` (default `true`) -- preserve shebang `#!` in preamble (bash scripts)
|
||||
|
||||
- `webkit` (default `false`) -- enable workarounds for WebKit bugs.
|
||||
PhantomJS users should set this option to `true`.
|
||||
- `v8` (default `false`) -- enable workarounds for Chrome & Node.js bugs
|
||||
|
||||
- `width` (default `80`) -- only takes effect when beautification is on, this
|
||||
specifies an (orientative) line width that the beautifier will try to
|
||||
@@ -1135,7 +1146,7 @@ To enable fast minify mode with the API use:
|
||||
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
|
||||
are known to have an adverse effect on debugging with source maps. This is
|
||||
@@ -1147,6 +1158,10 @@ disable the Uglify `compress` option and just use `mangle`.
|
||||
|
||||
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
|
||||
objects they have not been overridden.
|
||||
- `undefined`, `NaN` and `Infinity` have not been externally redefined.
|
||||
@@ -1174,3 +1189,7 @@ To allow for better optimizations, the compiler makes various assumptions:
|
||||
top.B = "PASS";
|
||||
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.",
|
||||
" --verbose Print diagnostic messages.",
|
||||
" --warn Print warning messages.",
|
||||
" --webkit Support non-standard Safari/Webkit.",
|
||||
" --wrap <name> Embed everything as a function with “exports” corresponding to “name” globally.",
|
||||
" --reduce-test Reduce a standalone test case (assumes cloned repository).",
|
||||
].join("\n"));
|
||||
@@ -142,6 +143,7 @@ function process_option(name, no_value) {
|
||||
case "timings":
|
||||
case "toplevel":
|
||||
case "validate":
|
||||
case "webkit":
|
||||
options[name] = true;
|
||||
break;
|
||||
case "keep-fnames":
|
||||
@@ -276,7 +278,9 @@ function convert_ast(fn) {
|
||||
function run() {
|
||||
var content = options.sourceMap && options.sourceMap.content;
|
||||
if (content && content != "inline") {
|
||||
UglifyJS.AST_Node.info("Using input source map: " + content);
|
||||
UglifyJS.AST_Node.info("Using input source map: {content}", {
|
||||
content : content,
|
||||
});
|
||||
options.sourceMap.content = read_file(content, content);
|
||||
}
|
||||
try {
|
||||
|
||||
184
lib/ast.js
184
lib/ast.js
@@ -137,17 +137,17 @@ var AST_Node = DEFNODE("Node", "start end", {
|
||||
}, null);
|
||||
|
||||
(AST_Node.log_function = function(fn, verbose) {
|
||||
var printed = Object.create(null);
|
||||
if (fn) {
|
||||
AST_Node.info = verbose ? function(text, props) {
|
||||
log("INFO: " + string_template(text, props));
|
||||
} : noop;
|
||||
AST_Node.warn = function(text, props) {
|
||||
log("WARN: " + string_template(text, props));
|
||||
};
|
||||
} else {
|
||||
if (!fn) {
|
||||
AST_Node.info = AST_Node.warn = noop;
|
||||
return;
|
||||
}
|
||||
var printed = Object.create(null);
|
||||
AST_Node.info = verbose ? function(text, props) {
|
||||
log("INFO: " + string_template(text, props));
|
||||
} : noop;
|
||||
AST_Node.warn = function(text, props) {
|
||||
log("WARN: " + string_template(text, props));
|
||||
};
|
||||
|
||||
function log(msg) {
|
||||
if (printed[msg]) return;
|
||||
@@ -414,8 +414,12 @@ var AST_ForIn = DEFNODE("ForIn", "init object", {
|
||||
_validate: function() {
|
||||
if (this.init instanceof AST_Definitions) {
|
||||
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)) {
|
||||
throw new Error("init must be assignable");
|
||||
} else {
|
||||
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");
|
||||
},
|
||||
@@ -496,12 +500,24 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
||||
}
|
||||
}, 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",
|
||||
$propdoc: {
|
||||
name: "[AST_SymbolDeclaration?] the name of this function",
|
||||
argnames: "[AST_SymbolFunarg*] array of function arguments",
|
||||
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array"
|
||||
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",
|
||||
},
|
||||
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) {
|
||||
var node = this;
|
||||
@@ -515,7 +531,9 @@ var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments length_read", {
|
||||
},
|
||||
_validate: function() {
|
||||
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);
|
||||
@@ -748,8 +766,23 @@ var AST_Const = DEFNODE("Const", null, {
|
||||
_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");
|
||||
validate_destructured(node.name, function(node) {
|
||||
if (!(node instanceof AST_SymbolConst)) throw new Error("name must be AST_SymbolConst");
|
||||
});
|
||||
if (node.value != null) must_be_expression(node, "value");
|
||||
});
|
||||
},
|
||||
}, AST_Definitions);
|
||||
|
||||
var AST_Let = DEFNODE("Let", null, {
|
||||
$documentation: "A `let` statement",
|
||||
_validate: function() {
|
||||
this.definitions.forEach(function(node) {
|
||||
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
|
||||
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");
|
||||
});
|
||||
},
|
||||
}, AST_Definitions);
|
||||
@@ -759,7 +792,9 @@ var AST_Var = DEFNODE("Var", null, {
|
||||
_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_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");
|
||||
});
|
||||
},
|
||||
@@ -958,6 +993,14 @@ var AST_Assign = DEFNODE("Assign", null, {
|
||||
$documentation: "An assignment expression — `a = b + 5`",
|
||||
_validate: function() {
|
||||
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);
|
||||
|
||||
@@ -981,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", {
|
||||
$documentation: "An object literal",
|
||||
$propdoc: {
|
||||
@@ -1004,24 +1118,28 @@ var AST_Object = DEFNODE("Object", "properties", {
|
||||
var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
|
||||
$documentation: "Base class for literal object properties",
|
||||
$propdoc: {
|
||||
key: "[string|AST_SymbolAccessor] property name. For ObjectKeyVal this is a string. For getters and setters this is an AST_SymbolAccessor.",
|
||||
value: "[AST_Node] property value. For getters and setters this is an AST_Accessor."
|
||||
key: "[string|AST_Node] property name. For computed property this is an AST_Node.",
|
||||
value: "[AST_Node] property value. For getters and setters this is an AST_Accessor.",
|
||||
},
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
if (node.key instanceof AST_Node) node.key.walk(visitor);
|
||||
node.value.walk(visitor);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", {
|
||||
$documentation: "A key: value object property",
|
||||
$propdoc: {
|
||||
quote: "[string] the original quote character"
|
||||
},
|
||||
_validate: function() {
|
||||
if (typeof this.key != "string") throw new Error("key must be string");
|
||||
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");
|
||||
}
|
||||
if (!(this.value instanceof AST_Node)) throw new Error("value must be AST_Node");
|
||||
},
|
||||
});
|
||||
|
||||
var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", null, {
|
||||
$documentation: "A key: value object property",
|
||||
_validate: function() {
|
||||
must_be_expression(this, "value");
|
||||
},
|
||||
}, AST_ObjectProperty);
|
||||
@@ -1029,7 +1147,6 @@ var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", {
|
||||
var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
|
||||
$documentation: "An object setter property",
|
||||
_validate: function() {
|
||||
if (!(this.key instanceof AST_SymbolAccessor)) throw new Error("key must be AST_SymbolAccessor");
|
||||
if (!(this.value instanceof AST_Accessor)) throw new Error("value must be AST_Accessor");
|
||||
},
|
||||
}, AST_ObjectProperty);
|
||||
@@ -1037,7 +1154,6 @@ var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
|
||||
var AST_ObjectGetter = DEFNODE("ObjectGetter", null, {
|
||||
$documentation: "An object getter property",
|
||||
_validate: function() {
|
||||
if (!(this.key instanceof AST_SymbolAccessor)) throw new Error("key must be AST_SymbolAccessor");
|
||||
if (!(this.value instanceof AST_Accessor)) throw new Error("value must be AST_Accessor");
|
||||
},
|
||||
}, AST_ObjectProperty);
|
||||
@@ -1054,10 +1170,6 @@ var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
|
||||
},
|
||||
});
|
||||
|
||||
var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, {
|
||||
$documentation: "The name of a property accessor (setter/getter function)"
|
||||
}, AST_Symbol);
|
||||
|
||||
var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", {
|
||||
$documentation: "A declaration symbol (symbol in var, function name or argument, symbol in catch)",
|
||||
}, AST_Symbol);
|
||||
@@ -1066,6 +1178,10 @@ var AST_SymbolConst = DEFNODE("SymbolConst", null, {
|
||||
$documentation: "Symbol defining a constant",
|
||||
}, AST_SymbolDeclaration);
|
||||
|
||||
var AST_SymbolLet = DEFNODE("SymbolLet", null, {
|
||||
$documentation: "Symbol defining a lexical-scoped variable",
|
||||
}, AST_SymbolDeclaration);
|
||||
|
||||
var AST_SymbolVar = DEFNODE("SymbolVar", null, {
|
||||
$documentation: "Symbol defining a variable",
|
||||
}, AST_SymbolDeclaration);
|
||||
|
||||
1334
lib/compress.js
1334
lib/compress.js
File diff suppressed because it is too large
Load Diff
@@ -33,7 +33,9 @@ function read_source_map(name, toplevel) {
|
||||
return to_ascii(match[2]);
|
||||
}
|
||||
}
|
||||
AST_Node.warn("inline source map not found: " + name);
|
||||
AST_Node.warn("inline source map not found: {name}", {
|
||||
name: name,
|
||||
});
|
||||
}
|
||||
|
||||
function parse_source_map(content) {
|
||||
@@ -87,6 +89,7 @@ function minify(files, options) {
|
||||
toplevel: false,
|
||||
validate: false,
|
||||
warnings: false,
|
||||
webkit: false,
|
||||
wrap: false,
|
||||
}, true);
|
||||
if (options.validate) AST_Node.enable_validation();
|
||||
@@ -99,6 +102,7 @@ function minify(files, options) {
|
||||
set_shorthand("ie8", options, [ "compress", "mangle", "output" ]);
|
||||
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
|
||||
set_shorthand("toplevel", options, [ "compress", "mangle" ]);
|
||||
set_shorthand("webkit", options, [ "mangle", "output" ]);
|
||||
var quoted_props;
|
||||
if (options.mangle) {
|
||||
options.mangle = defaults(options.mangle, {
|
||||
@@ -109,6 +113,7 @@ function minify(files, options) {
|
||||
properties: false,
|
||||
reserved: [],
|
||||
toplevel: false,
|
||||
webkit: false,
|
||||
}, true);
|
||||
if (options.mangle.properties) {
|
||||
if (typeof options.mangle.properties != "object") {
|
||||
@@ -258,6 +263,7 @@ function minify(files, options) {
|
||||
} catch (ex) {
|
||||
return { error: ex };
|
||||
} finally {
|
||||
AST_Node.log_function();
|
||||
AST_Node.disable_validation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,9 +115,6 @@
|
||||
value : from_moz(M.value)
|
||||
};
|
||||
if (M.kind == "init") return new AST_ObjectKeyVal(args);
|
||||
args.key = new AST_SymbolAccessor({
|
||||
name: args.key
|
||||
});
|
||||
args.value = new AST_Accessor(args.value);
|
||||
if (M.kind == "get") return new AST_ObjectGetter(args);
|
||||
if (M.kind == "set") return new AST_ObjectSetter(args);
|
||||
@@ -385,7 +382,7 @@
|
||||
def_to_moz(AST_ObjectProperty, function To_Moz_Property(M) {
|
||||
var key = {
|
||||
type: "Literal",
|
||||
value: M.key instanceof AST_SymbolAccessor ? M.key.name : M.key
|
||||
value: M.key
|
||||
};
|
||||
var kind;
|
||||
if (M instanceof AST_ObjectKeyVal) {
|
||||
|
||||
146
lib/output.js
146
lib/output.js
@@ -56,6 +56,7 @@ function OutputStream(options) {
|
||||
beautify : false,
|
||||
braces : false,
|
||||
comments : false,
|
||||
galio : false,
|
||||
ie8 : false,
|
||||
indent_level : 4,
|
||||
indent_start : 0,
|
||||
@@ -69,6 +70,7 @@ function OutputStream(options) {
|
||||
semicolons : true,
|
||||
shebang : true,
|
||||
source_map : null,
|
||||
v8 : false,
|
||||
webkit : false,
|
||||
width : 80,
|
||||
wrap_iife : false,
|
||||
@@ -107,6 +109,9 @@ function OutputStream(options) {
|
||||
var OUTPUT = "";
|
||||
|
||||
var to_utf8 = options.ascii_only ? function(str, identifier) {
|
||||
if (identifier) str = str.replace(/[\ud800-\udbff][\udc00-\udfff]/g, function(ch) {
|
||||
return "\\u{" + (ch.charCodeAt(0) - 0xd7c0 << 10 | ch.charCodeAt(1) - 0xdc00).toString(16) + "}";
|
||||
});
|
||||
return str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(ch) {
|
||||
var code = ch.charCodeAt(0).toString(16);
|
||||
if (code.length <= 2 && !identifier) {
|
||||
@@ -496,11 +501,11 @@ function OutputStream(options) {
|
||||
}
|
||||
}
|
||||
if (/comment[134]/.test(c.type)) {
|
||||
print("//" + c.value.replace(/[@#]__PURE__/g, ' ') + "\n");
|
||||
print("//" + c.value.replace(/[@#]__PURE__/g, " ") + "\n");
|
||||
indent();
|
||||
last_nlb = true;
|
||||
} else if (c.type == "comment2") {
|
||||
print("/*" + c.value.replace(/[@#]__PURE__/g, ' ') + "*/");
|
||||
print("/*" + c.value.replace(/[@#]__PURE__/g, " ") + "*/");
|
||||
last_nlb = false;
|
||||
}
|
||||
});
|
||||
@@ -554,10 +559,10 @@ function OutputStream(options) {
|
||||
space();
|
||||
}
|
||||
if (/comment[134]/.test(c.type)) {
|
||||
print("//" + c.value.replace(/[@#]__PURE__/g, ' '));
|
||||
print("//" + c.value.replace(/[@#]__PURE__/g, " "));
|
||||
need_newline_indented = true;
|
||||
} else if (c.type == "comment2") {
|
||||
print("/*" + c.value.replace(/[@#]__PURE__/g, ' ') + "*/");
|
||||
print("/*" + c.value.replace(/[@#]__PURE__/g, " ") + "*/");
|
||||
need_space = true;
|
||||
}
|
||||
});
|
||||
@@ -607,7 +612,7 @@ function OutputStream(options) {
|
||||
},
|
||||
parent : function(n) {
|
||||
return stack[stack.length - 2 - (n || 0)];
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -649,13 +654,7 @@ function OutputStream(options) {
|
||||
/* -----[ PARENTHESES ]----- */
|
||||
|
||||
function PARENS(nodetype, func) {
|
||||
if (Array.isArray(nodetype)) {
|
||||
nodetype.forEach(function(nodetype) {
|
||||
PARENS(nodetype, func);
|
||||
});
|
||||
} else {
|
||||
nodetype.DEFMETHOD("needs_parens", func);
|
||||
}
|
||||
nodetype.DEFMETHOD("needs_parens", func);
|
||||
}
|
||||
|
||||
PARENS(AST_Node, return_false);
|
||||
@@ -664,11 +663,11 @@ function OutputStream(options) {
|
||||
// the first token to appear in a statement.
|
||||
PARENS(AST_Function, function(output) {
|
||||
if (!output.has_parens() && first_in_statement(output)) return true;
|
||||
if (output.option('webkit')) {
|
||||
if (output.option("webkit")) {
|
||||
var p = output.parent();
|
||||
if (p instanceof AST_PropAccess && p.expression === this) return true;
|
||||
}
|
||||
if (output.option('wrap_iife')) {
|
||||
if (output.option("wrap_iife")) {
|
||||
var p = output.parent();
|
||||
if (p instanceof AST_Call && p.expression === this) return true;
|
||||
}
|
||||
@@ -676,9 +675,10 @@ function OutputStream(options) {
|
||||
|
||||
// same goes for an object literal, because otherwise it would be
|
||||
// interpreted as a block of code.
|
||||
PARENS(AST_Object, function(output) {
|
||||
function needs_parens_obj(output) {
|
||||
return !output.has_parens() && first_in_statement(output);
|
||||
});
|
||||
}
|
||||
PARENS(AST_Object, needs_parens_obj);
|
||||
|
||||
PARENS(AST_Unary, function(output) {
|
||||
var p = output.parent();
|
||||
@@ -696,7 +696,9 @@ function OutputStream(options) {
|
||||
// (false, true) ? (a = 10, b = 20) : (c = 30)
|
||||
// ==> 20 (side effect, set a := 10 and b := 20)
|
||||
|| p instanceof AST_Conditional
|
||||
// { [(1, 2)]: 3 }[2] ==> 3
|
||||
// { foo: (1, 2) }.foo ==> 2
|
||||
|| p instanceof AST_DestructuredKeyVal
|
||||
|| p instanceof AST_ObjectProperty
|
||||
// (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|
||||
|| p instanceof AST_PropAccess && p.expression === this
|
||||
@@ -743,7 +745,7 @@ function OutputStream(options) {
|
||||
var p = output.parent();
|
||||
if (p instanceof AST_New) return p.expression === this;
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=123506
|
||||
if (output.option('webkit')) {
|
||||
if (output.option("webkit")) {
|
||||
var g = output.parent(1);
|
||||
return this.expression instanceof AST_Function
|
||||
&& p instanceof AST_PropAccess
|
||||
@@ -766,24 +768,36 @@ function OutputStream(options) {
|
||||
var p = output.parent();
|
||||
if (p instanceof AST_PropAccess && p.expression === this) {
|
||||
var value = this.value;
|
||||
// https://github.com/mishoo/UglifyJS/issues/115
|
||||
// https://github.com/mishoo/UglifyJS/pull/1009
|
||||
return value < 0 || /^0/.test(make_num(value));
|
||||
// https://github.com/mishoo/UglifyJS/issues/115
|
||||
return value < 0
|
||||
// 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();
|
||||
// 1 + (a = 2) + 3 → 6, side effect setting a = 2
|
||||
if (p instanceof AST_Binary) return !(p instanceof AST_Assign);
|
||||
// (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
|
||||
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
|
||||
if (p instanceof AST_PropAccess) return p.expression === this;
|
||||
if (p instanceof AST_PropAccess) return p.expression === self;
|
||||
// !(a = false) → 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 ]----- */
|
||||
@@ -990,7 +1004,7 @@ function OutputStream(options) {
|
||||
/* -----[ if ]----- */
|
||||
function make_then(self, output) {
|
||||
var b = self.body;
|
||||
if (output.option("braces") && !(b instanceof AST_Const)
|
||||
if (output.option("braces") && !(b instanceof AST_Const || b instanceof AST_Let)
|
||||
|| output.option("ie8") && b instanceof AST_Do)
|
||||
return make_block(b, output);
|
||||
// The squeezer replaces "block"-s that contain only a single
|
||||
@@ -1124,6 +1138,7 @@ function OutputStream(options) {
|
||||
};
|
||||
}
|
||||
DEFPRINT(AST_Const, print_definitinos("const"));
|
||||
DEFPRINT(AST_Let, print_definitinos("let"));
|
||||
DEFPRINT(AST_Var, print_definitinos("var"));
|
||||
|
||||
function parenthesize_for_noin(node, output, noin) {
|
||||
@@ -1269,6 +1284,38 @@ function OutputStream(options) {
|
||||
output.space();
|
||||
} : 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) {
|
||||
var props = this.properties;
|
||||
if (props.length > 0) output.with_block(function() {
|
||||
@@ -1285,34 +1332,43 @@ function OutputStream(options) {
|
||||
else print_braced_empty(this, output);
|
||||
});
|
||||
|
||||
function print_property_name(key, quote, output) {
|
||||
if (output.option("quote_keys")) {
|
||||
function print_property_key(self, output) {
|
||||
var key = self.key;
|
||||
if (key instanceof AST_Node) {
|
||||
output.with_square(function() {
|
||||
key.print(output);
|
||||
});
|
||||
} else if (output.option("quote_keys")) {
|
||||
output.print_string(key);
|
||||
} else if ("" + +key == key && key >= 0) {
|
||||
output.print(make_num(key));
|
||||
} else if (RESERVED_WORDS[key] ? !output.option("ie8") : is_identifier_string(key)) {
|
||||
if (quote && output.option("keep_quoted_props")) {
|
||||
output.print_string(key, quote);
|
||||
} else {
|
||||
output.print_name(key);
|
||||
}
|
||||
} else {
|
||||
output.print_string(key, quote);
|
||||
var quote = self.start && self.start.quote;
|
||||
if (RESERVED_WORDS[key] ? !output.option("ie8") : is_identifier_string(key)) {
|
||||
if (quote && output.option("keep_quoted_props")) {
|
||||
output.print_string(key, quote);
|
||||
} else {
|
||||
output.print_name(key);
|
||||
}
|
||||
} else {
|
||||
output.print_string(key, quote);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEFPRINT(AST_ObjectKeyVal, function(output) {
|
||||
function print_key_value(output) {
|
||||
var self = this;
|
||||
print_property_name(self.key, self.quote, output);
|
||||
print_property_key(self, output);
|
||||
output.colon();
|
||||
self.value.print(output);
|
||||
});
|
||||
}
|
||||
DEFPRINT(AST_ObjectKeyVal, print_key_value);
|
||||
function print_accessor(type) {
|
||||
return function(output) {
|
||||
var self = this;
|
||||
output.print(type);
|
||||
output.space();
|
||||
print_property_name(self.key.name, self.quote, output);
|
||||
print_property_key(self, output);
|
||||
self.value._codegen(output, true);
|
||||
};
|
||||
}
|
||||
@@ -1381,7 +1437,7 @@ function OutputStream(options) {
|
||||
});
|
||||
|
||||
function force_statement(stat, output) {
|
||||
if (output.option("braces") && !(stat instanceof AST_Const)) {
|
||||
if (output.option("braces") && !(stat instanceof AST_Const || stat instanceof AST_Let)) {
|
||||
make_block(stat, output);
|
||||
} else if (!stat || stat instanceof AST_EmptyStatement) {
|
||||
output.force_semicolon();
|
||||
@@ -1470,6 +1526,7 @@ function OutputStream(options) {
|
||||
AST_Constant,
|
||||
AST_Debugger,
|
||||
AST_Definitions,
|
||||
AST_Destructured,
|
||||
AST_Finally,
|
||||
AST_Jump,
|
||||
AST_Lambda,
|
||||
@@ -1484,14 +1541,7 @@ function OutputStream(options) {
|
||||
output.add_mapping(this.start);
|
||||
});
|
||||
|
||||
DEFMAP([
|
||||
AST_ObjectGetter,
|
||||
AST_ObjectSetter,
|
||||
], function(output) {
|
||||
output.add_mapping(this.start, this.key.name);
|
||||
});
|
||||
|
||||
DEFMAP([ AST_ObjectProperty ], function(output) {
|
||||
output.add_mapping(this.start, this.key);
|
||||
DEFMAP([ AST_DestructuredKeyVal, AST_ObjectProperty ], function(output) {
|
||||
if (typeof this.key == "string") output.add_mapping(this.start, this.key);
|
||||
});
|
||||
})();
|
||||
|
||||
341
lib/parse.js
341
lib/parse.js
@@ -44,7 +44,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
var KEYWORDS = "break case catch const continue debugger default delete do else finally for function if in instanceof new return switch throw try typeof var void while with";
|
||||
var KEYWORDS = "break case catch const continue debugger default delete do else finally for function if in instanceof let new return switch throw try typeof var void while with";
|
||||
var KEYWORDS_ATOM = "false null true";
|
||||
var RESERVED_WORDS = [
|
||||
"abstract boolean byte char class double enum export extends final float goto implements import int interface let long native package private protected public short static super synchronized this throws transient volatile yield",
|
||||
@@ -58,8 +58,6 @@ RESERVED_WORDS = makePredicate(RESERVED_WORDS);
|
||||
KEYWORDS_BEFORE_EXPRESSION = makePredicate(KEYWORDS_BEFORE_EXPRESSION);
|
||||
KEYWORDS_ATOM = makePredicate(KEYWORDS_ATOM);
|
||||
|
||||
var OPERATOR_CHARS = makePredicate(characters("+-*&%=<>!?|~^"));
|
||||
|
||||
var RE_BIN_NUMBER = /^0b([01]+)$/i;
|
||||
var RE_HEX_NUMBER = /^0x([0-9a-f]+)$/i;
|
||||
var RE_OCT_NUMBER = /^0o?([0-7]+)$/i;
|
||||
@@ -111,31 +109,21 @@ var OPERATORS = makePredicate([
|
||||
"||"
|
||||
]);
|
||||
|
||||
var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000\uFEFF"));
|
||||
var NEWLINE_CHARS = "\n\r\u2028\u2029";
|
||||
var OPERATOR_CHARS = "+-*&%=<>!?|~^";
|
||||
var PUNC_BEFORE_EXPRESSION = "[{(,;:";
|
||||
var PUNC_CHARS = PUNC_BEFORE_EXPRESSION + ")}]";
|
||||
var WHITESPACE_CHARS = NEWLINE_CHARS + " \u00a0\t\f\u000b\u200b\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\uFEFF";
|
||||
var NON_IDENTIFIER_CHARS = makePredicate(characters("./'\"" + OPERATOR_CHARS + PUNC_CHARS + WHITESPACE_CHARS));
|
||||
|
||||
var NEWLINE_CHARS = makePredicate(characters("\n\r\u2028\u2029"));
|
||||
|
||||
var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,;:"));
|
||||
|
||||
var PUNC_CHARS = makePredicate(characters("[]{}(),;:"));
|
||||
NEWLINE_CHARS = makePredicate(characters(NEWLINE_CHARS));
|
||||
OPERATOR_CHARS = makePredicate(characters(OPERATOR_CHARS));
|
||||
PUNC_BEFORE_EXPRESSION = makePredicate(characters(PUNC_BEFORE_EXPRESSION));
|
||||
PUNC_CHARS = makePredicate(characters(PUNC_CHARS));
|
||||
WHITESPACE_CHARS = makePredicate(characters(WHITESPACE_CHARS));
|
||||
|
||||
/* -----[ Tokenizer ]----- */
|
||||
|
||||
// regexps adapted from http://xregexp.com/plugins/#unicode
|
||||
var UNICODE = {
|
||||
letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u037F\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u052F\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0620-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u08A0-\\u08B2\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0980\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0CF1\\u0CF2\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16EE-\\u16F8\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191E\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1CE9-\\u1CEC\\u1CEE-\\u1CF1\\u1CF5\\u1CF6\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2160-\\u2188\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005-\\u3007\\u3021-\\u3029\\u3031-\\u3035\\u3038-\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31BA\\u31F0-\\u31FF\\u3400-\\u4DB5\\u4E00-\\u9FCC\\uA000-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA66E\\uA67F-\\uA69D\\uA6A0-\\uA6EF\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA78E\\uA790-\\uA7AD\\uA7B0\\uA7B1\\uA7F7-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uA9E0-\\uA9E4\\uA9E6-\\uA9EF\\uA9FA-\\uA9FE\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA7E-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB30-\\uAB5A\\uAB5C-\\uAB5F\\uAB64\\uAB65\\uABC0-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"),
|
||||
digit: new RegExp("[\\u0030-\\u0039\\u0660-\\u0669\\u06F0-\\u06F9\\u07C0-\\u07C9\\u0966-\\u096F\\u09E6-\\u09EF\\u0A66-\\u0A6F\\u0AE6-\\u0AEF\\u0B66-\\u0B6F\\u0BE6-\\u0BEF\\u0C66-\\u0C6F\\u0CE6-\\u0CEF\\u0D66-\\u0D6F\\u0DE6-\\u0DEF\\u0E50-\\u0E59\\u0ED0-\\u0ED9\\u0F20-\\u0F29\\u1040-\\u1049\\u1090-\\u1099\\u17E0-\\u17E9\\u1810-\\u1819\\u1946-\\u194F\\u19D0-\\u19D9\\u1A80-\\u1A89\\u1A90-\\u1A99\\u1B50-\\u1B59\\u1BB0-\\u1BB9\\u1C40-\\u1C49\\u1C50-\\u1C59\\uA620-\\uA629\\uA8D0-\\uA8D9\\uA900-\\uA909\\uA9D0-\\uA9D9\\uA9F0-\\uA9F9\\uAA50-\\uAA59\\uABF0-\\uABF9\\uFF10-\\uFF19]"),
|
||||
non_spacing_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065E\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0900-\\u0902\\u093C\\u0941-\\u0948\\u094D\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09BC\\u09C1-\\u09C4\\u09CD\\u09E2\\u09E3\\u0A01\\u0A02\\u0A3C\\u0A41\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81\\u0A82\\u0ABC\\u0AC1-\\u0AC5\\u0AC7\\u0AC8\\u0ACD\\u0AE2\\u0AE3\\u0B01\\u0B3C\\u0B3F\\u0B41-\\u0B44\\u0B4D\\u0B56\\u0B62\\u0B63\\u0B82\\u0BC0\\u0BCD\\u0C3E-\\u0C40\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0CBC\\u0CBF\\u0CC6\\u0CCC\\u0CCD\\u0CE2\\u0CE3\\u0D41-\\u0D44\\u0D4D\\u0D62\\u0D63\\u0DCA\\u0DD2-\\u0DD4\\u0DD6\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F71-\\u0F7E\\u0F80-\\u0F84\\u0F86\\u0F87\\u0F90-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102D-\\u1030\\u1032-\\u1037\\u1039\\u103A\\u103D\\u103E\\u1058\\u1059\\u105E-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108D\\u109D\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B7-\\u17BD\\u17C6\\u17C9-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193B\\u1A17\\u1A18\\u1A56\\u1A58-\\u1A5E\\u1A60\\u1A62\\u1A65-\\u1A6C\\u1A73-\\u1A7C\\u1A7F\\u1B00-\\u1B03\\u1B34\\u1B36-\\u1B3A\\u1B3C\\u1B42\\u1B6B-\\u1B73\\u1B80\\u1B81\\u1BA2-\\u1BA5\\u1BA8\\u1BA9\\u1C2C-\\u1C33\\u1C36\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE0\\u1CE2-\\u1CE8\\u1CED\\u1DC0-\\u1DE6\\u1DFD-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA67C\\uA67D\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA825\\uA826\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA951\\uA980-\\uA982\\uA9B3\\uA9B6-\\uA9B9\\uA9BC\\uAA29-\\uAA2E\\uAA31\\uAA32\\uAA35\\uAA36\\uAA43\\uAA4C\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uABE5\\uABE8\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"),
|
||||
space_combining_mark: new RegExp("[\\u0903\\u093E-\\u0940\\u0949-\\u094C\\u094E\\u0982\\u0983\\u09BE-\\u09C0\\u09C7\\u09C8\\u09CB\\u09CC\\u09D7\\u0A03\\u0A3E-\\u0A40\\u0A83\\u0ABE-\\u0AC0\\u0AC9\\u0ACB\\u0ACC\\u0B02\\u0B03\\u0B3E\\u0B40\\u0B47\\u0B48\\u0B4B\\u0B4C\\u0B57\\u0BBE\\u0BBF\\u0BC1\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCC\\u0BD7\\u0C01-\\u0C03\\u0C41-\\u0C44\\u0C82\\u0C83\\u0CBE\\u0CC0-\\u0CC4\\u0CC7\\u0CC8\\u0CCA\\u0CCB\\u0CD5\\u0CD6\\u0D02\\u0D03\\u0D3E-\\u0D40\\u0D46-\\u0D48\\u0D4A-\\u0D4C\\u0D57\\u0D82\\u0D83\\u0DCF-\\u0DD1\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0F3E\\u0F3F\\u0F7F\\u102B\\u102C\\u1031\\u1038\\u103B\\u103C\\u1056\\u1057\\u1062-\\u1064\\u1067-\\u106D\\u1083\\u1084\\u1087-\\u108C\\u108F\\u109A-\\u109C\\u17B6\\u17BE-\\u17C5\\u17C7\\u17C8\\u1923-\\u1926\\u1929-\\u192B\\u1930\\u1931\\u1933-\\u1938\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A19-\\u1A1B\\u1A55\\u1A57\\u1A61\\u1A63\\u1A64\\u1A6D-\\u1A72\\u1B04\\u1B35\\u1B3B\\u1B3D-\\u1B41\\u1B43\\u1B44\\u1B82\\u1BA1\\u1BA6\\u1BA7\\u1BAA\\u1C24-\\u1C2B\\u1C34\\u1C35\\u1CE1\\u1CF2\\uA823\\uA824\\uA827\\uA880\\uA881\\uA8B4-\\uA8C3\\uA952\\uA953\\uA983\\uA9B4\\uA9B5\\uA9BA\\uA9BB\\uA9BD-\\uA9C0\\uAA2F\\uAA30\\uAA33\\uAA34\\uAA4D\\uAA7B\\uABE3\\uABE4\\uABE6\\uABE7\\uABE9\\uABEA\\uABEC]"),
|
||||
connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]")
|
||||
};
|
||||
|
||||
function is_letter(code) {
|
||||
return (code >= 97 && code <= 122)
|
||||
|| (code >= 65 && code <= 90)
|
||||
|| (code >= 0xaa && UNICODE.letter.test(String.fromCharCode(code)));
|
||||
}
|
||||
|
||||
function is_surrogate_pair_head(code) {
|
||||
return code >= 0xd800 && code <= 0xdbff;
|
||||
}
|
||||
@@ -148,32 +136,8 @@ function is_digit(code) {
|
||||
return code >= 48 && code <= 57;
|
||||
}
|
||||
|
||||
function is_unicode_digit(code) {
|
||||
return UNICODE.digit.test(String.fromCharCode(code));
|
||||
}
|
||||
|
||||
function is_unicode_combining_mark(ch) {
|
||||
return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch);
|
||||
}
|
||||
|
||||
function is_unicode_connector_punctuation(ch) {
|
||||
return UNICODE.connector_punctuation.test(ch);
|
||||
}
|
||||
|
||||
function is_identifier_start(code) {
|
||||
return code == 36 || code == 95 || is_letter(code);
|
||||
}
|
||||
|
||||
function is_identifier_char(ch) {
|
||||
var code = ch.charCodeAt(0);
|
||||
return is_identifier_start(code)
|
||||
|| is_digit(code)
|
||||
|| code == 8204 // \u200c: zero-width non-joiner <ZWNJ>
|
||||
|| code == 8205 // \u200d: zero-width joiner <ZWJ> (in my ECMA-262 PDF, this is also 200c)
|
||||
|| is_unicode_combining_mark(ch)
|
||||
|| is_unicode_connector_punctuation(ch)
|
||||
|| is_unicode_digit(code)
|
||||
;
|
||||
return !NON_IDENTIFIER_CHARS[ch];
|
||||
}
|
||||
|
||||
function is_identifier_string(str) {
|
||||
@@ -342,7 +306,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
case (after_e = false, 46): // .
|
||||
return (!has_dot && !has_x && !has_e) ? (has_dot = true) : false;
|
||||
}
|
||||
return is_digit(code) || is_letter(code) || ch == "_";
|
||||
return is_digit(code) || /[_0-9a-fo]/i.test(ch);
|
||||
});
|
||||
if (prefix) num = prefix + num;
|
||||
if (/^0[0-7_]+$/.test(num)) {
|
||||
@@ -358,20 +322,30 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
function read_escaped_char(in_string) {
|
||||
var ch = next(true, in_string);
|
||||
switch (ch.charCodeAt(0)) {
|
||||
case 110 : return "\n";
|
||||
case 114 : return "\r";
|
||||
case 116 : return "\t";
|
||||
case 98 : return "\b";
|
||||
case 118 : return "\u000b"; // \v
|
||||
case 102 : return "\f";
|
||||
case 120 : return String.fromCharCode(hex_bytes(2)); // \x
|
||||
case 117 : return String.fromCharCode(hex_bytes(4)); // \u
|
||||
case 10 : return ""; // newline
|
||||
case 13 : // \r
|
||||
if (peek() == "\n") { // DOS newline
|
||||
next(true, in_string);
|
||||
return "";
|
||||
}
|
||||
case 110: return "\n";
|
||||
case 114: return "\r";
|
||||
case 116: return "\t";
|
||||
case 98: return "\b";
|
||||
case 118: return "\u000b"; // \v
|
||||
case 102: return "\f";
|
||||
case 120: return String.fromCharCode(hex_bytes(2)); // \x
|
||||
case 117: // \u
|
||||
if (peek() != "{") return String.fromCharCode(hex_bytes(4));
|
||||
next();
|
||||
var num = 0;
|
||||
do {
|
||||
var digit = parseInt(next(true), 16);
|
||||
if (isNaN(digit)) parse_error("Invalid hex-character pattern in string");
|
||||
num = num * 16 + digit;
|
||||
} while (peek() != "}");
|
||||
next();
|
||||
if (num < 0x10000) return String.fromCharCode(num);
|
||||
if (num > 0x10ffff) parse_error("Invalid character code: " + num);
|
||||
return String.fromCharCode((num >> 10) + 0xd7c0) + String.fromCharCode((num & 0x03ff) + 0xdc00);
|
||||
case 13: // \r
|
||||
// DOS newline
|
||||
if (peek() == "\n") next(true, in_string);
|
||||
case 10: return ""; // \n
|
||||
}
|
||||
if (ch >= "0" && ch <= "7")
|
||||
return read_octal_escape_sequence(ch);
|
||||
@@ -448,7 +422,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
|
||||
function read_name() {
|
||||
var backslash = false, name = "", ch, escaped = false, hex;
|
||||
while ((ch = peek()) != null) {
|
||||
while (ch = peek()) {
|
||||
if (!backslash) {
|
||||
if (ch == "\\") escaped = backslash = true, next();
|
||||
else if (is_identifier_char(ch)) name += next();
|
||||
@@ -587,7 +561,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
if (is_digit(code)) return read_num();
|
||||
if (PUNC_CHARS[ch]) return token("punc", next());
|
||||
if (OPERATOR_CHARS[ch]) return read_operator();
|
||||
if (code == 92 || is_identifier_start(code)) return read_word();
|
||||
if (code == 92 || !NON_IDENTIFIER_CHARS[ch]) return read_word();
|
||||
break;
|
||||
}
|
||||
parse_error("Unexpected character '" + ch + "'");
|
||||
@@ -779,7 +753,7 @@ function parse($TEXT, options) {
|
||||
}
|
||||
}
|
||||
|
||||
var statement = embed_tokens(function(strict_defun) {
|
||||
var statement = embed_tokens(function() {
|
||||
handle_regexp();
|
||||
switch (S.token.type) {
|
||||
case "string":
|
||||
@@ -870,9 +844,6 @@ function parse($TEXT, options) {
|
||||
return for_();
|
||||
|
||||
case "function":
|
||||
if (!strict_defun && S.input.has_directive("use strict")) {
|
||||
croak("In strict mode code, functions can only be declared at top level or immediately within another function.");
|
||||
}
|
||||
next();
|
||||
return function_(AST_Defun);
|
||||
|
||||
@@ -880,6 +851,12 @@ function parse($TEXT, options) {
|
||||
next();
|
||||
return if_();
|
||||
|
||||
case "let":
|
||||
next();
|
||||
var node = let_();
|
||||
semicolon();
|
||||
return node;
|
||||
|
||||
case "return":
|
||||
if (S.in_function == 0 && !options.bare_returns)
|
||||
croak("'return' outside of function");
|
||||
@@ -996,14 +973,16 @@ function parse($TEXT, options) {
|
||||
if (!is("punc", ";")) {
|
||||
init = is("keyword", "const")
|
||||
? (next(), const_(true))
|
||||
: is("keyword", "let")
|
||||
? (next(), let_(true))
|
||||
: is("keyword", "var")
|
||||
? (next(), var_(true))
|
||||
: expression(true, true);
|
||||
if (is("operator", "in")) {
|
||||
if (init instanceof AST_Var) {
|
||||
if (init instanceof AST_Definitions) {
|
||||
if (init.definitions.length > 1)
|
||||
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);
|
||||
}
|
||||
next();
|
||||
@@ -1048,7 +1027,7 @@ function parse($TEXT, options) {
|
||||
var argnames = [];
|
||||
for (var first = true; !is("punc", ")");) {
|
||||
if (first) first = false; else expect(",");
|
||||
argnames.push(as_symbol(AST_SymbolFunarg));
|
||||
argnames.push(maybe_destructured(AST_SymbolFunarg));
|
||||
}
|
||||
next();
|
||||
var loop = S.in_loop;
|
||||
@@ -1058,7 +1037,7 @@ function parse($TEXT, options) {
|
||||
S.input.push_directives_stack();
|
||||
S.in_loop = 0;
|
||||
S.labels = [];
|
||||
var body = block_(true);
|
||||
var body = block_();
|
||||
if (S.input.has_directive("use strict")) {
|
||||
if (name) strict_verify_symbol(name);
|
||||
argnames.forEach(strict_verify_symbol);
|
||||
@@ -1087,12 +1066,12 @@ function parse($TEXT, options) {
|
||||
});
|
||||
}
|
||||
|
||||
function block_(strict_defun) {
|
||||
function block_() {
|
||||
expect("{");
|
||||
var a = [];
|
||||
while (!is("punc", "}")) {
|
||||
if (is("eof")) expect_token("punc", "}");
|
||||
a.push(statement(strict_defun));
|
||||
a.push(statement());
|
||||
}
|
||||
next();
|
||||
return a;
|
||||
@@ -1169,16 +1148,16 @@ function parse($TEXT, options) {
|
||||
});
|
||||
}
|
||||
|
||||
function vardefs(type, no_in, must_init) {
|
||||
function vardefs(type, no_in) {
|
||||
var a = [];
|
||||
for (;;) {
|
||||
var start = S.token;
|
||||
var name = as_symbol(type);
|
||||
var name = maybe_destructured(type);
|
||||
var value = null;
|
||||
if (is("operator", "=")) {
|
||||
next();
|
||||
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");
|
||||
}
|
||||
a.push(new AST_VarDef({
|
||||
@@ -1197,7 +1176,15 @@ function parse($TEXT, options) {
|
||||
var const_ = function(no_in) {
|
||||
return new AST_Const({
|
||||
start : prev(),
|
||||
definitions : vardefs(AST_SymbolConst, no_in, true),
|
||||
definitions : vardefs(AST_SymbolConst, no_in),
|
||||
end : prev()
|
||||
});
|
||||
};
|
||||
|
||||
var let_ = function(no_in) {
|
||||
return new AST_Let({
|
||||
start : prev(),
|
||||
definitions : vardefs(AST_SymbolLet, no_in),
|
||||
end : prev()
|
||||
});
|
||||
};
|
||||
@@ -1234,7 +1221,7 @@ function parse($TEXT, options) {
|
||||
var tok = S.token, ret;
|
||||
switch (tok.type) {
|
||||
case "name":
|
||||
ret = _make_symbol(AST_SymbolRef);
|
||||
ret = _make_symbol(AST_SymbolRef, tok);
|
||||
break;
|
||||
case "num":
|
||||
ret = new AST_Number({ start: tok, end: tok, value: tok.value });
|
||||
@@ -1321,7 +1308,8 @@ function parse($TEXT, options) {
|
||||
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 = [];
|
||||
while (!is("punc", closing)) {
|
||||
if (first) first = false; else expect(",");
|
||||
@@ -1329,7 +1317,7 @@ function parse($TEXT, options) {
|
||||
if (is("punc", ",") && allow_empty) {
|
||||
a.push(new AST_Hole({ start: S.token, end: S.token }));
|
||||
} else {
|
||||
a.push(expression(false));
|
||||
a.push(parser());
|
||||
}
|
||||
}
|
||||
next();
|
||||
@@ -1352,51 +1340,62 @@ function parse($TEXT, options) {
|
||||
var first = true, a = [];
|
||||
while (!is("punc", "}")) {
|
||||
if (first) first = false; else expect(",");
|
||||
if (!options.strict && is("punc", "}"))
|
||||
// allow trailing comma
|
||||
break;
|
||||
// allow trailing comma
|
||||
if (!options.strict && is("punc", "}")) break;
|
||||
var start = S.token;
|
||||
var type = start.type;
|
||||
var name = as_property_name();
|
||||
if (type == "name" && !is("punc", ":")) {
|
||||
var key = new AST_SymbolAccessor({
|
||||
start: S.token,
|
||||
name: "" + as_property_name(),
|
||||
end: prev()
|
||||
});
|
||||
if (name == "get") {
|
||||
a.push(new AST_ObjectGetter({
|
||||
start : start,
|
||||
key : key,
|
||||
value : create_accessor(),
|
||||
end : prev()
|
||||
}));
|
||||
continue;
|
||||
}
|
||||
if (name == "set") {
|
||||
a.push(new AST_ObjectSetter({
|
||||
start : start,
|
||||
key : key,
|
||||
value : create_accessor(),
|
||||
end : prev()
|
||||
}));
|
||||
continue;
|
||||
}
|
||||
var key = as_property_key();
|
||||
if (is("punc", "(")) {
|
||||
var func_start = S.token;
|
||||
var func = function_(AST_Function);
|
||||
func.start = func_start;
|
||||
func.end = prev();
|
||||
a.push(new AST_ObjectKeyVal({
|
||||
start: start,
|
||||
key: key,
|
||||
value: func,
|
||||
end: prev(),
|
||||
}));
|
||||
continue;
|
||||
}
|
||||
if (!is("punc", ":") && start.type == "name") switch (key) {
|
||||
case "get":
|
||||
a.push(new AST_ObjectGetter({
|
||||
start: start,
|
||||
key: as_property_key(),
|
||||
value: create_accessor(),
|
||||
end: prev(),
|
||||
}));
|
||||
continue;
|
||||
case "set":
|
||||
a.push(new AST_ObjectSetter({
|
||||
start: start,
|
||||
key: as_property_key(),
|
||||
value: create_accessor(),
|
||||
end: prev(),
|
||||
}));
|
||||
continue;
|
||||
default:
|
||||
a.push(new AST_ObjectKeyVal({
|
||||
start: start,
|
||||
key: key,
|
||||
value: _make_symbol(AST_SymbolRef, start),
|
||||
end: prev(),
|
||||
}));
|
||||
continue;
|
||||
}
|
||||
expect(":");
|
||||
a.push(new AST_ObjectKeyVal({
|
||||
start : start,
|
||||
quote : start.quote,
|
||||
key : "" + name,
|
||||
value : expression(false),
|
||||
end : prev()
|
||||
start: start,
|
||||
key: key,
|
||||
value: expression(false),
|
||||
end: prev(),
|
||||
}));
|
||||
}
|
||||
next();
|
||||
return new AST_Object({ properties: a });
|
||||
});
|
||||
|
||||
function as_property_name() {
|
||||
function as_property_key() {
|
||||
var tmp = S.token;
|
||||
switch (tmp.type) {
|
||||
case "operator":
|
||||
@@ -1407,7 +1406,13 @@ function parse($TEXT, options) {
|
||||
case "keyword":
|
||||
case "atom":
|
||||
next();
|
||||
return tmp.value;
|
||||
return "" + tmp.value;
|
||||
case "punc":
|
||||
if (tmp.value != "[") unexpected();
|
||||
next();
|
||||
var key = expression(false);
|
||||
expect("]");
|
||||
return key;
|
||||
default:
|
||||
unexpected();
|
||||
}
|
||||
@@ -1420,12 +1425,12 @@ function parse($TEXT, options) {
|
||||
return name;
|
||||
}
|
||||
|
||||
function _make_symbol(type) {
|
||||
var name = S.token.value;
|
||||
return new (name == "this" ? AST_This : type)({
|
||||
name : String(name),
|
||||
start : S.token,
|
||||
end : S.token
|
||||
function _make_symbol(type, token) {
|
||||
var name = token.value;
|
||||
return new (name === "this" ? AST_This : type)({
|
||||
name: "" + name,
|
||||
start: token,
|
||||
end: token,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1439,7 +1444,7 @@ function parse($TEXT, options) {
|
||||
if (!noerror) croak("Name expected");
|
||||
return null;
|
||||
}
|
||||
var sym = _make_symbol(type);
|
||||
var sym = _make_symbol(type, S.token);
|
||||
if (S.input.has_directive("use strict") && sym instanceof AST_SymbolDeclaration) {
|
||||
strict_verify_symbol(sym);
|
||||
}
|
||||
@@ -1447,6 +1452,54 @@ function parse($TEXT, options) {
|
||||
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) {
|
||||
var start = call.start;
|
||||
var comments = start.comments_before;
|
||||
@@ -1576,11 +1629,43 @@ function parse($TEXT, options) {
|
||||
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 start = S.token;
|
||||
var left = maybe_conditional(no_in), val = S.token.value;
|
||||
if (is("operator") && ASSIGNMENT[val]) {
|
||||
if (is_assignable(left)) {
|
||||
if (is_assignable(left) || val == "=" && (left = to_destructured(left)) instanceof AST_Destructured) {
|
||||
next();
|
||||
return new AST_Assign({
|
||||
start : start,
|
||||
@@ -1628,7 +1713,7 @@ function parse($TEXT, options) {
|
||||
var body = [];
|
||||
S.input.push_directives_stack();
|
||||
while (!is("eof"))
|
||||
body.push(statement(true));
|
||||
body.push(statement());
|
||||
S.input.pop_directives_stack();
|
||||
var end = prev();
|
||||
var toplevel = options.toplevel;
|
||||
|
||||
@@ -81,8 +81,8 @@ var builtins = function() {
|
||||
|
||||
function reserve_quoted_keys(ast, reserved) {
|
||||
ast.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_ObjectKeyVal) {
|
||||
if (node.quote) add(node.key);
|
||||
if (node instanceof AST_ObjectProperty) {
|
||||
if (node.start && node.start.quote) add(node.key);
|
||||
} else if (node instanceof AST_Sub) {
|
||||
addStrings(node.property, add);
|
||||
}
|
||||
@@ -165,11 +165,8 @@ function mangle_properties(ast, options) {
|
||||
}
|
||||
} else if (node instanceof AST_Dot) {
|
||||
add(node.property);
|
||||
} else if (node instanceof AST_ObjectKeyVal) {
|
||||
add(node.key);
|
||||
} else if (node instanceof AST_ObjectProperty) {
|
||||
// setter or getter, since KeyVal is handled above
|
||||
add(node.key.name);
|
||||
if (typeof node.key == "string") add(node.key);
|
||||
} else if (node instanceof AST_Sub) {
|
||||
addStrings(node.property, add);
|
||||
}
|
||||
@@ -198,11 +195,8 @@ function mangle_properties(ast, options) {
|
||||
}
|
||||
} else if (node instanceof AST_Dot) {
|
||||
node.property = mangle(node.property);
|
||||
} else if (node instanceof AST_ObjectKeyVal) {
|
||||
node.key = mangle(node.key);
|
||||
} else if (node instanceof AST_ObjectProperty) {
|
||||
// setter or getter
|
||||
node.key.name = mangle(node.key.name);
|
||||
if (typeof node.key == "string") node.key = mangle(node.key);
|
||||
} else if (node instanceof AST_Sub) {
|
||||
if (!options.keep_quoted) mangleStrings(node.property);
|
||||
}
|
||||
|
||||
72
lib/scope.js
72
lib/scope.js
@@ -72,7 +72,7 @@ SymbolDef.prototype = {
|
||||
if (def) {
|
||||
this.mangled_name = def.mangled_name || def.name;
|
||||
} else {
|
||||
this.mangled_name = next_mangled_name(this.scope, options, this);
|
||||
this.mangled_name = next_mangled_name(this, options);
|
||||
}
|
||||
if (this.global && cache) {
|
||||
cache.set(this.name, this.mangled_name);
|
||||
@@ -169,6 +169,8 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
} else if (node instanceof AST_SymbolLambda) {
|
||||
var def = defun.def_function(node, node.name == "arguments" ? undefined : defun);
|
||||
if (options.ie8) def.defun = defun.parent_scope.resolve();
|
||||
} else if (node instanceof AST_SymbolLet) {
|
||||
scope.def_variable(node);
|
||||
} else if (node instanceof AST_SymbolVar) {
|
||||
defun.def_variable(node, null);
|
||||
entangle(defun, scope);
|
||||
@@ -202,7 +204,17 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
|
||||
// pass 2: find back references and eval
|
||||
self.globals = new Dictionary();
|
||||
var in_arg = [];
|
||||
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.label) node.label.thedef.references.push(node);
|
||||
return true;
|
||||
@@ -210,10 +222,24 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
if (node instanceof AST_SymbolRef) {
|
||||
var name = node.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) {
|
||||
sym = self.def_global(node);
|
||||
} 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") {
|
||||
var parent = tw.parent();
|
||||
@@ -275,6 +301,9 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
function redefine(node, scope) {
|
||||
var name = node.name;
|
||||
var old_def = node.thedef;
|
||||
if (!all(old_def.orig, function(sym) {
|
||||
return !(sym instanceof AST_SymbolConst || sym instanceof AST_SymbolLet);
|
||||
})) return;
|
||||
var new_def = scope.find_variable(name);
|
||||
if (new_def) {
|
||||
var redef = new_def.redefined();
|
||||
@@ -403,7 +432,8 @@ function names_in_use(scope, options) {
|
||||
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 holes = scope.cname_holes;
|
||||
var names = Object.create(null);
|
||||
@@ -456,6 +486,7 @@ function _default_mangler_options(options) {
|
||||
keep_fnames : false,
|
||||
reserved : [],
|
||||
toplevel : false,
|
||||
webkit : false,
|
||||
});
|
||||
if (!Array.isArray(options.reserved)) options.reserved = [];
|
||||
// Never mangle arguments
|
||||
@@ -490,9 +521,24 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
||||
return true;
|
||||
}
|
||||
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) {
|
||||
if (!defer_redef(def)) to_mangle.push(def);
|
||||
if (!defer_redef(def)) node.to_mangle.push(def);
|
||||
});
|
||||
descend();
|
||||
if (options.cache && node instanceof AST_Toplevel) {
|
||||
@@ -503,7 +549,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
||||
sym.scope = node;
|
||||
sym.reference(options);
|
||||
}
|
||||
to_mangle.forEach(mangle);
|
||||
node.to_mangle.forEach(mangle);
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Label) {
|
||||
@@ -523,13 +569,19 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
||||
def.mangle(options);
|
||||
}
|
||||
|
||||
function defer_redef(def, node) {
|
||||
function defer_redef(def) {
|
||||
var sym = def.orig[0];
|
||||
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);
|
||||
def.references.forEach(reference);
|
||||
var node = def.orig[0];
|
||||
if (node instanceof AST_SymbolCatch || node instanceof AST_SymbolConst) reference(node);
|
||||
if (sym instanceof AST_SymbolCatch || sym instanceof AST_SymbolConst) reference(sym);
|
||||
return true;
|
||||
|
||||
function reference(sym) {
|
||||
|
||||
@@ -160,10 +160,21 @@ TreeTransformer.prototype = new TreeWalker;
|
||||
DEF(AST_Array, function(self, 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) {
|
||||
self.properties = do_list(self.properties, tw);
|
||||
});
|
||||
DEF(AST_ObjectProperty, function(self, tw) {
|
||||
if (self.key instanceof AST_Node) self.key = self.key.transform(tw);
|
||||
self.value = self.value.transform(tw);
|
||||
});
|
||||
})(function(node, descend) {
|
||||
|
||||
@@ -143,8 +143,9 @@ function push_uniq(array, el) {
|
||||
}
|
||||
|
||||
function string_template(text, props) {
|
||||
return text.replace(/\{(.+?)\}/g, function(str, p) {
|
||||
return props && props[p];
|
||||
return text.replace(/\{([^}]+)\}/g, function(str, p) {
|
||||
var value = props[p];
|
||||
return value instanceof AST_Node ? value.print_to_string() : value;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||
"license": "BSD-2-Clause",
|
||||
"version": "3.11.3",
|
||||
"version": "3.12.0",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
|
||||
@@ -63,7 +63,6 @@ function make_code(ast, options) {
|
||||
|
||||
function parse_test(file) {
|
||||
var script = fs.readFileSync(file, "utf8");
|
||||
// TODO try/catch can be removed after fixing https://github.com/mishoo/UglifyJS/issues/348
|
||||
try {
|
||||
var ast = U.parse(script, {
|
||||
filename: file
|
||||
@@ -315,6 +314,7 @@ function test_case(test) {
|
||||
if (test.mangle.properties) U.mangle_properties(output, test.mangle.properties);
|
||||
}
|
||||
var output_code = make_code(output, output_options);
|
||||
U.AST_Node.log_function();
|
||||
if (expect != output_code) {
|
||||
log([
|
||||
"!!! failed",
|
||||
@@ -386,7 +386,7 @@ function test_case(test) {
|
||||
mangle: test.mangle
|
||||
});
|
||||
var actual = stdout[toplevel ? 1 : 0];
|
||||
if (test.expect_stdout === true) {
|
||||
if (test.expect_stdout === true || test.expect_stdout instanceof Error && test.expect_stdout.name === actual.name) {
|
||||
test.expect_stdout = actual;
|
||||
}
|
||||
if (!sandbox.same_stdout(test.expect_stdout, actual)) {
|
||||
|
||||
@@ -807,3 +807,47 @@ issue_4200: {
|
||||
}
|
||||
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,35 +0,0 @@
|
||||
ascii_only_true: {
|
||||
options = {}
|
||||
beautify = {
|
||||
ascii_only : true,
|
||||
ie8 : false,
|
||||
beautify : false,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
return "\x000\x001\x007\x008\x00" +
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" +
|
||||
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
|
||||
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
|
||||
}
|
||||
}
|
||||
expect_exact: 'function f(){return"\\x000\\x001\\x007\\x008\\0"+"\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\b\\t\\n\\v\\f\\r\\x0e\\x0f"+"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f"+\' !"# ... }~\\x7f\\x80\\x81 ... \\xfe\\xff\\u0fff\\uffff\'}'
|
||||
}
|
||||
|
||||
ascii_only_false: {
|
||||
options = {}
|
||||
beautify = {
|
||||
ascii_only : false,
|
||||
ie8 : false,
|
||||
beautify : false,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
return "\x000\x001\x007\x008\x00" +
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" +
|
||||
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
|
||||
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
|
||||
}
|
||||
}
|
||||
expect_exact: 'function f(){return"\\x000\\x001\\x007\\x008\\0"+"\\0\x01\x02\x03\x04\x05\x06\x07\\b\\t\\n\\v\\f\\r\x0e\x0f"+"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"+\' !"# ... }~\x7f\x80\x81 ... \xfe\xff\u0fff\uffff\'}'
|
||||
}
|
||||
@@ -8556,3 +8556,49 @@ issue_4070: {
|
||||
}
|
||||
expect_stdout: "NaN"
|
||||
}
|
||||
|
||||
issue_4242: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
conditionals: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
if (console)
|
||||
var a = function(){}, b = (!1 === console || a)();
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
console && (!1 === console || function(){})();
|
||||
}());
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_4248: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
try {
|
||||
a = 1;
|
||||
b[1];
|
||||
} catch (e) {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
try {
|
||||
a = 1;
|
||||
b[1];
|
||||
} catch (e) {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
@@ -83,13 +83,11 @@ ifs_3_should_warn: {
|
||||
"WARN: Condition left of && always false [test/compress/conditionals.js:3,12]",
|
||||
"WARN: Condition always false [test/compress/conditionals.js:3,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/conditionals.js:3,34]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/conditionals.js:4,12]",
|
||||
"WARN: + in boolean context always true [test/compress/conditionals.js:10,19]",
|
||||
"WARN: Boolean || always true [test/compress/conditionals.js:10,12]",
|
||||
"WARN: Condition left of || always true [test/compress/conditionals.js:10,12]",
|
||||
"WARN: Condition always true [test/compress/conditionals.js:10,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/conditionals.js:12,15]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/conditionals.js:13,12]",
|
||||
"WARN: Dropping side-effect-free statement [test/compress/conditionals.js:3,12]",
|
||||
"WARN: Dropping side-effect-free statement [test/compress/conditionals.js:10,12]",
|
||||
]
|
||||
|
||||
@@ -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 = {}
|
||||
input: {
|
||||
@@ -11,8 +53,8 @@ mangle_catch_1: {
|
||||
expect: {
|
||||
try {
|
||||
throw "eeeee";
|
||||
} catch (e) {
|
||||
const o = typeof d;
|
||||
} catch (o) {
|
||||
const e = typeof d;
|
||||
}
|
||||
console.log(typeof a, typeof b);
|
||||
}
|
||||
@@ -57,6 +99,23 @@ retain_block: {
|
||||
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: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
@@ -161,31 +220,6 @@ merge_vars_3: {
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
reduce_merge_vars: {
|
||||
options = {
|
||||
merge_vars: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
const a = console;
|
||||
console.log(typeof a);
|
||||
var b = typeof a;
|
||||
console.log(b);
|
||||
}
|
||||
expect: {
|
||||
var b = console;
|
||||
console.log(typeof b);
|
||||
b = typeof b;
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: [
|
||||
"object",
|
||||
"object",
|
||||
]
|
||||
}
|
||||
|
||||
use_before_init_1: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
@@ -312,24 +346,6 @@ reduce_block_1: {
|
||||
expect_stdout: "object"
|
||||
}
|
||||
|
||||
reduce_block_1_toplevel: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
{
|
||||
const a = typeof console;
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var a = typeof console;
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "object"
|
||||
}
|
||||
|
||||
reduce_block_2: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
@@ -373,7 +389,7 @@ reduce_block_2_toplevel: {
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
hoist_props_1: {
|
||||
hoist_props: {
|
||||
options = {
|
||||
hoist_props: true,
|
||||
reduce_vars: true,
|
||||
@@ -397,28 +413,6 @@ hoist_props_1: {
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
hoist_props_2: {
|
||||
options = {
|
||||
hoist_props: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
{
|
||||
const o = {
|
||||
p: "PASS",
|
||||
};
|
||||
console.log(o.p);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var o_p = "PASS";
|
||||
console.log(o_p);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
loop_block_1: {
|
||||
options = {
|
||||
loops: true,
|
||||
@@ -503,7 +497,7 @@ catch_ie8_1: {
|
||||
}
|
||||
expect: {
|
||||
try {} catch (a) {}
|
||||
console.log(function a() {
|
||||
console.log(function() {
|
||||
}());
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
@@ -559,29 +553,6 @@ dead_block_after_return: {
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
const_to_var_scope_adjustment: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
for (var k in [ 42 ])
|
||||
console.log(function f() {
|
||||
if (k) {
|
||||
const a = 0;
|
||||
}
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
for (var k in [ 42 ])
|
||||
console.log(void (k && 0));
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
do_if_continue_1: {
|
||||
options = {
|
||||
if_return: true,
|
||||
@@ -687,7 +658,7 @@ legacy_scope: {
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_4191_1: {
|
||||
issue_4191: {
|
||||
options = {
|
||||
functions: true,
|
||||
reduce_vars: true,
|
||||
@@ -708,24 +679,6 @@ issue_4191_1: {
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_4191_2: {
|
||||
options = {
|
||||
functions: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
const a = function() {};
|
||||
console.log(typeof a, a());
|
||||
}
|
||||
expect: {
|
||||
function a() {};
|
||||
console.log(typeof a, a());
|
||||
}
|
||||
expect_stdout: "function undefined"
|
||||
}
|
||||
|
||||
issue_4193: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
@@ -1151,3 +1104,246 @@ issue_4225: {
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_4229: {
|
||||
options = {
|
||||
ie8: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
(function f() {
|
||||
f;
|
||||
const f = 42;
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function f() {
|
||||
f;
|
||||
const f = 42;
|
||||
})();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_4231: {
|
||||
options = {
|
||||
ie8: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
typeof a == 0;
|
||||
console.log(typeof function a() {
|
||||
const a = 0;
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
console.log(typeof function a() {
|
||||
const a = 0;
|
||||
});
|
||||
}
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
issue_4245: {
|
||||
options = {
|
||||
booleans: true,
|
||||
}
|
||||
input: {
|
||||
const a = f();
|
||||
function f() {
|
||||
typeof a;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
const a = f();
|
||||
function f() {
|
||||
a,
|
||||
1;
|
||||
}
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_4248: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
try {
|
||||
(function() {
|
||||
a = "PASS";
|
||||
b[a];
|
||||
const b = 0;
|
||||
})();
|
||||
} catch (e) {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var a = "FAIL";
|
||||
try {
|
||||
(function() {
|
||||
a = "PASS";
|
||||
b[a];
|
||||
const b = 0;
|
||||
})();
|
||||
} catch (e) {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4261: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
{
|
||||
const a = 42;
|
||||
(function() {
|
||||
function f() {
|
||||
console.log(a);
|
||||
}
|
||||
function g() {
|
||||
while (f());
|
||||
}
|
||||
(function() {
|
||||
while (g());
|
||||
})();
|
||||
})();
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
{
|
||||
const a = 42;
|
||||
(function() {
|
||||
function g() {
|
||||
while (void console.log(a));
|
||||
}
|
||||
(function() {
|
||||
while (g());
|
||||
})();
|
||||
})();
|
||||
}
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
issue_4274_1: {
|
||||
options = {
|
||||
loops: true,
|
||||
}
|
||||
input: {
|
||||
for (;;) {
|
||||
if (console.log("PASS")) {
|
||||
const a = 0;
|
||||
} else {
|
||||
break;
|
||||
var a;
|
||||
}
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
for (; console.log("PASS");) {
|
||||
{
|
||||
const a = 0;
|
||||
}
|
||||
var a;
|
||||
}
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_4274_2: {
|
||||
options = {
|
||||
loops: true,
|
||||
}
|
||||
input: {
|
||||
for (;;) {
|
||||
if (!console.log("PASS")) {
|
||||
break;
|
||||
var a;
|
||||
} else {
|
||||
const a = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
for (; console.log("PASS");) {
|
||||
{
|
||||
const a = 0;
|
||||
}
|
||||
var a;
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -61,8 +61,6 @@ dead_code_2_should_warn: {
|
||||
expect_stdout: true
|
||||
expect_warnings: [
|
||||
"WARN: Dropping unreachable code [test/compress/dead-code.js:8,12]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/dead-code.js:10,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/dead-code.js:10,16]",
|
||||
]
|
||||
node_version: "<=4"
|
||||
}
|
||||
@@ -103,11 +101,9 @@ dead_code_constant_boolean_should_warn_more: {
|
||||
"WARN: + in boolean context always true [test/compress/dead-code.js:1,33]",
|
||||
"WARN: Boolean || always true [test/compress/dead-code.js:1,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/dead-code.js:1,45]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/dead-code.js:3,12]",
|
||||
"WARN: Boolean expression always true [test/compress/dead-code.js:6,47]",
|
||||
"WARN: Boolean && always false [test/compress/dead-code.js:6,28]",
|
||||
"WARN: Dropping unreachable code [test/compress/dead-code.js:6,63]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/dead-code.js:9,12]",
|
||||
"WARN: Dropping side-effect-free statement [test/compress/dead-code.js:1,15]",
|
||||
"WARN: Dropping side-effect-free statement [test/compress/dead-code.js:6,28]",
|
||||
]
|
||||
|
||||
1649
test/compress/destructured.js
Normal file
1649
test/compress/destructured.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -3085,3 +3085,30 @@ issue_4184: {
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
issue_4235: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
{
|
||||
const f = 0;
|
||||
}
|
||||
(function f() {
|
||||
var f = console.log(f);
|
||||
})();
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
f = console.log(f),
|
||||
void 0;
|
||||
var f;
|
||||
})();
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
@@ -3047,3 +3047,30 @@ issue_4214: {
|
||||
}
|
||||
expect_stdout: "NaN"
|
||||
}
|
||||
|
||||
issue_4271: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
({
|
||||
p: null,
|
||||
q: (console.log("foo"), 42),
|
||||
p: function() {}
|
||||
})[console.log("bar"), "p"] && console.log("PASS");
|
||||
}
|
||||
expect: {
|
||||
({
|
||||
p: null,
|
||||
q: (console.log("foo"), 42),
|
||||
p: function() {}
|
||||
})[console.log("bar"), "p"],
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: [
|
||||
"foo",
|
||||
"bar",
|
||||
"PASS",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -521,7 +521,7 @@ issue_2531_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
passes: 3,
|
||||
passes: 2,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
@@ -556,9 +556,10 @@ issue_2531_3: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
passes: 3,
|
||||
passes: 2,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
@@ -2081,7 +2082,7 @@ issue_3016_1: {
|
||||
var b = 1;
|
||||
do {
|
||||
3[b];
|
||||
} while(0);
|
||||
} while (0);
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
@@ -2112,7 +2113,7 @@ issue_3016_2: {
|
||||
do {
|
||||
a = 3,
|
||||
a[b];
|
||||
} while(0);
|
||||
} while (0);
|
||||
var a;
|
||||
console.log(b);
|
||||
}
|
||||
@@ -2145,7 +2146,7 @@ issue_3016_2_ie8: {
|
||||
do {
|
||||
a = 3,
|
||||
a[b];
|
||||
} while(0);
|
||||
} while (0);
|
||||
var a;
|
||||
console.log(b);
|
||||
}
|
||||
@@ -2175,7 +2176,7 @@ issue_3016_3: {
|
||||
var b = 1;
|
||||
do {
|
||||
console.log((a = void 0, a ? "FAIL" : a = "PASS"));
|
||||
} while(b--);
|
||||
} while (b--);
|
||||
var a;
|
||||
}
|
||||
expect_stdout: [
|
||||
@@ -2208,7 +2209,7 @@ issue_3016_3_ie8: {
|
||||
var b = 1;
|
||||
do {
|
||||
console.log((a = void 0, a ? "FAIL" : a = "PASS"));
|
||||
} while(b--);
|
||||
} while (b--);
|
||||
var a;
|
||||
}
|
||||
expect_stdout: [
|
||||
@@ -5076,3 +5077,141 @@ issue_4186: {
|
||||
}
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
issue_4233: {
|
||||
options = {
|
||||
functions: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
try {
|
||||
var a = function() {};
|
||||
try {
|
||||
throw 42;
|
||||
} catch (a) {
|
||||
(function() {
|
||||
console.log(typeof a);
|
||||
})();
|
||||
var a;
|
||||
}
|
||||
} catch (e) {}
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
try {
|
||||
var a = function() {};
|
||||
try {
|
||||
throw 42;
|
||||
} catch (a) {
|
||||
(function() {
|
||||
console.log(typeof a);
|
||||
})();
|
||||
var a;
|
||||
}
|
||||
} catch (e) {}
|
||||
})();
|
||||
}
|
||||
expect_stdout: "number"
|
||||
}
|
||||
|
||||
issue_4259: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
functions: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = function b() {
|
||||
var c = b;
|
||||
for (b in c);
|
||||
};
|
||||
a();
|
||||
console.log(typeof a);
|
||||
}
|
||||
expect: {
|
||||
function a() {
|
||||
for (a in a);
|
||||
}
|
||||
a();
|
||||
console.log(typeof a);
|
||||
}
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
issue_4261: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
throw 42;
|
||||
} catch (e) {
|
||||
(function() {
|
||||
function f() {
|
||||
e.p;
|
||||
}
|
||||
function g() {
|
||||
while (f());
|
||||
}
|
||||
(function() {
|
||||
while (console.log(g()));
|
||||
})();
|
||||
})();
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
throw 42;
|
||||
} catch (e) {
|
||||
(function() {
|
||||
function g() {
|
||||
while (void e.p);
|
||||
}
|
||||
(function() {
|
||||
while (console.log(g()));
|
||||
})();
|
||||
})();
|
||||
}
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_4265: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
inline: true,
|
||||
sequences: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
console;
|
||||
if ([ function() {
|
||||
return this + console.log(a);
|
||||
a;
|
||||
var a;
|
||||
}() ]);
|
||||
return 0;
|
||||
}
|
||||
f();
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
return console, function() {
|
||||
return console.log(a);
|
||||
var a;
|
||||
}(), 0;
|
||||
}
|
||||
f();
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
@@ -297,6 +297,33 @@ name_collision_3: {
|
||||
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: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
|
||||
@@ -2859,3 +2859,48 @@ issue_4186: {
|
||||
}
|
||||
expect_stdout: "NaN"
|
||||
}
|
||||
|
||||
issue_4235: {
|
||||
options = {
|
||||
ie8: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
try {} catch (e) {}
|
||||
console.log(function e() {
|
||||
var e = 0;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
try {} catch (e) {}
|
||||
console.log(function e() {}());
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_4250: {
|
||||
options = {
|
||||
ie8: true,
|
||||
loops: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function f() {
|
||||
(function() {
|
||||
for (f in "f");
|
||||
})();
|
||||
return f;
|
||||
var f;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function f() {
|
||||
(function() {
|
||||
for (f in "f");
|
||||
})();
|
||||
return f;
|
||||
var f;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "0"
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ non_hoisted_function_after_return: {
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:4,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
|
||||
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:11,21]"
|
||||
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:11,21]",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -84,15 +84,12 @@ non_hoisted_function_after_return_2a: {
|
||||
}
|
||||
}
|
||||
expect_warnings: [
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:4,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:4,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]",
|
||||
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:4,16]",
|
||||
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:7,16]",
|
||||
"WARN: Dropping unused variable a [test/compress/issue-1034.js:4,20]",
|
||||
"WARN: Dropping unused function nope [test/compress/issue-1034.js:11,21]",
|
||||
"INFO: pass 0: last_count: Infinity, count: 35",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]",
|
||||
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:9,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
|
||||
"INFO: Dropping unused variable b [test/compress/issue-1034.js:7,20]",
|
||||
"INFO: Dropping unused variable c [test/compress/issue-1034.js:9,16]",
|
||||
@@ -138,10 +135,7 @@ non_hoisted_function_after_return_2b: {
|
||||
}
|
||||
}
|
||||
expect_warnings: [
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:6,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:6,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:8,12]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,12]",
|
||||
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:8,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
|
||||
]
|
||||
}
|
||||
@@ -242,15 +236,12 @@ non_hoisted_function_after_return_2a_strict: {
|
||||
}
|
||||
expect_stdout: "5 6"
|
||||
expect_warnings: [
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:5,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:5,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:8,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,16]",
|
||||
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:5,16]",
|
||||
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:8,16]",
|
||||
"WARN: Dropping unused variable a [test/compress/issue-1034.js:5,20]",
|
||||
"WARN: Dropping unused function nope [test/compress/issue-1034.js:12,21]",
|
||||
"INFO: pass 0: last_count: Infinity, count: 46",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:10,12]",
|
||||
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:10,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
|
||||
"INFO: Dropping unused variable b [test/compress/issue-1034.js:8,20]",
|
||||
"INFO: Dropping unused variable c [test/compress/issue-1034.js:10,16]",
|
||||
@@ -301,10 +292,7 @@ non_hoisted_function_after_return_2b_strict: {
|
||||
}
|
||||
expect_stdout: "5 6"
|
||||
expect_warnings: [
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]",
|
||||
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:9,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
|
||||
]
|
||||
}
|
||||
|
||||
1230
test/compress/let.js
Normal file
1230
test/compress/let.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1222,3 +1222,35 @@ do_continue: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4240: {
|
||||
options = {
|
||||
loops: true,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(a) {
|
||||
function f() {
|
||||
var o = { PASS: 42 };
|
||||
for (a in o);
|
||||
}
|
||||
(function() {
|
||||
if (f());
|
||||
})();
|
||||
console.log(a);
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function(a) {
|
||||
(function() {
|
||||
if (function() {
|
||||
for (a in { PASS: 42 });
|
||||
}());
|
||||
})();
|
||||
console.log(a);
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -3011,3 +3011,175 @@ issue_4168_use_strict: {
|
||||
}
|
||||
expect_stdout: "PASS true 42"
|
||||
}
|
||||
|
||||
issue_4237_1: {
|
||||
options = {
|
||||
merge_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
do {
|
||||
var b = a++;
|
||||
if (b)
|
||||
return "FAIL";
|
||||
continue;
|
||||
var c = 42;
|
||||
} while ("undefined" != typeof c);
|
||||
return "PASS";
|
||||
}(0));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
do {
|
||||
var b = a++;
|
||||
if (b)
|
||||
return "FAIL";
|
||||
continue;
|
||||
var c = 42;
|
||||
} while ("undefined" != typeof c);
|
||||
return "PASS";
|
||||
}(0));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4237_2: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
loops: true,
|
||||
merge_vars: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
do {
|
||||
switch (0) {
|
||||
case 0:
|
||||
var b = a++;
|
||||
default:
|
||||
while (b)
|
||||
return "FAIL";
|
||||
}
|
||||
try {
|
||||
var c = 0;
|
||||
} finally {
|
||||
continue;
|
||||
}
|
||||
var d = 0;
|
||||
} while ("undefined" != typeof d);
|
||||
return "PASS";
|
||||
}(0));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
do {
|
||||
switch (0) {
|
||||
case 0:
|
||||
var b = a++;
|
||||
if (b)
|
||||
return "FAIL";
|
||||
}
|
||||
try {
|
||||
var c = 0;
|
||||
} finally {
|
||||
continue;
|
||||
}
|
||||
var d = 0;
|
||||
} while ("undefined" != typeof d);
|
||||
return "PASS";
|
||||
}(0));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4253: {
|
||||
options = {
|
||||
merge_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
switch (0) {
|
||||
default:
|
||||
var a = "FAIL";
|
||||
a = a && a;
|
||||
try {
|
||||
break;
|
||||
} catch (e) {}
|
||||
var b = 42;
|
||||
}
|
||||
console.log(b);
|
||||
}
|
||||
expect: {
|
||||
switch (0) {
|
||||
default:
|
||||
var a = "FAIL";
|
||||
a = a && a;
|
||||
try {
|
||||
break;
|
||||
} catch (e) {}
|
||||
var b = 42;
|
||||
}
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_4255: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
loops: true,
|
||||
merge_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
L: for (var a = 2; --a;)
|
||||
for (var b = 0; console.log(b); --b)
|
||||
break L;
|
||||
}
|
||||
expect: {
|
||||
L: for (var a = 2; --a;) {
|
||||
var b = 0;
|
||||
if (console.log(b))
|
||||
break L;
|
||||
}
|
||||
}
|
||||
expect_stdout: "0"
|
||||
}
|
||||
|
||||
issue_4257: {
|
||||
options = {
|
||||
merge_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
for (var i = 0; i < 2; i++)
|
||||
switch (--a) {
|
||||
case 0:
|
||||
var b = 0;
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
var c = 1 + (0 | (b && A));
|
||||
console.log(c);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
for (var i = 0; i < 2; i++)
|
||||
switch (--a) {
|
||||
case 0:
|
||||
var b = 0;
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
var c = 1 + (0 | (b && A));
|
||||
console.log(c);
|
||||
}
|
||||
}
|
||||
expect_stdout: [
|
||||
"1",
|
||||
"1",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,49 +1,100 @@
|
||||
hex_numbers_in_parentheses_for_prototype_functions: {
|
||||
parentheses_for_prototype_functions: {
|
||||
beautify = {
|
||||
beautify: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
(-2);
|
||||
(-2).toFixed(0);
|
||||
(function() {
|
||||
console.log((-2));
|
||||
console.log((-2).toFixed(0));
|
||||
|
||||
(2);
|
||||
(2).toFixed(0);
|
||||
console.log((2));
|
||||
console.log((2).toFixed(0));
|
||||
|
||||
(0.2);
|
||||
(0.2).toFixed(0);
|
||||
console.log((0.2));
|
||||
console.log((0.2).toFixed(0));
|
||||
|
||||
(2.34e20);
|
||||
(2.34e20).toFixed(0);
|
||||
console.log((2.34e20));
|
||||
console.log((2.34e20).toFixed(0));
|
||||
|
||||
(0.00000002);
|
||||
(0.00000002).toFixed(0);
|
||||
console.log((0.00000002));
|
||||
console.log((0.00000002).toFixed(0));
|
||||
|
||||
(1000000000000000128);
|
||||
(1000000000000000128).toFixed(0);
|
||||
console.log((1000000000000000128));
|
||||
console.log((1000000000000000128).toFixed(0));
|
||||
|
||||
(-1000000000000000128);
|
||||
(-1000000000000000128).toFixed(0);
|
||||
}
|
||||
console.log((-1000000000000000128));
|
||||
console.log((-1000000000000000128).toFixed(0));
|
||||
})();
|
||||
}
|
||||
expect_exact: [
|
||||
"function f() {",
|
||||
" -2;",
|
||||
" (-2).toFixed(0);",
|
||||
" 2;",
|
||||
" 2..toFixed(0);",
|
||||
" .2;",
|
||||
" .2.toFixed(0);",
|
||||
" 234e18;",
|
||||
" 234e18.toFixed(0);",
|
||||
" 2e-8;",
|
||||
" 2e-8.toFixed(0);",
|
||||
" 0xde0b6b3a7640080;",
|
||||
" (0xde0b6b3a7640080).toFixed(0);",
|
||||
" -0xde0b6b3a7640080;",
|
||||
" (-0xde0b6b3a7640080).toFixed(0);",
|
||||
"}",
|
||||
"(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
|
||||
}
|
||||
|
||||
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: {
|
||||
|
||||
@@ -221,3 +221,142 @@ numeric_literal: {
|
||||
"8 7 8",
|
||||
]
|
||||
}
|
||||
|
||||
evaluate_computed_key: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
objects: true,
|
||||
}
|
||||
input: {
|
||||
console.log({
|
||||
["foo" + "bar"]: "PASS",
|
||||
}.foobar);
|
||||
}
|
||||
expect: {
|
||||
console.log({
|
||||
foobar: "PASS",
|
||||
}.foobar);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
keep_computed_key: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
({
|
||||
[console.log("PASS")]: 42,
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4269_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
objects: true,
|
||||
}
|
||||
input: {
|
||||
console.log({
|
||||
get 0() {
|
||||
return "FAIL";
|
||||
},
|
||||
[0]: "PASS",
|
||||
}[0]);
|
||||
}
|
||||
expect: {
|
||||
console.log({
|
||||
get 0() {
|
||||
return "FAIL";
|
||||
},
|
||||
[0]: "PASS",
|
||||
}[0]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4269_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
objects: true,
|
||||
}
|
||||
input: {
|
||||
console.log({
|
||||
get [0]() {
|
||||
return "FAIL";
|
||||
},
|
||||
0: "PASS",
|
||||
}[0]);
|
||||
}
|
||||
expect: {
|
||||
console.log({
|
||||
get [0]() {
|
||||
return "FAIL";
|
||||
},
|
||||
0: "PASS",
|
||||
}[0]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4269_3: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
objects: true,
|
||||
}
|
||||
input: {
|
||||
console.log({
|
||||
["foo"]: "bar",
|
||||
get 42() {
|
||||
return "FAIL";
|
||||
},
|
||||
42: "PASS",
|
||||
}[42]);
|
||||
}
|
||||
expect: {
|
||||
console.log({
|
||||
["foo"]: "bar",
|
||||
get 42() {
|
||||
return "FAIL";
|
||||
},
|
||||
42: "PASS",
|
||||
}[42]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4269_4: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
objects: true,
|
||||
}
|
||||
input: {
|
||||
console.log({
|
||||
get 42() {
|
||||
return "FAIL";
|
||||
},
|
||||
["foo"]: "bar",
|
||||
42: "PASS",
|
||||
}[42]);
|
||||
}
|
||||
expect: {
|
||||
console.log({
|
||||
get 42() {
|
||||
return "FAIL";
|
||||
},
|
||||
["foo"]: "bar",
|
||||
42: "PASS",
|
||||
}[42]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
@@ -1999,7 +1999,7 @@ issue_1606: {
|
||||
var a, b;
|
||||
function g(){};
|
||||
b = 2;
|
||||
x(b);
|
||||
x(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,37 @@
|
||||
ascii_only_false: {
|
||||
options = {}
|
||||
beautify = {
|
||||
ascii_only: false,
|
||||
}
|
||||
input: {
|
||||
console.log(
|
||||
"\x000\x001\x007\x008\x00",
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
|
||||
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
|
||||
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff"
|
||||
);
|
||||
}
|
||||
expect_exact: 'console.log("\\x000\\x001\\x007\\x008\\0","\\0\x01\x02\x03\x04\x05\x06\x07\\b\\t\\n\\v\\f\\r\x0e\x0f","\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",\' !"# ... }~\x7f\x80\x81 ... \xfe\xff\u0fff\uffff\');'
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
ascii_only_true: {
|
||||
options = {}
|
||||
beautify = {
|
||||
ascii_only: true,
|
||||
}
|
||||
input: {
|
||||
console.log(
|
||||
"\x000\x001\x007\x008\x00",
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
|
||||
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
|
||||
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff"
|
||||
);
|
||||
}
|
||||
expect_exact: 'console.log("\\x000\\x001\\x007\\x008\\0","\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\b\\t\\n\\v\\f\\r\\x0e\\x0f","\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f",\' !"# ... }~\\x7f\\x80\\x81 ... \\xfe\\xff\\u0fff\\uffff\');'
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unicode_parse_variables: {
|
||||
options = {}
|
||||
input: {
|
||||
@@ -141,3 +175,35 @@ issue_2569: {
|
||||
}
|
||||
expect_exact: 'new RegExp("[\\udc42-\\udcaa\\udd74-\\udd96\\ude45-\\ude4f\\udea3-\\udecc]");'
|
||||
}
|
||||
|
||||
surrogate_pair: {
|
||||
beautify = {
|
||||
ascii_only: false,
|
||||
}
|
||||
input: {
|
||||
var \u{2f800} = {
|
||||
\u{2f801}: "\u{100000}",
|
||||
};
|
||||
\u{2f800}.\u{2f802} = "\u{100001}";
|
||||
console.log(typeof \u{2f800}, \u{2f800}.\u{2f801}, \u{2f800}["\u{2f802}"]);
|
||||
}
|
||||
expect_exact: 'var \ud87e\udc00={"\ud87e\udc01":"\udbc0\udc00"};\ud87e\udc00.\ud87e\udc02="\udbc0\udc01";console.log(typeof \ud87e\udc00,\ud87e\udc00.\ud87e\udc01,\ud87e\udc00["\ud87e\udc02"]);'
|
||||
expect_stdout: "object \udbc0\udc00 \udbc0\udc01"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
surrogate_pair_ascii: {
|
||||
beautify = {
|
||||
ascii_only: true,
|
||||
}
|
||||
input: {
|
||||
var \u{2f800} = {
|
||||
\u{2f801}: "\u{100000}",
|
||||
};
|
||||
\u{2f800}.\u{2f802} = "\u{100001}";
|
||||
console.log(typeof \u{2f800}, \u{2f800}.\u{2f801}, \u{2f800}["\u{2f802}"]);
|
||||
}
|
||||
expect_exact: 'var \\u{2f800}={"\\ud87e\\udc01":"\\udbc0\\udc00"};\\u{2f800}.\\u{2f802}="\\udbc0\\udc01";console.log(typeof \\u{2f800},\\u{2f800}.\\u{2f801},\\u{2f800}["\\ud87e\\udc02"]);'
|
||||
expect_stdout: "object \udbc0\udc00 \udbc0\udc01"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
411
test/compress/varify.js
Normal file
411
test/compress/varify.js
Normal file
@@ -0,0 +1,411 @@
|
||||
reduce_merge_const: {
|
||||
options = {
|
||||
merge_vars: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
const a = console;
|
||||
console.log(typeof a);
|
||||
var b = typeof a;
|
||||
console.log(b);
|
||||
}
|
||||
expect: {
|
||||
var b = console;
|
||||
console.log(typeof b);
|
||||
b = typeof b;
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: [
|
||||
"object",
|
||||
"object",
|
||||
]
|
||||
}
|
||||
|
||||
reduce_merge_let: {
|
||||
options = {
|
||||
merge_vars: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
let a = console;
|
||||
console.log(typeof a);
|
||||
var b = typeof a;
|
||||
console.log(b);
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
var b = console;
|
||||
console.log(typeof b);
|
||||
b = typeof b;
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: [
|
||||
"object",
|
||||
"object",
|
||||
]
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
reduce_block_const: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
{
|
||||
const a = typeof console;
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var a = typeof console;
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "object"
|
||||
}
|
||||
|
||||
reduce_block_let: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
{
|
||||
let a = typeof console;
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
var a = typeof console;
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "object"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
hoist_props_const: {
|
||||
options = {
|
||||
hoist_props: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
{
|
||||
const o = {
|
||||
p: "PASS",
|
||||
};
|
||||
console.log(o.p);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var o_p = "PASS";
|
||||
console.log(o_p);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
hoist_props_let: {
|
||||
options = {
|
||||
hoist_props: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
{
|
||||
let o = {
|
||||
p: "PASS",
|
||||
};
|
||||
console.log(o.p);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
var o_p = "PASS";
|
||||
console.log(o_p);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
scope_adjustment_const: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
for (var k in [ 42 ])
|
||||
console.log(function f() {
|
||||
if (k) {
|
||||
const a = 0;
|
||||
}
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
for (var k in [ 42 ])
|
||||
console.log(void (k && 0));
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
scope_adjustment_let: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
for (var k in [ 42 ])
|
||||
console.log(function f() {
|
||||
if (k) {
|
||||
let a = 0;
|
||||
}
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
for (var k in [ 42 ])
|
||||
console.log(void (k && 0));
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4191_const: {
|
||||
options = {
|
||||
functions: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
const a = function() {};
|
||||
console.log(typeof a, a());
|
||||
}
|
||||
expect: {
|
||||
function a() {};
|
||||
console.log(typeof a, a());
|
||||
}
|
||||
expect_stdout: "function undefined"
|
||||
}
|
||||
|
||||
issue_4191_let: {
|
||||
options = {
|
||||
functions: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
let a = function() {};
|
||||
console.log(typeof a, a());
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
function a() {};
|
||||
console.log(typeof a, a());
|
||||
}
|
||||
expect_stdout: "function undefined"
|
||||
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"
|
||||
}
|
||||
@@ -60,7 +60,7 @@ if (typeof phantom == "undefined") {
|
||||
var port = server.address().port;
|
||||
if (debug) {
|
||||
console.log("http://localhost:" + port + "/");
|
||||
} else {
|
||||
} else (function install() {
|
||||
child_process.spawn(process.platform == "win32" ? "npm.cmd" : "npm", [
|
||||
"install",
|
||||
"phantomjs-prebuilt@2.1.14",
|
||||
@@ -71,7 +71,10 @@ if (typeof phantom == "undefined") {
|
||||
], {
|
||||
stdio: [ "ignore", 1, 2 ]
|
||||
}).on("exit", function(code) {
|
||||
if (code) throw new Error("npm install failed!");
|
||||
if (code) {
|
||||
console.log("npm install failed with code", code);
|
||||
return install();
|
||||
}
|
||||
var program = require("phantomjs-prebuilt").exec(process.argv[1], port);
|
||||
program.stdout.pipe(process.stdout);
|
||||
program.stderr.pipe(process.stderr);
|
||||
@@ -82,7 +85,7 @@ if (typeof phantom == "undefined") {
|
||||
process.exit(0);
|
||||
});
|
||||
});
|
||||
}
|
||||
})();
|
||||
});
|
||||
server.timeout = 0;
|
||||
} else {
|
||||
|
||||
@@ -1,64 +1,58 @@
|
||||
var assert = require("assert");
|
||||
var run_code = require("../sandbox").run_code;
|
||||
var UglifyJS = require("../node");
|
||||
|
||||
describe("String literals", function() {
|
||||
it("Should throw syntax error if a string literal contains a newline", function() {
|
||||
var inputs = [
|
||||
[
|
||||
"'\n'",
|
||||
"'\r'",
|
||||
'"\r\n"',
|
||||
"'\u2028'",
|
||||
'"\u2029"'
|
||||
];
|
||||
|
||||
var test = function(input) {
|
||||
return function() {
|
||||
'"\u2029"',
|
||||
].forEach(function(input) {
|
||||
assert.throws(function() {
|
||||
var ast = UglifyJS.parse(input);
|
||||
};
|
||||
};
|
||||
|
||||
var error = function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error
|
||||
&& e.message === "Unterminated string constant";
|
||||
};
|
||||
|
||||
for (var input in inputs) {
|
||||
assert.throws(test(inputs[input]), error);
|
||||
}
|
||||
}, function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error
|
||||
&& e.message === "Unterminated string constant";
|
||||
});
|
||||
});
|
||||
});
|
||||
it("Should handle line continuation correctly", function() {
|
||||
[
|
||||
'"\\\r"',
|
||||
'"\\\n"',
|
||||
'"\\\r\n"',
|
||||
].forEach(function(str) {
|
||||
var code = "console.log(" + str + ");";
|
||||
var result = UglifyJS.minify(code);
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(run_code(result.code), run_code(code));
|
||||
});
|
||||
});
|
||||
|
||||
it("Should not throw syntax error if a string has a line continuation", function() {
|
||||
var output = UglifyJS.parse('var a = "a\\\nb";').print_to_string();
|
||||
assert.equal(output, 'var a="ab";');
|
||||
var ast = UglifyJS.parse('var a = "a\\\nb";');
|
||||
assert.equal(ast.print_to_string(), 'var a="ab";');
|
||||
});
|
||||
|
||||
it("Should throw error in strict mode if string contains escaped octalIntegerLiteral", function() {
|
||||
var inputs = [
|
||||
[
|
||||
'"use strict";\n"\\76";',
|
||||
'"use strict";\nvar foo = "\\76";',
|
||||
'"use strict";\n"\\1";',
|
||||
'"use strict";\n"\\07";',
|
||||
'"use strict";\n"\\011"'
|
||||
];
|
||||
|
||||
var test = function(input) {
|
||||
return function() {
|
||||
'"use strict";\n"\\011"',
|
||||
].forEach(function(input) {
|
||||
assert.throws(function() {
|
||||
var output = UglifyJS.parse(input);
|
||||
}
|
||||
};
|
||||
|
||||
var error = function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error
|
||||
&& e.message === "Legacy octal escape sequences are not allowed in strict mode";
|
||||
}
|
||||
|
||||
for (var input in inputs) {
|
||||
assert.throws(test(inputs[input]), error);
|
||||
}
|
||||
}, function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error
|
||||
&& e.message === "Legacy octal escape sequences are not allowed in strict mode";
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("Should not throw error outside strict mode if string contains escaped octalIntegerLiteral", function() {
|
||||
var tests = [
|
||||
[
|
||||
[ ';"\\76";', ';">";' ],
|
||||
[ ';"\\0";', ';"\\0";' ],
|
||||
[ ';"\\08"', ';"\\x008";' ],
|
||||
@@ -66,19 +60,15 @@ describe("String literals", function() {
|
||||
[ ';"\\0008"', ';"\\x008";' ],
|
||||
[ ';"use\\\n strict";\n"\\07";', ';"use strict";"\07";' ],
|
||||
[ '"use strict" === "use strict";\n"\\76";', '"use strict"==="use strict";">";' ],
|
||||
];
|
||||
|
||||
for (var test in tests) {
|
||||
var output = UglifyJS.parse(tests[test][0]).print_to_string();
|
||||
assert.equal(output, tests[test][1]);
|
||||
}
|
||||
].forEach(function(test) {
|
||||
var ast = UglifyJS.parse(test[0]);
|
||||
assert.equal(ast.print_to_string(), test[1]);
|
||||
});
|
||||
});
|
||||
|
||||
it("Should not throw error when digit is 8 or 9", function() {
|
||||
assert.equal(UglifyJS.parse('"use strict";;"\\08"').print_to_string(), '"use strict";;"\\x008";');
|
||||
assert.equal(UglifyJS.parse('"use strict";;"\\09"').print_to_string(), '"use strict";;"\\x009";');
|
||||
});
|
||||
|
||||
it("Should not unescape unpaired surrogates", function() {
|
||||
var code = [];
|
||||
for (var i = 0; i <= 0xF; i++) {
|
||||
@@ -115,4 +105,33 @@ describe("String literals", function() {
|
||||
assert.ok(code.length > ascii.code.length);
|
||||
assert.strictEqual(eval(code), eval(ascii.code));
|
||||
});
|
||||
it("Should reject invalid Unicode escape sequence", function() {
|
||||
[
|
||||
'var foo = "\\u-111"',
|
||||
'var bar = "\\u{-1}"',
|
||||
'var baz = "\\ugggg"',
|
||||
].forEach(function(test) {
|
||||
assert.throws(function() {
|
||||
UglifyJS.parse(test);
|
||||
}, function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error
|
||||
&& e.message === "Invalid hex-character pattern in string";
|
||||
});
|
||||
});
|
||||
});
|
||||
it("Should reject invalid code points in Unicode escape sequence", function() {
|
||||
[
|
||||
// A bit over the valid range
|
||||
'"\\u{110000}"',
|
||||
// 32-bit overflow resulting in "a"
|
||||
'"\\u{100000061}"',
|
||||
].forEach(function(test) {
|
||||
assert.throws(function() {
|
||||
UglifyJS.parse(test);
|
||||
}, function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error
|
||||
&& /^Invalid character code: /.test(e.message);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ describe("tokens", function() {
|
||||
it("Should give correct positions for accessors", function() {
|
||||
// location 0 1 2 3 4
|
||||
// 01234567890123456789012345678901234567890123456789
|
||||
var ast = UglifyJS.parse("var obj = { get latest() { return undefined; } }");
|
||||
var ast = UglifyJS.parse("var obj = { get [prop]() { return undefined; } }");
|
||||
// test all AST_ObjectProperty tokens are set as expected
|
||||
var found = false;
|
||||
ast.walk(new UglifyJS.TreeWalker(function(node) {
|
||||
@@ -13,9 +13,9 @@ describe("tokens", function() {
|
||||
found = true;
|
||||
assert.equal(node.start.pos, 12);
|
||||
assert.equal(node.end.endpos, 46);
|
||||
assert(node.key instanceof UglifyJS.AST_SymbolAccessor);
|
||||
assert.equal(node.key.start.pos, 16);
|
||||
assert.equal(node.key.end.endpos, 22);
|
||||
assert(node.key instanceof UglifyJS.AST_SymbolRef);
|
||||
assert.equal(node.key.start.pos, 17);
|
||||
assert.equal(node.key.end.endpos, 21);
|
||||
assert(node.value instanceof UglifyJS.AST_Accessor);
|
||||
assert.equal(node.value.start.pos, 22);
|
||||
assert.equal(node.value.end.endpos, 46);
|
||||
|
||||
@@ -95,6 +95,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
|
||||
// quick ignores
|
||||
if (node instanceof U.AST_Accessor) return;
|
||||
if (node instanceof U.AST_Destructured) return;
|
||||
if (node instanceof U.AST_Directive) return;
|
||||
if (!in_list && node instanceof U.AST_EmptyStatement) return;
|
||||
if (node instanceof U.AST_Label) return;
|
||||
@@ -114,6 +115,8 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
|
||||
// ignore lvalues
|
||||
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) {
|
||||
case "++":
|
||||
case "--":
|
||||
@@ -250,13 +253,23 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
}
|
||||
}
|
||||
else if (node instanceof U.AST_ForIn) {
|
||||
var expr = [
|
||||
node.init,
|
||||
node.object,
|
||||
node.body,
|
||||
][ (node.start._permute * steps | 0) % 3 ];
|
||||
var expr;
|
||||
switch ((node.start._permute * steps | 0) % 3) {
|
||||
case 0:
|
||||
if (!(node.init instanceof U.AST_Definitions
|
||||
&& 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;
|
||||
if (expr && (expr !== node.body || !has_loopcontrol(expr, node, parent))) {
|
||||
if (expr) {
|
||||
CHANGED = true;
|
||||
return to_statement(expr);
|
||||
}
|
||||
@@ -389,6 +402,13 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
CHANGED = true;
|
||||
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
|
||||
@@ -593,7 +613,7 @@ function is_error(result) {
|
||||
}
|
||||
|
||||
function is_timed_out(result) {
|
||||
return is_error(result) && /timed out/.test(result);
|
||||
return is_error(result) && /timed out/.test(result.message);
|
||||
}
|
||||
|
||||
function is_statement(node) {
|
||||
|
||||
@@ -276,6 +276,7 @@ var NO_DEFUN = false;
|
||||
var DEFUN_OK = true;
|
||||
var DONT_STORE = true;
|
||||
var NO_CONST = true;
|
||||
var NO_DUPLICATE = true;
|
||||
|
||||
var VAR_NAMES = [
|
||||
"a",
|
||||
@@ -356,11 +357,15 @@ function createFunctions(n, recurmax, allowDefun, canThrow, stmtDepth) {
|
||||
return s;
|
||||
}
|
||||
|
||||
function createParams() {
|
||||
function createParams(noDuplicate) {
|
||||
var len = unique_vars.length;
|
||||
var params = [];
|
||||
for (var n = rng(4); --n >= 0;) {
|
||||
params.push(createVarName(MANDATORY));
|
||||
var name = createVarName(MANDATORY);
|
||||
if (noDuplicate) unique_vars.push(name);
|
||||
params.push(name);
|
||||
}
|
||||
unique_vars.length = len;
|
||||
return params.join(", ");
|
||||
}
|
||||
|
||||
@@ -372,6 +377,118 @@ function createArgs(recurmax, stmtDepth, canThrow) {
|
||||
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) {
|
||||
if (!generate_directive && !s[1] && /\("/.test(s[2])) s[2] = ";" + s[2];
|
||||
return s;
|
||||
@@ -381,41 +498,78 @@ function createBlockVariables(recurmax, stmtDepth, canThrow, fn) {
|
||||
var block_len = block_vars.length;
|
||||
var var_len = VAR_NAMES.length;
|
||||
var consts = [];
|
||||
var lets = [];
|
||||
unique_vars.push("a", "b", "c", "undefined", "NaN", "Infinity");
|
||||
while (!rng(block_vars.length > block_len ? 10 : 100)) {
|
||||
var name = createVarName(MANDATORY, DONT_STORE);
|
||||
consts.push(name);
|
||||
if (rng(2)) {
|
||||
consts.push(name);
|
||||
} else {
|
||||
lets.push(name);
|
||||
}
|
||||
block_vars.push(name);
|
||||
}
|
||||
unique_vars.length -= 6;
|
||||
fn(function() {
|
||||
var s = [];
|
||||
if (consts.length) {
|
||||
var save = VAR_NAMES;
|
||||
VAR_NAMES = VAR_NAMES.filter(function(name) {
|
||||
return consts.indexOf(name) < 0;
|
||||
});
|
||||
var len = VAR_NAMES.length;
|
||||
s.push("const " + consts.map(function(name) {
|
||||
if (rng(2)) {
|
||||
return createDefinitions("const", consts) + "\n" + createDefinitions("let", lets) + "\n";
|
||||
} else {
|
||||
return createDefinitions("let", lets) + "\n" + createDefinitions("const", consts) + "\n";
|
||||
}
|
||||
});
|
||||
block_vars.length = block_len;
|
||||
if (consts.length || lets.length) VAR_NAMES.splice(var_len, consts.length + lets.length);
|
||||
|
||||
function createDefinitions(type, names) {
|
||||
if (!names.length) return "";
|
||||
var save = VAR_NAMES;
|
||||
VAR_NAMES = VAR_NAMES.filter(function(name) {
|
||||
return names.indexOf(name) < 0;
|
||||
});
|
||||
var len = VAR_NAMES.length;
|
||||
var s = type + " ";
|
||||
switch (rng(10)) {
|
||||
case 0:
|
||||
while (!rng(10)) names.splice(rng(names.length + 1), 0, "");
|
||||
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(", ") + ";");
|
||||
VAR_NAMES = save.concat(VAR_NAMES.slice(len));
|
||||
}).join(", ") + ";";
|
||||
break;
|
||||
}
|
||||
return s.join("\n");
|
||||
});
|
||||
block_vars.length = block_len;
|
||||
if (consts.length) VAR_NAMES.splice(var_len, consts.length);
|
||||
VAR_NAMES = save.concat(VAR_NAMES.slice(len));
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
||||
if (--recurmax < 0) { return ";"; }
|
||||
if (!STMT_COUNT_FROM_GLOBAL) stmtDepth = 0;
|
||||
var s = [];
|
||||
var name;
|
||||
var name, args;
|
||||
var varNames = VAR_NAMES.slice();
|
||||
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||
var namesLenBefore = VAR_NAMES.length;
|
||||
if (allowDefun || rng(5) > 0) {
|
||||
name = "f" + funcs++;
|
||||
} else {
|
||||
@@ -423,7 +577,16 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
||||
name = createVarName(MANDATORY, !allowDefun);
|
||||
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());
|
||||
if (rng(5) === 0) {
|
||||
// functions with functions. lower the recursion to prevent a mess.
|
||||
@@ -434,17 +597,16 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
||||
}
|
||||
s.push("}", "");
|
||||
s = filterDirective(s).join("\n");
|
||||
|
||||
VAR_NAMES.length = namesLenBefore;
|
||||
});
|
||||
VAR_NAMES = varNames;
|
||||
|
||||
if (!allowDefun) {
|
||||
// avoid "function statements" (decl inside statements)
|
||||
s = "var " + createVarName(MANDATORY) + " = " + s;
|
||||
s += "(" + createArgs(recurmax, stmtDepth, canThrow) + ")";
|
||||
} else if (!(name in called) || rng(3) > 0) {
|
||||
s += "(" + (args || createArgs(recurmax, stmtDepth, canThrow)) + ")";
|
||||
} else if (!(name in called) || args || rng(3)) {
|
||||
s += "var " + createVarName(MANDATORY) + " = " + name;
|
||||
s += "(" + createArgs(recurmax, stmtDepth, canThrow) + ")";
|
||||
s += "(" + (args || createArgs(recurmax, stmtDepth, canThrow)) + ")";
|
||||
}
|
||||
|
||||
return s + ";";
|
||||
@@ -545,8 +707,9 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
||||
return [
|
||||
"{var expr" + loop + " = " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "; ",
|
||||
label.target + " for (",
|
||||
/^key/.test(key) ? "var " : "",
|
||||
key + " in expr" + loop + ") {",
|
||||
!/^key/.test(key) ? rng(10) ? "" : "var " : rng(10) ? "var " : rng(2) ? "let " : "const ",
|
||||
rng(10) ? key : rng(5) ? "[ " + key + " ]" : "{ length: " + key + " }",
|
||||
" in expr" + loop + ") {",
|
||||
rng(5) > 1 ? "c = 1 + c; var " + createVarName(MANDATORY) + " = expr" + loop + "[" + key + "]; " : "",
|
||||
createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth),
|
||||
"}}",
|
||||
@@ -560,7 +723,12 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
||||
// note: default does not _need_ to be last
|
||||
return "switch (" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") { " + createSwitchParts(recurmax, 4, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + "}";
|
||||
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:
|
||||
unique_vars.push("c");
|
||||
var name = createVarName(MANDATORY);
|
||||
@@ -703,7 +871,28 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
||||
case p++:
|
||||
return getVarName();
|
||||
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++:
|
||||
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
||||
case p++:
|
||||
@@ -848,7 +1037,10 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
||||
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;
|
||||
return "typeof " + name + ' == "function" && --_calls_ >= 0 && ' + name + "(" + createArgs(recurmax, stmtDepth, canThrow) + ")";
|
||||
}
|
||||
@@ -897,21 +1089,27 @@ function getDotKey(assign) {
|
||||
return key;
|
||||
}
|
||||
|
||||
function createAccessor(recurmax, stmtDepth, canThrow) {
|
||||
function createObjectKey(recurmax, stmtDepth, canThrow) {
|
||||
return rng(10) ? KEYS[rng(KEYS.length)] : "[" + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + "]";
|
||||
}
|
||||
|
||||
function createObjectFunction(recurmax, stmtDepth, canThrow) {
|
||||
var namesLenBefore = VAR_NAMES.length;
|
||||
var s;
|
||||
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||
var prop1 = getDotKey();
|
||||
if (rng(2) == 0) {
|
||||
switch (rng(3)) {
|
||||
case 0:
|
||||
s = [
|
||||
"get " + prop1 + "(){",
|
||||
"get " + createObjectKey(recurmax, stmtDepth, canThrow) + "(){",
|
||||
strictMode(),
|
||||
defns(),
|
||||
_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||
createStatement(recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth, STMT_RETURN_ETC),
|
||||
"},"
|
||||
"},",
|
||||
];
|
||||
} else {
|
||||
break;
|
||||
case 1:
|
||||
var prop1 = createObjectKey(recurmax, stmtDepth, canThrow);
|
||||
var prop2;
|
||||
do {
|
||||
prop2 = getDotKey();
|
||||
@@ -922,8 +1120,18 @@ function createAccessor(recurmax, stmtDepth, canThrow) {
|
||||
defns(),
|
||||
_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||
"this." + prop2 + createAssignment() + _createBinaryExpr(recurmax, COMMA_OK, stmtDepth, canThrow) + ";",
|
||||
"},"
|
||||
"},",
|
||||
];
|
||||
break;
|
||||
default:
|
||||
s = [
|
||||
createObjectKey(recurmax, stmtDepth, canThrow) + "(" + createParams(NO_DUPLICATE) + "){",
|
||||
strictMode(),
|
||||
defns(),
|
||||
_createStatements(3, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||
"},",
|
||||
]
|
||||
break;
|
||||
}
|
||||
});
|
||||
VAR_NAMES.length = namesLenBefore;
|
||||
@@ -933,13 +1141,16 @@ function createAccessor(recurmax, stmtDepth, canThrow) {
|
||||
function createObjectLiteral(recurmax, stmtDepth, canThrow) {
|
||||
recurmax--;
|
||||
var obj = ["({"];
|
||||
for (var i = rng(6); --i >= 0;) {
|
||||
if (rng(20) == 0) {
|
||||
obj.push(createAccessor(recurmax, stmtDepth, canThrow));
|
||||
} else {
|
||||
var key = KEYS[rng(KEYS.length)];
|
||||
obj.push(key + ":(" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "),");
|
||||
}
|
||||
for (var i = rng(6); --i >= 0;) switch (rng(30)) {
|
||||
case 0:
|
||||
obj.push(createObjectFunction(recurmax, stmtDepth, canThrow));
|
||||
break;
|
||||
case 1:
|
||||
obj.push(getVarName() + ",");
|
||||
break;
|
||||
default:
|
||||
obj.push(createObjectKey(recurmax, stmtDepth, canThrow) + ":(" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "),");
|
||||
break;
|
||||
}
|
||||
obj.push("})");
|
||||
return obj.join("\n");
|
||||
@@ -967,13 +1178,77 @@ function _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
|
||||
return "(" + assignee + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
||||
case 3:
|
||||
assignee = getVarName();
|
||||
expr = "(" + assignee + "[" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow)
|
||||
+ "]" + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
||||
switch (rng(20)) {
|
||||
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 + ")";
|
||||
case 4:
|
||||
assignee = getVarName();
|
||||
expr = "(" + assignee + "." + getDotKey(true) + createAssignment()
|
||||
+ _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
||||
switch (rng(20)) {
|
||||
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 + ")";
|
||||
default:
|
||||
return _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow);
|
||||
@@ -1316,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 uglify_code, uglify_result, ok;
|
||||
for (var round = 1; round <= num_iterations; round++) {
|
||||
@@ -1358,7 +1640,12 @@ for (var round = 1; round <= num_iterations; round++) {
|
||||
}
|
||||
}
|
||||
// ignore difference in error message caused by Temporal Dead Zone
|
||||
if (!ok && errored) ok = uglify_result.name == "ReferenceError" && original_result.name == "ReferenceError";
|
||||
if (!ok && errored && uglify_result.name == "ReferenceError" && original_result.name == "ReferenceError") ok = true;
|
||||
// ignore spurious time-outs
|
||||
if (!ok && errored && /timed out/.test(original_result.message) && !/timed out/.test(uglify_result.message)) {
|
||||
if (!orig_result[toplevel ? 3 : 2]) orig_result[toplevel ? 3 : 2] = sandbox.run_code(original_code, toplevel, 10000);
|
||||
ok = sandbox.same_stdout(orig_result[toplevel ? 3 : 2], uglify_result);
|
||||
}
|
||||
// ignore difference in error message caused by `in`
|
||||
// ignore difference in depth of termination caused by infinite recursion
|
||||
if (!ok) {
|
||||
|
||||
Reference in New Issue
Block a user