Compare commits
66 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bba7cd0a70 | ||
|
|
e1b2026929 | ||
|
|
c319030373 | ||
|
|
47b63ed1a0 | ||
|
|
7aefe97083 | ||
|
|
89198e0ad4 | ||
|
|
caea6aac81 | ||
|
|
f5224ca1f5 | ||
|
|
b7c49b72b3 | ||
|
|
8ce3c7d70f | ||
|
|
87cf715213 | ||
|
|
2c9c72e06c | ||
|
|
882968c68c | ||
|
|
acc2d7d845 | ||
|
|
9a5aede941 | ||
|
|
e6dd471f8f | ||
|
|
0f55bd92f1 | ||
|
|
7d9dad0289 | ||
|
|
44e494f16f | ||
|
|
2415a72e75 | ||
|
|
9c0718b162 | ||
|
|
d2c50ace99 | ||
|
|
1b646d3bc4 | ||
|
|
82d2aa4acf | ||
|
|
c1256c399a | ||
|
|
2c637fea8a | ||
|
|
4fa54b075c | ||
|
|
ab82be82b2 | ||
|
|
02fdcfde01 | ||
|
|
a96f087ac3 | ||
|
|
75e9fd8417 | ||
|
|
f68e267830 | ||
|
|
8b10b93ee1 | ||
|
|
549de028b6 | ||
|
|
f579f1aa47 | ||
|
|
fcc40d0502 | ||
|
|
b309527264 | ||
|
|
5d19bb8d5d | ||
|
|
af97629912 | ||
|
|
8c000033d3 | ||
|
|
fd0d28e465 | ||
|
|
2123f38394 | ||
|
|
58dff9ada3 | ||
|
|
4fdec765bc | ||
|
|
1020d37256 | ||
|
|
076739db07 | ||
|
|
515e93d88a | ||
|
|
57105b299e | ||
|
|
77e1bda426 | ||
|
|
a59593cac8 | ||
|
|
046bbde9d4 | ||
|
|
fea9da9866 | ||
|
|
4733159782 | ||
|
|
5fba98608c | ||
|
|
c587d7917d | ||
|
|
336336f53f | ||
|
|
4bde50ce85 | ||
|
|
fbecedf94c | ||
|
|
2f31f95095 | ||
|
|
6b603e1a62 | ||
|
|
499f8d89ff | ||
|
|
9eb65f3af3 | ||
|
|
2cbbf5c375 | ||
|
|
3c384cf9a8 | ||
|
|
37f4f56752 | ||
|
|
1e4985ed9e |
54
README.md
54
README.md
@@ -4,10 +4,12 @@ UglifyJS 3
|
|||||||
UglifyJS is a JavaScript parser, minifier, compressor and beautifier toolkit.
|
UglifyJS is a JavaScript parser, minifier, compressor and beautifier toolkit.
|
||||||
|
|
||||||
#### Note:
|
#### Note:
|
||||||
- **`uglify-js@3` has a simplified [API](#api-reference) and [CLI](#command-line-usage) that is not backwards compatible with [`uglify-js@2`](https://github.com/mishoo/UglifyJS/tree/v2.x)**.
|
- **`uglify-js@3` has a simplified [API](#api-reference) and [CLI](#command-line-usage)
|
||||||
|
that is not backwards compatible with [`uglify-js@2`](https://github.com/mishoo/UglifyJS/tree/v2.x)**.
|
||||||
- **Documentation for UglifyJS `2.x` releases can be found [here](https://github.com/mishoo/UglifyJS/tree/v2.x)**.
|
- **Documentation for UglifyJS `2.x` releases can be found [here](https://github.com/mishoo/UglifyJS/tree/v2.x)**.
|
||||||
- `uglify-js` only supports JavaScript (ECMAScript 5).
|
- `uglify-js` supports ECMAScript 5 and some newer language features.
|
||||||
- To minify ECMAScript 2015 or above, transpile using tools like [Babel](https://babeljs.io/).
|
- To minify ECMAScript 2015 or above, you may need to transpile using tools like
|
||||||
|
[Babel](https://babeljs.io/).
|
||||||
|
|
||||||
Install
|
Install
|
||||||
-------
|
-------
|
||||||
@@ -751,6 +753,8 @@ to be `false` and all symbol names will be omitted.
|
|||||||
annotation `/*@__PURE__*/` or `/*#__PURE__*/` immediately precedes the call. For
|
annotation `/*@__PURE__*/` or `/*#__PURE__*/` immediately precedes the call. For
|
||||||
example: `/*@__PURE__*/foo();`
|
example: `/*@__PURE__*/foo();`
|
||||||
|
|
||||||
|
- `spread` (default: `true`) -- flatten spread expressions.
|
||||||
|
|
||||||
- `strings` (default: `true`) -- compact string concatenations.
|
- `strings` (default: `true`) -- compact string concatenations.
|
||||||
|
|
||||||
- `switches` (default: `true`) -- de-duplicate and remove unreachable `switch` branches
|
- `switches` (default: `true`) -- de-duplicate and remove unreachable `switch` branches
|
||||||
@@ -1173,6 +1177,18 @@ To allow for better optimizations, the compiler makes various assumptions:
|
|||||||
- Object properties can be added, removed and modified (not prevented with
|
- Object properties can be added, removed and modified (not prevented with
|
||||||
`Object.defineProperty()`, `Object.defineProperties()`, `Object.freeze()`,
|
`Object.defineProperty()`, `Object.defineProperties()`, `Object.freeze()`,
|
||||||
`Object.preventExtensions()` or `Object.seal()`).
|
`Object.preventExtensions()` or `Object.seal()`).
|
||||||
|
- Earlier versions of JavaScript will throw `SyntaxError` with the following:
|
||||||
|
```js
|
||||||
|
({
|
||||||
|
p: 42,
|
||||||
|
get p() {},
|
||||||
|
});
|
||||||
|
// SyntaxError: Object literal may not have data and accessor property with
|
||||||
|
// the same name
|
||||||
|
```
|
||||||
|
UglifyJS may modify the input which in turn may suppress those errors.
|
||||||
|
- Iteration order of keys over an object which contains spread syntax in later
|
||||||
|
versions of Chrome and Node.js may be altered.
|
||||||
- When `toplevel` is enabled, UglifyJS effectively assumes input code is wrapped
|
- When `toplevel` is enabled, UglifyJS effectively assumes input code is wrapped
|
||||||
within `function(){ ... }`, thus forbids aliasing of declared global variables:
|
within `function(){ ... }`, thus forbids aliasing of declared global variables:
|
||||||
```js
|
```js
|
||||||
@@ -1193,3 +1209,35 @@ To allow for better optimizations, the compiler makes various assumptions:
|
|||||||
`function({}, arguments) {}` will result in `SyntaxError` in earlier versions
|
`function({}, arguments) {}` will result in `SyntaxError` in earlier versions
|
||||||
of Chrome and Node.js - UglifyJS may modify the input which in turn may
|
of Chrome and Node.js - UglifyJS may modify the input which in turn may
|
||||||
suppress those errors.
|
suppress those errors.
|
||||||
|
- Earlier versions of Chrome and Node.js will throw `ReferenceError` with the
|
||||||
|
following:
|
||||||
|
```js
|
||||||
|
var a;
|
||||||
|
try {
|
||||||
|
throw 42;
|
||||||
|
} catch ({
|
||||||
|
[a]: b,
|
||||||
|
// ReferenceError: a is not defined
|
||||||
|
}) {
|
||||||
|
let a;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
UglifyJS may modify the input which in turn may suppress those errors.
|
||||||
|
- Later versions of JavaScript will throw `SyntaxError` with the following:
|
||||||
|
```js
|
||||||
|
a => {
|
||||||
|
let a;
|
||||||
|
};
|
||||||
|
// SyntaxError: Identifier 'a' has already been declared
|
||||||
|
```
|
||||||
|
UglifyJS may modify the input which in turn may suppress those errors.
|
||||||
|
- Later versions of JavaScript will throw `SyntaxError` with the following:
|
||||||
|
```js
|
||||||
|
try {
|
||||||
|
// ...
|
||||||
|
} catch ({ message: a }) {
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
// SyntaxError: Identifier 'a' has already been declared
|
||||||
|
```
|
||||||
|
UglifyJS may modify the input which in turn may suppress those errors.
|
||||||
|
|||||||
166
lib/ast.js
166
lib/ast.js
@@ -209,7 +209,9 @@ var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
|
|||||||
|
|
||||||
function must_be_expression(node, prop) {
|
function must_be_expression(node, prop) {
|
||||||
if (!(node[prop] instanceof AST_Node)) throw new Error(prop + " must be AST_Node");
|
if (!(node[prop] instanceof AST_Node)) throw new Error(prop + " must be AST_Node");
|
||||||
if (node[prop] instanceof AST_Statement && !(node[prop] instanceof AST_Function)) {
|
if (node[prop] instanceof AST_Hole) throw new Error(prop + " cannot be AST_Hole");
|
||||||
|
if (node[prop] instanceof AST_Spread) throw new Error(prop + " cannot be AST_Spread");
|
||||||
|
if (node[prop] instanceof AST_Statement && !is_function(node[prop])) {
|
||||||
throw new Error(prop + " cannot be AST_Statement");
|
throw new Error(prop + " cannot be AST_Statement");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -278,7 +280,7 @@ var AST_Block = DEFNODE("Block", "body", {
|
|||||||
_validate: function() {
|
_validate: function() {
|
||||||
this.body.forEach(function(node) {
|
this.body.forEach(function(node) {
|
||||||
if (!(node instanceof AST_Statement)) throw new Error("body must be AST_Statement[]");
|
if (!(node instanceof AST_Statement)) throw new Error("body must be AST_Statement[]");
|
||||||
if (node instanceof AST_Function) throw new Error("body cannot contain AST_Function");
|
if (is_function(node)) throw new Error("body cannot contain AST_Function");
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}, AST_BlockScope);
|
}, AST_BlockScope);
|
||||||
@@ -294,7 +296,7 @@ var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", {
|
|||||||
},
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
if (!(this.body instanceof AST_Statement)) throw new Error("body must be AST_Statement");
|
if (!(this.body instanceof AST_Statement)) throw new Error("body must be AST_Statement");
|
||||||
if (this.body instanceof AST_Function) throw new Error("body cannot be AST_Function");
|
if (is_function(this.body)) throw new Error("body cannot be AST_Function");
|
||||||
},
|
},
|
||||||
}, AST_BlockScope);
|
}, AST_BlockScope);
|
||||||
|
|
||||||
@@ -388,7 +390,7 @@ var AST_For = DEFNODE("For", "init condition step", {
|
|||||||
if (this.init != null) {
|
if (this.init != null) {
|
||||||
if (!(this.init instanceof AST_Node)) throw new Error("init must be AST_Node");
|
if (!(this.init instanceof AST_Node)) throw new Error("init must be AST_Node");
|
||||||
if (this.init instanceof AST_Statement
|
if (this.init instanceof AST_Statement
|
||||||
&& !(this.init instanceof AST_Definitions || this.init instanceof AST_Function)) {
|
&& !(this.init instanceof AST_Definitions || is_function(this.init))) {
|
||||||
throw new Error("init cannot be AST_Statement");
|
throw new Error("init cannot be AST_Statement");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -500,10 +502,9 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
|||||||
}
|
}
|
||||||
}, AST_Scope);
|
}, AST_Scope);
|
||||||
|
|
||||||
var AST_Lambda = DEFNODE("Lambda", "name argnames length_read uses_arguments", {
|
var AST_Lambda = DEFNODE("Lambda", "argnames length_read uses_arguments", {
|
||||||
$documentation: "Base class for functions",
|
$documentation: "Base class for functions",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
name: "[AST_SymbolDeclaration?] the name of this function",
|
|
||||||
argnames: "[(AST_Destructured|AST_SymbolFunarg)*] array of function arguments and/or destructured literals",
|
argnames: "[(AST_Destructured|AST_SymbolFunarg)*] array of function arguments and/or destructured literals",
|
||||||
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array",
|
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array",
|
||||||
},
|
},
|
||||||
@@ -539,14 +540,53 @@ var AST_Lambda = DEFNODE("Lambda", "name argnames length_read uses_arguments", {
|
|||||||
}, AST_Scope);
|
}, AST_Scope);
|
||||||
|
|
||||||
var AST_Accessor = DEFNODE("Accessor", null, {
|
var AST_Accessor = DEFNODE("Accessor", null, {
|
||||||
$documentation: "A setter/getter function. The `name` property is always null.",
|
$documentation: "A getter/setter function",
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
if (this.name != null) throw new Error("name must be null");
|
if (this.name != null) throw new Error("name must be null");
|
||||||
},
|
},
|
||||||
}, AST_Lambda);
|
}, AST_Lambda);
|
||||||
|
|
||||||
var AST_Function = DEFNODE("Function", "inlined", {
|
function is_function(node) {
|
||||||
$documentation: "A function expression",
|
return node instanceof AST_Arrow || node instanceof AST_AsyncFunction || node instanceof AST_Function;
|
||||||
|
}
|
||||||
|
|
||||||
|
var AST_Arrow = DEFNODE("Arrow", "inlined value", {
|
||||||
|
$documentation: "An arrow function expression",
|
||||||
|
$propdoc: {
|
||||||
|
value: "[AST_Node?] simple return expression, or null if using function body.",
|
||||||
|
},
|
||||||
|
walk: function(visitor) {
|
||||||
|
var node = this;
|
||||||
|
visitor.visit(node, function() {
|
||||||
|
node.argnames.forEach(function(argname) {
|
||||||
|
argname.walk(visitor);
|
||||||
|
});
|
||||||
|
if (node.value) {
|
||||||
|
node.value.walk(visitor);
|
||||||
|
} else {
|
||||||
|
walk_body(node, visitor);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_validate: function() {
|
||||||
|
if (this.name != null) throw new Error("name must be null");
|
||||||
|
if (this.uses_arguments) throw new Error("uses_arguments must be false");
|
||||||
|
if (this.value != null) {
|
||||||
|
must_be_expression(this, "value");
|
||||||
|
if (this.body.length) throw new Error("body must be empty if value exists");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}, AST_Lambda);
|
||||||
|
|
||||||
|
function is_async(node) {
|
||||||
|
return node instanceof AST_AsyncDefun || node instanceof AST_AsyncFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
var AST_AsyncFunction = DEFNODE("AsyncFunction", "inlined name", {
|
||||||
|
$documentation: "An asynchronous function expression",
|
||||||
|
$propdoc: {
|
||||||
|
name: "[AST_SymbolLambda?] the name of this function",
|
||||||
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
if (this.name != null) {
|
if (this.name != null) {
|
||||||
if (!(this.name instanceof AST_SymbolLambda)) throw new Error("name must be AST_SymbolLambda");
|
if (!(this.name instanceof AST_SymbolLambda)) throw new Error("name must be AST_SymbolLambda");
|
||||||
@@ -554,8 +594,37 @@ var AST_Function = DEFNODE("Function", "inlined", {
|
|||||||
},
|
},
|
||||||
}, AST_Lambda);
|
}, AST_Lambda);
|
||||||
|
|
||||||
var AST_Defun = DEFNODE("Defun", "inlined", {
|
var AST_Function = DEFNODE("Function", "inlined name", {
|
||||||
|
$documentation: "A function expression",
|
||||||
|
$propdoc: {
|
||||||
|
name: "[AST_SymbolLambda?] the name of this function",
|
||||||
|
},
|
||||||
|
_validate: function() {
|
||||||
|
if (this.name != null) {
|
||||||
|
if (!(this.name instanceof AST_SymbolLambda)) throw new Error("name must be AST_SymbolLambda");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}, AST_Lambda);
|
||||||
|
|
||||||
|
function is_defun(node) {
|
||||||
|
return node instanceof AST_AsyncDefun || node instanceof AST_Defun;
|
||||||
|
}
|
||||||
|
|
||||||
|
var AST_AsyncDefun = DEFNODE("AsyncDefun", "inlined name", {
|
||||||
|
$documentation: "An asynchronous function definition",
|
||||||
|
$propdoc: {
|
||||||
|
name: "[AST_SymbolDefun] the name of this function",
|
||||||
|
},
|
||||||
|
_validate: function() {
|
||||||
|
if (!(this.name instanceof AST_SymbolDefun)) throw new Error("name must be AST_SymbolDefun");
|
||||||
|
},
|
||||||
|
}, AST_Lambda);
|
||||||
|
|
||||||
|
var AST_Defun = DEFNODE("Defun", "inlined name", {
|
||||||
$documentation: "A function definition",
|
$documentation: "A function definition",
|
||||||
|
$propdoc: {
|
||||||
|
name: "[AST_SymbolDefun] the name of this function",
|
||||||
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
if (!(this.name instanceof AST_SymbolDefun)) throw new Error("name must be AST_SymbolDefun");
|
if (!(this.name instanceof AST_SymbolDefun)) throw new Error("name must be AST_SymbolDefun");
|
||||||
},
|
},
|
||||||
@@ -640,7 +709,7 @@ var AST_If = DEFNODE("If", "condition alternative", {
|
|||||||
must_be_expression(this, "condition");
|
must_be_expression(this, "condition");
|
||||||
if (this.alternative != null) {
|
if (this.alternative != null) {
|
||||||
if (!(this.alternative instanceof AST_Statement)) throw new Error("alternative must be AST_Statement");
|
if (!(this.alternative instanceof AST_Statement)) throw new Error("alternative must be AST_Statement");
|
||||||
if (this.alternative instanceof AST_Function) throw new error("alternative cannot be AST_Function");
|
if (is_function(this.alternative)) throw new error("alternative cannot be AST_Function");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}, AST_StatementWithBody);
|
}, AST_StatementWithBody);
|
||||||
@@ -721,7 +790,7 @@ var AST_Try = DEFNODE("Try", "bcatch bfinally", {
|
|||||||
var AST_Catch = DEFNODE("Catch", "argname", {
|
var AST_Catch = DEFNODE("Catch", "argname", {
|
||||||
$documentation: "A `catch` node; only makes sense as part of a `try` statement",
|
$documentation: "A `catch` node; only makes sense as part of a `try` statement",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
argname: "[AST_SymbolCatch?] symbol for the exception, or null if not present",
|
argname: "[(AST_Destructured|AST_SymbolCatch)?] symbol for the exception, or null if not present",
|
||||||
},
|
},
|
||||||
walk: function(visitor) {
|
walk: function(visitor) {
|
||||||
var node = this;
|
var node = this;
|
||||||
@@ -731,9 +800,9 @@ var AST_Catch = DEFNODE("Catch", "argname", {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
if (this.argname != null) {
|
if (this.argname != null) validate_destructured(this.argname, function(node) {
|
||||||
if (!(this.argname instanceof AST_SymbolCatch)) throw new Error("argname must be AST_SymbolCatch");
|
if (!(node instanceof AST_SymbolCatch)) throw new Error("argname must be AST_SymbolCatch");
|
||||||
}
|
});
|
||||||
},
|
},
|
||||||
}, AST_Block);
|
}, AST_Block);
|
||||||
|
|
||||||
@@ -803,7 +872,7 @@ var AST_Var = DEFNODE("Var", null, {
|
|||||||
var AST_VarDef = DEFNODE("VarDef", "name value", {
|
var AST_VarDef = DEFNODE("VarDef", "name value", {
|
||||||
$documentation: "A variable declaration; only appears in a AST_Definitions node",
|
$documentation: "A variable declaration; only appears in a AST_Definitions node",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
name: "[AST_SymbolVar] name of the variable",
|
name: "[AST_Destructured|AST_SymbolVar] name of the variable",
|
||||||
value: "[AST_Node?] initializer, or null of there's no initializer"
|
value: "[AST_Node?] initializer, or null of there's no initializer"
|
||||||
},
|
},
|
||||||
walk: function(visitor) {
|
walk: function(visitor) {
|
||||||
@@ -817,10 +886,12 @@ var AST_VarDef = DEFNODE("VarDef", "name value", {
|
|||||||
|
|
||||||
/* -----[ OTHER ]----- */
|
/* -----[ OTHER ]----- */
|
||||||
|
|
||||||
function must_be_expressions(node, prop) {
|
function must_be_expressions(node, prop, allow_spread, allow_hole) {
|
||||||
node[prop].forEach(function(node) {
|
node[prop].forEach(function(node) {
|
||||||
if (!(node instanceof AST_Node)) throw new Error(prop + " must be AST_Node[]");
|
if (!(node instanceof AST_Node)) throw new Error(prop + " must be AST_Node[]");
|
||||||
if (node instanceof AST_Statement && !(node instanceof AST_Function)) {
|
if (!allow_hole && node instanceof AST_Hole) throw new Error(prop + " cannot be AST_Hole");
|
||||||
|
if (!allow_spread && node instanceof AST_Spread) throw new Error(prop + " cannot be AST_Spread");
|
||||||
|
if (node instanceof AST_Statement && !is_function(node)) {
|
||||||
throw new Error(prop + " cannot contain AST_Statement");
|
throw new Error(prop + " cannot contain AST_Statement");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -843,7 +914,7 @@ var AST_Call = DEFNODE("Call", "expression args pure", {
|
|||||||
},
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
must_be_expression(this, "expression");
|
must_be_expression(this, "expression");
|
||||||
must_be_expressions(this, "args");
|
must_be_expressions(this, "args", true);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -920,6 +991,22 @@ var AST_Sub = DEFNODE("Sub", null, {
|
|||||||
},
|
},
|
||||||
}, AST_PropAccess);
|
}, AST_PropAccess);
|
||||||
|
|
||||||
|
var AST_Spread = DEFNODE("Spread", "expression", {
|
||||||
|
$documentation: "Spread expression in array/object literals or function calls",
|
||||||
|
$propdoc: {
|
||||||
|
expression: "[AST_Node] expression to be expanded",
|
||||||
|
},
|
||||||
|
walk: function(visitor) {
|
||||||
|
var node = this;
|
||||||
|
visitor.visit(node, function() {
|
||||||
|
node.expression.walk(visitor);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_validate: function() {
|
||||||
|
must_be_expression(this, "expression");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
var AST_Unary = DEFNODE("Unary", "operator expression", {
|
var AST_Unary = DEFNODE("Unary", "operator expression", {
|
||||||
$documentation: "Base class for unary expressions",
|
$documentation: "Base class for unary expressions",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
@@ -1004,6 +1091,22 @@ var AST_Assign = DEFNODE("Assign", null, {
|
|||||||
},
|
},
|
||||||
}, AST_Binary);
|
}, AST_Binary);
|
||||||
|
|
||||||
|
var AST_Await = DEFNODE("Await", "expression", {
|
||||||
|
$documentation: "An await expression",
|
||||||
|
$propdoc: {
|
||||||
|
expression: "[AST_Node] expression with Promise to resolve on",
|
||||||
|
},
|
||||||
|
walk: function(visitor) {
|
||||||
|
var node = this;
|
||||||
|
visitor.visit(node, function() {
|
||||||
|
node.expression.walk(visitor);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_validate: function() {
|
||||||
|
must_be_expression(this, "expression");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
/* -----[ LITERALS ]----- */
|
/* -----[ LITERALS ]----- */
|
||||||
|
|
||||||
var AST_Array = DEFNODE("Array", "elements", {
|
var AST_Array = DEFNODE("Array", "elements", {
|
||||||
@@ -1020,7 +1123,7 @@ var AST_Array = DEFNODE("Array", "elements", {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
must_be_expressions(this, "elements");
|
must_be_expressions(this, "elements", true, true);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1098,7 +1201,7 @@ var AST_DestructuredObject = DEFNODE("DestructuredObject", "properties", {
|
|||||||
var AST_Object = DEFNODE("Object", "properties", {
|
var AST_Object = DEFNODE("Object", "properties", {
|
||||||
$documentation: "An object literal",
|
$documentation: "An object literal",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
properties: "[AST_ObjectProperty*] array of properties"
|
properties: "[(AST_ObjectProperty|AST_Spread)*] array of properties"
|
||||||
},
|
},
|
||||||
walk: function(visitor) {
|
walk: function(visitor) {
|
||||||
var node = this;
|
var node = this;
|
||||||
@@ -1110,7 +1213,9 @@ var AST_Object = DEFNODE("Object", "properties", {
|
|||||||
},
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
this.properties.forEach(function(node) {
|
this.properties.forEach(function(node) {
|
||||||
if (!(node instanceof AST_ObjectProperty)) throw new Error("properties must be AST_ObjectProperty[]");
|
if (!(node instanceof AST_ObjectProperty || node instanceof AST_Spread)) {
|
||||||
|
throw new Error("properties must contain AST_ObjectProperty and/or AST_Spread only");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -1213,7 +1318,7 @@ var AST_Label = DEFNODE("Label", "references", {
|
|||||||
}
|
}
|
||||||
}, AST_Symbol);
|
}, AST_Symbol);
|
||||||
|
|
||||||
var AST_SymbolRef = DEFNODE("SymbolRef", "fixed", {
|
var AST_SymbolRef = DEFNODE("SymbolRef", "fixed in_arg", {
|
||||||
$documentation: "Reference to some symbol (not definition/declaration)",
|
$documentation: "Reference to some symbol (not definition/declaration)",
|
||||||
}, AST_Symbol);
|
}, AST_Symbol);
|
||||||
|
|
||||||
@@ -1389,14 +1494,13 @@ TreeWalker.prototype = {
|
|||||||
|| p.tail_node() === self) {
|
|| p.tail_node() === self) {
|
||||||
self = p;
|
self = p;
|
||||||
} else if (p instanceof AST_Return) {
|
} else if (p instanceof AST_Return) {
|
||||||
var fn;
|
for (var call, fn = p; call = this.parent(++i); fn = call) {
|
||||||
do {
|
if (call.TYPE == "Call") {
|
||||||
fn = this.parent(++i);
|
if (!(fn instanceof AST_Lambda) || fn.name) return false;
|
||||||
if (!fn) return false;
|
} else if (fn instanceof AST_Lambda) {
|
||||||
} while (!(fn instanceof AST_Lambda));
|
return false;
|
||||||
if (fn.name) return false;
|
}
|
||||||
self = this.parent(++i);
|
}
|
||||||
if (!self || self.TYPE != "Call" || self.expression !== fn) return false;
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
868
lib/compress.js
868
lib/compress.js
File diff suppressed because it is too large
Load Diff
@@ -661,7 +661,7 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
// a function expression needs parens around it when it's provably
|
// a function expression needs parens around it when it's provably
|
||||||
// the first token to appear in a statement.
|
// the first token to appear in a statement.
|
||||||
PARENS(AST_Function, function(output) {
|
function needs_parens_function(output) {
|
||||||
if (!output.has_parens() && first_in_statement(output)) return true;
|
if (!output.has_parens() && first_in_statement(output)) return true;
|
||||||
if (output.option("webkit")) {
|
if (output.option("webkit")) {
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
@@ -671,12 +671,14 @@ function OutputStream(options) {
|
|||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
if (p instanceof AST_Call && p.expression === this) return true;
|
if (p instanceof AST_Call && p.expression === this) return true;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
PARENS(AST_AsyncFunction, needs_parens_function);
|
||||||
|
PARENS(AST_Function, needs_parens_function);
|
||||||
|
|
||||||
// same goes for an object literal, because otherwise it would be
|
// same goes for an object literal, because otherwise it would be
|
||||||
// interpreted as a block of code.
|
// interpreted as a block of code.
|
||||||
function needs_parens_obj(output) {
|
function needs_parens_obj(output) {
|
||||||
return !output.has_parens() && first_in_statement(output);
|
return !output.has_parens() && first_in_statement(output, true);
|
||||||
}
|
}
|
||||||
PARENS(AST_Object, needs_parens_obj);
|
PARENS(AST_Object, needs_parens_obj);
|
||||||
|
|
||||||
@@ -689,6 +691,10 @@ function OutputStream(options) {
|
|||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
// [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
|
// [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
|
||||||
return p instanceof AST_Array
|
return p instanceof AST_Array
|
||||||
|
// () => (foo, bar)
|
||||||
|
|| p instanceof AST_Arrow && p.value === this
|
||||||
|
// await (foo, bar)
|
||||||
|
|| p instanceof AST_Await
|
||||||
// 1 + (2, 3) + 4 ==> 8
|
// 1 + (2, 3) + 4 ==> 8
|
||||||
|| p instanceof AST_Binary
|
|| p instanceof AST_Binary
|
||||||
// new (foo, bar) or foo(1, (2, 3), 4)
|
// new (foo, bar) or foo(1, (2, 3), 4)
|
||||||
@@ -702,6 +708,8 @@ function OutputStream(options) {
|
|||||||
|| p instanceof AST_ObjectProperty
|
|| p instanceof AST_ObjectProperty
|
||||||
// (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|
// (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|
||||||
|| p instanceof AST_PropAccess && p.expression === this
|
|| p instanceof AST_PropAccess && p.expression === this
|
||||||
|
// ...(foo, bar, baz)
|
||||||
|
|| p instanceof AST_Spread
|
||||||
// !(foo, bar, baz)
|
// !(foo, bar, baz)
|
||||||
|| p instanceof AST_Unary
|
|| p instanceof AST_Unary
|
||||||
// var a = (1, 2), b = a + a; ==> b == 4
|
// var a = (1, 2), b = a + a; ==> b == 4
|
||||||
@@ -710,6 +718,8 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
PARENS(AST_Binary, function(output) {
|
PARENS(AST_Binary, function(output) {
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
|
// await (foo && bar)
|
||||||
|
if (p instanceof AST_Await) return true;
|
||||||
// this deals with precedence: 3 * (2 + 1)
|
// this deals with precedence: 3 * (2 + 1)
|
||||||
if (p instanceof AST_Binary) {
|
if (p instanceof AST_Binary) {
|
||||||
var po = p.operator, pp = PRECEDENCE[po];
|
var po = p.operator, pp = PRECEDENCE[po];
|
||||||
@@ -777,6 +787,8 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
function needs_parens_assign_cond(self, output) {
|
function needs_parens_assign_cond(self, output) {
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
|
// await (a = foo)
|
||||||
|
if (p instanceof AST_Await) return true;
|
||||||
// 1 + (a = 2) + 3 → 6, side effect setting a = 2
|
// 1 + (a = 2) + 3 → 6, side effect setting a = 2
|
||||||
if (p instanceof AST_Binary) return !(p instanceof AST_Assign);
|
if (p instanceof AST_Binary) return !(p instanceof AST_Assign);
|
||||||
// (a = func)() —or— new (a = Object)()
|
// (a = func)() —or— new (a = Object)()
|
||||||
@@ -788,6 +800,9 @@ function OutputStream(options) {
|
|||||||
// !(a = false) → true
|
// !(a = false) → true
|
||||||
if (p instanceof AST_Unary) return true;
|
if (p instanceof AST_Unary) return true;
|
||||||
}
|
}
|
||||||
|
PARENS(AST_Arrow, function(output) {
|
||||||
|
return needs_parens_assign_cond(this, output);
|
||||||
|
});
|
||||||
PARENS(AST_Assign, function(output) {
|
PARENS(AST_Assign, function(output) {
|
||||||
if (needs_parens_assign_cond(this, output)) return true;
|
if (needs_parens_assign_cond(this, output)) return true;
|
||||||
// v8 parser bug => workaround
|
// v8 parser bug => workaround
|
||||||
@@ -800,6 +815,16 @@ function OutputStream(options) {
|
|||||||
return needs_parens_assign_cond(this, output);
|
return needs_parens_assign_cond(this, output);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
PARENS(AST_Await, function(output) {
|
||||||
|
var p = output.parent();
|
||||||
|
// new (await foo)
|
||||||
|
// (await foo)(bar)
|
||||||
|
if (p instanceof AST_Call) return p.expression === this;
|
||||||
|
// (await foo).prop
|
||||||
|
// (await foo)["prop"]
|
||||||
|
if (p instanceof AST_PropAccess) return p.expression === this;
|
||||||
|
});
|
||||||
|
|
||||||
/* -----[ PRINTERS ]----- */
|
/* -----[ PRINTERS ]----- */
|
||||||
|
|
||||||
DEFPRINT(AST_Directive, function(output) {
|
DEFPRINT(AST_Directive, function(output) {
|
||||||
@@ -965,11 +990,26 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ functions ]----- */
|
/* -----[ functions ]----- */
|
||||||
DEFPRINT(AST_Lambda, function(output, nokeyword) {
|
DEFPRINT(AST_Arrow, function(output) {
|
||||||
var self = this;
|
var self = this;
|
||||||
if (!nokeyword) {
|
if (self.argnames.length == 1 && self.argnames[0] instanceof AST_SymbolFunarg) {
|
||||||
output.print("function");
|
self.argnames[0].print(output);
|
||||||
|
} else output.with_parens(function() {
|
||||||
|
self.argnames.forEach(function(arg, i) {
|
||||||
|
if (i) output.comma();
|
||||||
|
arg.print(output);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
output.space();
|
||||||
|
output.print("=>");
|
||||||
|
output.space();
|
||||||
|
if (self.value) {
|
||||||
|
self.value.print(output);
|
||||||
|
} else {
|
||||||
|
print_braced(self, output, true);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
function print_lambda(self, output) {
|
||||||
if (self.name) {
|
if (self.name) {
|
||||||
output.space();
|
output.space();
|
||||||
self.name.print(output);
|
self.name.print(output);
|
||||||
@@ -982,7 +1022,19 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
output.space();
|
output.space();
|
||||||
print_braced(self, output, true);
|
print_braced(self, output, true);
|
||||||
|
}
|
||||||
|
DEFPRINT(AST_Lambda, function(output) {
|
||||||
|
output.print("function");
|
||||||
|
print_lambda(this, output);
|
||||||
});
|
});
|
||||||
|
function print_async(output) {
|
||||||
|
output.print("async");
|
||||||
|
output.space();
|
||||||
|
output.print("function");
|
||||||
|
print_lambda(this, output);
|
||||||
|
}
|
||||||
|
DEFPRINT(AST_AsyncDefun, print_async);
|
||||||
|
DEFPRINT(AST_AsyncFunction, print_async);
|
||||||
|
|
||||||
/* -----[ jumps ]----- */
|
/* -----[ jumps ]----- */
|
||||||
function print_jump(kind, prop) {
|
function print_jump(kind, prop) {
|
||||||
@@ -1146,11 +1198,9 @@ function OutputStream(options) {
|
|||||||
// need to take some precautions here:
|
// need to take some precautions here:
|
||||||
// https://github.com/mishoo/UglifyJS/issues/60
|
// https://github.com/mishoo/UglifyJS/issues/60
|
||||||
if (noin) node.walk(new TreeWalker(function(node) {
|
if (noin) node.walk(new TreeWalker(function(node) {
|
||||||
if (parens || node instanceof AST_Scope) return true;
|
if (parens) return true;
|
||||||
if (node instanceof AST_Binary && node.operator == "in") {
|
if (node instanceof AST_Binary && node.operator == "in") return parens = true;
|
||||||
parens = true;
|
if (node instanceof AST_Scope && !(node instanceof AST_Arrow && node.value)) return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
node.print(output, parens);
|
node.print(output, parens);
|
||||||
}
|
}
|
||||||
@@ -1231,6 +1281,10 @@ function OutputStream(options) {
|
|||||||
this.property.print(output);
|
this.property.print(output);
|
||||||
output.print("]");
|
output.print("]");
|
||||||
});
|
});
|
||||||
|
DEFPRINT(AST_Spread, function(output) {
|
||||||
|
output.print("...");
|
||||||
|
this.expression.print(output);
|
||||||
|
});
|
||||||
DEFPRINT(AST_UnaryPrefix, function(output) {
|
DEFPRINT(AST_UnaryPrefix, function(output) {
|
||||||
var op = this.operator;
|
var op = this.operator;
|
||||||
var exp = this.expression;
|
var exp = this.expression;
|
||||||
@@ -1266,6 +1320,11 @@ function OutputStream(options) {
|
|||||||
output.colon();
|
output.colon();
|
||||||
self.alternative.print(output);
|
self.alternative.print(output);
|
||||||
});
|
});
|
||||||
|
DEFPRINT(AST_Await, function(output) {
|
||||||
|
output.print("await");
|
||||||
|
output.space();
|
||||||
|
this.expression.print(output);
|
||||||
|
});
|
||||||
|
|
||||||
/* -----[ literals ]----- */
|
/* -----[ literals ]----- */
|
||||||
DEFPRINT(AST_Array, function(output) {
|
DEFPRINT(AST_Array, function(output) {
|
||||||
@@ -1369,7 +1428,7 @@ function OutputStream(options) {
|
|||||||
output.print(type);
|
output.print(type);
|
||||||
output.space();
|
output.space();
|
||||||
print_property_key(self, output);
|
print_property_key(self, output);
|
||||||
self.value._codegen(output, true);
|
print_lambda(self.value, output);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
DEFPRINT(AST_ObjectGetter, print_accessor("get"));
|
DEFPRINT(AST_ObjectGetter, print_accessor("get"));
|
||||||
|
|||||||
346
lib/parse.js
346
lib/parse.js
@@ -47,7 +47,7 @@
|
|||||||
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 = "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 KEYWORDS_ATOM = "false null true";
|
||||||
var RESERVED_WORDS = [
|
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",
|
"await abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized this throws transient volatile yield",
|
||||||
KEYWORDS_ATOM,
|
KEYWORDS_ATOM,
|
||||||
KEYWORDS,
|
KEYWORDS,
|
||||||
].join(" ");
|
].join(" ");
|
||||||
@@ -501,7 +501,16 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
|||||||
|
|
||||||
function handle_dot() {
|
function handle_dot() {
|
||||||
next();
|
next();
|
||||||
return is_digit(peek().charCodeAt(0)) ? read_num(".") : token("punc", ".");
|
var ch = peek();
|
||||||
|
if (ch == ".") {
|
||||||
|
var op = ".";
|
||||||
|
do {
|
||||||
|
op += ".";
|
||||||
|
next();
|
||||||
|
} while (peek() == ".");
|
||||||
|
return token("operator", op);
|
||||||
|
}
|
||||||
|
return is_digit(ch.charCodeAt(0)) ? read_num(".") : token("punc", ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
function read_word() {
|
function read_word() {
|
||||||
@@ -560,6 +569,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
|||||||
}
|
}
|
||||||
if (is_digit(code)) return read_num();
|
if (is_digit(code)) return read_num();
|
||||||
if (PUNC_CHARS[ch]) return token("punc", next());
|
if (PUNC_CHARS[ch]) return token("punc", next());
|
||||||
|
if (looking_at("=>")) return token("punc", next() + next());
|
||||||
if (OPERATOR_CHARS[ch]) return read_operator();
|
if (OPERATOR_CHARS[ch]) return read_operator();
|
||||||
if (code == 92 || !NON_IDENTIFIER_CHARS[ch]) return read_word();
|
if (code == 92 || !NON_IDENTIFIER_CHARS[ch]) return read_word();
|
||||||
break;
|
break;
|
||||||
@@ -625,7 +635,7 @@ var PRECEDENCE = function(a, ret) {
|
|||||||
["*", "/", "%"]
|
["*", "/", "%"]
|
||||||
], {});
|
], {});
|
||||||
|
|
||||||
var ATOMIC_START_TOKEN = makePredicate("atom num string regexp name");
|
var ATOMIC_START_TOKEN = makePredicate("atom num regexp string");
|
||||||
|
|
||||||
/* -----[ Parser ]----- */
|
/* -----[ Parser ]----- */
|
||||||
|
|
||||||
@@ -644,13 +654,15 @@ function parse($TEXT, options) {
|
|||||||
input : typeof $TEXT == "string"
|
input : typeof $TEXT == "string"
|
||||||
? tokenizer($TEXT, options.filename, options.html5_comments, options.shebang)
|
? tokenizer($TEXT, options.filename, options.html5_comments, options.shebang)
|
||||||
: $TEXT,
|
: $TEXT,
|
||||||
token : null,
|
in_async : false,
|
||||||
prev : null,
|
|
||||||
peeked : null,
|
|
||||||
in_function : 0,
|
|
||||||
in_directives : true,
|
in_directives : true,
|
||||||
|
in_funarg : -1,
|
||||||
|
in_function : 0,
|
||||||
in_loop : 0,
|
in_loop : 0,
|
||||||
labels : []
|
labels : [],
|
||||||
|
peeked : null,
|
||||||
|
prev : null,
|
||||||
|
token : null,
|
||||||
};
|
};
|
||||||
|
|
||||||
S.token = next();
|
S.token = next();
|
||||||
@@ -730,7 +742,7 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
function parenthesised() {
|
function parenthesised() {
|
||||||
expect("(");
|
expect("(");
|
||||||
var exp = expression(true);
|
var exp = expression();
|
||||||
expect(")");
|
expect(")");
|
||||||
return exp;
|
return exp;
|
||||||
}
|
}
|
||||||
@@ -758,7 +770,7 @@ function parse($TEXT, options) {
|
|||||||
switch (S.token.type) {
|
switch (S.token.type) {
|
||||||
case "string":
|
case "string":
|
||||||
var dir = S.in_directives;
|
var dir = S.in_directives;
|
||||||
var body = expression(true);
|
var body = expression();
|
||||||
if (dir) {
|
if (dir) {
|
||||||
if (body instanceof AST_String) {
|
if (body instanceof AST_String) {
|
||||||
var value = body.start.raw.slice(1, -1);
|
var value = body.start.raw.slice(1, -1);
|
||||||
@@ -777,9 +789,20 @@ function parse($TEXT, options) {
|
|||||||
return simple_statement();
|
return simple_statement();
|
||||||
|
|
||||||
case "name":
|
case "name":
|
||||||
|
switch (S.token.value) {
|
||||||
|
case "async":
|
||||||
|
if (is_token(peek(), "keyword", "function")) {
|
||||||
|
next();
|
||||||
|
next();
|
||||||
|
return function_(AST_AsyncDefun);
|
||||||
|
}
|
||||||
|
case "await":
|
||||||
|
if (S.in_async) return simple_statement();
|
||||||
|
default:
|
||||||
return is_token(peek(), "punc", ":")
|
return is_token(peek(), "punc", ":")
|
||||||
? labeled_statement()
|
? labeled_statement()
|
||||||
: simple_statement();
|
: simple_statement();
|
||||||
|
}
|
||||||
|
|
||||||
case "punc":
|
case "punc":
|
||||||
switch (S.token.value) {
|
switch (S.token.value) {
|
||||||
@@ -865,7 +888,7 @@ function parse($TEXT, options) {
|
|||||||
if (is("punc", ";")) {
|
if (is("punc", ";")) {
|
||||||
next();
|
next();
|
||||||
} else if (!can_insert_semicolon()) {
|
} else if (!can_insert_semicolon()) {
|
||||||
value = expression(true);
|
value = expression();
|
||||||
semicolon();
|
semicolon();
|
||||||
}
|
}
|
||||||
return new AST_Return({
|
return new AST_Return({
|
||||||
@@ -883,7 +906,7 @@ function parse($TEXT, options) {
|
|||||||
next();
|
next();
|
||||||
if (has_newline_before(S.token))
|
if (has_newline_before(S.token))
|
||||||
croak("Illegal newline after 'throw'");
|
croak("Illegal newline after 'throw'");
|
||||||
var value = expression(true);
|
var value = expression();
|
||||||
semicolon();
|
semicolon();
|
||||||
return new AST_Throw({
|
return new AST_Throw({
|
||||||
value: value
|
value: value
|
||||||
@@ -934,9 +957,7 @@ function parse($TEXT, options) {
|
|||||||
// https://github.com/mishoo/UglifyJS/issues/287
|
// https://github.com/mishoo/UglifyJS/issues/287
|
||||||
label.references.forEach(function(ref) {
|
label.references.forEach(function(ref) {
|
||||||
if (ref instanceof AST_Continue) {
|
if (ref instanceof AST_Continue) {
|
||||||
ref = ref.label.start;
|
token_error(ref.label.start, "Continue label `" + label.name + "` must refer to IterationStatement");
|
||||||
croak("Continue label `" + label.name + "` refers to non-IterationStatement.",
|
|
||||||
ref.line, ref.col, ref.pos);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -944,7 +965,7 @@ function parse($TEXT, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function simple_statement() {
|
function simple_statement() {
|
||||||
var body = expression(true);
|
var body = expression();
|
||||||
semicolon();
|
semicolon();
|
||||||
return new AST_SimpleStatement({ body: body });
|
return new AST_SimpleStatement({ body: body });
|
||||||
}
|
}
|
||||||
@@ -958,7 +979,7 @@ function parse($TEXT, options) {
|
|||||||
ldef = find_if(function(l) {
|
ldef = find_if(function(l) {
|
||||||
return l.name == label.name;
|
return l.name == label.name;
|
||||||
}, S.labels);
|
}, S.labels);
|
||||||
if (!ldef) croak("Undefined label " + label.name);
|
if (!ldef) token_error(label.start, "Undefined label " + label.name);
|
||||||
label.thedef = ldef;
|
label.thedef = ldef;
|
||||||
} else if (S.in_loop == 0) croak(type.TYPE + " not inside a loop or switch");
|
} else if (S.in_loop == 0) croak(type.TYPE + " not inside a loop or switch");
|
||||||
semicolon();
|
semicolon();
|
||||||
@@ -977,13 +998,14 @@ function parse($TEXT, options) {
|
|||||||
? (next(), let_(true))
|
? (next(), let_(true))
|
||||||
: is("keyword", "var")
|
: is("keyword", "var")
|
||||||
? (next(), var_(true))
|
? (next(), var_(true))
|
||||||
: expression(true, true);
|
: expression(true);
|
||||||
if (is("operator", "in")) {
|
if (is("operator", "in")) {
|
||||||
if (init instanceof AST_Definitions) {
|
if (init instanceof AST_Definitions) {
|
||||||
if (init.definitions.length > 1)
|
if (init.definitions.length > 1) {
|
||||||
croak("Only one variable declaration allowed in for..in loop", init.start.line, init.start.col, init.start.pos);
|
token_error(init.start, "Only one variable declaration allowed in for..in loop");
|
||||||
|
}
|
||||||
} else if (!(is_assignable(init) || (init = to_destructured(init)) instanceof AST_Destructured)) {
|
} 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);
|
token_error(init.start, "Invalid left-hand side in for..in loop");
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
return for_in(init);
|
return for_in(init);
|
||||||
@@ -994,9 +1016,9 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
function regular_for(init) {
|
function regular_for(init) {
|
||||||
expect(";");
|
expect(";");
|
||||||
var test = is("punc", ";") ? null : expression(true);
|
var test = is("punc", ";") ? null : expression();
|
||||||
expect(";");
|
expect(";");
|
||||||
var step = is("punc", ")") ? null : expression(true);
|
var step = is("punc", ")") ? null : expression();
|
||||||
expect(")");
|
expect(")");
|
||||||
return new AST_For({
|
return new AST_For({
|
||||||
init : init,
|
init : init,
|
||||||
@@ -1007,7 +1029,7 @@ function parse($TEXT, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function for_in(init) {
|
function for_in(init) {
|
||||||
var obj = expression(true);
|
var obj = expression();
|
||||||
expect(")");
|
expect(")");
|
||||||
return new AST_ForIn({
|
return new AST_ForIn({
|
||||||
init : init,
|
init : init,
|
||||||
@@ -1016,20 +1038,93 @@ function parse($TEXT, options) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function to_funarg(node) {
|
||||||
|
if (node instanceof AST_Array) return new AST_DestructuredArray({
|
||||||
|
start: node.start,
|
||||||
|
elements: node.elements.map(function(node) {
|
||||||
|
return node instanceof AST_Hole ? node : to_funarg(node);
|
||||||
|
}),
|
||||||
|
end: node.end,
|
||||||
|
});
|
||||||
|
if (node instanceof AST_Object) return new AST_DestructuredObject({
|
||||||
|
start: node.start,
|
||||||
|
properties: node.properties.map(function(prop) {
|
||||||
|
if (!(prop instanceof AST_ObjectKeyVal)) token_error(prop.start, "Invalid destructuring assignment");
|
||||||
|
return new AST_DestructuredKeyVal({
|
||||||
|
start: prop.start,
|
||||||
|
key: prop.key,
|
||||||
|
value: to_funarg(prop.value),
|
||||||
|
end: prop.end,
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
end: node.end,
|
||||||
|
});
|
||||||
|
if (node instanceof AST_SymbolRef) return new AST_SymbolFunarg(node);
|
||||||
|
token_error(node.start, "Invalid arrow parameter");
|
||||||
|
}
|
||||||
|
|
||||||
|
function arrow(exprs, start) {
|
||||||
|
var was_async = S.in_async;
|
||||||
|
S.in_async = false;
|
||||||
|
var was_funarg = S.in_funarg;
|
||||||
|
S.in_funarg = S.in_function;
|
||||||
|
var argnames = exprs.map(to_funarg);
|
||||||
|
S.in_funarg = was_funarg;
|
||||||
|
expect("=>");
|
||||||
|
var body, value;
|
||||||
|
var loop = S.in_loop;
|
||||||
|
var labels = S.labels;
|
||||||
|
++S.in_function;
|
||||||
|
S.in_directives = true;
|
||||||
|
S.input.push_directives_stack();
|
||||||
|
S.in_loop = 0;
|
||||||
|
S.labels = [];
|
||||||
|
if (is("punc", "{")) {
|
||||||
|
body = block_();
|
||||||
|
value = null;
|
||||||
|
if (S.input.has_directive("use strict")) {
|
||||||
|
argnames.forEach(strict_verify_symbol);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
body = [];
|
||||||
|
value = maybe_assign();
|
||||||
|
}
|
||||||
|
S.input.pop_directives_stack();
|
||||||
|
--S.in_function;
|
||||||
|
S.in_loop = loop;
|
||||||
|
S.labels = labels;
|
||||||
|
S.in_async = was_async;
|
||||||
|
return new AST_Arrow({
|
||||||
|
start: start,
|
||||||
|
argnames: argnames,
|
||||||
|
body: body,
|
||||||
|
value: value,
|
||||||
|
end: prev(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var function_ = function(ctor) {
|
var function_ = function(ctor) {
|
||||||
var in_statement = ctor === AST_Defun;
|
var was_async = S.in_async;
|
||||||
var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null;
|
var name;
|
||||||
if (in_statement && !name)
|
if (ctor === AST_AsyncDefun) {
|
||||||
expect_token("name");
|
name = as_symbol(AST_SymbolDefun);
|
||||||
|
S.in_async = true;
|
||||||
|
} else if (ctor === AST_Defun) {
|
||||||
|
name = as_symbol(AST_SymbolDefun);
|
||||||
|
S.in_async = false;
|
||||||
|
} else {
|
||||||
|
S.in_async = ctor === AST_AsyncFunction;
|
||||||
|
name = as_symbol(AST_SymbolLambda, true);
|
||||||
|
}
|
||||||
if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration))
|
if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration))
|
||||||
unexpected(prev());
|
unexpected(prev());
|
||||||
expect("(");
|
expect("(");
|
||||||
var argnames = [];
|
var was_funarg = S.in_funarg;
|
||||||
for (var first = true; !is("punc", ")");) {
|
S.in_funarg = S.in_function;
|
||||||
if (first) first = false; else expect(",");
|
var argnames = expr_list(")", !options.strict, false, function() {
|
||||||
argnames.push(maybe_destructured(AST_SymbolFunarg));
|
return maybe_destructured(AST_SymbolFunarg);
|
||||||
}
|
});
|
||||||
next();
|
S.in_funarg = was_funarg;
|
||||||
var loop = S.in_loop;
|
var loop = S.in_loop;
|
||||||
var labels = S.labels;
|
var labels = S.labels;
|
||||||
++S.in_function;
|
++S.in_function;
|
||||||
@@ -1046,6 +1141,7 @@ function parse($TEXT, options) {
|
|||||||
--S.in_function;
|
--S.in_function;
|
||||||
S.in_loop = loop;
|
S.in_loop = loop;
|
||||||
S.labels = labels;
|
S.labels = labels;
|
||||||
|
S.in_async = was_async;
|
||||||
return new ctor({
|
return new ctor({
|
||||||
name: name,
|
name: name,
|
||||||
argnames: argnames,
|
argnames: argnames,
|
||||||
@@ -1087,7 +1183,7 @@ function parse($TEXT, options) {
|
|||||||
cur = [];
|
cur = [];
|
||||||
branch = new AST_Case({
|
branch = new AST_Case({
|
||||||
start : (tmp = S.token, next(), tmp),
|
start : (tmp = S.token, next(), tmp),
|
||||||
expression : expression(true),
|
expression : expression(),
|
||||||
body : cur
|
body : cur
|
||||||
});
|
});
|
||||||
a.push(branch);
|
a.push(branch);
|
||||||
@@ -1120,7 +1216,7 @@ function parse($TEXT, options) {
|
|||||||
var name = null;
|
var name = null;
|
||||||
if (is("punc", "(")) {
|
if (is("punc", "(")) {
|
||||||
next();
|
next();
|
||||||
name = as_symbol(AST_SymbolCatch);
|
name = maybe_destructured(AST_SymbolCatch);
|
||||||
expect(")");
|
expect(")");
|
||||||
}
|
}
|
||||||
bcatch = new AST_Catch({
|
bcatch = new AST_Catch({
|
||||||
@@ -1156,7 +1252,7 @@ function parse($TEXT, options) {
|
|||||||
var value = null;
|
var value = null;
|
||||||
if (is("operator", "=")) {
|
if (is("operator", "=")) {
|
||||||
next();
|
next();
|
||||||
value = expression(false, no_in);
|
value = maybe_assign(no_in);
|
||||||
} else if (!no_in && (type === AST_SymbolConst || name instanceof AST_Destructured)) {
|
} else if (!no_in && (type === AST_SymbolConst || name instanceof AST_Destructured)) {
|
||||||
croak("Missing initializer in declaration");
|
croak("Missing initializer in declaration");
|
||||||
}
|
}
|
||||||
@@ -1203,7 +1299,7 @@ function parse($TEXT, options) {
|
|||||||
var newexp = expr_atom(false), args;
|
var newexp = expr_atom(false), args;
|
||||||
if (is("punc", "(")) {
|
if (is("punc", "(")) {
|
||||||
next();
|
next();
|
||||||
args = expr_list(")");
|
args = expr_list(")", !options.strict);
|
||||||
} else {
|
} else {
|
||||||
args = [];
|
args = [];
|
||||||
}
|
}
|
||||||
@@ -1220,9 +1316,6 @@ function parse($TEXT, options) {
|
|||||||
function as_atom_node() {
|
function as_atom_node() {
|
||||||
var tok = S.token, ret;
|
var tok = S.token, ret;
|
||||||
switch (tok.type) {
|
switch (tok.type) {
|
||||||
case "name":
|
|
||||||
ret = _make_symbol(AST_SymbolRef, tok);
|
|
||||||
break;
|
|
||||||
case "num":
|
case "num":
|
||||||
ret = new AST_Number({ start: tok, end: tok, value: tok.value });
|
ret = new AST_Number({ start: tok, end: tok, value: tok.value });
|
||||||
break;
|
break;
|
||||||
@@ -1264,7 +1357,11 @@ function parse($TEXT, options) {
|
|||||||
switch (start.value) {
|
switch (start.value) {
|
||||||
case "(":
|
case "(":
|
||||||
next();
|
next();
|
||||||
var ex = expression(true);
|
if (is("punc", ")")) {
|
||||||
|
next();
|
||||||
|
return arrow([], start);
|
||||||
|
}
|
||||||
|
var ex = expression(false, true);
|
||||||
var len = start.comments_before.length;
|
var len = start.comments_before.length;
|
||||||
[].unshift.apply(ex.start.comments_before, start.comments_before);
|
[].unshift.apply(ex.start.comments_before, start.comments_before);
|
||||||
start.comments_before.length = 0;
|
start.comments_before.length = 0;
|
||||||
@@ -1287,6 +1384,7 @@ function parse($TEXT, options) {
|
|||||||
end.comments_after = ex.end.comments_after;
|
end.comments_after = ex.end.comments_after;
|
||||||
ex.end = end;
|
ex.end = end;
|
||||||
if (ex instanceof AST_Call) mark_pure(ex);
|
if (ex instanceof AST_Call) mark_pure(ex);
|
||||||
|
if (is("punc", "=>")) return arrow(ex instanceof AST_Sequence ? ex.expressions : [ ex ], start);
|
||||||
return subscripts(ex, allow_calls);
|
return subscripts(ex, allow_calls);
|
||||||
case "[":
|
case "[":
|
||||||
return subscripts(array_(), allow_calls);
|
return subscripts(array_(), allow_calls);
|
||||||
@@ -1295,13 +1393,25 @@ function parse($TEXT, options) {
|
|||||||
}
|
}
|
||||||
unexpected();
|
unexpected();
|
||||||
}
|
}
|
||||||
if (is("keyword", "function")) {
|
var ctor;
|
||||||
|
if (is("name", "async") && is_token(peek(), "keyword", "function")) {
|
||||||
next();
|
next();
|
||||||
var func = function_(AST_Function);
|
ctor = AST_AsyncFunction;
|
||||||
|
} else if (is("keyword", "function")) {
|
||||||
|
ctor = AST_Function;
|
||||||
|
}
|
||||||
|
if (ctor) {
|
||||||
|
next();
|
||||||
|
var func = function_(ctor);
|
||||||
func.start = start;
|
func.start = start;
|
||||||
func.end = prev();
|
func.end = prev();
|
||||||
return subscripts(func, allow_calls);
|
return subscripts(func, allow_calls);
|
||||||
}
|
}
|
||||||
|
if (is("name")) {
|
||||||
|
var sym = _make_symbol(AST_SymbolRef, start);
|
||||||
|
next();
|
||||||
|
return is("punc", "=>") ? arrow([ sym ], start) : subscripts(sym, allow_calls);
|
||||||
|
}
|
||||||
if (ATOMIC_START_TOKEN[S.token.type]) {
|
if (ATOMIC_START_TOKEN[S.token.type]) {
|
||||||
return subscripts(as_atom_node(), allow_calls);
|
return subscripts(as_atom_node(), allow_calls);
|
||||||
}
|
}
|
||||||
@@ -1309,13 +1419,19 @@ function parse($TEXT, options) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function expr_list(closing, allow_trailing_comma, allow_empty, parser) {
|
function expr_list(closing, allow_trailing_comma, allow_empty, parser) {
|
||||||
if (!parser) parser = expression;
|
if (!parser) parser = maybe_assign;
|
||||||
var first = true, a = [];
|
var first = true, a = [];
|
||||||
while (!is("punc", closing)) {
|
while (!is("punc", closing)) {
|
||||||
if (first) first = false; else expect(",");
|
if (first) first = false; else expect(",");
|
||||||
if (allow_trailing_comma && is("punc", closing)) break;
|
if (allow_trailing_comma && is("punc", closing)) break;
|
||||||
if (is("punc", ",") && allow_empty) {
|
if (allow_empty && is("punc", ",")) {
|
||||||
a.push(new AST_Hole({ start: S.token, end: S.token }));
|
a.push(new AST_Hole({ start: S.token, end: S.token }));
|
||||||
|
} else if (parser === maybe_assign && is("operator", "...")) {
|
||||||
|
a.push(new AST_Spread({
|
||||||
|
start: S.token,
|
||||||
|
expression: (next(), parser()),
|
||||||
|
end: prev(),
|
||||||
|
}));
|
||||||
} else {
|
} else {
|
||||||
a.push(parser());
|
a.push(parser());
|
||||||
}
|
}
|
||||||
@@ -1343,6 +1459,15 @@ function parse($TEXT, options) {
|
|||||||
// allow trailing comma
|
// allow trailing comma
|
||||||
if (!options.strict && is("punc", "}")) break;
|
if (!options.strict && is("punc", "}")) break;
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
|
if (is("operator", "...")) {
|
||||||
|
next();
|
||||||
|
a.push(new AST_Spread({
|
||||||
|
start: start,
|
||||||
|
expression: maybe_assign(),
|
||||||
|
end: prev(),
|
||||||
|
}));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
var key = as_property_key();
|
var key = as_property_key();
|
||||||
if (is("punc", "(")) {
|
if (is("punc", "(")) {
|
||||||
var func_start = S.token;
|
var func_start = S.token;
|
||||||
@@ -1357,7 +1482,39 @@ function parse($TEXT, options) {
|
|||||||
}));
|
}));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!is("punc", ":") && start.type == "name") switch (key) {
|
if (is("punc", ":")) {
|
||||||
|
next();
|
||||||
|
a.push(new AST_ObjectKeyVal({
|
||||||
|
start: start,
|
||||||
|
key: key,
|
||||||
|
value: maybe_assign(),
|
||||||
|
end: prev(),
|
||||||
|
}));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (is("punc", ",") || is("punc", "}")) {
|
||||||
|
a.push(new AST_ObjectKeyVal({
|
||||||
|
start: start,
|
||||||
|
key: key,
|
||||||
|
value: _make_symbol(AST_SymbolRef, start),
|
||||||
|
end: prev(),
|
||||||
|
}));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (start.type == "name") switch (key) {
|
||||||
|
case "async":
|
||||||
|
key = as_property_key();
|
||||||
|
var func_start = S.token;
|
||||||
|
var func = function_(AST_AsyncFunction);
|
||||||
|
func.start = func_start;
|
||||||
|
func.end = prev();
|
||||||
|
a.push(new AST_ObjectKeyVal({
|
||||||
|
start: start,
|
||||||
|
key: key,
|
||||||
|
value: func,
|
||||||
|
end: prev(),
|
||||||
|
}));
|
||||||
|
continue;
|
||||||
case "get":
|
case "get":
|
||||||
a.push(new AST_ObjectGetter({
|
a.push(new AST_ObjectGetter({
|
||||||
start: start,
|
start: start,
|
||||||
@@ -1374,22 +1531,8 @@ function parse($TEXT, options) {
|
|||||||
end: prev(),
|
end: prev(),
|
||||||
}));
|
}));
|
||||||
continue;
|
continue;
|
||||||
default:
|
|
||||||
a.push(new AST_ObjectKeyVal({
|
|
||||||
start: start,
|
|
||||||
key: key,
|
|
||||||
value: _make_symbol(AST_SymbolRef, start),
|
|
||||||
end: prev(),
|
|
||||||
}));
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
expect(":");
|
unexpected();
|
||||||
a.push(new AST_ObjectKeyVal({
|
|
||||||
start: start,
|
|
||||||
key: key,
|
|
||||||
value: expression(false),
|
|
||||||
end: prev(),
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
return new AST_Object({ properties: a });
|
return new AST_Object({ properties: a });
|
||||||
@@ -1408,9 +1551,8 @@ function parse($TEXT, options) {
|
|||||||
next();
|
next();
|
||||||
return "" + tmp.value;
|
return "" + tmp.value;
|
||||||
case "punc":
|
case "punc":
|
||||||
if (tmp.value != "[") unexpected();
|
expect("[");
|
||||||
next();
|
var key = maybe_assign();
|
||||||
var key = expression(false);
|
|
||||||
expect("]");
|
expect("]");
|
||||||
return key;
|
return key;
|
||||||
default:
|
default:
|
||||||
@@ -1427,6 +1569,7 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
function _make_symbol(type, token) {
|
function _make_symbol(type, token) {
|
||||||
var name = token.value;
|
var name = token.value;
|
||||||
|
if (name === "await" && S.in_async) unexpected(token);
|
||||||
return new (name === "this" ? AST_This : type)({
|
return new (name === "this" ? AST_This : type)({
|
||||||
name: "" + name,
|
name: "" + name,
|
||||||
start: token,
|
start: token,
|
||||||
@@ -1436,7 +1579,7 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
function strict_verify_symbol(sym) {
|
function strict_verify_symbol(sym) {
|
||||||
if (sym.name == "arguments" || sym.name == "eval")
|
if (sym.name == "arguments" || sym.name == "eval")
|
||||||
croak("Unexpected " + sym.name + " in strict mode", sym.start.line, sym.start.col, sym.start.pos);
|
token_error(sym.start, "Unexpected " + sym.name + " in strict mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
function as_symbol(type, noerror) {
|
function as_symbol(type, noerror) {
|
||||||
@@ -1472,16 +1615,8 @@ function parse($TEXT, options) {
|
|||||||
// allow trailing comma
|
// allow trailing comma
|
||||||
if (!options.strict && is("punc", "}")) break;
|
if (!options.strict && is("punc", "}")) break;
|
||||||
var key_start = S.token;
|
var key_start = S.token;
|
||||||
|
if (is("punc", "[") || is_token(peek(), "punc", ":")) {
|
||||||
var key = as_property_key();
|
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(":");
|
expect(":");
|
||||||
a.push(new AST_DestructuredKeyVal({
|
a.push(new AST_DestructuredKeyVal({
|
||||||
start: key_start,
|
start: key_start,
|
||||||
@@ -1489,6 +1624,14 @@ function parse($TEXT, options) {
|
|||||||
value: maybe_destructured(type),
|
value: maybe_destructured(type),
|
||||||
end: prev(),
|
end: prev(),
|
||||||
}));
|
}));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
a.push(new AST_DestructuredKeyVal({
|
||||||
|
start: key_start,
|
||||||
|
key: key_start.value,
|
||||||
|
value: as_symbol(type),
|
||||||
|
end: prev(),
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
return new AST_DestructuredObject({
|
return new AST_DestructuredObject({
|
||||||
@@ -1526,7 +1669,7 @@ function parse($TEXT, options) {
|
|||||||
}
|
}
|
||||||
if (is("punc", "[")) {
|
if (is("punc", "[")) {
|
||||||
next();
|
next();
|
||||||
var prop = expression(true);
|
var prop = expression();
|
||||||
expect("]");
|
expect("]");
|
||||||
return subscripts(new AST_Sub({
|
return subscripts(new AST_Sub({
|
||||||
start : start,
|
start : start,
|
||||||
@@ -1540,7 +1683,7 @@ function parse($TEXT, options) {
|
|||||||
var call = new AST_Call({
|
var call = new AST_Call({
|
||||||
start : start,
|
start : start,
|
||||||
expression : expr,
|
expression : expr,
|
||||||
args : expr_list(")"),
|
args : expr_list(")", !options.strict),
|
||||||
end : prev()
|
end : prev()
|
||||||
});
|
});
|
||||||
mark_pure(call);
|
mark_pure(call);
|
||||||
@@ -1549,17 +1692,17 @@ function parse($TEXT, options) {
|
|||||||
return expr;
|
return expr;
|
||||||
};
|
};
|
||||||
|
|
||||||
var maybe_unary = function(allow_calls) {
|
function maybe_unary() {
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
if (is("operator") && UNARY_PREFIX[start.value]) {
|
if (is("operator") && UNARY_PREFIX[start.value]) {
|
||||||
next();
|
next();
|
||||||
handle_regexp();
|
handle_regexp();
|
||||||
var ex = make_unary(AST_UnaryPrefix, start, maybe_unary(allow_calls));
|
var ex = make_unary(AST_UnaryPrefix, start, maybe_await());
|
||||||
ex.start = start;
|
ex.start = start;
|
||||||
ex.end = prev();
|
ex.end = prev();
|
||||||
return ex;
|
return ex;
|
||||||
}
|
}
|
||||||
var val = expr_atom(allow_calls);
|
var val = expr_atom(true);
|
||||||
while (is("operator") && UNARY_POSTFIX[S.token.value] && !has_newline_before(S.token)) {
|
while (is("operator") && UNARY_POSTFIX[S.token.value] && !has_newline_before(S.token)) {
|
||||||
val = make_unary(AST_UnaryPostfix, S.token, val);
|
val = make_unary(AST_UnaryPostfix, S.token, val);
|
||||||
val.start = start;
|
val.start = start;
|
||||||
@@ -1567,7 +1710,7 @@ function parse($TEXT, options) {
|
|||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
};
|
}
|
||||||
|
|
||||||
function make_unary(ctor, token, expr) {
|
function make_unary(ctor, token, expr) {
|
||||||
var op = token.value;
|
var op = token.value;
|
||||||
@@ -1575,23 +1718,36 @@ function parse($TEXT, options) {
|
|||||||
case "++":
|
case "++":
|
||||||
case "--":
|
case "--":
|
||||||
if (!is_assignable(expr))
|
if (!is_assignable(expr))
|
||||||
croak("Invalid use of " + op + " operator", token.line, token.col, token.pos);
|
token_error(token, "Invalid use of " + op + " operator");
|
||||||
break;
|
break;
|
||||||
case "delete":
|
case "delete":
|
||||||
if (expr instanceof AST_SymbolRef && S.input.has_directive("use strict"))
|
if (expr instanceof AST_SymbolRef && S.input.has_directive("use strict"))
|
||||||
croak("Calling delete on expression not allowed in strict mode", expr.start.line, expr.start.col, expr.start.pos);
|
token_error(expr.start, "Calling delete on expression not allowed in strict mode");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return new ctor({ operator: op, expression: expr });
|
return new ctor({ operator: op, expression: expr });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function maybe_await() {
|
||||||
|
var start = S.token;
|
||||||
|
if (!(S.in_async && is("name", "await"))) return maybe_unary();
|
||||||
|
if (S.in_funarg === S.in_function) croak("Invalid use of await in function argument");
|
||||||
|
S.input.context().regex_allowed = true;
|
||||||
|
next();
|
||||||
|
return new AST_Await({
|
||||||
|
start: start,
|
||||||
|
expression: maybe_await(),
|
||||||
|
end: prev(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var expr_op = function(left, min_prec, no_in) {
|
var expr_op = function(left, min_prec, no_in) {
|
||||||
var op = is("operator") ? S.token.value : null;
|
var op = is("operator") ? S.token.value : null;
|
||||||
if (op == "in" && no_in) op = null;
|
if (op == "in" && no_in) op = null;
|
||||||
var prec = op != null ? PRECEDENCE[op] : null;
|
var prec = op != null ? PRECEDENCE[op] : null;
|
||||||
if (prec != null && prec > min_prec) {
|
if (prec != null && prec > min_prec) {
|
||||||
next();
|
next();
|
||||||
var right = expr_op(maybe_unary(true), prec, no_in);
|
var right = expr_op(maybe_await(), prec, no_in);
|
||||||
return expr_op(new AST_Binary({
|
return expr_op(new AST_Binary({
|
||||||
start : left.start,
|
start : left.start,
|
||||||
left : left,
|
left : left,
|
||||||
@@ -1604,7 +1760,7 @@ function parse($TEXT, options) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function expr_ops(no_in) {
|
function expr_ops(no_in) {
|
||||||
return expr_op(maybe_unary(true), 0, no_in);
|
return expr_op(maybe_await(), 0, no_in);
|
||||||
}
|
}
|
||||||
|
|
||||||
var maybe_conditional = function(no_in) {
|
var maybe_conditional = function(no_in) {
|
||||||
@@ -1612,13 +1768,13 @@ function parse($TEXT, options) {
|
|||||||
var expr = expr_ops(no_in);
|
var expr = expr_ops(no_in);
|
||||||
if (is("operator", "?")) {
|
if (is("operator", "?")) {
|
||||||
next();
|
next();
|
||||||
var yes = expression(false);
|
var yes = maybe_assign();
|
||||||
expect(":");
|
expect(":");
|
||||||
return new AST_Conditional({
|
return new AST_Conditional({
|
||||||
start : start,
|
start : start,
|
||||||
condition : expr,
|
condition : expr,
|
||||||
consequent : yes,
|
consequent : yes,
|
||||||
alternative : expression(false, no_in),
|
alternative : maybe_assign(no_in),
|
||||||
end : prev()
|
end : prev()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1661,7 +1817,7 @@ function parse($TEXT, options) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var maybe_assign = function(no_in) {
|
function maybe_assign(no_in) {
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
var left = maybe_conditional(no_in), val = S.token.value;
|
var left = maybe_conditional(no_in), val = S.token.value;
|
||||||
if (is("operator") && ASSIGNMENT[val]) {
|
if (is("operator") && ASSIGNMENT[val]) {
|
||||||
@@ -1678,23 +1834,23 @@ function parse($TEXT, options) {
|
|||||||
croak("Invalid assignment");
|
croak("Invalid assignment");
|
||||||
}
|
}
|
||||||
return left;
|
return left;
|
||||||
};
|
}
|
||||||
|
|
||||||
var expression = function(commas, no_in) {
|
function expression(no_in, maybe_arrow) {
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
var exprs = [];
|
var exprs = [];
|
||||||
while (true) {
|
while (true) {
|
||||||
exprs.push(maybe_assign(no_in));
|
exprs.push(maybe_assign(no_in));
|
||||||
if (!commas || !is("punc", ",")) break;
|
if (!is("punc", ",")) break;
|
||||||
next();
|
next();
|
||||||
commas = true;
|
if (maybe_arrow && is("punc", ")") && is_token(peek(), "punc", "=>")) break;
|
||||||
}
|
}
|
||||||
return exprs.length == 1 ? exprs[0] : new AST_Sequence({
|
return exprs.length == 1 ? exprs[0] : new AST_Sequence({
|
||||||
start : start,
|
start : start,
|
||||||
expressions : exprs,
|
expressions : exprs,
|
||||||
end : peek()
|
end : prev()
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
function in_loop(cont) {
|
function in_loop(cont) {
|
||||||
++S.in_loop;
|
++S.in_loop;
|
||||||
@@ -1705,7 +1861,7 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
if (options.expression) {
|
if (options.expression) {
|
||||||
handle_regexp();
|
handle_regexp();
|
||||||
return expression(true);
|
return expression();
|
||||||
}
|
}
|
||||||
|
|
||||||
return function() {
|
return function() {
|
||||||
|
|||||||
76
lib/scope.js
76
lib/scope.js
@@ -100,6 +100,8 @@ SymbolDef.prototype = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var unary_side_effects = makePredicate("delete ++ --");
|
||||||
|
|
||||||
AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||||
options = defaults(options, {
|
options = defaults(options, {
|
||||||
cache: null,
|
cache: null,
|
||||||
@@ -112,7 +114,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
var next_def_id = 0;
|
var next_def_id = 0;
|
||||||
var scope = self.parent_scope = null;
|
var scope = self.parent_scope = null;
|
||||||
var tw = new TreeWalker(function(node, descend) {
|
var tw = new TreeWalker(function(node, descend) {
|
||||||
if (node instanceof AST_Defun) {
|
if (is_defun(node)) {
|
||||||
node.name.walk(tw);
|
node.name.walk(tw);
|
||||||
walk_scope(function() {
|
walk_scope(function() {
|
||||||
node.argnames.forEach(function(argname) {
|
node.argnames.forEach(function(argname) {
|
||||||
@@ -190,7 +192,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
function entangle(defun, scope) {
|
function entangle(defun, scope) {
|
||||||
if (defun === scope) return;
|
if (defun === scope) return;
|
||||||
node.mark_enclosed(options);
|
node.mark_enclosed(options);
|
||||||
var def = scope.find_variable(node);
|
var def = scope.find_variable(node.name);
|
||||||
if (node.thedef === def) return;
|
if (node.thedef === def) return;
|
||||||
node.thedef = def;
|
node.thedef = def;
|
||||||
def.orig.push(node);
|
def.orig.push(node);
|
||||||
@@ -206,19 +208,46 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
self.globals = new Dictionary();
|
self.globals = new Dictionary();
|
||||||
var in_arg = [];
|
var in_arg = [];
|
||||||
var tw = new TreeWalker(function(node) {
|
var tw = new TreeWalker(function(node) {
|
||||||
|
if (node instanceof AST_Catch) {
|
||||||
|
if (!(node.argname instanceof AST_Destructured)) return;
|
||||||
|
in_arg.push(node);
|
||||||
|
node.argname.walk(tw);
|
||||||
|
in_arg.pop();
|
||||||
|
walk_body(node, tw);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (node instanceof AST_Lambda) {
|
if (node instanceof AST_Lambda) {
|
||||||
in_arg.push(node);
|
in_arg.push(node);
|
||||||
node.argnames.forEach(function(argname) {
|
node.argnames.forEach(function(argname) {
|
||||||
argname.walk(tw);
|
argname.walk(tw);
|
||||||
});
|
});
|
||||||
in_arg.pop();
|
in_arg.pop();
|
||||||
|
if (node instanceof AST_Arrow && node.value) {
|
||||||
|
node.value.walk(tw);
|
||||||
|
} else {
|
||||||
walk_body(node, tw);
|
walk_body(node, tw);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_LoopControl) {
|
if (node instanceof AST_LoopControl) {
|
||||||
if (node.label) node.label.thedef.references.push(node);
|
if (node.label) node.label.thedef.references.push(node);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
// ensure mangling works if `catch` reuses a scope variable
|
||||||
|
if (node instanceof AST_SymbolCatch) {
|
||||||
|
var def = node.definition().redefined();
|
||||||
|
if (def) for (var s = node.scope; s; s = s.parent_scope) {
|
||||||
|
push_uniq(s.enclosed, def);
|
||||||
|
if (s === def.scope) break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// ensure compression works if `const` reuses a scope variable
|
||||||
|
if (node instanceof AST_SymbolConst) {
|
||||||
|
var redef = node.definition().redefined();
|
||||||
|
if (redef) redef.const_redefs = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
var name = node.name;
|
var name = node.name;
|
||||||
var sym = node.scope.find_variable(name);
|
var sym = node.scope.find_variable(name);
|
||||||
@@ -226,7 +255,9 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
i = in_arg.lastIndexOf(sym.scope, i - 1);
|
i = in_arg.lastIndexOf(sym.scope, i - 1);
|
||||||
if (i < 0) break;
|
if (i < 0) break;
|
||||||
var decl = sym.orig[0];
|
var decl = sym.orig[0];
|
||||||
if (decl instanceof AST_SymbolFunarg || decl instanceof AST_SymbolLambda) {
|
if (decl instanceof AST_SymbolCatch
|
||||||
|
|| decl instanceof AST_SymbolFunarg
|
||||||
|
|| decl instanceof AST_SymbolLambda) {
|
||||||
node.in_arg = true;
|
node.in_arg = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -234,9 +265,17 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
}
|
}
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
sym = self.def_global(node);
|
sym = self.def_global(node);
|
||||||
} else if (name == "arguments" && sym.scope instanceof AST_Lambda) {
|
} else if (name == "arguments"
|
||||||
if (!(tw.parent() instanceof AST_PropAccess)) {
|
&& sym.orig[0] instanceof AST_SymbolFunarg
|
||||||
sym.scope.uses_arguments = "d";
|
&& !(sym.orig[1] instanceof AST_SymbolFunarg)
|
||||||
|
&& !(sym.scope instanceof AST_Arrow)) {
|
||||||
|
var parent = tw.parent();
|
||||||
|
if (parent instanceof AST_Assign && parent.left === node
|
||||||
|
|| parent instanceof AST_Unary && unary_side_effects[parent.operator]) {
|
||||||
|
sym.scope.uses_arguments = 3;
|
||||||
|
} else if (sym.scope.uses_arguments < 2
|
||||||
|
&& !(parent instanceof AST_PropAccess && parent.expression === node)) {
|
||||||
|
sym.scope.uses_arguments = 2;
|
||||||
} else if (!sym.scope.uses_arguments) {
|
} else if (!sym.scope.uses_arguments) {
|
||||||
sym.scope.uses_arguments = true;
|
sym.scope.uses_arguments = true;
|
||||||
}
|
}
|
||||||
@@ -258,21 +297,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
node.reference(options);
|
node.reference(options);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// ensure mangling works if `catch` reuses a scope variable
|
|
||||||
if (node instanceof AST_SymbolCatch) {
|
|
||||||
var def = node.definition().redefined();
|
|
||||||
if (def) for (var s = node.scope; s; s = s.parent_scope) {
|
|
||||||
push_uniq(s.enclosed, def);
|
|
||||||
if (s === def.scope) break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// ensure compression works if `const` reuses a scope variable
|
|
||||||
if (node instanceof AST_SymbolConst) {
|
|
||||||
var redef = node.definition().redefined();
|
|
||||||
if (redef) redef.const_redefs = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
self.walk(tw);
|
self.walk(tw);
|
||||||
|
|
||||||
@@ -360,6 +384,9 @@ AST_BlockScope.DEFMETHOD("init_vars", function(parent_scope) {
|
|||||||
AST_Scope.DEFMETHOD("init_vars", function(parent_scope) {
|
AST_Scope.DEFMETHOD("init_vars", function(parent_scope) {
|
||||||
init_scope_vars(this, parent_scope);
|
init_scope_vars(this, parent_scope);
|
||||||
});
|
});
|
||||||
|
AST_Arrow.DEFMETHOD("init_vars", function(parent_scope) {
|
||||||
|
init_scope_vars(this, parent_scope);
|
||||||
|
});
|
||||||
AST_Lambda.DEFMETHOD("init_vars", function(parent_scope) {
|
AST_Lambda.DEFMETHOD("init_vars", function(parent_scope) {
|
||||||
init_scope_vars(this, parent_scope);
|
init_scope_vars(this, parent_scope);
|
||||||
this.uses_arguments = false;
|
this.uses_arguments = false;
|
||||||
@@ -390,14 +417,13 @@ AST_Symbol.DEFMETHOD("reference", function(options) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
AST_BlockScope.DEFMETHOD("find_variable", function(name) {
|
AST_BlockScope.DEFMETHOD("find_variable", function(name) {
|
||||||
if (name instanceof AST_Symbol) name = name.name;
|
|
||||||
return this.variables.get(name)
|
return this.variables.get(name)
|
||||||
|| (this.parent_scope && this.parent_scope.find_variable(name));
|
|| this.parent_scope && this.parent_scope.find_variable(name);
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_BlockScope.DEFMETHOD("def_function", function(symbol, init) {
|
AST_BlockScope.DEFMETHOD("def_function", function(symbol, init) {
|
||||||
var def = this.def_variable(symbol, init);
|
var def = this.def_variable(symbol, init);
|
||||||
if (!def.init || def.init instanceof AST_Defun) def.init = init;
|
if (!def.init || is_defun(def.init)) def.init = init;
|
||||||
this.functions.set(symbol.name, def);
|
this.functions.set(symbol.name, def);
|
||||||
return def;
|
return def;
|
||||||
});
|
});
|
||||||
@@ -406,7 +432,7 @@ AST_BlockScope.DEFMETHOD("def_variable", function(symbol, init) {
|
|||||||
var def = this.variables.get(symbol.name);
|
var def = this.variables.get(symbol.name);
|
||||||
if (def) {
|
if (def) {
|
||||||
def.orig.push(symbol);
|
def.orig.push(symbol);
|
||||||
if (def.init instanceof AST_Function) def.init = init;
|
if (is_function(def.init)) def.init = init;
|
||||||
} else {
|
} else {
|
||||||
def = this.make_def(symbol, init);
|
def = this.make_def(symbol, init);
|
||||||
this.variables.set(symbol.name, def);
|
this.variables.set(symbol.name, def);
|
||||||
|
|||||||
@@ -131,6 +131,14 @@ TreeTransformer.prototype = new TreeWalker;
|
|||||||
self.argnames = do_list(self.argnames, tw);
|
self.argnames = do_list(self.argnames, tw);
|
||||||
self.body = do_list(self.body, tw);
|
self.body = do_list(self.body, tw);
|
||||||
});
|
});
|
||||||
|
DEF(AST_Arrow, function(self, tw) {
|
||||||
|
self.argnames = do_list(self.argnames, tw);
|
||||||
|
if (self.value) {
|
||||||
|
self.value = self.value.transform(tw);
|
||||||
|
} else {
|
||||||
|
self.body = do_list(self.body, tw);
|
||||||
|
}
|
||||||
|
});
|
||||||
DEF(AST_Call, function(self, tw) {
|
DEF(AST_Call, function(self, tw) {
|
||||||
self.expression = self.expression.transform(tw);
|
self.expression = self.expression.transform(tw);
|
||||||
self.args = do_list(self.args, tw);
|
self.args = do_list(self.args, tw);
|
||||||
@@ -138,6 +146,9 @@ TreeTransformer.prototype = new TreeWalker;
|
|||||||
DEF(AST_Sequence, function(self, tw) {
|
DEF(AST_Sequence, function(self, tw) {
|
||||||
self.expressions = do_list(self.expressions, tw);
|
self.expressions = do_list(self.expressions, tw);
|
||||||
});
|
});
|
||||||
|
DEF(AST_Await, function(self, tw) {
|
||||||
|
self.expression = self.expression.transform(tw);
|
||||||
|
});
|
||||||
DEF(AST_Dot, function(self, tw) {
|
DEF(AST_Dot, function(self, tw) {
|
||||||
self.expression = self.expression.transform(tw);
|
self.expression = self.expression.transform(tw);
|
||||||
});
|
});
|
||||||
@@ -145,6 +156,9 @@ TreeTransformer.prototype = new TreeWalker;
|
|||||||
self.expression = self.expression.transform(tw);
|
self.expression = self.expression.transform(tw);
|
||||||
self.property = self.property.transform(tw);
|
self.property = self.property.transform(tw);
|
||||||
});
|
});
|
||||||
|
DEF(AST_Spread, function(self, tw) {
|
||||||
|
self.expression = self.expression.transform(tw);
|
||||||
|
});
|
||||||
DEF(AST_Unary, function(self, tw) {
|
DEF(AST_Unary, function(self, tw) {
|
||||||
self.expression = self.expression.transform(tw);
|
self.expression = self.expression.transform(tw);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -238,13 +238,15 @@ function HOP(obj, prop) {
|
|||||||
// return true if the node at the top of the stack (that means the
|
// return true if the node at the top of the stack (that means the
|
||||||
// innermost node in the current output) is lexically the first in
|
// innermost node in the current output) is lexically the first in
|
||||||
// a statement.
|
// a statement.
|
||||||
function first_in_statement(stack) {
|
function first_in_statement(stack, arrow) {
|
||||||
var node = stack.parent(-1);
|
var node = stack.parent(-1);
|
||||||
for (var i = 0, p; p = stack.parent(i++); node = p) {
|
for (var i = 0, p; p = stack.parent(i++); node = p) {
|
||||||
if (p.TYPE == "Call") {
|
if (p instanceof AST_Arrow) {
|
||||||
if (p.expression === node) continue;
|
return arrow && p.value === node;
|
||||||
} else if (p instanceof AST_Binary) {
|
} else if (p instanceof AST_Binary) {
|
||||||
if (p.left === node) continue;
|
if (p.left === node) continue;
|
||||||
|
} else if (p.TYPE == "Call") {
|
||||||
|
if (p.expression === node) continue;
|
||||||
} else if (p instanceof AST_Conditional) {
|
} else if (p instanceof AST_Conditional) {
|
||||||
if (p.condition === node) continue;
|
if (p.condition === node) continue;
|
||||||
} else if (p instanceof AST_PropAccess) {
|
} else if (p instanceof AST_PropAccess) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"version": "3.12.1",
|
"version": "3.12.3",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -851,3 +851,114 @@ issue_4291_2: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS 42 1"
|
expect_stdout: "PASS 42 1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4397: {
|
||||||
|
options = {
|
||||||
|
arguments: true,
|
||||||
|
keep_fargs: "strict",
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(typeof function() {
|
||||||
|
arguments += 0;
|
||||||
|
return arguments[0];
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(typeof function() {
|
||||||
|
arguments += 0;
|
||||||
|
return arguments[0];
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "string"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4410_1: {
|
||||||
|
options = {
|
||||||
|
arguments: true,
|
||||||
|
conditionals: true,
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function(a) {
|
||||||
|
console.log(arguments[0] === (a = 0) ? "FAIL" : "PASS");
|
||||||
|
})(1);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function(a) {
|
||||||
|
console.log(a === (a = 0) ? "FAIL" : "PASS");
|
||||||
|
})(1);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4410_2: {
|
||||||
|
options = {
|
||||||
|
arguments: true,
|
||||||
|
conditionals: true,
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function f(a) {
|
||||||
|
console.log(arguments[0] === (a = 0) ? "FAIL" : "PASS");
|
||||||
|
})(1);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function f(a) {
|
||||||
|
console.log(arguments[0] === (a = 0) ? "FAIL" : "PASS");
|
||||||
|
})(1);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4410_3: {
|
||||||
|
options = {
|
||||||
|
arguments: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
(function f(b) {
|
||||||
|
a-- && f();
|
||||||
|
for (var c = 2; c--;)
|
||||||
|
switch (arguments[0]) {
|
||||||
|
case b = 42:
|
||||||
|
case 42:
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
})(null);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1;
|
||||||
|
(function f(b) {
|
||||||
|
a-- && f();
|
||||||
|
for (var c = 2; c--;)
|
||||||
|
switch (arguments[0]) {
|
||||||
|
case b = 42:
|
||||||
|
case 42:
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
})(null);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4432: {
|
||||||
|
options = {
|
||||||
|
arguments: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a) {
|
||||||
|
for (a in { FAIL: 42 });
|
||||||
|
return arguments[0];
|
||||||
|
}() || "PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
for (a in { FAIL: 42 });
|
||||||
|
return arguments[0];
|
||||||
|
}() || "PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
589
test/compress/arrows.js
Normal file
589
test/compress/arrows.js
Normal file
@@ -0,0 +1,589 @@
|
|||||||
|
no_funarg: {
|
||||||
|
input: {
|
||||||
|
(() => console.log(42))();
|
||||||
|
}
|
||||||
|
expect_exact: "(()=>console.log(42))();"
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
single_funarg: {
|
||||||
|
input: {
|
||||||
|
(a => console.log(a))(42);
|
||||||
|
}
|
||||||
|
expect_exact: "(a=>console.log(a))(42);"
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
multiple_funargs: {
|
||||||
|
input: {
|
||||||
|
((a, b) => console.log(a, b))("foo", "bar");
|
||||||
|
}
|
||||||
|
expect_exact: '((a,b)=>console.log(a,b))("foo","bar");'
|
||||||
|
expect_stdout: "foo bar"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
destructured_funarg: {
|
||||||
|
input: {
|
||||||
|
(([ a, b, c ]) => console.log(a, b, c))("foo");
|
||||||
|
}
|
||||||
|
expect_exact: '(([a,b,c])=>console.log(a,b,c))("foo");'
|
||||||
|
expect_stdout: "f o o"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
await_parenthesis: {
|
||||||
|
input: {
|
||||||
|
async function f() {
|
||||||
|
await (a => a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_exact: "async function f(){await(a=>a)}"
|
||||||
|
}
|
||||||
|
|
||||||
|
for_parenthesis_init: {
|
||||||
|
input: {
|
||||||
|
for (a => (a in a); console.log(42););
|
||||||
|
}
|
||||||
|
expect_exact: "for((a=>a in a);console.log(42););"
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
for_parenthesis_condition: {
|
||||||
|
input: {
|
||||||
|
for (console.log(42); a => (a in a);)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
expect_exact: "for(console.log(42);a=>a in a;)break;"
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
for_parenthesis_step: {
|
||||||
|
input: {
|
||||||
|
for (; console.log(42); a => (a in a));
|
||||||
|
}
|
||||||
|
expect_exact: "for(;console.log(42);a=>a in a);"
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
for_assign_parenthesis_init: {
|
||||||
|
input: {
|
||||||
|
for (f = a => (a in a); console.log(42););
|
||||||
|
}
|
||||||
|
expect_exact: "for((f=a=>a in a);console.log(42););"
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
for_assign_parenthesis_condition: {
|
||||||
|
input: {
|
||||||
|
for (console.log(42); f = a => (a in a);)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
expect_exact: "for(console.log(42);f=a=>a in a;)break;"
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
for_assign_parenthesis_step: {
|
||||||
|
input: {
|
||||||
|
for (; console.log(42); f = a => (a in a));
|
||||||
|
}
|
||||||
|
expect_exact: "for(;console.log(42);f=a=>a in a);"
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
for_declaration_parenthesis_init: {
|
||||||
|
input: {
|
||||||
|
for (var f = a => (a in a); console.log(42););
|
||||||
|
}
|
||||||
|
expect_exact: "for(var f=(a=>a in a);console.log(42););"
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
for_statement_parenthesis_init: {
|
||||||
|
input: {
|
||||||
|
for (a => {
|
||||||
|
a in a;
|
||||||
|
}; console.log(42););
|
||||||
|
}
|
||||||
|
expect_exact: "for(a=>{a in a};console.log(42););"
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
body_call: {
|
||||||
|
input: {
|
||||||
|
(() => {
|
||||||
|
console.log("foo");
|
||||||
|
console.log("bar");
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_exact: '(()=>{console.log("foo");console.log("bar")})();'
|
||||||
|
expect_stdout: [
|
||||||
|
"foo",
|
||||||
|
"bar",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
body_conditional: {
|
||||||
|
input: {
|
||||||
|
console.log((a => {}) ? "PASS" : "FAIL");
|
||||||
|
}
|
||||||
|
expect_exact: 'console.log((a=>{})?"PASS":"FAIL");'
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
destructured_object_value: {
|
||||||
|
input: {
|
||||||
|
console.log((a => ({} = a))(42));
|
||||||
|
}
|
||||||
|
expect_exact: "console.log((a=>({}=a))(42));"
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
function_value: {
|
||||||
|
input: {
|
||||||
|
console.log((a => function() {
|
||||||
|
return a;
|
||||||
|
})(42)());
|
||||||
|
}
|
||||||
|
expect_exact: "console.log((a=>function(){return a})(42)());"
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
in_value: {
|
||||||
|
input: {
|
||||||
|
console.log((a => a in {
|
||||||
|
foo: 42,
|
||||||
|
})("foo"));
|
||||||
|
}
|
||||||
|
expect_exact: 'console.log((a=>a in{foo:42})("foo"));'
|
||||||
|
expect_stdout: "true"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
object_value: {
|
||||||
|
input: {
|
||||||
|
console.log((() => ({
|
||||||
|
4: 2,
|
||||||
|
}))()[4]);
|
||||||
|
}
|
||||||
|
expect_exact: "console.log((()=>({4:2}))()[4]);"
|
||||||
|
expect_stdout: "2"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
object_first_in_value: {
|
||||||
|
input: {
|
||||||
|
console.log((a => ({
|
||||||
|
p: a,
|
||||||
|
}.p ? "FAIL" : "PASS"))());
|
||||||
|
}
|
||||||
|
expect_exact: 'console.log((a=>({p:a}).p?"FAIL":"PASS")());'
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
sequence_value: {
|
||||||
|
input: {
|
||||||
|
console.log((a => (console.log("foo"), a))("bar"));
|
||||||
|
}
|
||||||
|
expect_exact: 'console.log((a=>(console.log("foo"),a))("bar"));'
|
||||||
|
expect_stdout: [
|
||||||
|
"foo",
|
||||||
|
"bar",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
side_effects_value: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log((a => function() {
|
||||||
|
return a;
|
||||||
|
})(42)());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log((a => function() {
|
||||||
|
return a;
|
||||||
|
})(42)());
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
arrow_property: {
|
||||||
|
input: {
|
||||||
|
console.log((a => 42).prototype);
|
||||||
|
}
|
||||||
|
expect_exact: "console.log((a=>42).prototype);"
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
assign_arrow: {
|
||||||
|
input: {
|
||||||
|
var f = a => a;
|
||||||
|
console.log(f(42));
|
||||||
|
}
|
||||||
|
expect_exact: "var f=a=>a;console.log(f(42));"
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
binary_arrow: {
|
||||||
|
input: {
|
||||||
|
console.log(4 || (() => 2));
|
||||||
|
}
|
||||||
|
expect_exact: "console.log(4||(()=>2));"
|
||||||
|
expect_stdout: "4"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
unary_arrow: {
|
||||||
|
input: {
|
||||||
|
console.log(+(() => 42));
|
||||||
|
}
|
||||||
|
expect_exact: "console.log(+(()=>42));"
|
||||||
|
expect_stdout: "NaN"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
trailing_comma: {
|
||||||
|
input: {
|
||||||
|
((a,) => console.log(a))(42);
|
||||||
|
}
|
||||||
|
expect_exact: "(a=>console.log(a))(42);"
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
drop_arguments: {
|
||||||
|
options = {
|
||||||
|
arguments: true,
|
||||||
|
keep_fargs: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function() {
|
||||||
|
return () => arguments[0];
|
||||||
|
}("PASS")("FAIL"));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(argument_0) {
|
||||||
|
return () => argument_0;
|
||||||
|
}("PASS")("FAIL"));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
funarg_arguments: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log((arguments => arguments)(42));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(42);
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
inline_arguments: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function() {
|
||||||
|
return () => arguments[0];
|
||||||
|
}("PASS")("FAIL"));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
return () => arguments[0];
|
||||||
|
}("PASS")("FAIL"));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
var_arguments: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
properties: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function() {
|
||||||
|
return () => {
|
||||||
|
var arguments = [ "PASS" ];
|
||||||
|
return arguments;
|
||||||
|
};
|
||||||
|
}("FAIL 1")("FAIL 2")[0]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
negate: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
if (!console ? 0 : () => 1)
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(console ? () => 1 : 0) && console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
inline_this: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
p: function() {
|
||||||
|
return function() {
|
||||||
|
return () => this.q;
|
||||||
|
}();
|
||||||
|
},
|
||||||
|
q: "FAIL",
|
||||||
|
};
|
||||||
|
q = "PASS";
|
||||||
|
console.log(o.p()());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
p: function() {
|
||||||
|
return function() {
|
||||||
|
return () => this.q;
|
||||||
|
}();
|
||||||
|
},
|
||||||
|
q: "FAIL",
|
||||||
|
};
|
||||||
|
q = "PASS";
|
||||||
|
console.log(o.p()());
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
trim_body: {
|
||||||
|
options = {
|
||||||
|
arrows: true,
|
||||||
|
if_return: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var f = a => {
|
||||||
|
return a;
|
||||||
|
};
|
||||||
|
var g = b => void b;
|
||||||
|
console.log(f("PASS"), g("FAIL"));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var f = a => a;
|
||||||
|
var g = b => {};
|
||||||
|
console.log(f("PASS"), g("FAIL"));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS undefined"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_value: {
|
||||||
|
options = {
|
||||||
|
arrows: true,
|
||||||
|
collapse_vars: true,
|
||||||
|
keep_fargs: "strict",
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 42;
|
||||||
|
console.log((b => Math.floor(b))(a));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 42;
|
||||||
|
console.log((() => Math.floor(a))());
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_iife_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
keep_fargs: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(a => console.log(a + a))(21);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(() => console.log(42))();
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_iife_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 21;
|
||||||
|
(() => console.log(a + a))();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(() => console.log(42))();
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_iife_3: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "foo";
|
||||||
|
(() => {
|
||||||
|
console.log(a);
|
||||||
|
console.log(a);
|
||||||
|
})();
|
||||||
|
a = "bar";
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(() => {
|
||||||
|
console.log("foo");
|
||||||
|
console.log("foo");
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo",
|
||||||
|
"foo",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
single_use_recursive: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
return (() => f)();
|
||||||
|
}
|
||||||
|
console.log(typeof f());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(typeof function f() {
|
||||||
|
return (() => f)();
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4388: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(arguments => console.log(arguments && arguments))();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(arguments => console.log(arguments && arguments))();
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4390: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function log() {
|
||||||
|
console.log.apply(console, arguments);
|
||||||
|
}
|
||||||
|
var a = 42, b = "FAIL";
|
||||||
|
b = "PASS";
|
||||||
|
(c => log(b, c))(a);
|
||||||
|
log(b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function log() {
|
||||||
|
console.log.apply(console, arguments);
|
||||||
|
}
|
||||||
|
var a = 42, b = "FAIL";
|
||||||
|
b = "PASS";
|
||||||
|
(c => log(b, c))(a);
|
||||||
|
log(b);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"PASS 42",
|
||||||
|
"PASS",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4401: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
var a = (b => b(a))(console.log || a);
|
||||||
|
var c = console.log;
|
||||||
|
c && c(typeof b);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
var a = (b => b(a))(console.log || a);
|
||||||
|
var c = console.log;
|
||||||
|
c && c(typeof b);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"undefined",
|
||||||
|
"undefined",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
642
test/compress/async.js
Normal file
642
test/compress/async.js
Normal file
@@ -0,0 +1,642 @@
|
|||||||
|
await_await: {
|
||||||
|
input: {
|
||||||
|
(async function() {
|
||||||
|
console.log("PASS");
|
||||||
|
await await 42;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(async function() {
|
||||||
|
console.log("PASS");
|
||||||
|
await await 42;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
defun_name: {
|
||||||
|
input: {
|
||||||
|
async function await() {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
await();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
async function await() {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
await();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
nested_await: {
|
||||||
|
input: {
|
||||||
|
(async function() {
|
||||||
|
console.log(function(await) {
|
||||||
|
return await;
|
||||||
|
}("PASS"));
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(async function() {
|
||||||
|
console.log(function(await) {
|
||||||
|
return await;
|
||||||
|
}("PASS"));
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_single_use_defun: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
async function f(a) {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
f("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(async function(a) {
|
||||||
|
console.log(a);
|
||||||
|
})("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
dont_inline: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(async function() {
|
||||||
|
A;
|
||||||
|
})().catch(function() {});
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(async function() {
|
||||||
|
A;
|
||||||
|
})().catch(function() {});
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
evaluate: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = async function() {}();
|
||||||
|
console.log(typeof a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = async function() {}();
|
||||||
|
console.log(typeof a);
|
||||||
|
}
|
||||||
|
expect_stdout: "object"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
negate: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console && async function() {} && console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console && async function() {} && console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
negate_iife: {
|
||||||
|
options = {
|
||||||
|
negate_iife: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(async function() {
|
||||||
|
console.log("PASS");
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
!async function() {
|
||||||
|
console.log("PASS");
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
object_function: {
|
||||||
|
options = {
|
||||||
|
properties: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
({
|
||||||
|
async f() {
|
||||||
|
console.log("PASS");
|
||||||
|
},
|
||||||
|
}).f();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(async function() {
|
||||||
|
console.log("PASS");
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_vars_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "FAIL";
|
||||||
|
(async function() {
|
||||||
|
a = "PASS";
|
||||||
|
await 42;
|
||||||
|
return "PASS";
|
||||||
|
})();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "FAIL";
|
||||||
|
(async function() {
|
||||||
|
a = "PASS";
|
||||||
|
await 42;
|
||||||
|
return "PASS";
|
||||||
|
})();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_vars_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "FAIL";
|
||||||
|
(async function() {
|
||||||
|
await (a = "PASS");
|
||||||
|
return "PASS";
|
||||||
|
})();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "FAIL";
|
||||||
|
(async function() {
|
||||||
|
await (a = "PASS");
|
||||||
|
return "PASS";
|
||||||
|
})();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_vars_3: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "FAIL";
|
||||||
|
(async function() {
|
||||||
|
await (a = "PASS", 42);
|
||||||
|
return "PASS";
|
||||||
|
})();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "FAIL";
|
||||||
|
(async function() {
|
||||||
|
await (a = "PASS", 42);
|
||||||
|
return "PASS";
|
||||||
|
})();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4335_1: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var await = "PASS";
|
||||||
|
(async function() {
|
||||||
|
console.log(function() {
|
||||||
|
return await;
|
||||||
|
}());
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var await = "PASS";
|
||||||
|
(async function() {
|
||||||
|
console.log(function() {
|
||||||
|
return await;
|
||||||
|
}());
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4335_2: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(async function() {
|
||||||
|
console.log(function() {
|
||||||
|
function await() {}
|
||||||
|
return "PASS";
|
||||||
|
}());
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(async function() {
|
||||||
|
console.log(function() {
|
||||||
|
function await() {}
|
||||||
|
return "PASS";
|
||||||
|
}());
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4337: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function(a) {
|
||||||
|
a();
|
||||||
|
})(async function() {
|
||||||
|
console.log("PASS");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function(a) {
|
||||||
|
(async function() {
|
||||||
|
console.log("PASS");
|
||||||
|
})();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4340: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(async function a(a) {
|
||||||
|
console.log(a || "PASS");
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(async function a(a) {
|
||||||
|
console.log(a || "PASS");
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
call_expression: {
|
||||||
|
input: {
|
||||||
|
console.log(typeof async function(log) {
|
||||||
|
(await log)("FAIL");
|
||||||
|
}(console.log).then);
|
||||||
|
}
|
||||||
|
expect_exact: 'console.log(typeof async function(log){(await log)("FAIL")}(console.log).then);'
|
||||||
|
expect_stdout: "function"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
property_access_expression: {
|
||||||
|
input: {
|
||||||
|
console.log(typeof async function(con) {
|
||||||
|
(await con).log("FAIL");
|
||||||
|
}(console).then);
|
||||||
|
}
|
||||||
|
expect_exact: 'console.log(typeof async function(con){(await con).log("FAIL")}(console).then);'
|
||||||
|
expect_stdout: "function"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_iife_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
keep_fargs: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(async function(a) {
|
||||||
|
console.log(a + a);
|
||||||
|
})(21);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(async function() {
|
||||||
|
console.log(42);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_iife_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 21;
|
||||||
|
(async function() {
|
||||||
|
console.log(a + a);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(async function() {
|
||||||
|
console.log(42);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_iife_3: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "foo";
|
||||||
|
(async function() {
|
||||||
|
console.log(a);
|
||||||
|
console.log(await a);
|
||||||
|
})();
|
||||||
|
a = "bar";
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "foo";
|
||||||
|
(async function() {
|
||||||
|
console.log(a);
|
||||||
|
console.log(await a);
|
||||||
|
})();
|
||||||
|
a = "bar";
|
||||||
|
}
|
||||||
|
expect_stdout: "foo"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4347_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "foo";
|
||||||
|
f();
|
||||||
|
a = "bar";
|
||||||
|
f();
|
||||||
|
async function f() {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "foo";
|
||||||
|
f();
|
||||||
|
a = "bar";
|
||||||
|
f();
|
||||||
|
async function f() {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo",
|
||||||
|
"bar",
|
||||||
|
]
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4347_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "PASS";
|
||||||
|
(async function() {
|
||||||
|
throw 42;
|
||||||
|
a = "FAIL";
|
||||||
|
})();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "PASS";
|
||||||
|
(async function() {
|
||||||
|
throw 42;
|
||||||
|
a = "FAIL";
|
||||||
|
})();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4349_1: {
|
||||||
|
input: {
|
||||||
|
console.log(typeof async function() {
|
||||||
|
await /abc/;
|
||||||
|
}().then);
|
||||||
|
}
|
||||||
|
expect_exact: "console.log(typeof async function(){await/abc/}().then);"
|
||||||
|
expect_stdout: "function"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4349_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(typeof async function() {
|
||||||
|
(function(a) {
|
||||||
|
this[a];
|
||||||
|
}(await 0));
|
||||||
|
}().then);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(typeof async function() {
|
||||||
|
(function(a) {
|
||||||
|
this[a];
|
||||||
|
}(await 0));
|
||||||
|
}().then);
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4349_3: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(typeof function(await) {
|
||||||
|
return async function(a) {
|
||||||
|
this[a];
|
||||||
|
}(await);
|
||||||
|
}(this).then);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(typeof function(await) {
|
||||||
|
return async function(a) {
|
||||||
|
this[a];
|
||||||
|
}(await);
|
||||||
|
}(this).then);
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4359: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
(async function(a) {
|
||||||
|
return a;
|
||||||
|
})(A);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
(async function(a) {
|
||||||
|
return a;
|
||||||
|
})(A);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4377: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
inline: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(typeof function() {
|
||||||
|
return function() {
|
||||||
|
f;
|
||||||
|
async function f() {}
|
||||||
|
return f();
|
||||||
|
}();
|
||||||
|
}().then);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(typeof function() {
|
||||||
|
return f();
|
||||||
|
async function f() {}
|
||||||
|
}().then);
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4406: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
A = "PASS";
|
||||||
|
B = "FAIL";
|
||||||
|
(function() {
|
||||||
|
var a, b;
|
||||||
|
a = A;
|
||||||
|
(async function({
|
||||||
|
[console.log(a)]: {},
|
||||||
|
}) {})((b = B) && { undefined: b });
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
A = "PASS";
|
||||||
|
B = "FAIL";
|
||||||
|
(function() {
|
||||||
|
var a, b;
|
||||||
|
a = A;
|
||||||
|
(async function({
|
||||||
|
[console.log(a)]: {},
|
||||||
|
}) {})((b = B) && { undefined: b });
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4417: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(async function() {
|
||||||
|
console.log(function() {
|
||||||
|
return await => 0;
|
||||||
|
}().prototype);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(async function() {
|
||||||
|
console.log(function() {
|
||||||
|
return await => 0;
|
||||||
|
}().prototype);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
@@ -153,3 +153,31 @@ issue_3690: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4374: {
|
||||||
|
options = {
|
||||||
|
booleans: true,
|
||||||
|
conditionals: true,
|
||||||
|
if_return: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
console.log(f());
|
||||||
|
function f(a) {
|
||||||
|
if (null) return 0;
|
||||||
|
if (a) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
console.log(function(a) {
|
||||||
|
return !null && a ? 1 : 0;
|
||||||
|
}());
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
}
|
||||||
|
|||||||
@@ -8602,3 +8602,63 @@ issue_4248: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "1"
|
expect_stdout: "1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4430_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
switch (a = 1, arguments[0]) {
|
||||||
|
case 1:
|
||||||
|
return "PASS";
|
||||||
|
case 2:
|
||||||
|
return "FAIL";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(f(2));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a) {
|
||||||
|
switch (a = 1, arguments[0]) {
|
||||||
|
case 1:
|
||||||
|
return "PASS";
|
||||||
|
case 2:
|
||||||
|
return "FAIL";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(f(2));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4430_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
switch (a = 0, arguments[0]) {
|
||||||
|
case 0:
|
||||||
|
return "PASS";
|
||||||
|
case 1:
|
||||||
|
return "FAIL";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(f(1));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a) {
|
||||||
|
switch (arguments[a = 0]) {
|
||||||
|
case 0:
|
||||||
|
return "PASS";
|
||||||
|
case 1:
|
||||||
|
return "FAIL";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(f(1));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1347,3 +1347,31 @@ issue_4305_2: {
|
|||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4365_1: {
|
||||||
|
options = {
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
const arguments = 42;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
const arguments = 42;
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4365_2: {
|
||||||
|
options = {
|
||||||
|
toplevel: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
const arguments = 42;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
const arguments = 42;
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|||||||
@@ -1375,3 +1375,27 @@ issue_4051: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4366: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
return "PASS";
|
||||||
|
({
|
||||||
|
p: 42,
|
||||||
|
get p() {},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log(f());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
return "PASS";
|
||||||
|
}
|
||||||
|
console.log(f());
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|||||||
@@ -750,6 +750,46 @@ simple_var: {
|
|||||||
node_version: ">=6"
|
node_version: ">=6"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drop_catch: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {} catch ({
|
||||||
|
[console.log("FAIL")]: e,
|
||||||
|
}) {} finally {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
drop_catch_var: {
|
||||||
|
options = {
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
throw new Error("PASS");
|
||||||
|
} catch ({ name, message }) {
|
||||||
|
console.log(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
throw new Error("PASS");
|
||||||
|
} catch ({ message }) {
|
||||||
|
console.log(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
collapse_vars_1: {
|
collapse_vars_1: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
@@ -1777,3 +1817,223 @@ issue_4323: {
|
|||||||
expect_stdout: "function"
|
expect_stdout: "function"
|
||||||
node_version: ">=6"
|
node_version: ">=6"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4355: {
|
||||||
|
options = {
|
||||||
|
loops: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a;
|
||||||
|
(function({
|
||||||
|
[function() {
|
||||||
|
for (a in "foo");
|
||||||
|
}()]: b,
|
||||||
|
}) {
|
||||||
|
var a;
|
||||||
|
})(0);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a;
|
||||||
|
(function({
|
||||||
|
[function() {
|
||||||
|
for (a in "foo");
|
||||||
|
}()]: b,
|
||||||
|
}) {})(0);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "2"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4372_1: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "FAIL";
|
||||||
|
a += {
|
||||||
|
[console.log(a)]: a,
|
||||||
|
} = a = "PASS";
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "FAIL";
|
||||||
|
a += {
|
||||||
|
[console.log(a)]: a,
|
||||||
|
} = a = "PASS";
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4372_2: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a;
|
||||||
|
[ a ] = a = [ "PASS", "FAIL" ];
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a;
|
||||||
|
[ a ] = [ "PASS", "FAIL" ];
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4383: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a) {
|
||||||
|
[ a[0] ] = [];
|
||||||
|
return a.length;
|
||||||
|
}([]));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
[ a[0] ] = [];
|
||||||
|
return a.length;
|
||||||
|
}([]));
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4386: {
|
||||||
|
options = {
|
||||||
|
arguments: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f({}) {
|
||||||
|
return arguments[0];
|
||||||
|
}
|
||||||
|
console.log(f("PASS"));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f({}) {
|
||||||
|
return arguments[0];
|
||||||
|
}
|
||||||
|
console.log(f("PASS"));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4395: {
|
||||||
|
options = {
|
||||||
|
arguments: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a, {}) {
|
||||||
|
a = "FAIL";
|
||||||
|
return arguments[0];
|
||||||
|
}("PASS", 42));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a, {}) {
|
||||||
|
a = "FAIL";
|
||||||
|
return arguments[0];
|
||||||
|
}("PASS", 42));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4399: {
|
||||||
|
options = {
|
||||||
|
arguments: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function({
|
||||||
|
[arguments[1]]: a,
|
||||||
|
}, b) {
|
||||||
|
return a;
|
||||||
|
}([ "PASS" ], 0));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function({
|
||||||
|
[arguments[1]]: a,
|
||||||
|
}, b) {
|
||||||
|
return a;
|
||||||
|
}([ "PASS" ], 0));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4420: {
|
||||||
|
options = {
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function() {
|
||||||
|
var a = 1;
|
||||||
|
try {
|
||||||
|
throw [ "FAIL", "PASS" ];
|
||||||
|
} catch ({
|
||||||
|
[a]: b,
|
||||||
|
}) {
|
||||||
|
let a = 0;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
var a = 1;
|
||||||
|
try {
|
||||||
|
throw [ "FAIL", "PASS" ];
|
||||||
|
} catch ({
|
||||||
|
[a]: b,
|
||||||
|
}) {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4425: {
|
||||||
|
rename = true
|
||||||
|
input: {
|
||||||
|
var a;
|
||||||
|
console.log(function() {
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
throw 42;
|
||||||
|
} catch ({
|
||||||
|
[a]: a,
|
||||||
|
}) {}
|
||||||
|
return "FAIL";
|
||||||
|
} catch (e) {
|
||||||
|
return "PASS";
|
||||||
|
}
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a;
|
||||||
|
console.log(function() {
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
throw 42;
|
||||||
|
} catch ({
|
||||||
|
[b]: b,
|
||||||
|
}) {}
|
||||||
|
return "FAIL";
|
||||||
|
} catch (c) {
|
||||||
|
return "PASS";
|
||||||
|
}
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|||||||
@@ -3112,3 +3112,44 @@ issue_4235: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "undefined"
|
expect_stdout: "undefined"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4404: {
|
||||||
|
options = {
|
||||||
|
pure_getters: "strict",
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
arguments[0] = "PASS";
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
f("FAIL");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a) {
|
||||||
|
arguments[0] = "PASS";
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
f("FAIL");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4413: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function f(arguments) {
|
||||||
|
var arguments = function() {};
|
||||||
|
return arguments.length;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(arguments) {
|
||||||
|
return function() {}.length;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
}
|
||||||
|
|||||||
@@ -3074,3 +3074,46 @@ issue_4271: {
|
|||||||
"PASS",
|
"PASS",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4393: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function f(a) {
|
||||||
|
a = "PASS";
|
||||||
|
console.log(arguments[0]);
|
||||||
|
})("FAIL");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function f(a) {
|
||||||
|
a = "PASS";
|
||||||
|
console.log(arguments[0]);
|
||||||
|
})("FAIL");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4422: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function f(a) {
|
||||||
|
a = "FAIL 1";
|
||||||
|
arguments[0] = "PASS";
|
||||||
|
return a;
|
||||||
|
}("FAIL 2"));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
a = "FAIL 1";
|
||||||
|
arguments[0] = "PASS";
|
||||||
|
return a;
|
||||||
|
}("FAIL 2"));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -5213,3 +5213,13 @@ issue_4265: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "undefined"
|
expect_stdout: "undefined"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trailing_comma: {
|
||||||
|
input: {
|
||||||
|
new function(a, b,) {
|
||||||
|
console.log(b, a,);
|
||||||
|
}(42, "PASS",);
|
||||||
|
}
|
||||||
|
expect_exact: 'new function(a,b){console.log(b,a)}(42,"PASS");'
|
||||||
|
expect_stdout: "PASS 42"
|
||||||
|
}
|
||||||
|
|||||||
@@ -588,7 +588,6 @@ issue_3197_1: {
|
|||||||
ie8: false,
|
ie8: false,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var window = {};
|
|
||||||
!function() {
|
!function() {
|
||||||
function Foo() {
|
function Foo() {
|
||||||
console.log(this instanceof Foo);
|
console.log(this instanceof Foo);
|
||||||
@@ -598,7 +597,6 @@ issue_3197_1: {
|
|||||||
new window.Foo();
|
new window.Foo();
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var window = {};
|
|
||||||
window.Foo = function o() {
|
window.Foo = function o() {
|
||||||
console.log(this instanceof o);
|
console.log(this instanceof o);
|
||||||
};
|
};
|
||||||
@@ -619,7 +617,6 @@ issue_3197_1_ie8: {
|
|||||||
ie8: true,
|
ie8: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var window = {};
|
|
||||||
!function() {
|
!function() {
|
||||||
function Foo() {
|
function Foo() {
|
||||||
console.log(this instanceof Foo);
|
console.log(this instanceof Foo);
|
||||||
@@ -629,7 +626,6 @@ issue_3197_1_ie8: {
|
|||||||
new window.Foo();
|
new window.Foo();
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var window = {};
|
|
||||||
window.Foo = function Foo() {
|
window.Foo = function Foo() {
|
||||||
console.log(this instanceof Foo);
|
console.log(this instanceof Foo);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1452,3 +1452,37 @@ issue_3619: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4353_1: {
|
||||||
|
options = {
|
||||||
|
keep_fargs: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function f(a) {}.length);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {}.length);
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4353_2: {
|
||||||
|
options = {
|
||||||
|
keep_fargs: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function f(a) {
|
||||||
|
while (console.log("PASS"));
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
while (console.log("PASS"));
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1255,3 +1255,28 @@ issue_4240: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4355: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
evaluate: true,
|
||||||
|
loops: true,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
while (function() {
|
||||||
|
var a;
|
||||||
|
for (a in console.log("PASS"))
|
||||||
|
var b = 0;
|
||||||
|
}())
|
||||||
|
var c;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
console.log("PASS");
|
||||||
|
})();
|
||||||
|
var c;
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ duplicate_key_strict: {
|
|||||||
"use strict";
|
"use strict";
|
||||||
var o = {
|
var o = {
|
||||||
a: 1,
|
a: 1,
|
||||||
b: 2,
|
|
||||||
a: 3,
|
a: 3,
|
||||||
|
b: 2,
|
||||||
};
|
};
|
||||||
for (var k in o)
|
for (var k in o)
|
||||||
console.log(k, o[k]);
|
console.log(k, o[k]);
|
||||||
@@ -257,6 +257,29 @@ keep_computed_key: {
|
|||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shorthand_keywords: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var async = 1, get = 2, set = 3, o = {
|
||||||
|
async,
|
||||||
|
get,
|
||||||
|
set,
|
||||||
|
};
|
||||||
|
console.log(o.async, o.get, o.set);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1, 2, 3);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 2 3"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
issue_4269_1: {
|
issue_4269_1: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
@@ -323,8 +346,8 @@ issue_4269_3: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log({
|
console.log({
|
||||||
["foo"]: "bar",
|
foo: "bar",
|
||||||
get 42() {
|
get [42]() {
|
||||||
return "FAIL";
|
return "FAIL";
|
||||||
},
|
},
|
||||||
42: "PASS",
|
42: "PASS",
|
||||||
@@ -353,10 +376,82 @@ issue_4269_4: {
|
|||||||
get 42() {
|
get 42() {
|
||||||
return "FAIL";
|
return "FAIL";
|
||||||
},
|
},
|
||||||
["foo"]: "bar",
|
foo: "bar",
|
||||||
|
[42]: "PASS",
|
||||||
|
}[42]);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4269_5: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
objects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log({
|
||||||
|
get 42() {
|
||||||
|
return "FAIL";
|
||||||
|
},
|
||||||
|
[console]: "bar",
|
||||||
|
42: "PASS",
|
||||||
|
}[42]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
get 42() {
|
||||||
|
return "FAIL";
|
||||||
|
},
|
||||||
|
[console]: "bar",
|
||||||
42: "PASS",
|
42: "PASS",
|
||||||
}[42]);
|
}[42]);
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4380: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
objects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log({
|
||||||
|
get 0() {
|
||||||
|
return "FAIL 1";
|
||||||
|
},
|
||||||
|
0: "FAIL 2",
|
||||||
|
[0]: "PASS",
|
||||||
|
}[0]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
get 0() {
|
||||||
|
return "FAIL 1";
|
||||||
|
},
|
||||||
|
[0]: ("FAIL 2", "PASS"),
|
||||||
|
}[0]);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4415: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
objects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log({
|
||||||
|
["00"]: "FAIL",
|
||||||
|
}[0] || "PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
"00": "FAIL",
|
||||||
|
}[0] || "PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|||||||
@@ -470,3 +470,39 @@ issue_4325: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4366_1: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
({
|
||||||
|
p: 42,
|
||||||
|
get p() {},
|
||||||
|
q: console.log("PASS"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4366_2: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
({
|
||||||
|
set p(v) {},
|
||||||
|
q: console.log("PASS"),
|
||||||
|
p: 42,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|||||||
806
test/compress/spread.js
Normal file
806
test/compress/spread.js
Normal file
@@ -0,0 +1,806 @@
|
|||||||
|
collapse_vars_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a;
|
||||||
|
[ ...a = "PASS", "PASS"].slice();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a;
|
||||||
|
[ ...a = "PASS", "PASS"].slice();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_vars_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "FAIL";
|
||||||
|
try {
|
||||||
|
a = "PASS";
|
||||||
|
[ ...42, "PASS"].slice();
|
||||||
|
} catch (e) {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "FAIL";
|
||||||
|
try {
|
||||||
|
a = "PASS";
|
||||||
|
[ ...42, "PASS"].slice();
|
||||||
|
} catch (e) {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_vars_3: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "FAIL";
|
||||||
|
try {
|
||||||
|
[ ...(a = "PASS", 42), "PASS"].slice();
|
||||||
|
} catch (e) {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "FAIL";
|
||||||
|
try {
|
||||||
|
[ ...(a = "PASS", 42), "PASS"].slice();
|
||||||
|
} catch (e) {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_vars_4: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a) {
|
||||||
|
return a;
|
||||||
|
}(...[ "PASS", "FAIL" ]));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
return a;
|
||||||
|
}(...[ "PASS", "FAIL" ]));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
dont_inline: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a) {
|
||||||
|
return a;
|
||||||
|
}(...[ "PASS", "FAIL" ]));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
return a;
|
||||||
|
}(...[ "PASS", "FAIL" ]));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
do_inline: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
spread: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a) {
|
||||||
|
return a;
|
||||||
|
}(...[ "PASS", "FAIL" ]));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(("FAIL", "PASS"));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
drop_empty_call_1: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
(function() {})(...null);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
[ ...null ];
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
drop_empty_call_2: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
spread: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {})(...[ console.log("PASS") ]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
convert_hole: {
|
||||||
|
options = {
|
||||||
|
spread: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(...[ "PASS", , 42 ]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PASS", void 0, 42);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS undefined 42"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
keep_property_access: {
|
||||||
|
options = {
|
||||||
|
properties: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function() {
|
||||||
|
return [ ..."foo" ][0];
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
return [ ..."foo" ][0];
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "f"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
keep_fargs: {
|
||||||
|
options = {
|
||||||
|
keep_fargs: "strict",
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = [ "PASS" ];
|
||||||
|
(function(b, c) {
|
||||||
|
console.log(c);
|
||||||
|
})(console, ...a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = [ "PASS" ];
|
||||||
|
(function(b, c) {
|
||||||
|
console.log(c);
|
||||||
|
})(console, ...a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_vars_1: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(b, c) {
|
||||||
|
return c ? "PASS" : "FAIL";
|
||||||
|
}(..."foo"));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(b, c) {
|
||||||
|
return c ? "PASS" : "FAIL";
|
||||||
|
}(..."foo"));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_vars_2: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(b, c) {
|
||||||
|
return c ? "PASS" : "FAIL";
|
||||||
|
}(..."foo"));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(b, c) {
|
||||||
|
return c ? "PASS" : "FAIL";
|
||||||
|
}(..."foo"));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
convert_setter: {
|
||||||
|
options = {
|
||||||
|
objects: true,
|
||||||
|
spread: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
...{
|
||||||
|
set PASS(v) {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
for (var k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
PASS: void 0,
|
||||||
|
};
|
||||||
|
for (var k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS undefined"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
keep_getter_1: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
({
|
||||||
|
...{
|
||||||
|
get p() {
|
||||||
|
console.log("PASS");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
get q() {
|
||||||
|
console.log("FAIL");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
({
|
||||||
|
...{
|
||||||
|
get p() {
|
||||||
|
console.log("PASS");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
keep_getter_2: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
({
|
||||||
|
...(console.log("foo"), {
|
||||||
|
get p() {
|
||||||
|
console.log("bar");
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
({
|
||||||
|
...(console.log("foo"), {
|
||||||
|
get p() {
|
||||||
|
console.log("bar");
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo",
|
||||||
|
"bar",
|
||||||
|
]
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
keep_getter_3: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
({
|
||||||
|
...function() {
|
||||||
|
return {
|
||||||
|
get p() {
|
||||||
|
console.log("PASS");
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
({
|
||||||
|
...function() {
|
||||||
|
return {
|
||||||
|
get p() {
|
||||||
|
console.log("PASS");
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
keep_getter_4: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
get p() {
|
||||||
|
console.log("PASS");
|
||||||
|
},
|
||||||
|
};
|
||||||
|
({
|
||||||
|
q: o,
|
||||||
|
...o,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
get p() {
|
||||||
|
console.log("PASS");
|
||||||
|
},
|
||||||
|
};
|
||||||
|
({
|
||||||
|
...o,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
keep_accessor: {
|
||||||
|
options = {
|
||||||
|
objects: true,
|
||||||
|
spread: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
...{
|
||||||
|
get p() {
|
||||||
|
console.log("GET");
|
||||||
|
return this.r;
|
||||||
|
},
|
||||||
|
set q(v) {
|
||||||
|
console.log("SET", v);
|
||||||
|
},
|
||||||
|
r: 42,
|
||||||
|
},
|
||||||
|
r: null,
|
||||||
|
};
|
||||||
|
for (var k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
...{
|
||||||
|
get p() {
|
||||||
|
console.log("GET");
|
||||||
|
return this.r;
|
||||||
|
},
|
||||||
|
set q(v) {
|
||||||
|
console.log("SET", v);
|
||||||
|
},
|
||||||
|
r: 42,
|
||||||
|
},
|
||||||
|
r: null,
|
||||||
|
};
|
||||||
|
for (var k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"GET",
|
||||||
|
"p 42",
|
||||||
|
"q undefined",
|
||||||
|
"r null",
|
||||||
|
]
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
object_key_order_1: {
|
||||||
|
options = {
|
||||||
|
objects: true,
|
||||||
|
spread: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
...{},
|
||||||
|
a: 1,
|
||||||
|
b: 2,
|
||||||
|
a: 3,
|
||||||
|
};
|
||||||
|
for (var k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
a: (1, 3),
|
||||||
|
b: 2,
|
||||||
|
};
|
||||||
|
for (var k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"a 3",
|
||||||
|
"b 2",
|
||||||
|
]
|
||||||
|
node_version: ">=8 <=10"
|
||||||
|
}
|
||||||
|
|
||||||
|
object_key_order_2: {
|
||||||
|
options = {
|
||||||
|
objects: true,
|
||||||
|
spread: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
a: 1,
|
||||||
|
...{},
|
||||||
|
b: 2,
|
||||||
|
a: 3,
|
||||||
|
};
|
||||||
|
for (var k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
a: (1, 3),
|
||||||
|
b: 2,
|
||||||
|
};
|
||||||
|
for (var k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"a 3",
|
||||||
|
"b 2",
|
||||||
|
]
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
object_key_order_3: {
|
||||||
|
options = {
|
||||||
|
objects: true,
|
||||||
|
spread: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
a: 1,
|
||||||
|
b: 2,
|
||||||
|
...{},
|
||||||
|
a: 3,
|
||||||
|
};
|
||||||
|
for (var k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
a: (1, 3),
|
||||||
|
b: 2,
|
||||||
|
};
|
||||||
|
for (var k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"a 3",
|
||||||
|
"b 2",
|
||||||
|
]
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
object_key_order_4: {
|
||||||
|
options = {
|
||||||
|
objects: true,
|
||||||
|
spread: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
a: 1,
|
||||||
|
b: 2,
|
||||||
|
a: 3,
|
||||||
|
...{},
|
||||||
|
};
|
||||||
|
for (var k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
a: (1, 3),
|
||||||
|
b: 2,
|
||||||
|
};
|
||||||
|
for (var k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"a 3",
|
||||||
|
"b 2",
|
||||||
|
]
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
object_spread_array: {
|
||||||
|
options = {
|
||||||
|
objects: true,
|
||||||
|
spread: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
...[ "foo", "bar" ],
|
||||||
|
};
|
||||||
|
for (var k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
...[ "foo", "bar" ],
|
||||||
|
};
|
||||||
|
for (var k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"0 foo",
|
||||||
|
"1 bar",
|
||||||
|
]
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
object_spread_string: {
|
||||||
|
options = {
|
||||||
|
objects: true,
|
||||||
|
spread: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
..."foo",
|
||||||
|
};
|
||||||
|
for (var k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
..."foo",
|
||||||
|
};
|
||||||
|
for (var k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"0 f",
|
||||||
|
"1 o",
|
||||||
|
"2 o",
|
||||||
|
]
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
unused_var_side_effects: {
|
||||||
|
options = {
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function f(a) {
|
||||||
|
var b = {
|
||||||
|
...a,
|
||||||
|
};
|
||||||
|
})({
|
||||||
|
get p() {
|
||||||
|
console.log("PASS");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function(a) {
|
||||||
|
({
|
||||||
|
...a,
|
||||||
|
});
|
||||||
|
})({
|
||||||
|
get p() {
|
||||||
|
console.log("PASS");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4329: {
|
||||||
|
options = {
|
||||||
|
objects: true,
|
||||||
|
spread: 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: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4331: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "PASS", b;
|
||||||
|
console,
|
||||||
|
b = a;
|
||||||
|
(function() {
|
||||||
|
a++;
|
||||||
|
})(...a);
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "PASS", b;
|
||||||
|
console;
|
||||||
|
(function() {
|
||||||
|
a++;
|
||||||
|
})(...b = a);
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4342: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
new function() {}(...42);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
[ ...42 ];
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4345: {
|
||||||
|
options = {
|
||||||
|
objects: true,
|
||||||
|
spread: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log({
|
||||||
|
...{
|
||||||
|
get 42() {
|
||||||
|
return "FAIL";
|
||||||
|
},
|
||||||
|
...{},
|
||||||
|
42: "PASS",
|
||||||
|
},
|
||||||
|
}[42]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
...{
|
||||||
|
get 42() {
|
||||||
|
return "FAIL";
|
||||||
|
},
|
||||||
|
[42]: "PASS",
|
||||||
|
},
|
||||||
|
}[42]);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4361: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function() {
|
||||||
|
var a = console.log("foo");
|
||||||
|
console;
|
||||||
|
var b = {
|
||||||
|
...a,
|
||||||
|
};
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
var a = console.log("foo");
|
||||||
|
console;
|
||||||
|
({
|
||||||
|
...a,
|
||||||
|
});
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo",
|
||||||
|
"undefined",
|
||||||
|
]
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4363: {
|
||||||
|
options = {
|
||||||
|
objects: true,
|
||||||
|
spread: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
({
|
||||||
|
...{
|
||||||
|
set [console.log("PASS")](v) {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
({
|
||||||
|
[console.log("PASS")]: void 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
8
test/input/invalid/destructured_var.js
Normal file
8
test/input/invalid/destructured_var.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
function f() {
|
||||||
|
var { eval } = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function g() {
|
||||||
|
"use strict";
|
||||||
|
var { eval } = 42;
|
||||||
|
}
|
||||||
7
test/input/reduce/destructured_catch.js
Normal file
7
test/input/reduce/destructured_catch.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
try {
|
||||||
|
"foo" in 42;
|
||||||
|
} catch ({
|
||||||
|
message,
|
||||||
|
}) {
|
||||||
|
console.log(message);
|
||||||
|
}
|
||||||
15
test/input/reduce/destructured_catch.reduced.js
Normal file
15
test/input/reduce/destructured_catch.reduced.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// (beautified)
|
||||||
|
try {
|
||||||
|
1 in 0;
|
||||||
|
} catch ({
|
||||||
|
message: message
|
||||||
|
}) {
|
||||||
|
console.log(message);
|
||||||
|
}
|
||||||
|
// output: Cannot use 'in' operator to search for '1' in 0
|
||||||
|
//
|
||||||
|
// minify: Cannot use 'in' operator to search for '0' in 0
|
||||||
|
//
|
||||||
|
// options: {
|
||||||
|
// "mangle": false
|
||||||
|
// }
|
||||||
65
test/mocha/async.js
Normal file
65
test/mocha/async.js
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
var assert = require("assert");
|
||||||
|
var UglifyJS = require("../node");
|
||||||
|
|
||||||
|
describe("async", function() {
|
||||||
|
it("Should reject `await` as symbol name within async functions only", function() {
|
||||||
|
[
|
||||||
|
"function await() {}",
|
||||||
|
"function(await) {}",
|
||||||
|
"function() { await; }",
|
||||||
|
"function() { await:{} }",
|
||||||
|
"function() { var await; }",
|
||||||
|
"function() { function await() {} }",
|
||||||
|
"function() { try {} catch (await) {} }",
|
||||||
|
].forEach(function(code) {
|
||||||
|
var ast = UglifyJS.parse("(" + code + ")();");
|
||||||
|
assert.strictEqual(ast.TYPE, "Toplevel");
|
||||||
|
assert.strictEqual(ast.body.length, 1);
|
||||||
|
assert.strictEqual(ast.body[0].TYPE, "SimpleStatement");
|
||||||
|
assert.strictEqual(ast.body[0].body.TYPE, "Call");
|
||||||
|
assert.strictEqual(ast.body[0].body.expression.TYPE, "Function");
|
||||||
|
assert.throws(function() {
|
||||||
|
UglifyJS.parse("(async " + code + ")();");
|
||||||
|
}, function(e) {
|
||||||
|
return e instanceof UglifyJS.JS_Parse_Error;
|
||||||
|
}, code);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Should reject `await` expression outside of async functions", function() {
|
||||||
|
[
|
||||||
|
"await 42;",
|
||||||
|
"function f() { await 42; }",
|
||||||
|
"async function f() { function g() { await 42; } }",
|
||||||
|
].forEach(function(code) {
|
||||||
|
assert.throws(function() {
|
||||||
|
UglifyJS.parse(code);
|
||||||
|
}, function(e) {
|
||||||
|
return e instanceof UglifyJS.JS_Parse_Error;
|
||||||
|
}, code);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Should reject `await` expression directly on computed key of function argument", function() {
|
||||||
|
[
|
||||||
|
"function f({ [await 42]: a }) {}",
|
||||||
|
"async function f({ [await 42]: a }) {}",
|
||||||
|
].forEach(function(code) {
|
||||||
|
assert.throws(function() {
|
||||||
|
UglifyJS.parse(code);
|
||||||
|
}, function(e) {
|
||||||
|
return e instanceof UglifyJS.JS_Parse_Error;
|
||||||
|
}, code);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Should accept `await` expression nested within computed key of function argument", function() {
|
||||||
|
[
|
||||||
|
"function f({ [async function() { await 42; }()]: a }) {}",
|
||||||
|
"async function f({ [async function() { await 42; }()]: a }) {}",
|
||||||
|
].forEach(function(code) {
|
||||||
|
var ast = UglifyJS.parse(code);
|
||||||
|
assert.strictEqual(ast.TYPE, "Toplevel");
|
||||||
|
assert.strictEqual(ast.body.length, 1);
|
||||||
|
assert.strictEqual(ast.body[0].argnames.length, 1);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].TYPE, "DestructuredObject");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -573,6 +573,20 @@ describe("bin/uglifyjs", function() {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it("Should throw syntax error (var { eval })", function(done) {
|
||||||
|
var command = uglifyjscmd + " test/input/invalid/destructured_var.js";
|
||||||
|
exec(command, function(err, stdout, stderr) {
|
||||||
|
assert.ok(err);
|
||||||
|
assert.strictEqual(stdout, "");
|
||||||
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
|
"Parse error at test/input/invalid/destructured_var.js:7,10",
|
||||||
|
" var { eval } = 42;",
|
||||||
|
" ^",
|
||||||
|
"ERROR: Unexpected eval in strict mode"
|
||||||
|
].join("\n"));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
it("Should throw syntax error (else)", function(done) {
|
it("Should throw syntax error (else)", function(done) {
|
||||||
var command = uglifyjscmd + " test/input/invalid/else.js";
|
var command = uglifyjscmd + " test/input/invalid/else.js";
|
||||||
exec(command, function(err, stdout, stderr) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
|
|||||||
@@ -313,4 +313,12 @@ describe("test/reduce.js", function() {
|
|||||||
if (result.error) throw result.error;
|
if (result.error) throw result.error;
|
||||||
assert.strictEqual(result.code, read("test/input/reduce/diff_error.reduced.js"));
|
assert.strictEqual(result.code, read("test/input/reduce/diff_error.reduced.js"));
|
||||||
});
|
});
|
||||||
|
it("Should handle destructured catch expressions", function() {
|
||||||
|
if (semver.satisfies(process.version, "<6")) return;
|
||||||
|
var result = reduce_test(read("test/input/reduce/destructured_catch.js"), {
|
||||||
|
mangle: false,
|
||||||
|
});
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
assert.strictEqual(result.code, read("test/input/reduce/destructured_catch.reduced.js"));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,9 +18,18 @@ var sandbox = require("./sandbox");
|
|||||||
|
|
||||||
Error.stackTraceLimit = Infinity;
|
Error.stackTraceLimit = Infinity;
|
||||||
module.exports = function reduce_test(testcase, minify_options, reduce_options) {
|
module.exports = function reduce_test(testcase, minify_options, reduce_options) {
|
||||||
if (testcase instanceof U.AST_Node) testcase = testcase.print_to_string();
|
|
||||||
minify_options = minify_options || {};
|
minify_options = minify_options || {};
|
||||||
reduce_options = reduce_options || {};
|
reduce_options = reduce_options || {};
|
||||||
|
var print_options = {};
|
||||||
|
[
|
||||||
|
"ie8",
|
||||||
|
"v8",
|
||||||
|
"webkit",
|
||||||
|
].forEach(function(name) {
|
||||||
|
var value = minify_options[name] || minify_options.output && minify_options.output[name];
|
||||||
|
if (value) print_options[name] = value;
|
||||||
|
});
|
||||||
|
if (testcase instanceof U.AST_Node) testcase = testcase.print_to_string(print_options);
|
||||||
var max_iterations = reduce_options.max_iterations || 1000;
|
var max_iterations = reduce_options.max_iterations || 1000;
|
||||||
var max_timeout = reduce_options.max_timeout || 10000;
|
var max_timeout = reduce_options.max_timeout || 10000;
|
||||||
var warnings = [];
|
var warnings = [];
|
||||||
@@ -135,7 +144,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
if (expr && !(expr instanceof U.AST_Hole)) {
|
if (expr && !(expr instanceof U.AST_Hole)) {
|
||||||
node.start._permute++;
|
node.start._permute++;
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
return expr;
|
return expr instanceof U.AST_Spread ? expr.expression : expr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (node instanceof U.AST_Binary) {
|
else if (node instanceof U.AST_Binary) {
|
||||||
@@ -164,7 +173,13 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
][ ((node.start._permute += step) * steps | 0) % 3 ];
|
][ ((node.start._permute += step) * steps | 0) % 3 ];
|
||||||
if (expr) {
|
if (expr) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
return expr;
|
return expr instanceof U.AST_Spread ? expr.expression : expr;
|
||||||
|
}
|
||||||
|
if (node.expression instanceof U.AST_Arrow && node.expression.value) {
|
||||||
|
var seq = node.args.slice();
|
||||||
|
seq.push(node.expression.value);
|
||||||
|
CHANGED = true;
|
||||||
|
return to_sequence(seq);
|
||||||
}
|
}
|
||||||
if (node.expression instanceof U.AST_Function) {
|
if (node.expression instanceof U.AST_Function) {
|
||||||
// hoist and return expressions from the IIFE function expression
|
// hoist and return expressions from the IIFE function expression
|
||||||
@@ -381,9 +396,8 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (in_list) {
|
if (in_list) {
|
||||||
// special case to drop object properties and switch branches
|
// drop switch branches
|
||||||
if (parent instanceof U.AST_Object
|
if (parent instanceof U.AST_Switch && parent.expression != node) {
|
||||||
|| parent instanceof U.AST_Switch && parent.expression != node) {
|
|
||||||
node.start._permute++;
|
node.start._permute++;
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
return List.skip;
|
return List.skip;
|
||||||
@@ -404,7 +418,9 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// skip element/property from (destructured) array/object
|
// skip element/property from (destructured) array/object
|
||||||
if (parent instanceof U.AST_Array || parent instanceof U.AST_Destructured || parent instanceof AST_Object) {
|
if (parent instanceof U.AST_Array
|
||||||
|
|| parent instanceof U.AST_Destructured
|
||||||
|
|| parent instanceof U.AST_Object) {
|
||||||
node.start._permute++;
|
node.start._permute++;
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
return List.skip;
|
return List.skip;
|
||||||
@@ -449,7 +465,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
if (node.TYPE == "Call" && node.expression.print_to_string() == "console.log") {
|
if (node.TYPE == "Call" && node.expression.print_to_string() == "console.log") {
|
||||||
return to_sequence(node.args);
|
return to_sequence(node.args);
|
||||||
}
|
}
|
||||||
if (node instanceof U.AST_Catch && node.argname) {
|
if (node instanceof U.AST_Catch && node.argname instanceof U.AST_SymbolCatch) {
|
||||||
descend(node, this);
|
descend(node, this);
|
||||||
node.body.unshift(new U.AST_SimpleStatement({
|
node.body.unshift(new U.AST_SimpleStatement({
|
||||||
body: wrap_with_console_log(new U.AST_SymbolRef(node.argname)),
|
body: wrap_with_console_log(new U.AST_SymbolRef(node.argname)),
|
||||||
@@ -458,7 +474,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
var code = testcase_ast.print_to_string();
|
var code = testcase_ast.print_to_string(print_options);
|
||||||
var diff = test_for_diff(code, minify_options, result_cache, max_timeout);
|
var diff = test_for_diff(code, minify_options, result_cache, max_timeout);
|
||||||
if (diff && !diff.timed_out && !diff.error) {
|
if (diff && !diff.timed_out && !diff.error) {
|
||||||
testcase = code;
|
testcase = code;
|
||||||
@@ -482,7 +498,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
var code_ast = testcase_ast.clone(true).transform(tt);
|
var code_ast = testcase_ast.clone(true).transform(tt);
|
||||||
if (!CHANGED) break;
|
if (!CHANGED) break;
|
||||||
try {
|
try {
|
||||||
var code = code_ast.print_to_string();
|
var code = code_ast.print_to_string(print_options);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
// AST is not well formed.
|
// AST is not well formed.
|
||||||
// no harm done - just log the error, ignore latest change and continue iterating.
|
// no harm done - just log the error, ignore latest change and continue iterating.
|
||||||
@@ -524,11 +540,13 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
var beautified = U.minify(testcase, {
|
var beautified = U.minify(testcase, {
|
||||||
compress: false,
|
compress: false,
|
||||||
mangle: false,
|
mangle: false,
|
||||||
output: {
|
output: function() {
|
||||||
beautify: true,
|
var options = JSON.parse(JSON.stringify(print_options));
|
||||||
braces: true,
|
options.beautify = true;
|
||||||
comments: true,
|
options.braces = true;
|
||||||
},
|
options.comments = true;
|
||||||
|
return options;
|
||||||
|
}(),
|
||||||
});
|
});
|
||||||
testcase = {
|
testcase = {
|
||||||
code: testcase,
|
code: testcase,
|
||||||
@@ -617,7 +635,8 @@ function is_timed_out(result) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function is_statement(node) {
|
function is_statement(node) {
|
||||||
return node instanceof U.AST_Statement && !(node instanceof U.AST_Function);
|
return node instanceof U.AST_Statement
|
||||||
|
&& !(node instanceof U.AST_Arrow || node instanceof U.AST_AsyncFunction || node instanceof U.AST_Function);
|
||||||
}
|
}
|
||||||
|
|
||||||
function merge_sequence(array, node) {
|
function merge_sequence(array, node) {
|
||||||
|
|||||||
@@ -26,10 +26,19 @@ var setupContext = new vm.Script([
|
|||||||
]).join("\n"));
|
]).join("\n"));
|
||||||
|
|
||||||
function createContext() {
|
function createContext() {
|
||||||
var ctx = vm.createContext(Object.defineProperty({}, "console", { value: { log: log } }));
|
var ctx = vm.createContext(Object.defineProperties({}, {
|
||||||
|
console: { value: { log: log } },
|
||||||
|
global: { get: self },
|
||||||
|
self: { get: self },
|
||||||
|
window: { get: self },
|
||||||
|
}));
|
||||||
var global = setupContext.runInContext(ctx);
|
var global = setupContext.runInContext(ctx);
|
||||||
return ctx;
|
return ctx;
|
||||||
|
|
||||||
|
function self() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
function safe_log(arg, level) {
|
function safe_log(arg, level) {
|
||||||
if (arg) switch (typeof arg) {
|
if (arg) switch (typeof arg) {
|
||||||
case "function":
|
case "function":
|
||||||
@@ -37,6 +46,7 @@ function createContext() {
|
|||||||
case "object":
|
case "object":
|
||||||
if (arg === global) return "[object global]";
|
if (arg === global) return "[object global]";
|
||||||
if (/Error$/.test(arg.name)) return arg.toString();
|
if (/Error$/.test(arg.name)) return arg.toString();
|
||||||
|
if (typeof arg.then == "function") return "[object Promise]";
|
||||||
arg.constructor.toString();
|
arg.constructor.toString();
|
||||||
if (level--) for (var key in arg) {
|
if (level--) for (var key in arg) {
|
||||||
var desc = Object.getOwnPropertyDescriptor(arg, key);
|
var desc = Object.getOwnPropertyDescriptor(arg, key);
|
||||||
|
|||||||
@@ -126,6 +126,24 @@ for (var i = 2; i < process.argv.length; ++i) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var SUPPORT = function(matrix) {
|
||||||
|
for (var name in matrix) {
|
||||||
|
matrix[name] = typeof sandbox.run_code(matrix[name]) == "string";
|
||||||
|
}
|
||||||
|
return matrix;
|
||||||
|
}({
|
||||||
|
arrow: "a => 0;",
|
||||||
|
async: "async function f(){}",
|
||||||
|
catch_omit_var: "try {} catch {}",
|
||||||
|
computed_key: "({[0]: 0});",
|
||||||
|
const_block: "var a; { const a = 0; }",
|
||||||
|
destructuring: "[] = [];",
|
||||||
|
let: "let a;",
|
||||||
|
spread: "[...[]];",
|
||||||
|
spread_object: "({...0});",
|
||||||
|
trailing_comma: "function f(a,) {}",
|
||||||
|
});
|
||||||
|
|
||||||
var VALUES = [
|
var VALUES = [
|
||||||
'"a"',
|
'"a"',
|
||||||
'"b"',
|
'"b"',
|
||||||
@@ -298,6 +316,8 @@ var VAR_NAMES = [
|
|||||||
"arguments",
|
"arguments",
|
||||||
"Math",
|
"Math",
|
||||||
"parseInt",
|
"parseInt",
|
||||||
|
"async",
|
||||||
|
"await",
|
||||||
];
|
];
|
||||||
var INITIAL_NAMES_LEN = VAR_NAMES.length;
|
var INITIAL_NAMES_LEN = VAR_NAMES.length;
|
||||||
|
|
||||||
@@ -317,6 +337,7 @@ var TYPEOF_OUTCOMES = [
|
|||||||
var avoid_vars = [];
|
var avoid_vars = [];
|
||||||
var block_vars = [];
|
var block_vars = [];
|
||||||
var unique_vars = [];
|
var unique_vars = [];
|
||||||
|
var async = false;
|
||||||
var loops = 0;
|
var loops = 0;
|
||||||
var funcs = 0;
|
var funcs = 0;
|
||||||
var called = Object.create(null);
|
var called = Object.create(null);
|
||||||
@@ -335,13 +356,14 @@ function createTopLevelCode() {
|
|||||||
VAR_NAMES.length = INITIAL_NAMES_LEN; // prune any previous names still in the list
|
VAR_NAMES.length = INITIAL_NAMES_LEN; // prune any previous names still in the list
|
||||||
block_vars.length = 0;
|
block_vars.length = 0;
|
||||||
unique_vars.length = 0;
|
unique_vars.length = 0;
|
||||||
|
async = false;
|
||||||
loops = 0;
|
loops = 0;
|
||||||
funcs = 0;
|
funcs = 0;
|
||||||
called = Object.create(null);
|
called = Object.create(null);
|
||||||
return [
|
return [
|
||||||
strictMode(),
|
strictMode(),
|
||||||
"var _calls_ = 10, a = 100, b = 10, c = 0;",
|
"var _calls_ = 10, a = 100, b = 10, c = 0;",
|
||||||
rng(2) == 0
|
rng(2)
|
||||||
? createStatements(3, MAX_GENERATION_RECURSION_DEPTH, CANNOT_THROW, CANNOT_BREAK, CANNOT_CONTINUE, CANNOT_RETURN, 0)
|
? createStatements(3, MAX_GENERATION_RECURSION_DEPTH, CANNOT_THROW, CANNOT_BREAK, CANNOT_CONTINUE, CANNOT_RETURN, 0)
|
||||||
: createFunctions(rng(MAX_GENERATED_TOPLEVELS_PER_RUN) + 1, MAX_GENERATION_RECURSION_DEPTH, DEFUN_OK, CANNOT_THROW, 0),
|
: createFunctions(rng(MAX_GENERATED_TOPLEVELS_PER_RUN) + 1, MAX_GENERATION_RECURSION_DEPTH, DEFUN_OK, CANNOT_THROW, 0),
|
||||||
// preceding `null` makes for a cleaner output (empty string still shows up etc)
|
// preceding `null` makes for a cleaner output (empty string still shows up etc)
|
||||||
@@ -358,7 +380,13 @@ function createFunctions(n, recurmax, allowDefun, canThrow, stmtDepth) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createParams(noDuplicate) {
|
function addTrailingComma(list) {
|
||||||
|
return SUPPORT.trailing_comma && list && rng(20) == 0 ? list + "," : list;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createParams(was_async, noDuplicate) {
|
||||||
|
var save_async = async;
|
||||||
|
if (was_async) async = true;
|
||||||
var len = unique_vars.length;
|
var len = unique_vars.length;
|
||||||
var params = [];
|
var params = [];
|
||||||
for (var n = rng(4); --n >= 0;) {
|
for (var n = rng(4); --n >= 0;) {
|
||||||
@@ -367,18 +395,34 @@ function createParams(noDuplicate) {
|
|||||||
params.push(name);
|
params.push(name);
|
||||||
}
|
}
|
||||||
unique_vars.length = len;
|
unique_vars.length = len;
|
||||||
return params.join(", ");
|
async = save_async;
|
||||||
|
return addTrailingComma(params.join(", "));
|
||||||
}
|
}
|
||||||
|
|
||||||
function createArgs(recurmax, stmtDepth, canThrow) {
|
function createArgs(recurmax, stmtDepth, canThrow) {
|
||||||
|
recurmax--;
|
||||||
var args = [];
|
var args = [];
|
||||||
for (var n = rng(4); --n >= 0;) {
|
for (var n = rng(4); --n >= 0;) switch (SUPPORT.spread ? rng(50) : 3) {
|
||||||
args.push(rng(2) ? createValue() : createExpression(recurmax - 1, COMMA_OK, stmtDepth, canThrow));
|
case 0:
|
||||||
|
case 1:
|
||||||
|
var name = getVarName();
|
||||||
|
if (canThrow && rng(8) === 0) {
|
||||||
|
args.push("..." + name);
|
||||||
|
} else {
|
||||||
|
args.push('...("" + ' + name + ")");
|
||||||
}
|
}
|
||||||
return args.join(", ");
|
break;
|
||||||
|
case 2:
|
||||||
|
args.push("..." + createArrayLiteral(recurmax, stmtDepth, canThrow));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
args.push(rng(2) ? createValue() : createExpression(recurmax, NO_COMMA, stmtDepth, canThrow));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return addTrailingComma(args.join(", "));
|
||||||
}
|
}
|
||||||
|
|
||||||
function createAssignmentPairs(recurmax, noComma, stmtDepth, canThrow, varNames, maybe, dontStore) {
|
function createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, was_async) {
|
||||||
var avoid = [];
|
var avoid = [];
|
||||||
var len = unique_vars.length;
|
var len = unique_vars.length;
|
||||||
var pairs = createPairs(recurmax);
|
var pairs = createPairs(recurmax);
|
||||||
@@ -386,39 +430,46 @@ function createAssignmentPairs(recurmax, noComma, stmtDepth, canThrow, varNames,
|
|||||||
return pairs;
|
return pairs;
|
||||||
|
|
||||||
function createAssignmentValue(recurmax) {
|
function createAssignmentValue(recurmax) {
|
||||||
var current = VAR_NAMES;
|
var save_async = async;
|
||||||
VAR_NAMES = (varNames || VAR_NAMES).slice();
|
if (was_async != null) async = was_async;
|
||||||
var value = varNames && rng(2) ? createValue() : createExpression(recurmax, noComma, stmtDepth, canThrow);
|
var save_vars = nameLenBefore && VAR_NAMES.splice(nameLenBefore);
|
||||||
VAR_NAMES = current;
|
var value = nameLenBefore && rng(2) ? createValue() : createExpression(recurmax, NO_COMMA, stmtDepth, canThrow);
|
||||||
|
if (save_vars) [].push.apply(VAR_NAMES, save_vars);
|
||||||
|
async = save_async;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createKey(recurmax, keys) {
|
function createKey(recurmax, keys) {
|
||||||
addAvoidVars(avoid);
|
|
||||||
var key;
|
var key;
|
||||||
do {
|
do {
|
||||||
key = createObjectKey(recurmax, stmtDepth, canThrow);
|
key = createObjectKey(recurmax, stmtDepth, canThrow);
|
||||||
} while (keys.indexOf(key) >= 0);
|
} while (keys.indexOf(key) >= 0);
|
||||||
removeAvoidVars(avoid);
|
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createName() {
|
||||||
|
unique_vars.push("a", "b", "c", "undefined", "NaN", "Infinity");
|
||||||
|
var save_async = async;
|
||||||
|
if (was_async) async = true;
|
||||||
|
var name = createVarName(MANDATORY);
|
||||||
|
async = save_async;
|
||||||
|
unique_vars.length -= 6;
|
||||||
|
avoid.push(name);
|
||||||
|
unique_vars.push(name);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
function createPairs(recurmax) {
|
function createPairs(recurmax) {
|
||||||
var names = [], values = [];
|
var names = [], values = [];
|
||||||
var m = rng(4), n = rng(4);
|
var m = rng(4), n = rng(4);
|
||||||
if (!varNames) m = Math.max(m, n, 1);
|
if (!nameLenBefore) m = Math.max(m, n, 1);
|
||||||
for (var i = Math.max(m, n); --i >= 0;) {
|
for (var i = Math.max(m, n); --i >= 0;) {
|
||||||
if (i < m && i < n) {
|
if (i < m && i < n) {
|
||||||
createDestructured(recurmax, names, values);
|
createDestructured(recurmax, names, values);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (i < m) {
|
if (i < m) {
|
||||||
unique_vars.push("a", "b", "c", "undefined", "NaN", "Infinity");
|
names.unshift(createName());
|
||||||
var name = createVarName(maybe, dontStore);
|
|
||||||
unique_vars.length -= 6;
|
|
||||||
avoid.push(name);
|
|
||||||
unique_vars.push(name);
|
|
||||||
names.unshift(name);
|
|
||||||
}
|
}
|
||||||
if (i < n) {
|
if (i < n) {
|
||||||
values.unshift(createAssignmentValue(recurmax));
|
values.unshift(createAssignmentValue(recurmax));
|
||||||
@@ -441,7 +492,14 @@ function createAssignmentPairs(recurmax, noComma, stmtDepth, canThrow, varNames,
|
|||||||
while (!rng(10)) {
|
while (!rng(10)) {
|
||||||
var index = rng(pairs.names.length + 1);
|
var index = rng(pairs.names.length + 1);
|
||||||
pairs.names.splice(index, 0, "");
|
pairs.names.splice(index, 0, "");
|
||||||
|
if (index < pairs.values.length) {
|
||||||
pairs.values.splice(index, 0, rng(2) ? createAssignmentValue(recurmax) : "");
|
pairs.values.splice(index, 0, rng(2) ? createAssignmentValue(recurmax) : "");
|
||||||
|
} else switch (rng(5)) {
|
||||||
|
case 0:
|
||||||
|
pairs.values[index] = createAssignmentValue(recurmax);
|
||||||
|
case 1:
|
||||||
|
pairs.values.length = index + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
names.unshift("[ " + pairs.names.join(", ") + " ]");
|
names.unshift("[ " + pairs.names.join(", ") + " ]");
|
||||||
values.unshift("[ " + pairs.values.join(", ") + " ]");
|
values.unshift("[ " + pairs.values.join(", ") + " ]");
|
||||||
@@ -463,23 +521,32 @@ function createAssignmentPairs(recurmax, noComma, stmtDepth, canThrow, varNames,
|
|||||||
keys[index] = key;
|
keys[index] = key;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
names.unshift("{ " + pairs.names.map(function(name, index) {
|
var save_async = async;
|
||||||
|
if (was_async != null) {
|
||||||
|
async = false;
|
||||||
|
if (save_async || was_async) avoid.push("await");
|
||||||
|
}
|
||||||
|
addAvoidVars(avoid);
|
||||||
|
var save_vars = nameLenBefore && VAR_NAMES.splice(nameLenBefore);
|
||||||
|
names.unshift("{ " + addTrailingComma(pairs.names.map(function(name, index) {
|
||||||
var key = index in keys ? keys[index] : rng(10) && createKey(recurmax, keys);
|
var key = index in keys ? keys[index] : rng(10) && createKey(recurmax, keys);
|
||||||
return key ? key + ": " + name : name;
|
return key ? key + ": " + name : name;
|
||||||
}).join(", ") + " }");
|
}).join(", ")) + " }");
|
||||||
values.unshift("{ " + pairs.values.map(function(value, index) {
|
if (was_async != null) {
|
||||||
|
async = was_async;
|
||||||
|
if (save_async || was_async) removeAvoidVars([ avoid.pop() ]);
|
||||||
|
}
|
||||||
|
values.unshift("{ " + addTrailingComma(pairs.values.map(function(value, index) {
|
||||||
var key = index in keys ? keys[index] : createKey(recurmax, keys);
|
var key = index in keys ? keys[index] : createKey(recurmax, keys);
|
||||||
return key + ": " + value;
|
return key + ": " + value;
|
||||||
}).join(", ") + " }");
|
}).join(", ")) + " }");
|
||||||
|
if (save_vars) [].push.apply(VAR_NAMES, save_vars);
|
||||||
|
removeAvoidVars(avoid);
|
||||||
|
async = save_async;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
unique_vars.push("a", "b", "c", "undefined", "NaN", "Infinity");
|
names.unshift(createName());
|
||||||
var name = createVarName(maybe, dontStore);
|
|
||||||
unique_vars.length -= 6;
|
|
||||||
avoid.push(name);
|
|
||||||
unique_vars.push(name);
|
|
||||||
names.unshift(name);
|
|
||||||
values.unshift(createAssignmentValue(recurmax));
|
values.unshift(createAssignmentValue(recurmax));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -493,16 +560,16 @@ function filterDirective(s) {
|
|||||||
|
|
||||||
function createBlockVariables(recurmax, stmtDepth, canThrow, fn) {
|
function createBlockVariables(recurmax, stmtDepth, canThrow, fn) {
|
||||||
var block_len = block_vars.length;
|
var block_len = block_vars.length;
|
||||||
var var_len = VAR_NAMES.length;
|
var nameLenBefore = VAR_NAMES.length;
|
||||||
var consts = [];
|
var consts = [];
|
||||||
var lets = [];
|
var lets = [];
|
||||||
unique_vars.push("a", "b", "c", "undefined", "NaN", "Infinity");
|
unique_vars.push("a", "b", "c", "undefined", "NaN", "Infinity");
|
||||||
while (!rng(block_vars.length > block_len ? 10 : 100)) {
|
while (!rng(block_vars.length > block_len ? 10 : 100)) {
|
||||||
var name = createVarName(MANDATORY, DONT_STORE);
|
var name = createVarName(MANDATORY);
|
||||||
if (rng(2)) {
|
if (SUPPORT.let && rng(2)) {
|
||||||
consts.push(name);
|
|
||||||
} else {
|
|
||||||
lets.push(name);
|
lets.push(name);
|
||||||
|
} else {
|
||||||
|
consts.push(name);
|
||||||
}
|
}
|
||||||
block_vars.push(name);
|
block_vars.push(name);
|
||||||
}
|
}
|
||||||
@@ -516,13 +583,13 @@ function createBlockVariables(recurmax, stmtDepth, canThrow, fn) {
|
|||||||
return createDefinitions("let", lets) + "\n" + createDefinitions("const", consts) + "\n";
|
return createDefinitions("let", lets) + "\n" + createDefinitions("const", consts) + "\n";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
VAR_NAMES.length = nameLenBefore;
|
||||||
block_vars.length = block_len;
|
block_vars.length = block_len;
|
||||||
if (consts.length || lets.length) VAR_NAMES.splice(var_len, consts.length + lets.length);
|
|
||||||
|
|
||||||
function createDefinitions(type, names) {
|
function createDefinitions(type, names) {
|
||||||
if (!names.length) return "";
|
if (!names.length) return "";
|
||||||
var s = type + " ";
|
var s = type + " ";
|
||||||
switch (rng(10)) {
|
switch (SUPPORT.destructuring ? rng(10) : 2) {
|
||||||
case 0:
|
case 0:
|
||||||
while (!rng(10)) names.splice(rng(names.length + 1), 0, "");
|
while (!rng(10)) names.splice(rng(names.length + 1), 0, "");
|
||||||
s += "[ " + names.join(", ") + " ] = [ " + names.map(function() {
|
s += "[ " + names.join(", ") + " ] = [ " + names.map(function() {
|
||||||
@@ -550,6 +617,7 @@ function createBlockVariables(recurmax, stmtDepth, canThrow, fn) {
|
|||||||
removeAvoidVars([ name ]);
|
removeAvoidVars([ name ]);
|
||||||
return name + " = " + value;
|
return name + " = " + value;
|
||||||
}).join(", ") + ";";
|
}).join(", ") + ";";
|
||||||
|
names.length = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
removeAvoidVars(names);
|
removeAvoidVars(names);
|
||||||
@@ -557,12 +625,28 @@ function createBlockVariables(recurmax, stmtDepth, canThrow, fn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mayCreateBlockVariables(recurmax, stmtDepth, canThrow, fn) {
|
||||||
|
if (SUPPORT.const_block) {
|
||||||
|
createBlockVariables(recurmax, stmtDepth, canThrow, fn);
|
||||||
|
} else {
|
||||||
|
fn(function() {
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeFunction(name) {
|
||||||
|
return (async ? "async function " : "function ") + name;
|
||||||
|
}
|
||||||
|
|
||||||
function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
||||||
if (--recurmax < 0) { return ";"; }
|
if (--recurmax < 0) { return ";"; }
|
||||||
if (!STMT_COUNT_FROM_GLOBAL) stmtDepth = 0;
|
if (!STMT_COUNT_FROM_GLOBAL) stmtDepth = 0;
|
||||||
var s = [];
|
var s = [];
|
||||||
var name, args;
|
var name, args;
|
||||||
var varNames = VAR_NAMES.slice();
|
var nameLenBefore = VAR_NAMES.length;
|
||||||
|
var save_async = async;
|
||||||
|
async = SUPPORT.async && rng(50) == 0;
|
||||||
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||||
if (allowDefun || rng(5) > 0) {
|
if (allowDefun || rng(5) > 0) {
|
||||||
name = "f" + funcs++;
|
name = "f" + funcs++;
|
||||||
@@ -572,15 +656,15 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
|||||||
unique_vars.length -= 3;
|
unique_vars.length -= 3;
|
||||||
}
|
}
|
||||||
var params;
|
var params;
|
||||||
if ((!allowDefun || !(name in called)) && rng(2)) {
|
if (SUPPORT.destructuring && (!allowDefun || !(name in called)) && rng(2)) {
|
||||||
called[name] = false;
|
called[name] = false;
|
||||||
var pairs = createAssignmentPairs(recurmax, COMMA_OK, stmtDepth, canThrow, varNames, MANDATORY);
|
var pairs = createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, save_async);
|
||||||
params = pairs.names.join(", ");
|
params = addTrailingComma(pairs.names.join(", "));
|
||||||
args = pairs.values.join(", ");
|
args = addTrailingComma(pairs.values.join(", "));
|
||||||
} else {
|
} else {
|
||||||
params = createParams();
|
params = createParams(save_async);
|
||||||
}
|
}
|
||||||
s.push("function " + name + "(" + params + "){", strictMode());
|
s.push(makeFunction(name) + "(" + params + "){", strictMode());
|
||||||
s.push(defns());
|
s.push(defns());
|
||||||
if (rng(5) === 0) {
|
if (rng(5) === 0) {
|
||||||
// functions with functions. lower the recursion to prevent a mess.
|
// functions with functions. lower the recursion to prevent a mess.
|
||||||
@@ -592,7 +676,8 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
|||||||
s.push("}", "");
|
s.push("}", "");
|
||||||
s = filterDirective(s).join("\n");
|
s = filterDirective(s).join("\n");
|
||||||
});
|
});
|
||||||
VAR_NAMES = varNames;
|
async = save_async;
|
||||||
|
VAR_NAMES.length = nameLenBefore;
|
||||||
|
|
||||||
if (!allowDefun) {
|
if (!allowDefun) {
|
||||||
// avoid "function statements" (decl inside statements)
|
// avoid "function statements" (decl inside statements)
|
||||||
@@ -617,7 +702,7 @@ function _createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotR
|
|||||||
|
|
||||||
function createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) {
|
function createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) {
|
||||||
var s = "";
|
var s = "";
|
||||||
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
mayCreateBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||||
s += defns() + "\n";
|
s += defns() + "\n";
|
||||||
s += _createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth);
|
s += _createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth);
|
||||||
});
|
});
|
||||||
@@ -677,22 +762,22 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
|||||||
var label = createLabel(canBreak);
|
var label = createLabel(canBreak);
|
||||||
return label.target + "{" + createStatements(rng(5) + 1, recurmax, canThrow, label.break, canContinue, cannotReturn, stmtDepth) + "}";
|
return label.target + "{" + createStatements(rng(5) + 1, recurmax, canThrow, label.break, canContinue, cannotReturn, stmtDepth) + "}";
|
||||||
case STMT_IF_ELSE:
|
case STMT_IF_ELSE:
|
||||||
return "if (" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ")" + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + (rng(2) === 1 ? " else " + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) : "");
|
return "if (" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ")" + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + (rng(2) ? " else " + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) : "");
|
||||||
case STMT_DO_WHILE:
|
case STMT_DO_WHILE:
|
||||||
var label = createLabel(canBreak, canContinue);
|
var label = createLabel(canBreak, canContinue);
|
||||||
canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK);
|
canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK);
|
||||||
canContinue = label.continue || enableLoopControl(canContinue, CAN_CONTINUE);
|
canContinue = label.continue || enableLoopControl(canContinue, CAN_CONTINUE);
|
||||||
return "{var brake" + loop + " = 5; " + label.target + "do {" + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + "} while ((" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") && --brake" + loop + " > 0);}";
|
return "{var brake" + loop + " = 5; " + label.target + "do {" + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + "} while (" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + " && --brake" + loop + " > 0);}";
|
||||||
case STMT_WHILE:
|
case STMT_WHILE:
|
||||||
var label = createLabel(canBreak, canContinue);
|
var label = createLabel(canBreak, canContinue);
|
||||||
canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK);
|
canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK);
|
||||||
canContinue = label.continue || enableLoopControl(canContinue, CAN_CONTINUE);
|
canContinue = label.continue || enableLoopControl(canContinue, CAN_CONTINUE);
|
||||||
return "{var brake" + loop + " = 5; " + label.target + "while ((" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") && --brake" + loop + " > 0)" + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + "}";
|
return "{var brake" + loop + " = 5; " + label.target + "while (" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + " && --brake" + loop + " > 0)" + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + "}";
|
||||||
case STMT_FOR_LOOP:
|
case STMT_FOR_LOOP:
|
||||||
var label = createLabel(canBreak, canContinue);
|
var label = createLabel(canBreak, canContinue);
|
||||||
canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK);
|
canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK);
|
||||||
canContinue = label.continue || enableLoopControl(canContinue, CAN_CONTINUE);
|
canContinue = label.continue || enableLoopControl(canContinue, CAN_CONTINUE);
|
||||||
return label.target + "for (var brake" + loop + " = 5; (" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") && brake" + loop + " > 0; --brake" + loop + ")" + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth);
|
return label.target + "for (var brake" + loop + " = 5; " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + " && brake" + loop + " > 0; --brake" + loop + ")" + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth);
|
||||||
case STMT_FOR_IN:
|
case STMT_FOR_IN:
|
||||||
var label = createLabel(canBreak, canContinue);
|
var label = createLabel(canBreak, canContinue);
|
||||||
canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK);
|
canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK);
|
||||||
@@ -701,8 +786,8 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
|||||||
return [
|
return [
|
||||||
"{var expr" + loop + " = " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "; ",
|
"{var expr" + loop + " = " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "; ",
|
||||||
label.target + " for (",
|
label.target + " for (",
|
||||||
!/^key/.test(key) ? rng(10) ? "" : "var " : rng(10) ? "var " : rng(2) ? "let " : "const ",
|
!/^key/.test(key) ? rng(10) ? "" : "var " : !SUPPORT.let || rng(10) ? "var " : rng(2) ? "let " : "const ",
|
||||||
rng(10) ? key : rng(5) ? "[ " + key + " ]" : "{ length: " + key + " }",
|
!SUPPORT.destructuring || rng(10) ? key : rng(5) ? "[ " + key + " ]" : "{ length: " + key + " }",
|
||||||
" in expr" + loop + ") {",
|
" in expr" + loop + ") {",
|
||||||
rng(5) > 1 ? "c = 1 + c; var " + createVarName(MANDATORY) + " = expr" + loop + "[" + key + "]; " : "",
|
rng(5) > 1 ? "c = 1 + c; var " + createVarName(MANDATORY) + " = expr" + loop + "[" + key + "]; " : "",
|
||||||
createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth),
|
createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth),
|
||||||
@@ -717,8 +802,8 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
|||||||
// note: default does not _need_ to be last
|
// note: default does not _need_ to be last
|
||||||
return "switch (" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") { " + createSwitchParts(recurmax, 4, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + "}";
|
return "switch (" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") { " + createSwitchParts(recurmax, 4, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + "}";
|
||||||
case STMT_VAR:
|
case STMT_VAR:
|
||||||
if (!rng(20)) {
|
if (SUPPORT.destructuring && rng(20) == 0) {
|
||||||
var pairs = createAssignmentPairs(recurmax, NO_COMMA, stmtDepth, canThrow, null, MANDATORY);
|
var pairs = createAssignmentPairs(recurmax, stmtDepth, canThrow);
|
||||||
return "var " + pairs.names.map(function(name, index) {
|
return "var " + pairs.names.map(function(name, index) {
|
||||||
return index in pairs.values ? name + " = " + pairs.values[index] : name;
|
return index in pairs.values ? name + " = " + pairs.values[index] : name;
|
||||||
}).join(", ") + ";";
|
}).join(", ") + ";";
|
||||||
@@ -777,18 +862,41 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
|||||||
if (n !== 1) {
|
if (n !== 1) {
|
||||||
// the catch var should only be accessible in the catch clause...
|
// the catch var should only be accessible in the catch clause...
|
||||||
// we have to do go through some trouble here to prevent leaking it
|
// we have to do go through some trouble here to prevent leaking it
|
||||||
|
mayCreateBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||||
|
var block_len = block_vars.length;
|
||||||
var nameLenBefore = VAR_NAMES.length;
|
var nameLenBefore = VAR_NAMES.length;
|
||||||
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
var unique_len = unique_vars.length;
|
||||||
var catchName = createVarName(MANDATORY);
|
if (SUPPORT.catch_omit_var && !rng(20)) {
|
||||||
var freshCatchName = VAR_NAMES.length !== nameLenBefore;
|
s += " catch { ";
|
||||||
if (!catch_redef) unique_vars.push(catchName);
|
} else if (canThrow && SUPPORT.destructuring && !rng(20)) {
|
||||||
s += " catch (" + catchName + ") { ";
|
unique_vars.push("a", "b", "c", "undefined", "NaN", "Infinity");
|
||||||
|
var name = createVarName(MANDATORY);
|
||||||
|
block_vars.push(name);
|
||||||
|
var message = createVarName(MANDATORY);
|
||||||
|
block_vars.push(message);
|
||||||
|
unique_vars.length -= 6;
|
||||||
|
if (SUPPORT.computed_key && rng(10) == 0) {
|
||||||
|
s += " catch ({ message: " + message + ", ";
|
||||||
|
addAvoidVars([ name ]);
|
||||||
|
s += "[" + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + "]: " + name;
|
||||||
|
removeAvoidVars([ name ]);
|
||||||
|
s += " }) { ";
|
||||||
|
} else {
|
||||||
|
s += " catch ({ name: " + name + ", message: " + message + " }) { ";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var name = createVarName(MANDATORY);
|
||||||
|
if (!catch_redef) unique_vars.push(name);
|
||||||
|
s += " catch (" + name + ") { ";
|
||||||
|
}
|
||||||
|
var catches = VAR_NAMES.length - nameLenBefore;
|
||||||
s += defns() + "\n";
|
s += defns() + "\n";
|
||||||
s += _createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth);
|
s += _createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth);
|
||||||
s += " }";
|
s += " }";
|
||||||
// remove catch name
|
// remove catch variables
|
||||||
if (!catch_redef) unique_vars.pop();
|
block_vars.length = block_len;
|
||||||
if (freshCatchName) VAR_NAMES.splice(nameLenBefore, 1);
|
if (catches > 0) VAR_NAMES.splice(nameLenBefore, catches);
|
||||||
|
unique_vars.length = unique_len;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (n !== 0) s += " finally { " + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + " }";
|
if (n !== 0) s += " finally { " + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + " }";
|
||||||
@@ -838,7 +946,8 @@ function createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
case 2:
|
case 2:
|
||||||
return "((c = c + 1) + (" + _createExpression(recurmax, noComma, stmtDepth, canThrow) + "))"; // c only gets incremented
|
return "((c = c + 1) + (" + _createExpression(recurmax, noComma, stmtDepth, canThrow) + "))"; // c only gets incremented
|
||||||
default:
|
default:
|
||||||
return "(" + _createExpression(recurmax, noComma, stmtDepth, canThrow) + ")";
|
var expr = "(" + _createExpression(recurmax, noComma, stmtDepth, canThrow) + ")";
|
||||||
|
return async && rng(50) == 0 ? "(await" + expr + ")" : expr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -847,10 +956,10 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
switch (rng(_createExpression.N)) {
|
switch (rng(_createExpression.N)) {
|
||||||
case p++:
|
case p++:
|
||||||
case p++:
|
case p++:
|
||||||
return createUnaryPrefix() + (rng(2) === 1 ? "a" : "b");
|
return createUnaryPrefix() + (rng(2) ? "a" : "b");
|
||||||
case p++:
|
case p++:
|
||||||
case p++:
|
case p++:
|
||||||
return (rng(2) === 1 ? "a" : "b") + createUnaryPostfix();
|
return (rng(2) ? "a" : "b") + createUnaryPostfix();
|
||||||
case p++:
|
case p++:
|
||||||
case p++:
|
case p++:
|
||||||
// parens needed because assignments aren't valid unless they're the left-most op(s) in an expression
|
// parens needed because assignments aren't valid unless they're the left-most op(s) in an expression
|
||||||
@@ -865,7 +974,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
case p++:
|
case p++:
|
||||||
return getVarName();
|
return getVarName();
|
||||||
case p++:
|
case p++:
|
||||||
switch (rng(20)) {
|
switch (SUPPORT.destructuring ? rng(20) : 2) {
|
||||||
case 0:
|
case 0:
|
||||||
return [
|
return [
|
||||||
"[ ",
|
"[ ",
|
||||||
@@ -890,26 +999,72 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
case p++:
|
case p++:
|
||||||
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
||||||
case p++:
|
case p++:
|
||||||
return createExpression(recurmax, noComma, stmtDepth, canThrow) + "?" + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ":" + createExpression(recurmax, noComma, stmtDepth, canThrow);
|
return createExpression(recurmax, noComma, stmtDepth, canThrow) + " ? " + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + " : " + createExpression(recurmax, noComma, stmtDepth, canThrow);
|
||||||
case p++:
|
case p++:
|
||||||
case p++:
|
case p++:
|
||||||
var nameLenBefore = VAR_NAMES.length;
|
var nameLenBefore = VAR_NAMES.length;
|
||||||
|
var save_async = async;
|
||||||
|
async = SUPPORT.async && rng(50) == 0;
|
||||||
unique_vars.push("c");
|
unique_vars.push("c");
|
||||||
var name = createVarName(MAYBE); // note: this name is only accessible from _within_ the function. and immutable at that.
|
var name = createVarName(MAYBE); // note: this name is only accessible from _within_ the function. and immutable at that.
|
||||||
unique_vars.pop();
|
unique_vars.pop();
|
||||||
var s = [];
|
var s = [];
|
||||||
switch (rng(5)) {
|
switch (rng(5)) {
|
||||||
case 0:
|
case 0:
|
||||||
|
if (SUPPORT.arrow && !async && !name && rng(2)) {
|
||||||
|
var args, suffix;
|
||||||
|
(rng(2) ? createBlockVariables : function() {
|
||||||
|
arguments[3]();
|
||||||
|
})(recurmax, stmtDepth, canThrow, function(defns) {
|
||||||
|
var params;
|
||||||
|
if (SUPPORT.destructuring && rng(2)) {
|
||||||
|
var pairs = createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, save_async);
|
||||||
|
params = addTrailingComma(pairs.names.join(", "));
|
||||||
|
args = addTrailingComma(pairs.values.join(", "));
|
||||||
|
} else {
|
||||||
|
params = createParams(save_async, NO_DUPLICATE);
|
||||||
|
}
|
||||||
|
if (defns) {
|
||||||
s.push(
|
s.push(
|
||||||
"(function " + name + "(){",
|
"((" + params + ") => {",
|
||||||
|
strictMode(),
|
||||||
|
defns(),
|
||||||
|
_createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth)
|
||||||
|
);
|
||||||
|
suffix = "})";
|
||||||
|
} else {
|
||||||
|
s.push("((" + params + ") => ");
|
||||||
|
switch (rng(10)) {
|
||||||
|
case 0:
|
||||||
|
s.push('(typeof arguments != "undefined" && arguments && arguments[' + rng(3) + "])");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
s.push("(this && this." + getDotKey() + ")");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
s.push(createExpression(recurmax, NO_COMMA, stmtDepth, canThrow));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
suffix = ")";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
async = save_async;
|
||||||
|
VAR_NAMES.length = nameLenBefore;
|
||||||
|
if (!args && rng(2)) args = createArgs(recurmax, stmtDepth, canThrow);
|
||||||
|
if (args) suffix += "(" + args + ")";
|
||||||
|
s.push(suffix);
|
||||||
|
} else {
|
||||||
|
s.push(
|
||||||
|
"(" + makeFunction(name) + "(){",
|
||||||
strictMode(),
|
strictMode(),
|
||||||
createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
rng(2) == 0 ? "})" : "})()"
|
rng(2) ? "})" : "})()"
|
||||||
);
|
);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
s.push(
|
s.push(
|
||||||
"+function " + name + "(){",
|
"+" + makeFunction(name) + "(){",
|
||||||
strictMode(),
|
strictMode(),
|
||||||
createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
"}()"
|
"}()"
|
||||||
@@ -917,7 +1072,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
s.push(
|
s.push(
|
||||||
"!function " + name + "(){",
|
"!" + makeFunction(name) + "(){",
|
||||||
strictMode(),
|
strictMode(),
|
||||||
createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
"}()"
|
"}()"
|
||||||
@@ -925,17 +1080,18 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
s.push(
|
s.push(
|
||||||
"void function " + name + "(){",
|
"void " + makeFunction(name) + "(){",
|
||||||
strictMode(),
|
strictMode(),
|
||||||
createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
"}()"
|
"}()"
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
async = false;
|
||||||
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||||
var instantiate = rng(4) ? "new " : "";
|
var instantiate = rng(4) ? "new " : "";
|
||||||
s.push(
|
s.push(
|
||||||
instantiate + "function " + name + "(){",
|
instantiate + "function " + name + "(" + createParams(save_async) + "){",
|
||||||
strictMode(),
|
strictMode(),
|
||||||
defns()
|
defns()
|
||||||
);
|
);
|
||||||
@@ -943,13 +1099,14 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
if (rng(2)) s.push("this." + getDotKey(true) + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ";");
|
if (rng(2)) s.push("this." + getDotKey(true) + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ";");
|
||||||
else s.push("this[" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "]" + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ";");
|
else s.push("this[" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "]" + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ";");
|
||||||
}
|
}
|
||||||
s.push(
|
s.push(_createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth));
|
||||||
_createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
|
||||||
rng(2) == 0 ? "}" : "}()"
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
async = save_async;
|
||||||
|
VAR_NAMES.length = nameLenBefore;
|
||||||
|
s.push(rng(2) ? "}" : "}(" + createArgs(recurmax, stmtDepth, canThrow) + ")");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
async = save_async;
|
||||||
VAR_NAMES.length = nameLenBefore;
|
VAR_NAMES.length = nameLenBefore;
|
||||||
return filterDirective(s).join("\n");
|
return filterDirective(s).join("\n");
|
||||||
case p++:
|
case p++:
|
||||||
@@ -986,14 +1143,13 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
case p++:
|
case p++:
|
||||||
return createUnarySafePrefix() + "(" + createNestedBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
return createUnarySafePrefix() + "(" + createNestedBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
||||||
case p++:
|
case p++:
|
||||||
return " ((" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") || a || 3).toString() ";
|
return " (" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + " || a || 3).toString() ";
|
||||||
case p++:
|
case p++:
|
||||||
return " /[abc4]/.test(((" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") || b || 5).toString()) ";
|
return " /[abc4]/.test((" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + " || b || 5).toString()) ";
|
||||||
case p++:
|
case p++:
|
||||||
return " /[abc4]/g.exec(((" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") || b || 5).toString()) ";
|
return " /[abc4]/g.exec((" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + " || b || 5).toString()) ";
|
||||||
case p++:
|
case p++:
|
||||||
return " ((" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) +
|
return " (" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + " || " + rng(10) + ").toString()[" +
|
||||||
") || " + rng(10) + ").toString()[" +
|
|
||||||
createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "] ";
|
createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "] ";
|
||||||
case p++:
|
case p++:
|
||||||
return createArrayLiteral(recurmax, stmtDepth, canThrow);
|
return createArrayLiteral(recurmax, stmtDepth, canThrow);
|
||||||
@@ -1044,13 +1200,30 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
|
|
||||||
function createArrayLiteral(recurmax, stmtDepth, canThrow) {
|
function createArrayLiteral(recurmax, stmtDepth, canThrow) {
|
||||||
recurmax--;
|
recurmax--;
|
||||||
var arr = "[";
|
var arr = [];
|
||||||
for (var i = rng(6); --i >= 0;) {
|
for (var i = rng(6); --i >= 0;) switch (SUPPORT.spread ? rng(50) : 3 + rng(47)) {
|
||||||
// in rare cases produce an array hole element
|
case 0:
|
||||||
var element = rng(20) ? createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) : "";
|
case 1:
|
||||||
arr += element + ", ";
|
var name = getVarName();
|
||||||
|
if (canThrow && rng(8) === 0) {
|
||||||
|
arr.push("..." + name);
|
||||||
|
} else {
|
||||||
|
arr.push('...("" + ' + name + ")");
|
||||||
}
|
}
|
||||||
return arr + "]";
|
break;
|
||||||
|
case 2:
|
||||||
|
arr.push("..." + createArrayLiteral(recurmax, stmtDepth, canThrow));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
// in rare cases produce an array hole element
|
||||||
|
arr.push("");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
arr.push(createExpression(recurmax, COMMA_OK, stmtDepth, canThrow));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return "[" + arr.join(", ") + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
var SAFE_KEYS = [
|
var SAFE_KEYS = [
|
||||||
@@ -1084,17 +1257,23 @@ function getDotKey(assign) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createObjectKey(recurmax, stmtDepth, canThrow) {
|
function createObjectKey(recurmax, stmtDepth, canThrow) {
|
||||||
return rng(10) ? KEYS[rng(KEYS.length)] : "[" + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + "]";
|
if (SUPPORT.computed_key && rng(10) == 0) {
|
||||||
|
return "[" + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + "]";
|
||||||
|
}
|
||||||
|
return KEYS[rng(KEYS.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
function createObjectFunction(recurmax, stmtDepth, canThrow) {
|
function createObjectFunction(recurmax, stmtDepth, canThrow) {
|
||||||
var namesLenBefore = VAR_NAMES.length;
|
var nameLenBefore = VAR_NAMES.length;
|
||||||
|
var save_async = async;
|
||||||
var s;
|
var s;
|
||||||
|
var name = createObjectKey(recurmax, stmtDepth, canThrow);
|
||||||
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||||
switch (rng(3)) {
|
switch (rng(SUPPORT.computed_key ? 3 : 2)) {
|
||||||
case 0:
|
case 0:
|
||||||
|
async = false;
|
||||||
s = [
|
s = [
|
||||||
"get " + createObjectKey(recurmax, stmtDepth, canThrow) + "(){",
|
"get " + name + "(){",
|
||||||
strictMode(),
|
strictMode(),
|
||||||
defns(),
|
defns(),
|
||||||
_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
@@ -1103,23 +1282,24 @@ function createObjectFunction(recurmax, stmtDepth, canThrow) {
|
|||||||
];
|
];
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
var prop1 = createObjectKey(recurmax, stmtDepth, canThrow);
|
var prop;
|
||||||
var prop2;
|
|
||||||
do {
|
do {
|
||||||
prop2 = getDotKey();
|
prop = getDotKey();
|
||||||
} while (prop1 == prop2);
|
} while (name == prop);
|
||||||
|
async = false;
|
||||||
s = [
|
s = [
|
||||||
"set " + prop1 + "(" + createVarName(MANDATORY) + "){",
|
"set " + name + "(" + createVarName(MANDATORY) + "){",
|
||||||
strictMode(),
|
strictMode(),
|
||||||
defns(),
|
defns(),
|
||||||
_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
"this." + prop2 + createAssignment() + _createBinaryExpr(recurmax, COMMA_OK, stmtDepth, canThrow) + ";",
|
"this." + prop + createAssignment() + _createBinaryExpr(recurmax, COMMA_OK, stmtDepth, canThrow) + ";",
|
||||||
"},",
|
"},",
|
||||||
];
|
];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
async = SUPPORT.async && rng(50) == 0;
|
||||||
s = [
|
s = [
|
||||||
createObjectKey(recurmax, stmtDepth, canThrow) + "(" + createParams(NO_DUPLICATE) + "){",
|
(async ? "async " : "") + name + "(" + createParams(save_async, NO_DUPLICATE) + "){",
|
||||||
strictMode(),
|
strictMode(),
|
||||||
defns(),
|
defns(),
|
||||||
_createStatements(3, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
_createStatements(3, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
@@ -1128,22 +1308,31 @@ function createObjectFunction(recurmax, stmtDepth, canThrow) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
VAR_NAMES.length = namesLenBefore;
|
async = save_async;
|
||||||
|
VAR_NAMES.length = nameLenBefore;
|
||||||
return filterDirective(s).join("\n");
|
return filterDirective(s).join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
function createObjectLiteral(recurmax, stmtDepth, canThrow) {
|
function createObjectLiteral(recurmax, stmtDepth, canThrow) {
|
||||||
recurmax--;
|
recurmax--;
|
||||||
var obj = ["({"];
|
var obj = ["({"];
|
||||||
for (var i = rng(6); --i >= 0;) switch (rng(30)) {
|
var offset = SUPPORT.spread_object ? 0 : SUPPORT.computed_key ? 2 : 4;
|
||||||
|
for (var i = rng(6); --i >= 0;) switch (offset + rng(50 - offset)) {
|
||||||
case 0:
|
case 0:
|
||||||
obj.push(createObjectFunction(recurmax, stmtDepth, canThrow));
|
obj.push("..." + getVarName() + ",");
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
|
obj.push("..." + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ",");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
obj.push(getVarName() + ",");
|
obj.push(getVarName() + ",");
|
||||||
break;
|
break;
|
||||||
|
case 4:
|
||||||
|
obj.push(createObjectFunction(recurmax, stmtDepth, canThrow));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
obj.push(createObjectKey(recurmax, stmtDepth, canThrow) + ":(" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "),");
|
obj.push(createObjectKey(recurmax, stmtDepth, canThrow) + ": " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ",");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
obj.push("})");
|
obj.push("})");
|
||||||
@@ -1172,7 +1361,7 @@ function _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
return "(" + assignee + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
return "(" + assignee + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
||||||
case 3:
|
case 3:
|
||||||
assignee = getVarName();
|
assignee = getVarName();
|
||||||
switch (rng(20)) {
|
switch (SUPPORT.destructuring ? rng(20) : 2) {
|
||||||
case 0:
|
case 0:
|
||||||
expr = [
|
expr = [
|
||||||
"([ ",
|
"([ ",
|
||||||
@@ -1209,7 +1398,7 @@ function _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
return canThrow && rng(10) == 0 ? expr : "(" + assignee + " && " + expr + ")";
|
return canThrow && rng(10) == 0 ? expr : "(" + assignee + " && " + expr + ")";
|
||||||
case 4:
|
case 4:
|
||||||
assignee = getVarName();
|
assignee = getVarName();
|
||||||
switch (rng(20)) {
|
switch (SUPPORT.destructuring ? rng(20) : 2) {
|
||||||
case 0:
|
case 0:
|
||||||
expr = [
|
expr = [
|
||||||
"([ ",
|
"([ ",
|
||||||
@@ -1311,7 +1500,7 @@ function getVarName(noConst) {
|
|||||||
do {
|
do {
|
||||||
if (--tries < 0) return "a";
|
if (--tries < 0) return "a";
|
||||||
name = VAR_NAMES[INITIAL_NAMES_LEN + rng(VAR_NAMES.length - INITIAL_NAMES_LEN)];
|
name = VAR_NAMES[INITIAL_NAMES_LEN + rng(VAR_NAMES.length - INITIAL_NAMES_LEN)];
|
||||||
} while (!name || avoid_vars.indexOf(name) >= 0 || noConst && block_vars.indexOf(name) >= 0);
|
} while (!name || avoid_vars.indexOf(name) >= 0 || noConst && block_vars.indexOf(name) >= 0 || async && name == "await");
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1322,8 +1511,8 @@ function createVarName(maybe, dontStore) {
|
|||||||
do {
|
do {
|
||||||
name = VAR_NAMES[rng(VAR_NAMES.length)];
|
name = VAR_NAMES[rng(VAR_NAMES.length)];
|
||||||
if (suffix) name += "_" + suffix;
|
if (suffix) name += "_" + suffix;
|
||||||
} while (unique_vars.indexOf(name) >= 0 || block_vars.indexOf(name) >= 0);
|
} while (unique_vars.indexOf(name) >= 0 || block_vars.indexOf(name) >= 0 || async && name == "await");
|
||||||
if (suffix && !dontStore) VAR_NAMES.push(name);
|
if (!dontStore) VAR_NAMES.push(name);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
@@ -1350,25 +1539,35 @@ function errorln(msg) {
|
|||||||
writeln(process.stderr, msg);
|
writeln(process.stderr, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
function try_beautify(code, toplevel, result, printfn) {
|
function try_beautify(code, toplevel, result, printfn, options) {
|
||||||
var beautified = UglifyJS.minify(code, {
|
var beautified = UglifyJS.minify(code, JSON.parse(beautify_options));
|
||||||
compress: false,
|
|
||||||
mangle: false,
|
|
||||||
output: {
|
|
||||||
beautify: true,
|
|
||||||
braces: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (beautified.error) {
|
if (beautified.error) {
|
||||||
printfn("// !!! beautify failed !!!");
|
printfn("// !!! beautify failed !!!");
|
||||||
printfn(beautified.error);
|
printfn(beautified.error);
|
||||||
} else if (sandbox.same_stdout(sandbox.run_code(beautified.code, toplevel), result)) {
|
beautified = null;
|
||||||
|
} else if (!sandbox.same_stdout(sandbox.run_code(beautified.code, toplevel), result)) {
|
||||||
|
beautified = null;
|
||||||
|
} else if (options) {
|
||||||
|
var uglified = UglifyJS.minify(beautified.code, JSON.parse(options));
|
||||||
|
var expected, actual;
|
||||||
|
if (typeof uglify_code != "string" || uglified.error) {
|
||||||
|
expected = uglify_code;
|
||||||
|
actual = uglified.error;
|
||||||
|
} else {
|
||||||
|
expected = uglify_result;
|
||||||
|
actual = sandbox.run_code(uglified.code, toplevel);
|
||||||
|
}
|
||||||
|
if (!sandbox.same_stdout(expected, actual)) {
|
||||||
|
beautified = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (beautified) {
|
||||||
printfn("// (beautified)");
|
printfn("// (beautified)");
|
||||||
printfn(beautified.code);
|
printfn(beautified.code);
|
||||||
return;
|
} else {
|
||||||
}
|
|
||||||
printfn("//");
|
printfn("//");
|
||||||
printfn(code);
|
printfn(code);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var default_options = UglifyJS.default_options();
|
var default_options = UglifyJS.default_options();
|
||||||
@@ -1441,37 +1640,7 @@ function log(options) {
|
|||||||
errorln("//=============================================================");
|
errorln("//=============================================================");
|
||||||
if (!ok) errorln("// !!!!!! Failed... round " + round);
|
if (!ok) errorln("// !!!!!! Failed... round " + round);
|
||||||
errorln("// original code");
|
errorln("// original code");
|
||||||
var beautified = UglifyJS.minify(original_code, {
|
try_beautify(original_code, toplevel, original_result, errorln, options);
|
||||||
compress: false,
|
|
||||||
mangle: false,
|
|
||||||
output: {
|
|
||||||
beautify: true,
|
|
||||||
braces: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (beautified.error) {
|
|
||||||
errorln("// !!! beautify failed !!!");
|
|
||||||
errorln(beautified.error);
|
|
||||||
errorln("//");
|
|
||||||
errorln(original_code);
|
|
||||||
} else {
|
|
||||||
var uglified = UglifyJS.minify(beautified.code, JSON.parse(options));
|
|
||||||
var expected, actual;
|
|
||||||
if (typeof uglify_code != "string" || uglified.error) {
|
|
||||||
expected = uglify_code;
|
|
||||||
actual = uglified.error;
|
|
||||||
} else {
|
|
||||||
expected = uglify_result;
|
|
||||||
actual = sandbox.run_code(uglified.code, toplevel);
|
|
||||||
}
|
|
||||||
if (sandbox.same_stdout(expected, actual)) {
|
|
||||||
errorln("// (beautified)");
|
|
||||||
errorln(beautified.code);
|
|
||||||
} else {
|
|
||||||
errorln("//");
|
|
||||||
errorln(original_code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
errorln();
|
errorln();
|
||||||
errorln();
|
errorln();
|
||||||
errorln("//-------------------------------------------------------------");
|
errorln("//-------------------------------------------------------------");
|
||||||
@@ -1547,7 +1716,7 @@ function patch_try_catch(orig, toplevel) {
|
|||||||
offset: 0,
|
offset: 0,
|
||||||
tries: [],
|
tries: [],
|
||||||
} ];
|
} ];
|
||||||
var re = /(?:(?:^|[\s{}):;])try|}\s*catch\s*\(([^)]+)\)|}\s*finally)\s*(?={)/g;
|
var re = /(?:(?:^|[\s{}):;])try|}\s*catch\s*\(([^)[{]+)\)|}\s*finally)\s*(?={)/g;
|
||||||
while (stack.length) {
|
while (stack.length) {
|
||||||
var code = stack[0].code;
|
var code = stack[0].code;
|
||||||
var offset = stack[0].offset;
|
var offset = stack[0].offset;
|
||||||
@@ -1591,6 +1760,9 @@ function patch_try_catch(orig, toplevel) {
|
|||||||
} else if (result.name == "TypeError" && /'in'/.test(result.message)) {
|
} else if (result.name == "TypeError" && /'in'/.test(result.message)) {
|
||||||
index = result.ufuzz_catch;
|
index = result.ufuzz_catch;
|
||||||
return orig.slice(0, index) + result.ufuzz_var + ' = new Error("invalid `in`");' + orig.slice(index);
|
return orig.slice(0, index) + result.ufuzz_var + ' = new Error("invalid `in`");' + orig.slice(index);
|
||||||
|
} else if (result.name == "TypeError" && /not iterable/.test(result.message)) {
|
||||||
|
index = result.ufuzz_catch;
|
||||||
|
return orig.slice(0, index) + result.ufuzz_var + ' = new Error("spread not iterable");' + orig.slice(index);
|
||||||
} else if (result.name == "RangeError" && result.message == "Maximum call stack size exceeded") {
|
} else if (result.name == "RangeError" && result.message == "Maximum call stack size exceeded") {
|
||||||
index = result.ufuzz_try;
|
index = result.ufuzz_try;
|
||||||
return orig.slice(0, index) + 'throw new Error("skipping infinite recursion");' + orig.slice(index);
|
return orig.slice(0, index) + 'throw new Error("skipping infinite recursion");' + orig.slice(index);
|
||||||
@@ -1600,13 +1772,23 @@ function patch_try_catch(orig, toplevel) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var beautify_options = {
|
||||||
|
compress: false,
|
||||||
|
mangle: false,
|
||||||
|
output: {
|
||||||
|
beautify: true,
|
||||||
|
braces: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
var minify_options = require("./options.json");
|
var minify_options = require("./options.json");
|
||||||
if (typeof sandbox.run_code("console.log([ 1 ], {} = 2);") != "string") {
|
if (SUPPORT.destructuring && typeof sandbox.run_code("console.log([ 1 ], {} = 2);") != "string") {
|
||||||
|
beautify_options.output.v8 = true;
|
||||||
minify_options.forEach(function(o) {
|
minify_options.forEach(function(o) {
|
||||||
if (!("output" in o)) o.output = {};
|
if (!("output" in o)) o.output = {};
|
||||||
o.output.v8 = true;
|
o.output.v8 = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
beautify_options = JSON.stringify(beautify_options);
|
||||||
minify_options = minify_options.map(JSON.stringify);
|
minify_options = minify_options.map(JSON.stringify);
|
||||||
var original_code, original_result, errored;
|
var original_code, original_result, errored;
|
||||||
var uglify_code, uglify_result, ok;
|
var uglify_code, uglify_result, ok;
|
||||||
@@ -1656,6 +1838,7 @@ for (var round = 1; round <= num_iterations; round++) {
|
|||||||
ok = sandbox.same_stdout(orig_result[toplevel ? 3 : 2], uglify_result);
|
ok = sandbox.same_stdout(orig_result[toplevel ? 3 : 2], uglify_result);
|
||||||
}
|
}
|
||||||
// ignore difference in error message caused by `in`
|
// ignore difference in error message caused by `in`
|
||||||
|
// ignore difference in error message caused by spread syntax
|
||||||
// ignore difference in depth of termination caused by infinite recursion
|
// ignore difference in depth of termination caused by infinite recursion
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
var orig_skipped = patch_try_catch(original_code, toplevel);
|
var orig_skipped = patch_try_catch(original_code, toplevel);
|
||||||
|
|||||||
Reference in New Issue
Block a user