Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1786c69070 | ||
|
|
95ef4d5377 | ||
|
|
04017215cc | ||
|
|
142bd1bd1a | ||
|
|
8cb509d50e | ||
|
|
baf4903aa7 | ||
|
|
35465d590e | ||
|
|
ccd91b9952 | ||
|
|
47a5e6e17a | ||
|
|
090ee895e1 | ||
|
|
1cd1a1e5ee | ||
|
|
1d835ac17d | ||
|
|
9e07ac4102 | ||
|
|
92d1391e5e | ||
|
|
b4ff6d0f2d | ||
|
|
9882a9f4af | ||
|
|
40f36b9e01 | ||
|
|
6e105c5ca6 | ||
|
|
af35cd32f2 | ||
|
|
7de8daa4b1 | ||
|
|
305a4bdcee | ||
|
|
3472cf1a90 | ||
|
|
6d4c0fa6fa | ||
|
|
3cca0d6249 | ||
|
|
12ac49b970 | ||
|
|
8c670cae93 | ||
|
|
0e3da27727 | ||
|
|
13cdc167a2 | ||
|
|
51803cdcb2 | ||
|
|
8fa470c17c | ||
|
|
90410f9fc3 | ||
|
|
ef3831437d | ||
|
|
171c544705 | ||
|
|
3c609e2f4a | ||
|
|
f0ae03ed39 | ||
|
|
31c6b45036 | ||
|
|
3ac533e644 | ||
|
|
38a46c86d7 | ||
|
|
0f0759ec15 | ||
|
|
7f501f9fed | ||
|
|
72844eb5a4 | ||
|
|
09d93cc6c8 | ||
|
|
dd1374aa8a | ||
|
|
fdf2e8c5b0 | ||
|
|
a9d934ab4e | ||
|
|
2a053710bd | ||
|
|
219aac6a84 | ||
|
|
2039185051 | ||
|
|
ad27c14202 | ||
|
|
a62b086184 | ||
|
|
335456cf77 | ||
|
|
d64d0b0bec | ||
|
|
3ac575f2e8 | ||
|
|
d33a3a3253 | ||
|
|
d7456a2dc2 | ||
|
|
d97672613d |
9
.github/workflows/ufuzz.yml
vendored
9
.github/workflows/ufuzz.yml
vendored
@@ -6,6 +6,7 @@ on:
|
|||||||
env:
|
env:
|
||||||
BASE_URL: https://api.github.com/repos/${{ github.repository }}
|
BASE_URL: https://api.github.com/repos/${{ github.repository }}
|
||||||
CAUSE: ${{ github.event_name }}
|
CAUSE: ${{ github.event_name }}
|
||||||
|
RUN_NUM: ${{ github.run_number }}
|
||||||
TOKEN: ${{ github.token }}
|
TOKEN: ${{ github.token }}
|
||||||
jobs:
|
jobs:
|
||||||
ufuzz:
|
ufuzz:
|
||||||
@@ -36,12 +37,8 @@ jobs:
|
|||||||
npm config set update-notifier false
|
npm config set update-notifier false
|
||||||
npm --version
|
npm --version
|
||||||
while !(npm install); do echo "'npm install' failed - retrying..."; done
|
while !(npm install); do echo "'npm install' failed - retrying..."; done
|
||||||
PERIOD=1800000
|
|
||||||
if [[ $CAUSE == "schedule" ]]; then
|
if [[ $CAUSE == "schedule" ]]; then
|
||||||
PERIOD=`node test/ufuzz/actions $BASE_URL $TOKEN`
|
node test/ufuzz/job $BASE_URL $TOKEN $RUN_NUM
|
||||||
fi
|
|
||||||
if (( $PERIOD == 0 )); then
|
|
||||||
echo "too many jobs in queue - skipping..."
|
|
||||||
else
|
else
|
||||||
node test/ufuzz/job $PERIOD
|
node test/ufuzz/job 5000
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -688,6 +688,8 @@ to be `false` and all symbol names will be omitted.
|
|||||||
- `loops` (default: `true`) -- optimizations for `do`, `while` and `for` loops
|
- `loops` (default: `true`) -- optimizations for `do`, `while` and `for` loops
|
||||||
when we can statically determine the condition.
|
when we can statically determine the condition.
|
||||||
|
|
||||||
|
- `merge_vars` (default: `true`) -- combine and reuse variables.
|
||||||
|
|
||||||
- `negate_iife` (default: `true`) -- negate "Immediately-Called Function Expressions"
|
- `negate_iife` (default: `true`) -- negate "Immediately-Called Function Expressions"
|
||||||
where the return value is discarded, to avoid the parens that the
|
where the return value is discarded, to avoid the parens that the
|
||||||
code generator would insert.
|
code generator would insert.
|
||||||
|
|||||||
13
bin/uglifyjs
13
bin/uglifyjs
@@ -342,7 +342,18 @@ function run() {
|
|||||||
}
|
}
|
||||||
fatal(ex);
|
fatal(ex);
|
||||||
} else if (output == "ast") {
|
} else if (output == "ast") {
|
||||||
if (!options.compress && !options.mangle) result.ast.figure_out_scope({});
|
if (!options.compress && !options.mangle) {
|
||||||
|
var toplevel = result.ast;
|
||||||
|
if (!(toplevel instanceof UglifyJS.AST_Toplevel)) {
|
||||||
|
if (!(toplevel instanceof UglifyJS.AST_Statement)) toplevel = new UglifyJS.AST_SimpleStatement({
|
||||||
|
body: toplevel,
|
||||||
|
});
|
||||||
|
toplevel = new UglifyJS.AST_Toplevel({
|
||||||
|
body: [ toplevel ],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
toplevel.figure_out_scope({});
|
||||||
|
}
|
||||||
print(JSON.stringify(result.ast, function(key, value) {
|
print(JSON.stringify(result.ast, function(key, value) {
|
||||||
if (value) switch (key) {
|
if (value) switch (key) {
|
||||||
case "thedef":
|
case "thedef":
|
||||||
|
|||||||
44
lib/ast.js
44
lib/ast.js
@@ -412,33 +412,46 @@ var AST_With = DEFNODE("With", "expression", {
|
|||||||
|
|
||||||
/* -----[ scope and functions ]----- */
|
/* -----[ scope and functions ]----- */
|
||||||
|
|
||||||
var AST_Scope = DEFNODE("Scope", "cname enclosed uses_eval uses_with parent_scope functions variables make_def", {
|
var AST_BlockScope = DEFNODE("BlockScope", "enclosed functions make_def parent_scope variables", {
|
||||||
$documentation: "Base class for all statements introducing a lexical scope",
|
$documentation: "Base class for all statements introducing a lexical scope",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
cname: "[integer/S] current index for mangling variables (used internally by the mangler)",
|
|
||||||
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
|
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
|
||||||
uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`",
|
|
||||||
uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
|
|
||||||
parent_scope: "[AST_Scope?/S] link to the parent scope",
|
|
||||||
functions: "[Object/S] like `variables`, but only lists function declarations",
|
functions: "[Object/S] like `variables`, but only lists function declarations",
|
||||||
|
parent_scope: "[AST_Scope?/S] link to the parent scope",
|
||||||
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
|
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
|
||||||
},
|
},
|
||||||
clone: function(deep) {
|
clone: function(deep) {
|
||||||
var node = this._clone(deep);
|
var node = this._clone(deep);
|
||||||
if (this.variables) node.variables = this.variables.clone();
|
|
||||||
if (this.functions) node.functions = this.functions.clone();
|
|
||||||
if (this.enclosed) node.enclosed = this.enclosed.slice();
|
if (this.enclosed) node.enclosed = this.enclosed.slice();
|
||||||
|
if (this.functions) node.functions = this.functions.clone();
|
||||||
|
if (this.variables) node.variables = this.variables.clone();
|
||||||
return node;
|
return node;
|
||||||
},
|
},
|
||||||
|
pinned: function() {
|
||||||
|
return this.resolve().pinned();
|
||||||
|
},
|
||||||
|
resolve: function() {
|
||||||
|
return this.parent_scope.resolve();
|
||||||
|
},
|
||||||
|
_validate: function() {
|
||||||
|
if (this.parent_scope == null) return;
|
||||||
|
if (!(this.parent_scope instanceof AST_BlockScope)) throw new Error("parent_scope must be AST_BlockScope");
|
||||||
|
if (!(this.resolve() instanceof AST_Scope)) throw new Error("must be contained within AST_Scope");
|
||||||
|
},
|
||||||
|
}, AST_Block);
|
||||||
|
|
||||||
|
var AST_Scope = DEFNODE("Scope", "cname uses_eval uses_with", {
|
||||||
|
$documentation: "Base class for all statements introducing a lexical scope",
|
||||||
|
$propdoc: {
|
||||||
|
cname: "[integer/S] current index for mangling variables (used internally by the mangler)",
|
||||||
|
uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`",
|
||||||
|
uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
|
||||||
|
},
|
||||||
pinned: function() {
|
pinned: function() {
|
||||||
return this.uses_eval || this.uses_with;
|
return this.uses_eval || this.uses_with;
|
||||||
},
|
},
|
||||||
_validate: function() {
|
resolve: return_this,
|
||||||
if (this.parent_scope != null) {
|
}, AST_BlockScope);
|
||||||
if (!(this.parent_scope instanceof AST_Scope)) throw new Error("parent_scope must be AST_Scope");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}, AST_Block);
|
|
||||||
|
|
||||||
var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
||||||
$documentation: "The toplevel scope",
|
$documentation: "The toplevel scope",
|
||||||
@@ -631,6 +644,9 @@ var AST_Switch = DEFNODE("Switch", "expression", {
|
|||||||
},
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
must_be_expression(this, "expression");
|
must_be_expression(this, "expression");
|
||||||
|
this.body.forEach(function(node) {
|
||||||
|
if (!(node instanceof AST_SwitchBranch)) throw new Error("body must be AST_SwitchBranch[]");
|
||||||
|
});
|
||||||
},
|
},
|
||||||
}, AST_Block);
|
}, AST_Block);
|
||||||
|
|
||||||
@@ -700,7 +716,7 @@ var AST_Catch = DEFNODE("Catch", "argname", {
|
|||||||
_validate: function() {
|
_validate: function() {
|
||||||
if (!(this.argname instanceof AST_SymbolCatch)) throw new Error("argname must be AST_SymbolCatch");
|
if (!(this.argname instanceof AST_SymbolCatch)) throw new Error("argname must be AST_SymbolCatch");
|
||||||
},
|
},
|
||||||
}, AST_Block);
|
}, AST_BlockScope);
|
||||||
|
|
||||||
var AST_Finally = DEFNODE("Finally", null, {
|
var AST_Finally = DEFNODE("Finally", null, {
|
||||||
$documentation: "A `finally` node; only makes sense as part of a `try` statement"
|
$documentation: "A `finally` node; only makes sense as part of a `try` statement"
|
||||||
|
|||||||
649
lib/compress.js
649
lib/compress.js
@@ -73,6 +73,7 @@ function Compressor(options, false_by_default) {
|
|||||||
keep_fnames : false,
|
keep_fnames : false,
|
||||||
keep_infinity : false,
|
keep_infinity : false,
|
||||||
loops : !false_by_default,
|
loops : !false_by_default,
|
||||||
|
merge_vars : !false_by_default,
|
||||||
negate_iife : !false_by_default,
|
negate_iife : !false_by_default,
|
||||||
objects : !false_by_default,
|
objects : !false_by_default,
|
||||||
passes : 1,
|
passes : 1,
|
||||||
@@ -225,7 +226,8 @@ merge(Compressor.prototype, {
|
|||||||
// output and performance.
|
// output and performance.
|
||||||
descend(node, this);
|
descend(node, this);
|
||||||
var opt = node.optimize(this);
|
var opt = node.optimize(this);
|
||||||
if (is_scope && opt === node) {
|
if (is_scope && opt === node && !this.has_directive("use asm") && !opt.pinned()) {
|
||||||
|
opt.merge_variables(this);
|
||||||
opt.drop_unused(this);
|
opt.drop_unused(this);
|
||||||
descend(opt, this);
|
descend(opt, this);
|
||||||
}
|
}
|
||||||
@@ -670,15 +672,6 @@ merge(Compressor.prototype, {
|
|||||||
exp.left.definition().bool_fn++;
|
exp.left.definition().bool_fn++;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
def(AST_Case, function(tw) {
|
|
||||||
push(tw);
|
|
||||||
this.expression.walk(tw);
|
|
||||||
pop(tw);
|
|
||||||
push(tw);
|
|
||||||
walk_body(this, tw);
|
|
||||||
pop(tw);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
def(AST_Conditional, function(tw) {
|
def(AST_Conditional, function(tw) {
|
||||||
this.condition.walk(tw);
|
this.condition.walk(tw);
|
||||||
push(tw);
|
push(tw);
|
||||||
@@ -689,12 +682,6 @@ merge(Compressor.prototype, {
|
|||||||
pop(tw);
|
pop(tw);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
def(AST_Default, function(tw, descend) {
|
|
||||||
push(tw);
|
|
||||||
descend();
|
|
||||||
pop(tw);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
def(AST_Defun, function(tw, descend, compressor) {
|
def(AST_Defun, function(tw, descend, compressor) {
|
||||||
var id = this.name.definition().id;
|
var id = this.name.definition().id;
|
||||||
if (tw.defun_visited[id]) return true;
|
if (tw.defun_visited[id]) return true;
|
||||||
@@ -784,6 +771,7 @@ merge(Compressor.prototype, {
|
|||||||
var j = fn.argnames.indexOf(arg);
|
var j = fn.argnames.indexOf(arg);
|
||||||
return (j < 0 ? value : iife.args[j]) || make_node(AST_Undefined, iife);
|
return (j < 0 ? value : iife.args[j]) || make_node(AST_Undefined, iife);
|
||||||
};
|
};
|
||||||
|
d.fixed.assigns = [ arg ];
|
||||||
} else {
|
} else {
|
||||||
d.fixed = false;
|
d.fixed = false;
|
||||||
}
|
}
|
||||||
@@ -820,6 +808,27 @@ merge(Compressor.prototype, {
|
|||||||
pop(tw);
|
pop(tw);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
def(AST_Switch, function(tw) {
|
||||||
|
this.expression.walk(tw);
|
||||||
|
var first = true;
|
||||||
|
this.body.forEach(function(branch) {
|
||||||
|
if (branch instanceof AST_Default) return;
|
||||||
|
branch.expression.walk(tw);
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
push(tw);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (!first) pop(tw);
|
||||||
|
walk_body(this, tw);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
def(AST_SwitchBranch, function(tw) {
|
||||||
|
push(tw);
|
||||||
|
walk_body(this, tw);
|
||||||
|
pop(tw);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
def(AST_SymbolCatch, function() {
|
def(AST_SymbolCatch, function() {
|
||||||
this.definition().fixed = false;
|
this.definition().fixed = false;
|
||||||
});
|
});
|
||||||
@@ -1028,18 +1037,6 @@ merge(Compressor.prototype, {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function find_variable(compressor, name) {
|
|
||||||
var scope, i = 0;
|
|
||||||
while (scope = compressor.parent(i++)) {
|
|
||||||
if (scope instanceof AST_Scope) break;
|
|
||||||
if (scope instanceof AST_Catch) {
|
|
||||||
scope = scope.argname.definition().scope;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return scope.find_variable(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
function make_node(ctor, orig, props) {
|
function make_node(ctor, orig, props) {
|
||||||
if (!props) props = {};
|
if (!props) props = {};
|
||||||
if (orig) {
|
if (orig) {
|
||||||
@@ -1450,9 +1447,15 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handle_custom_scan_order(node, tt) {
|
function handle_custom_scan_order(node, tt) {
|
||||||
|
// Scan object only in a for-in statement
|
||||||
|
if (node instanceof AST_ForIn) {
|
||||||
|
node.object = node.object.transform(tt);
|
||||||
|
abort = true;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
// Skip (non-executed) functions
|
// Skip (non-executed) functions
|
||||||
if (node instanceof AST_Scope) return node;
|
if (node instanceof AST_Scope) return node;
|
||||||
// Scan case expressions first in a switch statement
|
// Scan first case expression only in a switch statement
|
||||||
if (node instanceof AST_Switch) {
|
if (node instanceof AST_Switch) {
|
||||||
node.expression = node.expression.transform(tt);
|
node.expression = node.expression.transform(tt);
|
||||||
for (var i = 0; !abort && i < node.body.length; i++) {
|
for (var i = 0; !abort && i < node.body.length; i++) {
|
||||||
@@ -1485,7 +1488,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (node instanceof AST_Debugger) return true;
|
if (node instanceof AST_Debugger) return true;
|
||||||
if (node instanceof AST_Defun) return funarg && lhs.name === node.name.name;
|
if (node instanceof AST_Defun) return funarg && lhs.name === node.name.name;
|
||||||
if (node instanceof AST_IterationStatement) return !(node instanceof AST_For);
|
if (node instanceof AST_DWLoop) return true;
|
||||||
if (node instanceof AST_LoopControl) return true;
|
if (node instanceof AST_LoopControl) return true;
|
||||||
if (node instanceof AST_Try) return true;
|
if (node instanceof AST_Try) return true;
|
||||||
if (node instanceof AST_With) return true;
|
if (node instanceof AST_With) return true;
|
||||||
@@ -2113,25 +2116,31 @@ merge(Compressor.prototype, {
|
|||||||
eliminate_spurious_blocks(stat.body);
|
eliminate_spurious_blocks(stat.body);
|
||||||
[].splice.apply(statements, [i, 1].concat(stat.body));
|
[].splice.apply(statements, [i, 1].concat(stat.body));
|
||||||
i += stat.body.length;
|
i += stat.body.length;
|
||||||
} else if (stat instanceof AST_EmptyStatement) {
|
continue;
|
||||||
CHANGED = true;
|
}
|
||||||
statements.splice(i, 1);
|
if (stat instanceof AST_Directive) {
|
||||||
} else if (stat instanceof AST_Directive) {
|
if (member(stat.value, seen_dirs)) {
|
||||||
if (!member(stat.value, seen_dirs)) {
|
|
||||||
i++;
|
|
||||||
seen_dirs.push(stat.value);
|
|
||||||
} else {
|
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
statements.splice(i, 1);
|
statements.splice(i, 1);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
} else i++;
|
seen_dirs.push(stat.value);
|
||||||
|
}
|
||||||
|
if (stat instanceof AST_EmptyStatement) {
|
||||||
|
CHANGED = true;
|
||||||
|
statements.splice(i, 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle_if_return(statements, compressor) {
|
function handle_if_return(statements, compressor) {
|
||||||
var self = compressor.self();
|
var self = compressor.self();
|
||||||
var parent = compressor.parent();
|
var parent = compressor.parent();
|
||||||
var in_lambda = self instanceof AST_Lambda;
|
var in_lambda = last_of(function(node) {
|
||||||
|
return node instanceof AST_Lambda;
|
||||||
|
});
|
||||||
var in_iife = in_lambda && parent && parent.TYPE == "Call";
|
var in_iife = in_lambda && parent && parent.TYPE == "Call";
|
||||||
var multiple_if_returns = has_multiple_if_returns(statements);
|
var multiple_if_returns = has_multiple_if_returns(statements);
|
||||||
for (var i = statements.length; --i >= 0;) {
|
for (var i = statements.length; --i >= 0;) {
|
||||||
@@ -2234,7 +2243,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
//---
|
//---
|
||||||
// if (foo()) return x; return y; => return foo() ? x : y;
|
// if (foo()) return x; return y; => return foo() ? x : y;
|
||||||
if ((in_bool || value) && !stat.alternative && next instanceof AST_Return) {
|
if (!stat.alternative && next instanceof AST_Return) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
stat = stat.clone();
|
stat = stat.clone();
|
||||||
stat.alternative = next;
|
stat.alternative = next;
|
||||||
@@ -2295,12 +2304,39 @@ merge(Compressor.prototype, {
|
|||||||
return !value || value instanceof AST_UnaryPrefix && value.operator == "void";
|
return !value || value instanceof AST_UnaryPrefix && value.operator == "void";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function is_last_statement(body, stat) {
|
||||||
|
var index = body.lastIndexOf(stat);
|
||||||
|
if (index < 0) return false;
|
||||||
|
while (++index < body.length) {
|
||||||
|
if (!is_declaration(body[index])) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function last_of(predicate) {
|
||||||
|
var block = self, stat, level = 0;
|
||||||
|
do {
|
||||||
|
do {
|
||||||
|
if (predicate(block)) return true;
|
||||||
|
block = compressor.parent(level++);
|
||||||
|
} while (block instanceof AST_If && (stat = block));
|
||||||
|
} while ((block instanceof AST_BlockStatement || block instanceof AST_Scope)
|
||||||
|
&& is_last_statement(block.body, stat));
|
||||||
|
}
|
||||||
|
|
||||||
|
function match_target(target) {
|
||||||
|
return last_of(function(node) {
|
||||||
|
return node === target;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function can_merge_flow(ab) {
|
function can_merge_flow(ab) {
|
||||||
if (!ab) return false;
|
if (ab instanceof AST_Return) return in_lambda && is_return_void(ab.value);
|
||||||
var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab) : null;
|
if (!(ab instanceof AST_LoopControl)) return false;
|
||||||
return ab instanceof AST_Return && in_lambda && is_return_void(ab.value)
|
var lct = compressor.loopcontrol_target(ab);
|
||||||
|| ab instanceof AST_Continue && self === loop_body(lct)
|
if (ab instanceof AST_Continue) return match_target(loop_body(lct));
|
||||||
|| ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct;
|
if (lct instanceof AST_IterationStatement) return false;
|
||||||
|
return match_target(lct);
|
||||||
}
|
}
|
||||||
|
|
||||||
function extract_functions() {
|
function extract_functions() {
|
||||||
@@ -2327,20 +2363,14 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
function next_index(i) {
|
function next_index(i) {
|
||||||
for (var j = i + 1; j < statements.length; j++) {
|
for (var j = i + 1; j < statements.length; j++) {
|
||||||
var stat = statements[j];
|
if (!is_declaration(statements[j])) break;
|
||||||
if (!(stat instanceof AST_Var && declarations_only(stat))) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
function prev_index(i) {
|
function prev_index(i) {
|
||||||
for (var j = i; --j >= 0;) {
|
for (var j = i; --j >= 0;) {
|
||||||
var stat = statements[j];
|
if (!is_declaration(statements[j])) break;
|
||||||
if (!(stat instanceof AST_Var && declarations_only(stat))) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
@@ -2383,6 +2413,10 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function is_declaration(stat) {
|
||||||
|
return stat instanceof AST_Defun || stat instanceof AST_Var && declarations_only(stat);
|
||||||
|
}
|
||||||
|
|
||||||
function sequencesize(statements, compressor) {
|
function sequencesize(statements, compressor) {
|
||||||
if (statements.length < 2) return;
|
if (statements.length < 2) return;
|
||||||
var seq = [], n = 0;
|
var seq = [], n = 0;
|
||||||
@@ -2399,8 +2433,7 @@ merge(Compressor.prototype, {
|
|||||||
var body = stat.body;
|
var body = stat.body;
|
||||||
if (seq.length > 0) body = body.drop_side_effect_free(compressor);
|
if (seq.length > 0) body = body.drop_side_effect_free(compressor);
|
||||||
if (body) merge_sequence(seq, body);
|
if (body) merge_sequence(seq, body);
|
||||||
} else if (stat instanceof AST_Definitions && declarations_only(stat)
|
} else if (is_declaration(stat)) {
|
||||||
|| stat instanceof AST_Defun) {
|
|
||||||
statements[n++] = stat;
|
statements[n++] = stat;
|
||||||
} else {
|
} else {
|
||||||
push_seq();
|
push_seq();
|
||||||
@@ -2871,9 +2904,12 @@ merge(Compressor.prototype, {
|
|||||||
var fixed = this.fixed_value();
|
var fixed = this.fixed_value();
|
||||||
if (!fixed) return true;
|
if (!fixed) return true;
|
||||||
this._dot_throw = return_true;
|
this._dot_throw = return_true;
|
||||||
var result = fixed._dot_throw(compressor);
|
if (fixed._dot_throw(compressor)) {
|
||||||
delete this._dot_throw;
|
delete this._dot_throw;
|
||||||
return result;
|
return true;
|
||||||
|
}
|
||||||
|
this._dot_throw = return_false;
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
def(AST_UnaryPrefix, function() {
|
def(AST_UnaryPrefix, function() {
|
||||||
return this.operator == "void";
|
return this.operator == "void";
|
||||||
@@ -3068,7 +3104,12 @@ merge(Compressor.prototype, {
|
|||||||
(function(def) {
|
(function(def) {
|
||||||
def(AST_Node, return_false);
|
def(AST_Node, return_false);
|
||||||
def(AST_Assign, function(compressor) {
|
def(AST_Assign, function(compressor) {
|
||||||
return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor);
|
switch (this.operator) {
|
||||||
|
case "+=":
|
||||||
|
if (this.left.is_string(compressor)) return true;
|
||||||
|
case "=":
|
||||||
|
return this.right.is_string(compressor);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
def(AST_Binary, function(compressor) {
|
def(AST_Binary, function(compressor) {
|
||||||
return this.operator == "+" &&
|
return this.operator == "+" &&
|
||||||
@@ -3393,7 +3434,7 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
var value = node._eval(compressor, ignore_side_effects, cached, depth);
|
var value = node._eval(compressor, ignore_side_effects, cached, depth);
|
||||||
if (value === node) return this;
|
if (typeof value == "object") return this;
|
||||||
modified(lhs);
|
modified(lhs);
|
||||||
return value;
|
return value;
|
||||||
});
|
});
|
||||||
@@ -3857,7 +3898,8 @@ merge(Compressor.prototype, {
|
|||||||
if (is_undeclared_ref(expr) && global_pure_fns[expr.name]) return true;
|
if (is_undeclared_ref(expr) && global_pure_fns[expr.name]) return true;
|
||||||
if (expr instanceof AST_Dot && is_undeclared_ref(expr.expression)) {
|
if (expr instanceof AST_Dot && is_undeclared_ref(expr.expression)) {
|
||||||
var static_fn = static_fns[expr.expression.name];
|
var static_fn = static_fns[expr.expression.name];
|
||||||
return static_fn && static_fn[expr.property];
|
return static_fn && (static_fn[expr.property]
|
||||||
|
|| expr.expression.name == "Math" && expr.property == "random");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this.pure || !compressor.pure_funcs(this);
|
return this.pure || !compressor.pure_funcs(this);
|
||||||
@@ -4123,13 +4165,7 @@ merge(Compressor.prototype, {
|
|||||||
var scopes = [];
|
var scopes = [];
|
||||||
self.walk(new TreeWalker(function(node, descend) {
|
self.walk(new TreeWalker(function(node, descend) {
|
||||||
if (!result) return true;
|
if (!result) return true;
|
||||||
if (node instanceof AST_Catch) {
|
if (node instanceof AST_BlockScope) {
|
||||||
scopes.push(node.argname.scope);
|
|
||||||
descend();
|
|
||||||
scopes.pop();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (node instanceof AST_Scope) {
|
|
||||||
if (node === self) return;
|
if (node === self) return;
|
||||||
scopes.push(node);
|
scopes.push(node);
|
||||||
descend();
|
descend();
|
||||||
@@ -4137,14 +4173,14 @@ merge(Compressor.prototype, {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
if (self.inlined) {
|
if (self.inlined || node.redef) {
|
||||||
result = false;
|
result = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (self.variables.has(node.name)) return true;
|
if (self.variables.has(node.name)) return true;
|
||||||
var def = node.definition();
|
var def = node.definition();
|
||||||
if (member(def.scope, scopes)) return true;
|
if (member(def.scope, scopes)) return true;
|
||||||
if (scope) {
|
if (scope && !def.redefined()) {
|
||||||
var scope_def = scope.find_variable(node);
|
var scope_def = scope.find_variable(node);
|
||||||
if (def.undeclared ? !scope_def : scope_def === def) {
|
if (def.undeclared ? !scope_def : scope_def === def) {
|
||||||
result = "f";
|
result = "f";
|
||||||
@@ -4284,11 +4320,267 @@ merge(Compressor.prototype, {
|
|||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AST_Scope.DEFMETHOD("merge_variables", function(compressor) {
|
||||||
|
if (!compressor.option("merge_vars")) return;
|
||||||
|
var self = this, segment = {}, root;
|
||||||
|
var first = [], last = [], index = 0;
|
||||||
|
var declarations = new Dictionary();
|
||||||
|
var references = Object.create(null);
|
||||||
|
var prev = Object.create(null);
|
||||||
|
var tw = new TreeWalker(function(node, descend) {
|
||||||
|
if (node instanceof AST_Assign) {
|
||||||
|
var sym = node.left;
|
||||||
|
if (!(sym instanceof AST_SymbolRef)) return;
|
||||||
|
if (node.operator != "=") mark(sym, true, false);
|
||||||
|
node.right.walk(tw);
|
||||||
|
mark(sym, false, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_Binary) {
|
||||||
|
if (!lazy_op[node.operator]) return;
|
||||||
|
node.left.walk(tw);
|
||||||
|
push();
|
||||||
|
node.right.walk(tw);
|
||||||
|
pop();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_Conditional) {
|
||||||
|
node.condition.walk(tw);
|
||||||
|
push();
|
||||||
|
node.consequent.walk(tw);
|
||||||
|
pop();
|
||||||
|
push();
|
||||||
|
node.alternative.walk(tw);
|
||||||
|
pop();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_For) {
|
||||||
|
if (node.init) node.init.walk(tw);
|
||||||
|
push();
|
||||||
|
segment.block = node;
|
||||||
|
segment.loop = true;
|
||||||
|
if (node.condition) node.condition.walk(tw);
|
||||||
|
node.body.walk(tw);
|
||||||
|
if (node.step) node.step.walk(tw);
|
||||||
|
pop();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_ForIn) {
|
||||||
|
node.object.walk(tw);
|
||||||
|
push();
|
||||||
|
segment.block = node;
|
||||||
|
segment.loop = true;
|
||||||
|
node.init.walk(tw);
|
||||||
|
node.body.walk(tw);
|
||||||
|
pop();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_If) {
|
||||||
|
node.condition.walk(tw);
|
||||||
|
push();
|
||||||
|
node.body.walk(tw);
|
||||||
|
pop();
|
||||||
|
if (node.alternative) {
|
||||||
|
push();
|
||||||
|
node.alternative.walk(tw);
|
||||||
|
pop();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_IterationStatement) {
|
||||||
|
push();
|
||||||
|
segment.block = node;
|
||||||
|
segment.loop = true;
|
||||||
|
descend();
|
||||||
|
pop();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_LabeledStatement) {
|
||||||
|
push();
|
||||||
|
segment.block = node;
|
||||||
|
node.body.walk(tw);
|
||||||
|
pop();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_Scope) {
|
||||||
|
push();
|
||||||
|
segment.block = node;
|
||||||
|
if (node === self) root = segment;
|
||||||
|
if (node instanceof AST_Lambda) {
|
||||||
|
if (node.name) references[node.name.definition().id] = false;
|
||||||
|
if (node.uses_arguments && !tw.has_directive("use strict")) node.argnames.forEach(function(node) {
|
||||||
|
references[node.definition().id] = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
descend();
|
||||||
|
pop();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_Switch) {
|
||||||
|
node.expression.walk(tw);
|
||||||
|
var save = segment;
|
||||||
|
node.body.forEach(function(branch) {
|
||||||
|
if (branch instanceof AST_Default) return;
|
||||||
|
branch.expression.walk(tw);
|
||||||
|
if (save === segment) push();
|
||||||
|
});
|
||||||
|
segment = save;
|
||||||
|
node.body.forEach(function(branch) {
|
||||||
|
push();
|
||||||
|
walk_body(branch, tw);
|
||||||
|
pop();
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_SymbolFunarg) {
|
||||||
|
if (!node.__unused) mark(node, false, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_SymbolRef) {
|
||||||
|
mark(node, true, false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_Try) {
|
||||||
|
push();
|
||||||
|
segment.block = node;
|
||||||
|
walk_body(node, tw);
|
||||||
|
pop();
|
||||||
|
if (node.bcatch) {
|
||||||
|
var def = node.bcatch.argname.definition();
|
||||||
|
references[def.id] = false;
|
||||||
|
if (def = def.redefined()) references[def.id] = false;
|
||||||
|
push();
|
||||||
|
if (node.bfinally) segment.block = node.bcatch;
|
||||||
|
walk_body(node.bcatch, tw);
|
||||||
|
pop();
|
||||||
|
}
|
||||||
|
if (node.bfinally) node.bfinally.walk(tw);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_Unary) {
|
||||||
|
if (!unary_arithmetic[node.operator]) return;
|
||||||
|
var sym = node.expression;
|
||||||
|
if (!(sym instanceof AST_SymbolRef)) return;
|
||||||
|
mark(sym, true, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_VarDef) {
|
||||||
|
if (node.value) {
|
||||||
|
node.value.walk(tw);
|
||||||
|
mark(node.name, false, true);
|
||||||
|
} else {
|
||||||
|
var id = node.name.definition().id;
|
||||||
|
if (!(id in references)) {
|
||||||
|
declarations.add(id, node.name);
|
||||||
|
} else if (references[id]) {
|
||||||
|
references[id].push(node.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tw.directives = Object.create(compressor.directives);
|
||||||
|
self.walk(tw);
|
||||||
|
var merged = Object.create(null);
|
||||||
|
while (first.length && last.length) {
|
||||||
|
var head = first.pop();
|
||||||
|
var def = head.definition;
|
||||||
|
if (!(def.id in prev)) continue;
|
||||||
|
if (!references[def.id]) continue;
|
||||||
|
var head_refs = {
|
||||||
|
start: references[def.id].start,
|
||||||
|
};
|
||||||
|
while (def.id in merged) def = merged[def.id];
|
||||||
|
head_refs.end = references[def.id].end;
|
||||||
|
var skipped = [];
|
||||||
|
do {
|
||||||
|
var tail = last.pop();
|
||||||
|
if (!tail) continue;
|
||||||
|
if (tail.index > head.index) continue;
|
||||||
|
var id = tail.definition.id;
|
||||||
|
var tail_refs = references[id];
|
||||||
|
if (!tail_refs) continue;
|
||||||
|
if (head_refs.start.block !== tail_refs.start.block
|
||||||
|
|| !mergeable(head_refs, tail_refs)
|
||||||
|
|| head_refs.start.loop && !mergeable(tail_refs, head_refs)) {
|
||||||
|
skipped.unshift(tail);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var orig = [], refs = [];
|
||||||
|
tail_refs.forEach(function(sym) {
|
||||||
|
sym.thedef = def;
|
||||||
|
sym.name = def.name;
|
||||||
|
if (sym instanceof AST_SymbolRef) {
|
||||||
|
refs.push(sym);
|
||||||
|
} else {
|
||||||
|
orig.push(sym);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
def.orig = orig.concat(def.orig);
|
||||||
|
def.references = refs.concat(def.references);
|
||||||
|
def.fixed = tail.definition.fixed && def.fixed;
|
||||||
|
merged[id] = def;
|
||||||
|
break;
|
||||||
|
} while (last.length);
|
||||||
|
if (skipped.length) last = last.concat(skipped);
|
||||||
|
}
|
||||||
|
|
||||||
|
function push() {
|
||||||
|
segment = Object.create(segment);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pop() {
|
||||||
|
segment = Object.getPrototypeOf(segment);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mark(sym, read, write) {
|
||||||
|
var def = sym.definition();
|
||||||
|
if (def.id in references) {
|
||||||
|
var refs = references[def.id];
|
||||||
|
if (!refs) return;
|
||||||
|
if (refs.start.block !== segment.block) return references[def.id] = false;
|
||||||
|
refs.push(sym);
|
||||||
|
refs.end = segment;
|
||||||
|
if (def.id in prev) {
|
||||||
|
last[prev[def.id]] = null;
|
||||||
|
} else if (!read) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (self.variables.get(def.name) !== def || compressor.exposed(def) || sym.name == "arguments") {
|
||||||
|
return references[def.id] = false;
|
||||||
|
} else {
|
||||||
|
var refs = declarations.get(def.id) || [];
|
||||||
|
refs.push(sym);
|
||||||
|
references[def.id] = refs;
|
||||||
|
if (!read) {
|
||||||
|
refs.start = segment;
|
||||||
|
return first.push({
|
||||||
|
index: index++,
|
||||||
|
definition: def,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (segment.block !== self) return references[def.id] = false;
|
||||||
|
refs.start = root;
|
||||||
|
}
|
||||||
|
prev[def.id] = last.length;
|
||||||
|
last.push({
|
||||||
|
index: index++,
|
||||||
|
definition: def,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function must_visit(base, segment) {
|
||||||
|
return base === segment || base.isPrototypeOf(segment);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mergeable(head, tail) {
|
||||||
|
return must_visit(head.start, head.end) || must_visit(head.start, tail.start);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
|
AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
|
||||||
if (!compressor.option("unused")) return;
|
if (!compressor.option("unused")) return;
|
||||||
if (compressor.has_directive("use asm")) return;
|
|
||||||
var self = this;
|
var self = this;
|
||||||
if (self.pinned()) return;
|
|
||||||
var drop_funcs = !(self instanceof AST_Toplevel) || compressor.toplevel.funcs;
|
var drop_funcs = !(self instanceof AST_Toplevel) || compressor.toplevel.funcs;
|
||||||
var drop_vars = !(self instanceof AST_Toplevel) || compressor.toplevel.vars;
|
var drop_vars = !(self instanceof AST_Toplevel) || compressor.toplevel.vars;
|
||||||
var assign_as_unused = /keep_assign/.test(compressor.option("unused")) ? return_false : function(node, props) {
|
var assign_as_unused = /keep_assign/.test(compressor.option("unused")) ? return_false : function(node, props) {
|
||||||
@@ -4354,7 +4646,9 @@ merge(Compressor.prototype, {
|
|||||||
return true; // don't go in nested scopes
|
return true; // don't go in nested scopes
|
||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolFunarg && scope === self) {
|
if (node instanceof AST_SymbolFunarg && scope === self) {
|
||||||
var_defs_by_id.add(node.definition().id, node);
|
var node_def = node.definition();
|
||||||
|
var_defs_by_id.add(node_def.id, node);
|
||||||
|
assignments.add(node_def.id, node);
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Definitions && scope === self) {
|
if (node instanceof AST_Definitions && scope === self) {
|
||||||
node.definitions.forEach(function(def) {
|
node.definitions.forEach(function(def) {
|
||||||
@@ -4379,6 +4673,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return scan_ref_scoped(node, descend, true);
|
return scan_ref_scoped(node, descend, true);
|
||||||
});
|
});
|
||||||
|
tw.directives = Object.create(compressor.directives);
|
||||||
self.walk(tw);
|
self.walk(tw);
|
||||||
// pass 2: for every used symbol we need to walk its
|
// pass 2: for every used symbol we need to walk its
|
||||||
// initialization code to figure out if it uses other
|
// initialization code to figure out if it uses other
|
||||||
@@ -4467,6 +4762,13 @@ merge(Compressor.prototype, {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (node instanceof AST_UnaryPostfix
|
||||||
|
&& node.expression instanceof AST_SymbolRef
|
||||||
|
&& indexOf_assign(node.expression.definition(), node) < 0) {
|
||||||
|
return make_node(AST_UnaryPrefix, node, {
|
||||||
|
operator: "+",
|
||||||
|
expression: node.expression
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Call) calls_to_drop_args.push(node);
|
if (node instanceof AST_Call) calls_to_drop_args.push(node);
|
||||||
@@ -4487,14 +4789,16 @@ merge(Compressor.prototype, {
|
|||||||
var trim = compressor.drop_fargs(node, parent);
|
var trim = compressor.drop_fargs(node, parent);
|
||||||
for (var a = node.argnames, i = a.length; --i >= 0;) {
|
for (var a = node.argnames, i = a.length; --i >= 0;) {
|
||||||
var sym = a[i];
|
var sym = a[i];
|
||||||
if (!(sym.definition().id in in_use_ids)) {
|
var def = sym.definition();
|
||||||
|
if (def.id in in_use_ids) {
|
||||||
|
trim = false;
|
||||||
|
if (indexOf_assign(def, sym) < 0) sym.__unused = null;
|
||||||
|
} else {
|
||||||
sym.__unused = true;
|
sym.__unused = true;
|
||||||
if (trim) {
|
if (trim) {
|
||||||
log(sym, "Dropping unused function argument {name}");
|
log(sym, "Dropping unused function argument {name}");
|
||||||
a.pop();
|
a.pop();
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
trim = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fns_with_marked_args.push(node);
|
fns_with_marked_args.push(node);
|
||||||
@@ -4539,14 +4843,16 @@ merge(Compressor.prototype, {
|
|||||||
&& !compressor.option("ie8")
|
&& !compressor.option("ie8")
|
||||||
&& var_defs.length == 1
|
&& var_defs.length == 1
|
||||||
&& sym.assignments == 0
|
&& sym.assignments == 0
|
||||||
&& def.value === def.name.fixed_value()
|
|
||||||
&& def.value instanceof AST_Function
|
&& def.value instanceof AST_Function
|
||||||
|
&& (sym.references.length ? all(sym.references, function(ref) {
|
||||||
|
return def.value === ref.fixed_value();
|
||||||
|
}) : def.value === def.name.fixed_value())
|
||||||
&& (!def.value.name || (old_def = def.value.name.definition()).assignments == 0
|
&& (!def.value.name || (old_def = def.value.name.definition()).assignments == 0
|
||||||
&& (old_def.name == def.name.name || all(old_def.references, function(ref) {
|
&& (old_def.name == def.name.name || all(old_def.references, function(ref) {
|
||||||
return ref.scope.find_variable(def.name) === def.name.definition();
|
return ref.scope.find_variable(def.name) === def.name.definition();
|
||||||
})))
|
})))
|
||||||
&& can_rename(def.value, def.name.name)
|
&& can_declare_defun()
|
||||||
&& (!compressor.has_directive("use strict") || parent instanceof AST_Scope)) {
|
&& can_rename(def.value, def.name.name)) {
|
||||||
AST_Node.warn("Declaring {name} as function [{file}:{line},{col}]", template(def.name));
|
AST_Node.warn("Declaring {name} as function [{file}:{line},{col}]", template(def.name));
|
||||||
var defun = make_node(AST_Defun, def, def.value);
|
var defun = make_node(AST_Defun, def, def.value);
|
||||||
defun.name = make_node(AST_SymbolDefun, def.name, def.name);
|
defun.name = make_node(AST_SymbolDefun, def.name, def.name);
|
||||||
@@ -4602,6 +4908,13 @@ merge(Compressor.prototype, {
|
|||||||
var def = fn.variables.get(name);
|
var def = fn.variables.get(name);
|
||||||
return !def || fn.name && def === fn.name.definition();
|
return !def || fn.name && def === fn.name.definition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function can_declare_defun() {
|
||||||
|
if (compressor.has_directive("use strict")) return parent instanceof AST_Scope;
|
||||||
|
return parent instanceof AST_Block
|
||||||
|
|| parent instanceof AST_For && parent.init === node
|
||||||
|
|| parent instanceof AST_If;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
switch (head.length) {
|
switch (head.length) {
|
||||||
case 0:
|
case 0:
|
||||||
@@ -4855,6 +5168,13 @@ merge(Compressor.prototype, {
|
|||||||
if (!(node_def.id in in_use_ids)) {
|
if (!(node_def.id in in_use_ids)) {
|
||||||
in_use_ids[node_def.id] = true;
|
in_use_ids[node_def.id] = true;
|
||||||
in_use.push(node_def);
|
in_use.push(node_def);
|
||||||
|
if (node.scope !== node_def.scope) {
|
||||||
|
var redef = node_def.redefined();
|
||||||
|
if (redef && !(redef.id in in_use_ids)) {
|
||||||
|
in_use_ids[redef.id] = true;
|
||||||
|
in_use.push(redef);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (track_assigns(node_def, node)) add_assigns(node_def, node);
|
if (track_assigns(node_def, node)) add_assigns(node_def, node);
|
||||||
return true;
|
return true;
|
||||||
@@ -5083,7 +5403,7 @@ merge(Compressor.prototype, {
|
|||||||
process_boolean_returns(this, compressor);
|
process_boolean_returns(this, compressor);
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("var_names", function() {
|
AST_BlockScope.DEFMETHOD("var_names", function() {
|
||||||
var var_names = this._var_names;
|
var var_names = this._var_names;
|
||||||
if (!var_names) {
|
if (!var_names) {
|
||||||
this._var_names = var_names = Object.create(null);
|
this._var_names = var_names = Object.create(null);
|
||||||
@@ -6154,10 +6474,10 @@ merge(Compressor.prototype, {
|
|||||||
var side_effects = [];
|
var side_effects = [];
|
||||||
for (var i = 0; i < args.length; i++) {
|
for (var i = 0; i < args.length; i++) {
|
||||||
var trim = i >= fn.argnames.length;
|
var trim = i >= fn.argnames.length;
|
||||||
if (trim || fn.argnames[i].__unused) {
|
if (trim || "__unused" in fn.argnames[i]) {
|
||||||
var node = args[i].drop_side_effect_free(compressor);
|
var node = args[i].drop_side_effect_free(compressor);
|
||||||
if (drop_fargs) {
|
if (drop_fargs && (trim || fn.argnames[i].__unused)) {
|
||||||
fn.argnames.splice(i, 1);
|
if (!trim) fn.argnames.splice(i, 1);
|
||||||
args.splice(i, 1);
|
args.splice(i, 1);
|
||||||
if (node) side_effects.push(node);
|
if (node) side_effects.push(node);
|
||||||
i--;
|
i--;
|
||||||
@@ -6168,15 +6488,14 @@ merge(Compressor.prototype, {
|
|||||||
side_effects = [];
|
side_effects = [];
|
||||||
} else if (!trim) {
|
} else if (!trim) {
|
||||||
if (side_effects.length) {
|
if (side_effects.length) {
|
||||||
node = make_sequence(call, side_effects);
|
args[pos++] = make_sequence(call, side_effects);
|
||||||
side_effects = [];
|
side_effects = [];
|
||||||
} else {
|
} else {
|
||||||
node = make_node(AST_Number, args[i], {
|
args[pos++] = make_node(AST_Number, args[i], {
|
||||||
value: 0
|
value: 0
|
||||||
});
|
});
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
args[pos++] = node;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
side_effects.push(args[i]);
|
side_effects.push(args[i]);
|
||||||
@@ -6429,7 +6748,7 @@ merge(Compressor.prototype, {
|
|||||||
if (self.args.length == 0) return make_node(AST_Function, self, {
|
if (self.args.length == 0) return make_node(AST_Function, self, {
|
||||||
argnames: [],
|
argnames: [],
|
||||||
body: []
|
body: []
|
||||||
});
|
}).init_scope_vars(exp.scope);
|
||||||
if (all(self.args, function(x) {
|
if (all(self.args, function(x) {
|
||||||
return x instanceof AST_String;
|
return x instanceof AST_String;
|
||||||
})) {
|
})) {
|
||||||
@@ -6497,7 +6816,7 @@ merge(Compressor.prototype, {
|
|||||||
&& !fn.pinned()
|
&& !fn.pinned()
|
||||||
&& !(fn.name && fn instanceof AST_Function)
|
&& !(fn.name && fn instanceof AST_Function)
|
||||||
&& (exp === fn || !recursive_ref(compressor, def = exp.definition())
|
&& (exp === fn || !recursive_ref(compressor, def = exp.definition())
|
||||||
&& fn.is_constant_expression(compressor.find_parent(AST_Scope)))
|
&& fn.is_constant_expression(compressor.find_parent(AST_BlockScope)))
|
||||||
&& (value = can_flatten_body(stat))
|
&& (value = can_flatten_body(stat))
|
||||||
&& !fn.contains_this()) {
|
&& !fn.contains_this()) {
|
||||||
var replacing = exp === fn || compressor.option("unused") && def.references.length - def.replaced == 1;
|
var replacing = exp === fn || compressor.option("unused") && def.references.length - def.replaced == 1;
|
||||||
@@ -6523,7 +6842,7 @@ merge(Compressor.prototype, {
|
|||||||
return arg;
|
return arg;
|
||||||
})).optimize(compressor);
|
})).optimize(compressor);
|
||||||
node = maintain_this_binding(compressor, compressor.parent(), compressor.self(), node);
|
node = maintain_this_binding(compressor, compressor.parent(), compressor.self(), node);
|
||||||
if (replacing || best_of(compressor, self, node) === node) {
|
if (replacing || best_of_expression(node, self) === node) {
|
||||||
refs.forEach(function(ref) {
|
refs.forEach(function(ref) {
|
||||||
var def = ref.definition();
|
var def = ref.definition();
|
||||||
def.references.push(ref);
|
def.references.push(ref);
|
||||||
@@ -6739,9 +7058,10 @@ merge(Compressor.prototype, {
|
|||||||
value: null
|
value: null
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
if (!value) return;
|
||||||
var sym = make_node(AST_SymbolRef, name, name);
|
var sym = make_node(AST_SymbolRef, name, name);
|
||||||
def.references.push(sym);
|
def.references.push(sym);
|
||||||
if (value) expressions.push(make_node(AST_Assign, self, {
|
expressions.push(make_node(AST_Assign, self, {
|
||||||
operator: "=",
|
operator: "=",
|
||||||
left: sym,
|
left: sym,
|
||||||
right: value
|
right: value
|
||||||
@@ -6762,7 +7082,12 @@ merge(Compressor.prototype, {
|
|||||||
var symbol = make_node(AST_SymbolVar, name, name);
|
var symbol = make_node(AST_SymbolVar, name, name);
|
||||||
name.definition().orig.push(symbol);
|
name.definition().orig.push(symbol);
|
||||||
if (!value && in_loop) value = make_node(AST_Undefined, self);
|
if (!value && in_loop) value = make_node(AST_Undefined, self);
|
||||||
append_var(decls, expressions, symbol, value);
|
if ("__unused" in name) {
|
||||||
|
append_var(decls, expressions, symbol);
|
||||||
|
if (value) expressions.push(value);
|
||||||
|
} else {
|
||||||
|
append_var(decls, expressions, symbol, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
decls.reverse();
|
decls.reverse();
|
||||||
@@ -7065,10 +7390,9 @@ merge(Compressor.prototype, {
|
|||||||
var indexFns = makePredicate("indexOf lastIndexOf");
|
var indexFns = makePredicate("indexOf lastIndexOf");
|
||||||
var commutativeOperators = makePredicate("== === != !== * & | ^");
|
var commutativeOperators = makePredicate("== === != !== * & | ^");
|
||||||
function is_object(node) {
|
function is_object(node) {
|
||||||
while ((node = node.tail_node()) instanceof AST_SymbolRef) {
|
if (node instanceof AST_Assign) return node.operator == "=" && is_object(node.right);
|
||||||
node = node.fixed_value();
|
if (node instanceof AST_Sequence) return is_object(node.tail_node());
|
||||||
if (!node) return false;
|
if (node instanceof AST_SymbolRef) return is_object(node.fixed_value());
|
||||||
}
|
|
||||||
return node instanceof AST_Array
|
return node instanceof AST_Array
|
||||||
|| node instanceof AST_Lambda
|
|| node instanceof AST_Lambda
|
||||||
|| node instanceof AST_New
|
|| node instanceof AST_New
|
||||||
@@ -7399,29 +7723,6 @@ merge(Compressor.prototype, {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// (x + "foo") + ("bar" + y) => (x + "foobar") + y
|
|
||||||
if (self.left instanceof AST_Binary
|
|
||||||
&& self.left.operator == "+"
|
|
||||||
&& self.left.is_string(compressor)
|
|
||||||
&& self.left.right instanceof AST_Constant
|
|
||||||
&& self.right instanceof AST_Binary
|
|
||||||
&& self.right.operator == "+"
|
|
||||||
&& self.right.left instanceof AST_Constant
|
|
||||||
&& self.right.is_string(compressor)) {
|
|
||||||
self = make_node(AST_Binary, self, {
|
|
||||||
operator: "+",
|
|
||||||
left: make_node(AST_Binary, self.left, {
|
|
||||||
operator: "+",
|
|
||||||
left: self.left.left,
|
|
||||||
right: make_node(AST_String, self.left.right, {
|
|
||||||
value: "" + self.left.right.value + self.right.left.value,
|
|
||||||
start: self.left.right.start,
|
|
||||||
end: self.right.left.end
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
right: self.right.right
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// a + -b => a - b
|
// a + -b => a - b
|
||||||
if (self.right instanceof AST_UnaryPrefix
|
if (self.right instanceof AST_UnaryPrefix
|
||||||
&& self.right.operator == "-"
|
&& self.right.operator == "-"
|
||||||
@@ -7483,14 +7784,15 @@ merge(Compressor.prototype, {
|
|||||||
associative = compressor.option("unsafe_math");
|
associative = compressor.option("unsafe_math");
|
||||||
// +a - b => a - b
|
// +a - b => a - b
|
||||||
// a - +b => a - b
|
// a - +b => a - b
|
||||||
if (self.operator != "+") {
|
if (self.operator != "+") [ "left", "right" ].forEach(function(operand) {
|
||||||
if (self.left instanceof AST_UnaryPrefix && self.left.operator == "+") {
|
var node = self[operand];
|
||||||
self.left = self.left.expression;
|
if (node instanceof AST_UnaryPrefix && node.operator == "+") {
|
||||||
|
var exp = node.expression;
|
||||||
|
if (exp.is_boolean(compressor) || exp.is_number(compressor) || exp.is_string(compressor)) {
|
||||||
|
self[operand] = exp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (self.right instanceof AST_UnaryPrefix && self.right.operator == "+") {
|
});
|
||||||
self.right = self.right.expression;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "&":
|
case "&":
|
||||||
case "|":
|
case "|":
|
||||||
case "^":
|
case "^":
|
||||||
@@ -7779,9 +8081,11 @@ merge(Compressor.prototype, {
|
|||||||
single_use = false;
|
single_use = false;
|
||||||
} else if (recursive_ref(compressor, def)) {
|
} else if (recursive_ref(compressor, def)) {
|
||||||
single_use = false;
|
single_use = false;
|
||||||
} else if (compressor.option("ie8") && fixed.name && def !== fixed.name.definition()) {
|
} else if (fixed.name && fixed.name.definition() !== def) {
|
||||||
single_use = false;
|
single_use = false;
|
||||||
} else if (def.scope !== self.scope || def.orig[0] instanceof AST_SymbolFunarg) {
|
} else if (fixed.parent_scope !== self.scope
|
||||||
|
|| !(self.scope instanceof AST_Scope)
|
||||||
|
|| def.orig[0] instanceof AST_SymbolFunarg) {
|
||||||
single_use = fixed.is_constant_expression(self.scope);
|
single_use = fixed.is_constant_expression(self.scope);
|
||||||
if (single_use == "f") {
|
if (single_use == "f") {
|
||||||
var scope = self.scope;
|
var scope = self.scope;
|
||||||
@@ -7929,7 +8233,7 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
OPT(AST_Undefined, function(self, compressor) {
|
OPT(AST_Undefined, function(self, compressor) {
|
||||||
if (compressor.option("unsafe_undefined")) {
|
if (compressor.option("unsafe_undefined")) {
|
||||||
var undef = find_variable(compressor, "undefined");
|
var undef = compressor.find_parent(AST_BlockScope).find_variable("undefined");
|
||||||
if (undef) {
|
if (undef) {
|
||||||
var ref = make_node(AST_SymbolRef, self, {
|
var ref = make_node(AST_SymbolRef, self, {
|
||||||
name : "undefined",
|
name : "undefined",
|
||||||
@@ -7955,7 +8259,7 @@ merge(Compressor.prototype, {
|
|||||||
if (lhs && is_atomic(lhs, self)) return self;
|
if (lhs && is_atomic(lhs, self)) return self;
|
||||||
if (compressor.option("keep_infinity")
|
if (compressor.option("keep_infinity")
|
||||||
&& !(lhs && !is_atomic(lhs, self))
|
&& !(lhs && !is_atomic(lhs, self))
|
||||||
&& !find_variable(compressor, "Infinity"))
|
&& !compressor.find_parent(AST_BlockScope).find_variable("Infinity"))
|
||||||
return self;
|
return self;
|
||||||
return make_node(AST_Binary, self, {
|
return make_node(AST_Binary, self, {
|
||||||
operator: "/",
|
operator: "/",
|
||||||
@@ -7971,7 +8275,7 @@ merge(Compressor.prototype, {
|
|||||||
OPT(AST_NaN, function(self, compressor) {
|
OPT(AST_NaN, function(self, compressor) {
|
||||||
var lhs = is_lhs(compressor.self(), compressor.parent());
|
var lhs = is_lhs(compressor.self(), compressor.parent());
|
||||||
if (lhs && !is_atomic(lhs, self)
|
if (lhs && !is_atomic(lhs, self)
|
||||||
|| find_variable(compressor, "NaN")) {
|
|| compressor.find_parent(AST_BlockScope).find_variable("NaN")) {
|
||||||
return make_node(AST_Binary, self, {
|
return make_node(AST_Binary, self, {
|
||||||
operator: "/",
|
operator: "/",
|
||||||
left: make_node(AST_Number, self, {
|
left: make_node(AST_Number, self, {
|
||||||
@@ -8208,35 +8512,26 @@ merge(Compressor.prototype, {
|
|||||||
condition,
|
condition,
|
||||||
consequent
|
consequent
|
||||||
]).optimize(compressor);
|
]).optimize(compressor);
|
||||||
|
// x ? y.p : z.p => (x ? y : z).p
|
||||||
|
// x ? y(a) : z(a) => (x ? y : z)(a)
|
||||||
|
// x ? y.f(a) : z.f(a) => (x ? y : z).f(a)
|
||||||
|
var combined = combine_tail(consequent, alternative, true);
|
||||||
|
if (combined) return combined;
|
||||||
|
// x ? y(a) : y(b) => y(x ? a : b)
|
||||||
|
var arg_index;
|
||||||
if (consequent instanceof AST_Call
|
if (consequent instanceof AST_Call
|
||||||
&& alternative.TYPE === consequent.TYPE
|
&& alternative.TYPE == consequent.TYPE
|
||||||
&& consequent.args.length == alternative.args.length) {
|
&& (arg_index = arg_diff(consequent, alternative)) >= 0
|
||||||
var arg_index = arg_diff();
|
&& consequent.expression.equivalent_to(alternative.expression)
|
||||||
// x ? y(a) : z(a) => (x ? y : z)(a)
|
&& !condition.has_side_effects(compressor)
|
||||||
if (arg_index == -1
|
&& !consequent.expression.has_side_effects(compressor)) {
|
||||||
&& !(consequent.expression instanceof AST_PropAccess)
|
var node = consequent.clone();
|
||||||
&& !(alternative.expression instanceof AST_PropAccess)) {
|
node.args[arg_index] = make_node(AST_Conditional, self, {
|
||||||
var node = consequent.clone();
|
condition: condition,
|
||||||
node.expression = make_node(AST_Conditional, self, {
|
consequent: consequent.args[arg_index],
|
||||||
condition: condition,
|
alternative: alternative.args[arg_index]
|
||||||
consequent: consequent.expression,
|
});
|
||||||
alternative: alternative.expression
|
return node;
|
||||||
});
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
// x ? y(a) : y(b) => y(x ? a : b)
|
|
||||||
if (arg_index >= 0
|
|
||||||
&& consequent.expression.equivalent_to(alternative.expression)
|
|
||||||
&& !condition.has_side_effects(compressor)
|
|
||||||
&& !consequent.expression.has_side_effects(compressor)) {
|
|
||||||
var node = consequent.clone();
|
|
||||||
node.args[arg_index] = make_node(AST_Conditional, self, {
|
|
||||||
condition: condition,
|
|
||||||
consequent: consequent.args[arg_index],
|
|
||||||
alternative: alternative.args[arg_index]
|
|
||||||
});
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// x ? (y ? a : b) : b => x && y ? a : b
|
// x ? (y ? a : b) : b => x && y ? a : b
|
||||||
if (consequent instanceof AST_Conditional
|
if (consequent instanceof AST_Conditional
|
||||||
@@ -8437,10 +8732,12 @@ merge(Compressor.prototype, {
|
|||||||
&& node.expression.value);
|
&& node.expression.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function arg_diff() {
|
function arg_diff(consequent, alternative) {
|
||||||
var a = consequent.args;
|
var a = consequent.args;
|
||||||
var b = alternative.args;
|
var b = alternative.args;
|
||||||
for (var i = 0, len = a.length; i < len; i++) {
|
var len = a.length;
|
||||||
|
if (len != b.length) return -2;
|
||||||
|
for (var i = 0; i < len; i++) {
|
||||||
if (!a[i].equivalent_to(b[i])) {
|
if (!a[i].equivalent_to(b[i])) {
|
||||||
for (var j = i + 1; j < len; j++) {
|
for (var j = i + 1; j < len; j++) {
|
||||||
if (!a[j].equivalent_to(b[j])) return -2;
|
if (!a[j].equivalent_to(b[j])) return -2;
|
||||||
@@ -8451,6 +8748,32 @@ merge(Compressor.prototype, {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function is_tail_equivalent(consequent, alternative) {
|
||||||
|
if (consequent.TYPE != alternative.TYPE) return;
|
||||||
|
if (consequent instanceof AST_Call) {
|
||||||
|
if (arg_diff(consequent, alternative) != -1) return;
|
||||||
|
return consequent.TYPE != "Call"
|
||||||
|
|| !(consequent.expression instanceof AST_PropAccess
|
||||||
|
|| alternative.expression instanceof AST_PropAccess)
|
||||||
|
|| is_tail_equivalent(consequent.expression, alternative.expression);
|
||||||
|
}
|
||||||
|
if (consequent instanceof AST_Dot) return consequent.property == alternative.property;
|
||||||
|
if (consequent instanceof AST_Sub) return consequent.property.equivalent_to(alternative.property);
|
||||||
|
}
|
||||||
|
|
||||||
|
function combine_tail(consequent, alternative, top) {
|
||||||
|
if (!is_tail_equivalent(consequent, alternative)) return !top && make_node(AST_Conditional, self, {
|
||||||
|
condition: condition,
|
||||||
|
consequent: consequent,
|
||||||
|
alternative: alternative
|
||||||
|
});
|
||||||
|
var exp = combine_tail(consequent.expression, alternative.expression);
|
||||||
|
if (!exp) return;
|
||||||
|
var node = consequent.clone();
|
||||||
|
node.expression = exp;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
function can_shift_lhs_of_tail(node) {
|
function can_shift_lhs_of_tail(node) {
|
||||||
return node === node.tail_node() || all(node.expressions.slice(0, -1), function(expr) {
|
return node === node.tail_node() || all(node.expressions.slice(0, -1), function(expr) {
|
||||||
return !expr.has_side_effects(compressor);
|
return !expr.has_side_effects(compressor);
|
||||||
@@ -8717,7 +9040,7 @@ merge(Compressor.prototype, {
|
|||||||
self.expression = make_node(AST_Function, self.expression, {
|
self.expression = make_node(AST_Function, self.expression, {
|
||||||
argnames: [],
|
argnames: [],
|
||||||
body: []
|
body: []
|
||||||
});
|
}).init_scope_vars(exp.scope);
|
||||||
break;
|
break;
|
||||||
case "Number":
|
case "Number":
|
||||||
self.expression = make_node(AST_Number, self.expression, {
|
self.expression = make_node(AST_Number, self.expression, {
|
||||||
|
|||||||
15
lib/parse.js
15
lib/parse.js
@@ -44,11 +44,14 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var KEYWORDS = 'break case catch const continue debugger default delete do else finally for function if in instanceof new return switch throw try typeof var void while with';
|
var KEYWORDS = "break case catch const continue debugger default delete do else finally for function if in instanceof 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 = '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'
|
var RESERVED_WORDS = [
|
||||||
+ " " + KEYWORDS_ATOM + " " + KEYWORDS;
|
"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",
|
||||||
var KEYWORDS_BEFORE_EXPRESSION = 'return new delete throw else case';
|
KEYWORDS_ATOM,
|
||||||
|
KEYWORDS,
|
||||||
|
].join(" ");
|
||||||
|
var KEYWORDS_BEFORE_EXPRESSION = "return new delete throw else case";
|
||||||
|
|
||||||
KEYWORDS = makePredicate(KEYWORDS);
|
KEYWORDS = makePredicate(KEYWORDS);
|
||||||
RESERVED_WORDS = makePredicate(RESERVED_WORDS);
|
RESERVED_WORDS = makePredicate(RESERVED_WORDS);
|
||||||
@@ -438,7 +441,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
|||||||
var skip_multiline_comment = with_eof_error("Unterminated multiline comment", function() {
|
var skip_multiline_comment = with_eof_error("Unterminated multiline comment", function() {
|
||||||
var regex_allowed = S.regex_allowed;
|
var regex_allowed = S.regex_allowed;
|
||||||
var i = find("*/", true);
|
var i = find("*/", true);
|
||||||
var text = S.text.substring(S.pos, i).replace(/\r\n|\r|\u2028|\u2029/g, '\n');
|
var text = S.text.substring(S.pos, i).replace(/\r\n|\r|\u2028|\u2029/g, "\n");
|
||||||
// update stream position
|
// update stream position
|
||||||
forward(text.length /* doesn't count \r\n as 2 char while S.pos - i does */ + 2);
|
forward(text.length /* doesn't count \r\n as 2 char while S.pos - i does */ + 2);
|
||||||
S.comments_before.push(token("comment2", text, true));
|
S.comments_before.push(token("comment2", text, true));
|
||||||
|
|||||||
130
lib/scope.js
130
lib/scope.js
@@ -59,13 +59,9 @@ function SymbolDef(id, scope, orig, init) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SymbolDef.prototype = {
|
SymbolDef.prototype = {
|
||||||
unmangleable: function(options) {
|
forEach: function(fn) {
|
||||||
return this.global && !options.toplevel
|
this.orig.forEach(fn);
|
||||||
|| this.undeclared
|
this.references.forEach(fn);
|
||||||
|| !options.eval && this.scope.pinned()
|
|
||||||
|| options.keep_fnames
|
|
||||||
&& (this.orig[0] instanceof AST_SymbolLambda
|
|
||||||
|| this.orig[0] instanceof AST_SymbolDefun);
|
|
||||||
},
|
},
|
||||||
mangle: function(options) {
|
mangle: function(options) {
|
||||||
var cache = options.cache && options.cache.props;
|
var cache = options.cache && options.cache.props;
|
||||||
@@ -85,7 +81,15 @@ SymbolDef.prototype = {
|
|||||||
},
|
},
|
||||||
redefined: function() {
|
redefined: function() {
|
||||||
return this.defun && this.defun.variables.get(this.name);
|
return this.defun && this.defun.variables.get(this.name);
|
||||||
}
|
},
|
||||||
|
unmangleable: function(options) {
|
||||||
|
return this.global && !options.toplevel
|
||||||
|
|| this.undeclared
|
||||||
|
|| !options.eval && this.scope.pinned()
|
||||||
|
|| options.keep_fnames
|
||||||
|
&& (this.orig[0] instanceof AST_SymbolLambda
|
||||||
|
|| this.orig[0] instanceof AST_SymbolDefun);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||||
@@ -100,22 +104,18 @@ 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_Catch) {
|
if (node instanceof AST_Defun) {
|
||||||
var save_scope = scope;
|
node.name.walk(tw);
|
||||||
scope = new AST_Scope(node);
|
walk_scope(function() {
|
||||||
scope.init_scope_vars(save_scope);
|
node.argnames.forEach(function(argname) {
|
||||||
descend();
|
argname.walk(tw);
|
||||||
scope = save_scope;
|
});
|
||||||
|
walk_body(node, tw);
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Scope) {
|
if (node instanceof AST_BlockScope) {
|
||||||
node.init_scope_vars(scope);
|
walk_scope(descend);
|
||||||
var save_scope = scope;
|
|
||||||
var save_defun = defun;
|
|
||||||
defun = scope = node;
|
|
||||||
descend();
|
|
||||||
scope = save_scope;
|
|
||||||
defun = save_defun;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_With) {
|
if (node instanceof AST_With) {
|
||||||
@@ -129,25 +129,41 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
node.thedef = node;
|
node.thedef = node;
|
||||||
node.references = [];
|
node.references = [];
|
||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolDefun) {
|
if (node instanceof AST_SymbolCatch) {
|
||||||
// This should be defined in the parent scope, as we encounter the
|
scope.def_variable(node).defun = defun;
|
||||||
// AST_Defun node before getting to its AST_Symbol.
|
} else if (node instanceof AST_SymbolDefun) {
|
||||||
(node.scope = defun.parent_scope.resolve()).def_function(node, defun);
|
defun.def_function(node, tw.parent());
|
||||||
|
entangle(defun, scope);
|
||||||
|
} else if (node instanceof AST_SymbolFunarg) {
|
||||||
|
defun.def_variable(node);
|
||||||
|
entangle(defun, scope);
|
||||||
} else if (node instanceof AST_SymbolLambda) {
|
} else if (node instanceof AST_SymbolLambda) {
|
||||||
var def = defun.def_function(node, node.name == "arguments" ? undefined : defun);
|
var def = defun.def_function(node, node.name == "arguments" ? undefined : defun);
|
||||||
if (options.ie8) def.defun = defun.parent_scope.resolve();
|
if (options.ie8) def.defun = defun.parent_scope.resolve();
|
||||||
} else if (node instanceof AST_SymbolVar) {
|
} else if (node instanceof AST_SymbolVar) {
|
||||||
defun.def_variable(node, node.TYPE == "SymbolVar" ? null : undefined);
|
defun.def_variable(node, null);
|
||||||
if (defun !== scope) {
|
entangle(defun, scope);
|
||||||
node.mark_enclosed(options);
|
}
|
||||||
var def = scope.find_variable(node);
|
|
||||||
if (node.thedef !== def) {
|
function walk_scope(descend) {
|
||||||
node.thedef = def;
|
node.init_scope_vars(scope);
|
||||||
}
|
var save_defun = defun;
|
||||||
node.reference(options);
|
var save_scope = scope;
|
||||||
}
|
if (node instanceof AST_Scope) defun = node;
|
||||||
} else if (node instanceof AST_SymbolCatch) {
|
scope = node;
|
||||||
scope.def_variable(node).defun = defun;
|
descend();
|
||||||
|
scope = save_scope;
|
||||||
|
defun = save_defun;
|
||||||
|
}
|
||||||
|
|
||||||
|
function entangle(defun, scope) {
|
||||||
|
if (defun === scope) return;
|
||||||
|
node.mark_enclosed(options);
|
||||||
|
var def = scope.find_variable(node);
|
||||||
|
if (node.thedef === def) return;
|
||||||
|
node.thedef = def;
|
||||||
|
def.orig.push(node);
|
||||||
|
node.mark_enclosed(options);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
self.make_def = function(orig, init) {
|
self.make_def = function(orig, init) {
|
||||||
@@ -234,7 +250,8 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
new_def = scope.def_variable(node);
|
new_def = scope.def_variable(node);
|
||||||
}
|
}
|
||||||
old_def.defun = new_def.scope;
|
old_def.defun = new_def.scope;
|
||||||
old_def.orig.concat(old_def.references).forEach(function(node) {
|
old_def.forEach(function(node) {
|
||||||
|
node.redef = true;
|
||||||
node.thedef = new_def;
|
node.thedef = new_def;
|
||||||
node.reference(options);
|
node.reference(options);
|
||||||
});
|
});
|
||||||
@@ -267,7 +284,7 @@ function init_scope_vars(scope, parent) {
|
|||||||
if (parent) scope.make_def = parent.make_def; // top-level tracking of SymbolDef instances
|
if (parent) scope.make_def = parent.make_def; // top-level tracking of SymbolDef instances
|
||||||
}
|
}
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope) {
|
AST_BlockScope.DEFMETHOD("init_scope_vars", function(parent_scope) {
|
||||||
init_scope_vars(this, parent_scope);
|
init_scope_vars(this, parent_scope);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -279,6 +296,7 @@ AST_Lambda.DEFMETHOD("init_scope_vars", function(parent_scope) {
|
|||||||
start: this.start,
|
start: this.start,
|
||||||
end: this.end,
|
end: this.end,
|
||||||
}));
|
}));
|
||||||
|
return this;
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Symbol.DEFMETHOD("mark_enclosed", function(options) {
|
AST_Symbol.DEFMETHOD("mark_enclosed", function(options) {
|
||||||
@@ -299,20 +317,20 @@ AST_Symbol.DEFMETHOD("reference", function(options) {
|
|||||||
this.mark_enclosed(options);
|
this.mark_enclosed(options);
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("find_variable", function(name) {
|
AST_BlockScope.DEFMETHOD("find_variable", function(name) {
|
||||||
if (name instanceof AST_Symbol) name = name.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_Scope.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 || def.init instanceof AST_Defun) def.init = init;
|
||||||
this.functions.set(symbol.name, def);
|
this.functions.set(symbol.name, def);
|
||||||
return def;
|
return def;
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
|
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);
|
||||||
@@ -325,16 +343,10 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
|
|||||||
return symbol.thedef = def;
|
return symbol.thedef = def;
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Lambda.DEFMETHOD("resolve", return_this);
|
|
||||||
AST_Scope.DEFMETHOD("resolve", function() {
|
|
||||||
return this.parent_scope.resolve();
|
|
||||||
});
|
|
||||||
AST_Toplevel.DEFMETHOD("resolve", return_this);
|
|
||||||
|
|
||||||
function names_in_use(scope, options) {
|
function names_in_use(scope, options) {
|
||||||
var names = scope.names_in_use;
|
var names = scope.names_in_use;
|
||||||
if (!names) {
|
if (!names) {
|
||||||
scope.names_in_use = names = Object.create(scope.mangled_names || null);
|
scope.names_in_use = names = Object.create(null);
|
||||||
scope.cname_holes = [];
|
scope.cname_holes = [];
|
||||||
var cache = options.cache && options.cache.props;
|
var cache = options.cache && options.cache.props;
|
||||||
scope.enclosed.forEach(function(def) {
|
scope.enclosed.forEach(function(def) {
|
||||||
@@ -352,7 +364,7 @@ function next_mangled_name(scope, options, def) {
|
|||||||
var holes = scope.cname_holes;
|
var holes = scope.cname_holes;
|
||||||
var names = Object.create(null);
|
var names = Object.create(null);
|
||||||
var scopes = [ scope ];
|
var scopes = [ scope ];
|
||||||
def.references.forEach(function(sym) {
|
def.forEach(function(sym) {
|
||||||
var scope = sym.scope;
|
var scope = sym.scope;
|
||||||
do {
|
do {
|
||||||
if (scopes.indexOf(scope) < 0) {
|
if (scopes.indexOf(scope) < 0) {
|
||||||
@@ -368,7 +380,7 @@ function next_mangled_name(scope, options, def) {
|
|||||||
name = base54(holes[i]);
|
name = base54(holes[i]);
|
||||||
if (names[name]) continue;
|
if (names[name]) continue;
|
||||||
holes.splice(i, 1);
|
holes.splice(i, 1);
|
||||||
scope.names_in_use[name] = true;
|
in_use[name] = true;
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -377,7 +389,7 @@ function next_mangled_name(scope, options, def) {
|
|||||||
if (!names[name]) break;
|
if (!names[name]) break;
|
||||||
holes.push(scope.cname);
|
holes.push(scope.cname);
|
||||||
}
|
}
|
||||||
scope.names_in_use[name] = true;
|
in_use[name] = true;
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,7 +430,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|||||||
var lname = -1;
|
var lname = -1;
|
||||||
|
|
||||||
if (options.cache && options.cache.props) {
|
if (options.cache && options.cache.props) {
|
||||||
var mangled_names = this.mangled_names = Object.create(null);
|
var mangled_names = names_in_use(this, options);
|
||||||
options.cache.props.each(function(mangled_name) {
|
options.cache.props.each(function(mangled_name) {
|
||||||
mangled_names[mangled_name] = true;
|
mangled_names[mangled_name] = true;
|
||||||
});
|
});
|
||||||
@@ -490,12 +502,11 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|||||||
|
|
||||||
AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) {
|
AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) {
|
||||||
var cache = options.cache && options.cache.props;
|
var cache = options.cache && options.cache.props;
|
||||||
var avoid = Object.create(null);
|
var avoid = Object.create(RESERVED_WORDS);
|
||||||
options.reserved.forEach(to_avoid);
|
options.reserved.forEach(to_avoid);
|
||||||
this.globals.each(add_def);
|
this.globals.each(add_def);
|
||||||
this.walk(new TreeWalker(function(node) {
|
this.walk(new TreeWalker(function(node) {
|
||||||
if (node instanceof AST_Scope) node.variables.each(add_def);
|
if (node instanceof AST_BlockScope) node.variables.each(add_def);
|
||||||
if (node instanceof AST_SymbolCatch) add_def(node.definition());
|
|
||||||
}));
|
}));
|
||||||
return avoid;
|
return avoid;
|
||||||
|
|
||||||
@@ -519,15 +530,14 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
|
|||||||
var cname = 0;
|
var cname = 0;
|
||||||
this.globals.each(rename);
|
this.globals.each(rename);
|
||||||
this.walk(new TreeWalker(function(node) {
|
this.walk(new TreeWalker(function(node) {
|
||||||
if (node instanceof AST_Scope) node.variables.each(rename);
|
if (node instanceof AST_BlockScope) node.variables.each(rename);
|
||||||
if (node instanceof AST_SymbolCatch) rename(node.definition());
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
function next_name() {
|
function next_name() {
|
||||||
var name;
|
var name;
|
||||||
do {
|
do {
|
||||||
name = base54(cname++);
|
name = base54(cname++);
|
||||||
} while (avoid[name] || RESERVED_WORDS[name]);
|
} while (avoid[name]);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -538,7 +548,7 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
|
|||||||
var redef = def.redefined();
|
var redef = def.redefined();
|
||||||
var name = redef ? redef.rename || redef.name : next_name();
|
var name = redef ? redef.rename || redef.name : next_name();
|
||||||
def.rename = name;
|
def.rename = name;
|
||||||
def.orig.concat(def.references).forEach(function(sym) {
|
def.forEach(function(sym) {
|
||||||
if (sym.definition() === def) sym.name = name;
|
if (sym.definition() === def) sym.name = name;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.10.4",
|
"version": "3.11.1",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ asm_mixed: {
|
|||||||
return +sum;
|
return +sum;
|
||||||
}
|
}
|
||||||
function geometricMean(start, end) {
|
function geometricMean(start, end) {
|
||||||
return start |= 0, end |= 0, +exp(logSum(start, end) / (end - start | 0));
|
return start |= 0, end |= 0, +exp(+logSum(start, end) / (end - start | 0));
|
||||||
}
|
}
|
||||||
var exp = stdlib.Math.exp, log = stdlib.Math.log, values = new stdlib.Float64Array(buffer);
|
var exp = stdlib.Math.exp, log = stdlib.Math.log, values = new stdlib.Float64Array(buffer);
|
||||||
return { geometricMean: geometricMean };
|
return { geometricMean: geometricMean };
|
||||||
|
|||||||
@@ -62,18 +62,18 @@ collapse_vars_side_effects_1: {
|
|||||||
expect: {
|
expect: {
|
||||||
function f1() {
|
function f1() {
|
||||||
var s = "abcdef", i = 2;
|
var s = "abcdef", i = 2;
|
||||||
console.log.bind(console)(s.charAt(i++), s.charAt(i++), s.charAt(4), 7);
|
console.log.bind(console)(s.charAt(i++), s.charAt(+i), s.charAt(4), 7);
|
||||||
}
|
}
|
||||||
function f2() {
|
function f2() {
|
||||||
var s = "abcdef", i = 2;
|
var s = "abcdef", i = 2;
|
||||||
console.log.bind(console)(s.charAt(i++), 5, s.charAt(i++), s.charAt(i++), 7);
|
console.log.bind(console)(s.charAt(i++), 5, s.charAt(i++), s.charAt(+i), 7);
|
||||||
}
|
}
|
||||||
function f3() {
|
function f3() {
|
||||||
var s = "abcdef",
|
var s = "abcdef",
|
||||||
i = 2,
|
i = 2,
|
||||||
log = console.log.bind(console),
|
log = console.log.bind(console),
|
||||||
x = s.charAt(i++),
|
x = s.charAt(i++),
|
||||||
y = s.charAt(i++);
|
y = s.charAt(+i);
|
||||||
log(x, s.charAt(4), y, 7);
|
log(x, s.charAt(4), y, 7);
|
||||||
}
|
}
|
||||||
function f4() {
|
function f4() {
|
||||||
@@ -3073,7 +3073,6 @@ issue_2298: {
|
|||||||
expect: {
|
expect: {
|
||||||
!function() {
|
!function() {
|
||||||
(function() {
|
(function() {
|
||||||
0;
|
|
||||||
try {
|
try {
|
||||||
!function(b) {
|
!function(b) {
|
||||||
(void 0)[1] = "foo";
|
(void 0)[1] = "foo";
|
||||||
|
|||||||
@@ -238,6 +238,41 @@ concat_8: {
|
|||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
concat_9: {
|
||||||
|
options = {
|
||||||
|
booleans: true,
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
strings: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "foo";
|
||||||
|
console.log(
|
||||||
|
12 + (34 + a),
|
||||||
|
null + (34 + a),
|
||||||
|
12 + (null + a),
|
||||||
|
false + (34 + a),
|
||||||
|
12 + (false + a),
|
||||||
|
"bar" + (34 + a),
|
||||||
|
12 + ("bar" + a)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "foo";
|
||||||
|
console.log(
|
||||||
|
"1234" + a,
|
||||||
|
"null34" + a,
|
||||||
|
"12null" + a,
|
||||||
|
!1 + (34 + a),
|
||||||
|
12 + (!1 + a),
|
||||||
|
"bar34" + a,
|
||||||
|
"12bar" + a
|
||||||
|
);
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
issue_3689: {
|
issue_3689: {
|
||||||
options = {
|
options = {
|
||||||
strings: true,
|
strings: true,
|
||||||
|
|||||||
@@ -783,6 +783,28 @@ cond_12: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cond_13: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
x ? y(a) : z(a);
|
||||||
|
x ? y.f(a) : z.f(a);
|
||||||
|
x ? y.f(a) : z.g(a);
|
||||||
|
x ? y.f()(a) : z.g()(a);
|
||||||
|
x ? y.f.u(a) : z.g.u(a);
|
||||||
|
x ? y.f().u(a) : z.g().u(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(x ? y : z)(a);
|
||||||
|
(x ? y : z).f(a);
|
||||||
|
x ? y.f(a) : z.g(a);
|
||||||
|
(x ? y.f() : z.g())(a);
|
||||||
|
(x ? y.f : z.g).u(a);
|
||||||
|
(x ? y.f() : z.g()).u(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ternary_boolean_consequent: {
|
ternary_boolean_consequent: {
|
||||||
options = {
|
options = {
|
||||||
booleans: true,
|
booleans: true,
|
||||||
|
|||||||
@@ -1730,7 +1730,7 @@ chained_3: {
|
|||||||
expect: {
|
expect: {
|
||||||
console.log(function(a, b) {
|
console.log(function(a, b) {
|
||||||
var c = b;
|
var c = b;
|
||||||
b++;
|
+b;
|
||||||
return c;
|
return c;
|
||||||
}(0, 2));
|
}(0, 2));
|
||||||
}
|
}
|
||||||
@@ -1997,7 +1997,7 @@ issue_3146_4: {
|
|||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
issue_3192: {
|
issue_3192_1: {
|
||||||
options = {
|
options = {
|
||||||
unused: true,
|
unused: true,
|
||||||
}
|
}
|
||||||
@@ -2025,6 +2025,26 @@ issue_3192: {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_3192_2: {
|
||||||
|
options = {
|
||||||
|
keep_fargs: "strict",
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
(function(a) {
|
||||||
|
console.log(a = "foo", arguments[0]);
|
||||||
|
})("bar");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
(function() {
|
||||||
|
console.log("foo", arguments[0]);
|
||||||
|
})("bar");
|
||||||
|
}
|
||||||
|
expect_stdout: "foo bar"
|
||||||
|
}
|
||||||
|
|
||||||
issue_3233: {
|
issue_3233: {
|
||||||
options = {
|
options = {
|
||||||
pure_getters: "strict",
|
pure_getters: "strict",
|
||||||
@@ -2161,8 +2181,7 @@ issue_3515_1: {
|
|||||||
expect: {
|
expect: {
|
||||||
var c = 0;
|
var c = 0;
|
||||||
(function() {
|
(function() {
|
||||||
this[c++] = 0;
|
for (var key20 in !(this[c++] = 0));
|
||||||
for (var key20 in !0);
|
|
||||||
})();
|
})();
|
||||||
console.log(c);
|
console.log(c);
|
||||||
}
|
}
|
||||||
@@ -2718,7 +2737,7 @@ issue_3962_1: {
|
|||||||
0..toString();
|
0..toString();
|
||||||
} while (0);
|
} while (0);
|
||||||
if (c) console.log("PASS");
|
if (c) console.log("PASS");
|
||||||
}((a--, 1)), 0);
|
}(1), 0);
|
||||||
void 0;
|
void 0;
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
@@ -2751,7 +2770,7 @@ issue_3962_2: {
|
|||||||
0..toString();
|
0..toString();
|
||||||
} while (0);
|
} while (0);
|
||||||
if (c) console.log("PASS");
|
if (c) console.log("PASS");
|
||||||
}((a--, 1)), 0);
|
}(1), 0);
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
@@ -2834,11 +2853,11 @@ issue_4025: {
|
|||||||
console.log(a, b, d);
|
console.log(a, b, d);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var d, c = 0;
|
var c = 0;
|
||||||
try {
|
try {
|
||||||
console.log(c);
|
console.log(c);
|
||||||
} finally {
|
} finally {
|
||||||
d = c + 1;
|
var d = c + 1;
|
||||||
c = 0;
|
c = 0;
|
||||||
}
|
}
|
||||||
console.log(1, 1, d);
|
console.log(1, 1, d);
|
||||||
@@ -2905,3 +2924,102 @@ forin_var_2: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "undefined"
|
expect_stdout: "undefined"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4133: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
merge_vars: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
var b = [ a-- ], c = b && b[c];
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var b = 1;
|
||||||
|
console.log(0);
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4144: {
|
||||||
|
options = {
|
||||||
|
keep_fargs: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function(a, b) {
|
||||||
|
var b = console, c = ++b;
|
||||||
|
})(console.log("PASS"), 0);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function(b) {
|
||||||
|
b = console,
|
||||||
|
++b;
|
||||||
|
})(console.log("PASS"));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4146: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b) {
|
||||||
|
function g() {}
|
||||||
|
var a = g;
|
||||||
|
var c = b;
|
||||||
|
c.p;
|
||||||
|
console.log(typeof a);
|
||||||
|
}
|
||||||
|
f("FAIL", 42);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function(a, b) {
|
||||||
|
a = function () {};
|
||||||
|
var c = b;
|
||||||
|
c.p;
|
||||||
|
console.log(typeof a);
|
||||||
|
})(0, 42);
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
}
|
||||||
|
|
||||||
|
single_use_catch_redefined: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
try {
|
||||||
|
throw 2;
|
||||||
|
} catch (a) {
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(g());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1;
|
||||||
|
try {
|
||||||
|
throw 2;
|
||||||
|
} catch (a) {
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(g());
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|||||||
@@ -2908,3 +2908,109 @@ issue_4077: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4119_1: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
dead_code: true,
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b;
|
||||||
|
b = a = [];
|
||||||
|
a[0] += 0;
|
||||||
|
if (+b + 1) {
|
||||||
|
console.log("FAIL");
|
||||||
|
} else {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a, b;
|
||||||
|
b = a = [];
|
||||||
|
a[0] += 0;
|
||||||
|
+b + 1 ? console.log("FAIL") : console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4119_2: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a;
|
||||||
|
(function(b) {
|
||||||
|
a[0] += 0;
|
||||||
|
console.log(+b + 1 ? "FAIL" : "PASS");
|
||||||
|
})(a = []);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a;
|
||||||
|
(function(b) {
|
||||||
|
a[0] += 0;
|
||||||
|
console.log(+b + 1 ? "FAIL" : "PASS");
|
||||||
|
})(a = []);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4119_3: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b;
|
||||||
|
b = a = {
|
||||||
|
p: 42,
|
||||||
|
};
|
||||||
|
delete a.p;
|
||||||
|
console.log(b.p ? "FAIL" : "PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a, b;
|
||||||
|
b = a = {
|
||||||
|
p: 42,
|
||||||
|
};
|
||||||
|
delete a.p;
|
||||||
|
console.log(b.p ? "FAIL" : "PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4119_4: {
|
||||||
|
options = {
|
||||||
|
booleans: true,
|
||||||
|
conditionals: true,
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b;
|
||||||
|
b = a = {
|
||||||
|
p: 42,
|
||||||
|
};
|
||||||
|
delete a.p;
|
||||||
|
console.log(!b ? "FAIL" : "PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a, b;
|
||||||
|
b = a = {
|
||||||
|
p: 42,
|
||||||
|
};
|
||||||
|
delete a.p;
|
||||||
|
console.log((b, 0, "PASS"));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -2676,7 +2676,7 @@ cross_references_3: {
|
|||||||
};
|
};
|
||||||
return Math.square(n) + Math.cube(n);
|
return Math.square(n) + Math.cube(n);
|
||||||
};
|
};
|
||||||
}(Math)(2));
|
}()(2));
|
||||||
console.log(Math.square(3), Math.cube(3));
|
console.log(Math.square(3), Math.cube(3));
|
||||||
}
|
}
|
||||||
expect_stdout: [
|
expect_stdout: [
|
||||||
@@ -4777,3 +4777,213 @@ issue_4006: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "-1"
|
expect_stdout: "-1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4155: {
|
||||||
|
options = {
|
||||||
|
functions: true,
|
||||||
|
inline: true,
|
||||||
|
merge_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
var a;
|
||||||
|
(function() {
|
||||||
|
console.log(a);
|
||||||
|
})(a);
|
||||||
|
var b = function() {};
|
||||||
|
b && console.log(typeof b);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
void console.log(b);
|
||||||
|
var b = function() {};
|
||||||
|
b && console.log(typeof b);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"undefined",
|
||||||
|
"function",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4159: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 42, c = function(b) {
|
||||||
|
(b = a) && console.log(a++, b);
|
||||||
|
}(c = a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 42;
|
||||||
|
(b = a) && console.log(a++, b);
|
||||||
|
var b;
|
||||||
|
}
|
||||||
|
expect_stdout: "42 42"
|
||||||
|
}
|
||||||
|
|
||||||
|
direct_inline: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b) {
|
||||||
|
function g(c) {
|
||||||
|
return c >> 1;
|
||||||
|
}
|
||||||
|
return g(a) + g(b);
|
||||||
|
}
|
||||||
|
console.log(f(13, 31));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b) {
|
||||||
|
return (a >> 1) + (b >> 1);
|
||||||
|
}
|
||||||
|
console.log(f(13, 31));
|
||||||
|
}
|
||||||
|
expect_stdout: "21"
|
||||||
|
}
|
||||||
|
|
||||||
|
direct_inline_catch_redefined: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
function f() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
throw 2;
|
||||||
|
} catch (a) {
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
console.log(a, f(), g());
|
||||||
|
}
|
||||||
|
console.log(a, f(), g());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1;
|
||||||
|
function f() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
throw 2;
|
||||||
|
} catch (a) {
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
console.log(a, f(), g());
|
||||||
|
}
|
||||||
|
console.log(a, a, g());
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4171_1: {
|
||||||
|
options = {
|
||||||
|
functions: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a) {
|
||||||
|
try {
|
||||||
|
while (a)
|
||||||
|
var e = function() {};
|
||||||
|
} catch (e) {
|
||||||
|
return function() {
|
||||||
|
return e;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}(!console));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
try {
|
||||||
|
while (a)
|
||||||
|
var e = function() {};
|
||||||
|
} catch (e) {
|
||||||
|
return function() {
|
||||||
|
return e;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}(!console));
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4171_2: {
|
||||||
|
options = {
|
||||||
|
functions: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a) {
|
||||||
|
try {
|
||||||
|
while (a);
|
||||||
|
} catch (e) {
|
||||||
|
return function() {
|
||||||
|
return e;
|
||||||
|
};
|
||||||
|
} finally {
|
||||||
|
var e = function() {};
|
||||||
|
}
|
||||||
|
}(!console));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
try {
|
||||||
|
while (a);
|
||||||
|
} catch (e) {
|
||||||
|
return function() {
|
||||||
|
return e;
|
||||||
|
};
|
||||||
|
} finally {
|
||||||
|
function e() {}
|
||||||
|
}
|
||||||
|
}(!console));
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
catch_defun: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
throw 42;
|
||||||
|
} catch (a) {
|
||||||
|
function f() {
|
||||||
|
return typeof a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(f());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
throw 42;
|
||||||
|
} catch (o) {
|
||||||
|
function t() {
|
||||||
|
return typeof o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(t());
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|||||||
@@ -2714,3 +2714,108 @@ issue_2737: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "function"
|
expect_stdout: "function"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
single_use_catch_redefined: {
|
||||||
|
options = {
|
||||||
|
ie8: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
try {
|
||||||
|
throw 2;
|
||||||
|
} catch (a) {
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(g());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1;
|
||||||
|
try {
|
||||||
|
throw 2;
|
||||||
|
} catch (a) {
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(g());
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
single_use_inline_catch_redefined: {
|
||||||
|
options = {
|
||||||
|
ie8: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
try {
|
||||||
|
throw 2;
|
||||||
|
} catch (a) {
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(g());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1;
|
||||||
|
try {
|
||||||
|
throw 2;
|
||||||
|
} catch (a) {
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(g());
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
direct_inline_catch_redefined: {
|
||||||
|
options = {
|
||||||
|
ie8: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
function f() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
throw 2;
|
||||||
|
} catch (a) {
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
console.log(a, f(), g());
|
||||||
|
}
|
||||||
|
console.log(a, f(), g());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1;
|
||||||
|
function f() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
throw 2;
|
||||||
|
} catch (a) {
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
console.log(a, f(), g());
|
||||||
|
}
|
||||||
|
console.log(a, a, g());
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|||||||
@@ -594,3 +594,157 @@ iife_if_return_simple: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nested_if_break: {
|
||||||
|
options = {
|
||||||
|
if_return: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
for (var i = 0; i < 3; i++)
|
||||||
|
L1: if ("number" == typeof i) {
|
||||||
|
if (0 === i) break L1;
|
||||||
|
console.log(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
for (var i = 0; i < 3; i++)
|
||||||
|
L1: if ("number" == typeof i)
|
||||||
|
if (0 !== i) console.log(i);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
nested_if_continue: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
if_return: true,
|
||||||
|
join_vars: true,
|
||||||
|
loops: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(n) {
|
||||||
|
var i = 0;
|
||||||
|
do {
|
||||||
|
if ("number" == typeof n) {
|
||||||
|
if (0 === n) {
|
||||||
|
console.log("even", i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (1 === n) {
|
||||||
|
console.log("odd", i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
} while (0 <= (n -= 2));
|
||||||
|
}
|
||||||
|
f(37);
|
||||||
|
f(42);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(n) {
|
||||||
|
for (var i = 0;
|
||||||
|
"number" == typeof n
|
||||||
|
&& (0 !== n
|
||||||
|
? 1 !== n
|
||||||
|
? i++
|
||||||
|
: console.log("odd", i)
|
||||||
|
: console.log("even", i)),
|
||||||
|
0 <= (n -= 2););
|
||||||
|
}
|
||||||
|
f(37);
|
||||||
|
f(42);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"odd 18",
|
||||||
|
"even 21",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
nested_if_return: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
if_return: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
if (A) {
|
||||||
|
if (B)
|
||||||
|
return B;
|
||||||
|
if (C)
|
||||||
|
return D;
|
||||||
|
if (E)
|
||||||
|
return F;
|
||||||
|
if (G)
|
||||||
|
return H;
|
||||||
|
if (I) {
|
||||||
|
if (J)
|
||||||
|
return K;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (L) {
|
||||||
|
if (M)
|
||||||
|
return;
|
||||||
|
return N;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
if (A)
|
||||||
|
return B || (C ? D : E ? F : G ? H : I ? J ? K : void 0 : L && !M ? N : void 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_866_1: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
if_return: true,
|
||||||
|
sequences: false,
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
if (a)
|
||||||
|
return "";
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a) {
|
||||||
|
if (a)
|
||||||
|
return "";
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_866_2: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
if_return: true,
|
||||||
|
sequences: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
if (a)
|
||||||
|
if (b)
|
||||||
|
c;
|
||||||
|
else
|
||||||
|
return d;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
if (a) {
|
||||||
|
if (!b)
|
||||||
|
return d;
|
||||||
|
c;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ multiple_functions: {
|
|||||||
( function() {
|
( function() {
|
||||||
// NOTE: other compression steps will reduce this
|
// NOTE: other compression steps will reduce this
|
||||||
// down to just `window`.
|
// down to just `window`.
|
||||||
if ( window );
|
if ( !window );
|
||||||
function f() {}
|
function f() {}
|
||||||
function g() {}
|
function g() {}
|
||||||
} )();
|
} )();
|
||||||
@@ -38,7 +38,7 @@ single_function: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
( function() {
|
( function() {
|
||||||
if ( window );
|
if ( !window );
|
||||||
function f() {}
|
function f() {}
|
||||||
} )();
|
} )();
|
||||||
}
|
}
|
||||||
@@ -67,7 +67,7 @@ deeply_nested: {
|
|||||||
// NOTE: other compression steps will reduce this
|
// NOTE: other compression steps will reduce this
|
||||||
// down to just `window`.
|
// down to just `window`.
|
||||||
if ( window )
|
if ( window )
|
||||||
if (document);
|
if ( !document );
|
||||||
function f() {}
|
function f() {}
|
||||||
function g() {}
|
function g() {}
|
||||||
function h() {}
|
function h() {}
|
||||||
|
|||||||
@@ -306,7 +306,6 @@ issue_2298: {
|
|||||||
expect: {
|
expect: {
|
||||||
!function() {
|
!function() {
|
||||||
(function() {
|
(function() {
|
||||||
0;
|
|
||||||
try {
|
try {
|
||||||
!function() {
|
!function() {
|
||||||
(void 0)[1] = "foo";
|
(void 0)[1] = "foo";
|
||||||
|
|||||||
3010
test/compress/merge_vars.js
Normal file
3010
test/compress/merge_vars.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -91,7 +91,7 @@ evaluate_1: {
|
|||||||
expect: {
|
expect: {
|
||||||
console.log(
|
console.log(
|
||||||
x + 1 + 2,
|
x + 1 + 2,
|
||||||
2 * x,
|
2 * +x,
|
||||||
+x + 1 + 2,
|
+x + 1 + 2,
|
||||||
1 + x + 2 + 3,
|
1 + x + 2 + 3,
|
||||||
3 | x,
|
3 | x,
|
||||||
@@ -130,7 +130,7 @@ evaluate_1_unsafe_math: {
|
|||||||
expect: {
|
expect: {
|
||||||
console.log(
|
console.log(
|
||||||
x + 1 + 2,
|
x + 1 + 2,
|
||||||
2 * x,
|
2 * +x,
|
||||||
+x + 3,
|
+x + 3,
|
||||||
1 + x + 2 + 3,
|
1 + x + 2 + 3,
|
||||||
3 | x,
|
3 | x,
|
||||||
@@ -148,45 +148,52 @@ evaluate_1_unsafe_math: {
|
|||||||
evaluate_2: {
|
evaluate_2: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
unsafe_math: false,
|
unsafe_math: false,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var x = "42", y = null;
|
function f(num) {
|
||||||
[
|
var x = "" + num, y = null;
|
||||||
x + 1 + 2,
|
[
|
||||||
x * 1 * 2,
|
x + 1 + 2,
|
||||||
+x + 1 + 2,
|
x * 1 * 2,
|
||||||
1 + x + 2 + 3,
|
+x + 1 + 2,
|
||||||
1 | x | 2 | 3,
|
1 + x + 2 + 3,
|
||||||
1 + x-- + 2 + 3,
|
1 | x | 2 | 3,
|
||||||
1 + (x*y + 2) + 3,
|
1 + x-- + 2 + 3,
|
||||||
1 + (2 + x + 3),
|
1 + (x*y + 2) + 3,
|
||||||
1 + (2 + ~x + 3),
|
1 + (2 + x + 3),
|
||||||
-y + (2 + ~x + 3),
|
1 + (2 + ~x + 3),
|
||||||
1 & (2 & x & 3),
|
-y + (2 + ~x + 3),
|
||||||
1 + (2 + (x |= 0) + 3),
|
1 & (2 & x & 3),
|
||||||
].forEach(function(n) {
|
1 + (2 + (x |= 0) + 3),
|
||||||
console.log(typeof n, n);
|
].forEach(function(n) {
|
||||||
});
|
console.log(typeof n, n);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
f(42);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var x = "42", y = null;
|
function f(num) {
|
||||||
[
|
var x = "" + num, y = null;
|
||||||
x + 1 + 2,
|
[
|
||||||
2 * x,
|
x + "12",
|
||||||
+x + 1 + 2,
|
2 * x,
|
||||||
1 + x + 2 + 3,
|
+x + 1 + 2,
|
||||||
3 | x,
|
1 + x + "23",
|
||||||
1 + x-- + 2 + 3,
|
3 | x,
|
||||||
x*y + 2 + 1 + 3,
|
1 + x-- + 2 + 3,
|
||||||
1 + (2 + x + 3),
|
x*y + 2 + 1 + 3,
|
||||||
2 + ~x + 3 + 1,
|
2 + x + 3 + 1,
|
||||||
2 + ~x + 3 - y,
|
2 + ~x + 3 + 1,
|
||||||
0 & x,
|
2 + ~x + 3,
|
||||||
2 + (x |= 0) + 3 + 1,
|
0 & x,
|
||||||
].forEach(function(n) {
|
2 + (x |= 0) + 3 + 1,
|
||||||
console.log(typeof n, n);
|
].forEach(function(n) {
|
||||||
});
|
console.log(typeof n, n);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
f(42);
|
||||||
}
|
}
|
||||||
expect_stdout: [
|
expect_stdout: [
|
||||||
"string 4212",
|
"string 4212",
|
||||||
@@ -207,45 +214,52 @@ evaluate_2: {
|
|||||||
evaluate_2_unsafe_math: {
|
evaluate_2_unsafe_math: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
unsafe_math: true,
|
unsafe_math: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var x = "42", y = null;
|
function f(num) {
|
||||||
[
|
var x = "" + num, y = null;
|
||||||
x + 1 + 2,
|
[
|
||||||
x * 1 * 2,
|
x + 1 + 2,
|
||||||
+x + 1 + 2,
|
x * 1 * 2,
|
||||||
1 + x + 2 + 3,
|
+x + 1 + 2,
|
||||||
1 | x | 2 | 3,
|
1 + x + 2 + 3,
|
||||||
1 + x-- + 2 + 3,
|
1 | x | 2 | 3,
|
||||||
1 + (x*y + 2) + 3,
|
1 + x-- + 2 + 3,
|
||||||
1 + (2 + x + 3),
|
1 + (x*y + 2) + 3,
|
||||||
1 + (2 + ~x + 3),
|
1 + (2 + x + 3),
|
||||||
-y + (2 + ~x + 3),
|
1 + (2 + ~x + 3),
|
||||||
1 & (2 & x & 3),
|
-y + (2 + ~x + 3),
|
||||||
1 + (2 + (x |= 0) + 3),
|
1 & (2 & x & 3),
|
||||||
].forEach(function(n) {
|
1 + (2 + (x |= 0) + 3),
|
||||||
console.log(typeof n, n);
|
].forEach(function(n) {
|
||||||
});
|
console.log(typeof n, n);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
f(42);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var x = "42", y = null;
|
function f(num) {
|
||||||
[
|
var x = "" + num, y = null;
|
||||||
x + 1 + 2,
|
[
|
||||||
2 * x,
|
x + "12",
|
||||||
+x + 3,
|
2 * x,
|
||||||
1 + x + 2 + 3,
|
+x + 3,
|
||||||
3 | x,
|
1 + x + "23",
|
||||||
6 + x--,
|
3 | x,
|
||||||
x*y + 6,
|
6 + x--,
|
||||||
1 + (2 + x + 3),
|
x*y + 6,
|
||||||
6 + ~x,
|
6 + x,
|
||||||
5 + ~x - y,
|
6 + ~x,
|
||||||
0 & x,
|
5 + ~x,
|
||||||
6 + (x |= 0),
|
0 & x,
|
||||||
].forEach(function(n) {
|
6 + (x |= 0),
|
||||||
console.log(typeof n, n);
|
].forEach(function(n) {
|
||||||
});
|
console.log(typeof n, n);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
f(42);
|
||||||
}
|
}
|
||||||
expect_stdout: [
|
expect_stdout: [
|
||||||
"string 4212",
|
"string 4212",
|
||||||
@@ -310,45 +324,52 @@ evaluate_4: {
|
|||||||
evaluate_5: {
|
evaluate_5: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
unsafe_math: false,
|
unsafe_math: false,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var a = "1";
|
function f(num) {
|
||||||
[
|
var a = "" + num;
|
||||||
+a + 2 + 3,
|
[
|
||||||
+a + 2 - 3,
|
+a + 2 + 3,
|
||||||
+a - 2 + 3,
|
+a + 2 - 3,
|
||||||
+a - 2 - 3,
|
+a - 2 + 3,
|
||||||
2 + +a + 3,
|
+a - 2 - 3,
|
||||||
2 + +a - 3,
|
2 + +a + 3,
|
||||||
2 - +a + 3,
|
2 + +a - 3,
|
||||||
2 - +a - 3,
|
2 - +a + 3,
|
||||||
2 + 3 + +a,
|
2 - +a - 3,
|
||||||
2 + 3 - +a,
|
2 + 3 + +a,
|
||||||
2 - 3 + +a,
|
2 + 3 - +a,
|
||||||
2 - 3 - +a,
|
2 - 3 + +a,
|
||||||
].forEach(function(n) {
|
2 - 3 - +a,
|
||||||
console.log(typeof n, n);
|
].forEach(function(n) {
|
||||||
});
|
console.log(typeof n, n);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
f(1);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var a = "1";
|
function f(num) {
|
||||||
[
|
var a = "" + num;
|
||||||
+a + 2 + 3,
|
[
|
||||||
+a + 2 - 3,
|
+a + 2 + 3,
|
||||||
a - 2 + 3,
|
+a + 2 - 3,
|
||||||
a - 2 - 3,
|
a - 2 + 3,
|
||||||
+a + 2 + 3,
|
a - 2 - 3,
|
||||||
+a + 2 - 3,
|
+a + 2 + 3,
|
||||||
2 - a + 3,
|
+a + 2 - 3,
|
||||||
2 - a - 3,
|
2 - a + 3,
|
||||||
+a + 5,
|
2 - a - 3,
|
||||||
5 - a,
|
+a + 5,
|
||||||
+a - 1,
|
5 - a,
|
||||||
-1 - a,
|
+a - 1,
|
||||||
].forEach(function(n) {
|
-1 - a,
|
||||||
console.log(typeof n, n);
|
].forEach(function(n) {
|
||||||
});
|
console.log(typeof n, n);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
f(1);
|
||||||
}
|
}
|
||||||
expect_stdout: [
|
expect_stdout: [
|
||||||
"number 6",
|
"number 6",
|
||||||
@@ -369,45 +390,52 @@ evaluate_5: {
|
|||||||
evaluate_5_unsafe_math: {
|
evaluate_5_unsafe_math: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
unsafe_math: true,
|
unsafe_math: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var a = "1";
|
function f(num) {
|
||||||
[
|
var a = "" + num;
|
||||||
+a + 2 + 3,
|
[
|
||||||
+a + 2 - 3,
|
+a + 2 + 3,
|
||||||
+a - 2 + 3,
|
+a + 2 - 3,
|
||||||
+a - 2 - 3,
|
+a - 2 + 3,
|
||||||
2 + +a + 3,
|
+a - 2 - 3,
|
||||||
2 + +a - 3,
|
2 + +a + 3,
|
||||||
2 - +a + 3,
|
2 + +a - 3,
|
||||||
2 - +a - 3,
|
2 - +a + 3,
|
||||||
2 + 3 + +a,
|
2 - +a - 3,
|
||||||
2 + 3 - +a,
|
2 + 3 + +a,
|
||||||
2 - 3 + +a,
|
2 + 3 - +a,
|
||||||
2 - 3 - +a,
|
2 - 3 + +a,
|
||||||
].forEach(function(n) {
|
2 - 3 - +a,
|
||||||
console.log(typeof n, n);
|
].forEach(function(n) {
|
||||||
});
|
console.log(typeof n, n);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
f(1);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var a = "1";
|
function f(num) {
|
||||||
[
|
var a = "" + num;
|
||||||
+a + 5,
|
[
|
||||||
+a + -1,
|
+a + 5,
|
||||||
a - -1,
|
+a + -1,
|
||||||
a - 5,
|
a - -1,
|
||||||
+a + 5,
|
a - 5,
|
||||||
+a + -1,
|
+a + 5,
|
||||||
5 - a,
|
+a + -1,
|
||||||
-1 - a,
|
5 - a,
|
||||||
+a + 5,
|
-1 - a,
|
||||||
5 - a,
|
+a + 5,
|
||||||
+a - 1,
|
5 - a,
|
||||||
-1 - a,
|
+a - 1,
|
||||||
].forEach(function(n) {
|
-1 - a,
|
||||||
console.log(typeof n, n);
|
].forEach(function(n) {
|
||||||
});
|
console.log(typeof n, n);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
f(1);
|
||||||
}
|
}
|
||||||
expect_stdout: [
|
expect_stdout: [
|
||||||
"number 6",
|
"number 6",
|
||||||
@@ -546,37 +574,44 @@ evaluate_6_unsafe_math: {
|
|||||||
evaluate_7: {
|
evaluate_7: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
unsafe_math: false,
|
unsafe_math: false,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var x = "42", y;
|
function f(num, y) {
|
||||||
[
|
var x = "" + num;
|
||||||
+x + 2 + (3 + !y),
|
[
|
||||||
+x + 2 + (3 - !y),
|
+x + 2 + (3 + !y),
|
||||||
+x + 2 - (3 + !y),
|
+x + 2 + (3 - !y),
|
||||||
+x + 2 - (3 - !y),
|
+x + 2 - (3 + !y),
|
||||||
+x - 2 + (3 + !y),
|
+x + 2 - (3 - !y),
|
||||||
+x - 2 + (3 - !y),
|
+x - 2 + (3 + !y),
|
||||||
+x - 2 - (3 + !y),
|
+x - 2 + (3 - !y),
|
||||||
+x - 2 - (3 - !y),
|
+x - 2 - (3 + !y),
|
||||||
].forEach(function(n) {
|
+x - 2 - (3 - !y),
|
||||||
console.log(typeof n, n);
|
].forEach(function(n) {
|
||||||
});
|
console.log(typeof n, n);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
f(42);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var x = "42", y;
|
function f(num, y) {
|
||||||
[
|
var x = "" + num;
|
||||||
+x + 2 + (3 + !y),
|
[
|
||||||
+x + 2 + (3 - !y),
|
+x + 2 + (3 + !y),
|
||||||
+x + 2 - (3 + !y),
|
+x + 2 + (3 - !y),
|
||||||
+x + 2 - (3 - !y),
|
+x + 2 - (3 + !y),
|
||||||
x - 2 + (3 + !y),
|
+x + 2 - (3 - !y),
|
||||||
x - 2 + (3 - !y),
|
x - 2 + (3 + !y),
|
||||||
x - 2 - (3 + !y),
|
x - 2 + (3 - !y),
|
||||||
x - 2 - (3 - !y),
|
x - 2 - (3 + !y),
|
||||||
].forEach(function(n) {
|
x - 2 - (3 - !y),
|
||||||
console.log(typeof n, n);
|
].forEach(function(n) {
|
||||||
});
|
console.log(typeof n, n);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
f(42);
|
||||||
}
|
}
|
||||||
expect_stdout: [
|
expect_stdout: [
|
||||||
"number 48",
|
"number 48",
|
||||||
@@ -593,37 +628,44 @@ evaluate_7: {
|
|||||||
evaluate_7_unsafe_math: {
|
evaluate_7_unsafe_math: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
unsafe_math: true,
|
unsafe_math: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var x = "42", y;
|
function f(num, y) {
|
||||||
[
|
var x = "" + num;
|
||||||
+x + 2 + (3 + !y),
|
[
|
||||||
+x + 2 + (3 - !y),
|
+x + 2 + (3 + !y),
|
||||||
+x + 2 - (3 + !y),
|
+x + 2 + (3 - !y),
|
||||||
+x + 2 - (3 - !y),
|
+x + 2 - (3 + !y),
|
||||||
+x - 2 + (3 + !y),
|
+x + 2 - (3 - !y),
|
||||||
+x - 2 + (3 - !y),
|
+x - 2 + (3 + !y),
|
||||||
+x - 2 - (3 + !y),
|
+x - 2 + (3 - !y),
|
||||||
+x - 2 - (3 - !y),
|
+x - 2 - (3 + !y),
|
||||||
].forEach(function(n) {
|
+x - 2 - (3 - !y),
|
||||||
console.log(typeof n, n);
|
].forEach(function(n) {
|
||||||
});
|
console.log(typeof n, n);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
f(42);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var x = "42", y;
|
function f(num, y) {
|
||||||
[
|
var x = "" + num;
|
||||||
+x + 5 + !y,
|
[
|
||||||
+x + 5 - !y,
|
+x + 5 + !y,
|
||||||
+x + -1 - !y,
|
+x + 5 - !y,
|
||||||
+x + -1 + !y,
|
+x + -1 - !y,
|
||||||
x - -1 + !y,
|
+x + -1 + !y,
|
||||||
x - -1 - !y,
|
x - -1 + !y,
|
||||||
x - 5 - !y,
|
x - -1 - !y,
|
||||||
x - 5 + !y,
|
x - 5 - !y,
|
||||||
].forEach(function(n) {
|
x - 5 + !y,
|
||||||
console.log(typeof n, n);
|
].forEach(function(n) {
|
||||||
});
|
console.log(typeof n, n);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
f(42);
|
||||||
}
|
}
|
||||||
expect_stdout: [
|
expect_stdout: [
|
||||||
"number 48",
|
"number 48",
|
||||||
@@ -1267,3 +1309,29 @@ issue_3695: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "NaN"
|
expect_stdout: "NaN"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4137: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(+(A = []) * (A[0] = 1));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(+(A = []) * (A[0] = 1));
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4142: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log("" + +(0 === console));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("" + +(0 === console));
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
}
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ modified: {
|
|||||||
expect: {
|
expect: {
|
||||||
function f0() {
|
function f0() {
|
||||||
var b = 2;
|
var b = 2;
|
||||||
b++;
|
+b;
|
||||||
console.log(2);
|
console.log(2);
|
||||||
console.log(4);
|
console.log(4);
|
||||||
}
|
}
|
||||||
@@ -1624,7 +1624,7 @@ defun_label: {
|
|||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
double_reference: {
|
double_reference_1: {
|
||||||
options = {
|
options = {
|
||||||
reduce_funcs: true,
|
reduce_funcs: true,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
@@ -1638,6 +1638,32 @@ double_reference: {
|
|||||||
g();
|
g();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
var g = function g() {
|
||||||
|
g();
|
||||||
|
};
|
||||||
|
g();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double_reference_2: {
|
||||||
|
options = {
|
||||||
|
functions: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
var g = function g() {
|
||||||
|
g();
|
||||||
|
};
|
||||||
|
g();
|
||||||
|
}
|
||||||
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function f() {
|
function f() {
|
||||||
(function g() {
|
(function g() {
|
||||||
@@ -1647,6 +1673,60 @@ double_reference: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double_reference_3: {
|
||||||
|
options = {
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var x = function f() {
|
||||||
|
return f;
|
||||||
|
};
|
||||||
|
function g() {
|
||||||
|
return x();
|
||||||
|
}
|
||||||
|
console.log(g() === g());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var x = function f() {
|
||||||
|
return f;
|
||||||
|
};
|
||||||
|
function g() {
|
||||||
|
return x();
|
||||||
|
}
|
||||||
|
console.log(g() === g());
|
||||||
|
}
|
||||||
|
expect_stdout: "true"
|
||||||
|
}
|
||||||
|
|
||||||
|
double_reference_4: {
|
||||||
|
options = {
|
||||||
|
comparisons: true,
|
||||||
|
functions: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var x = function f() {
|
||||||
|
return f;
|
||||||
|
};
|
||||||
|
function g() {
|
||||||
|
return x();
|
||||||
|
}
|
||||||
|
console.log(g() === g());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(true);
|
||||||
|
}
|
||||||
|
expect_stdout: "true"
|
||||||
|
}
|
||||||
|
|
||||||
iife_arguments_1: {
|
iife_arguments_1: {
|
||||||
options = {
|
options = {
|
||||||
reduce_funcs: true,
|
reduce_funcs: true,
|
||||||
@@ -1686,8 +1766,35 @@ iife_arguments_2: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
(function() {
|
(function() {
|
||||||
console.log(function f() {
|
var x = function f() {
|
||||||
return f;
|
return f;
|
||||||
|
};
|
||||||
|
console.log(x() === arguments[0]);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
iife_arguments_3: {
|
||||||
|
options = {
|
||||||
|
functions: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
var x = function f() {
|
||||||
|
return f;
|
||||||
|
};
|
||||||
|
console.log(x() === arguments[0]);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
console.log(function x() {
|
||||||
|
return x;
|
||||||
}() === arguments[0]);
|
}() === arguments[0]);
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
@@ -2069,6 +2176,7 @@ issue_1670_6: {
|
|||||||
keep_fargs: false,
|
keep_fargs: false,
|
||||||
reduce_funcs: true,
|
reduce_funcs: true,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
|
sequences: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
switches: true,
|
switches: true,
|
||||||
unused: true,
|
unused: true,
|
||||||
@@ -2086,10 +2194,9 @@ issue_1670_6: {
|
|||||||
})(1);
|
})(1);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
(function(a) {
|
(function() {
|
||||||
a = 1;
|
console.log(1);
|
||||||
console.log(a);
|
})();
|
||||||
})(1);
|
|
||||||
}
|
}
|
||||||
expect_stdout: "1"
|
expect_stdout: "1"
|
||||||
}
|
}
|
||||||
@@ -2308,7 +2415,7 @@ redefine_farg_2: {
|
|||||||
console.log(typeof [], "number",function(a, b) {
|
console.log(typeof [], "number",function(a, b) {
|
||||||
a = b;
|
a = b;
|
||||||
return typeof a;
|
return typeof a;
|
||||||
}([]));
|
}());
|
||||||
}
|
}
|
||||||
expect_stdout: "object number undefined"
|
expect_stdout: "object number undefined"
|
||||||
}
|
}
|
||||||
@@ -5267,11 +5374,11 @@ defun_catch_4: {
|
|||||||
try {
|
try {
|
||||||
throw 42;
|
throw 42;
|
||||||
} catch (a) {
|
} catch (a) {
|
||||||
|
function a() {}
|
||||||
console.log(a);
|
console.log(a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect_stdout: "42"
|
expect_stdout: true
|
||||||
node_version: "<=4"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
defun_catch_5: {
|
defun_catch_5: {
|
||||||
@@ -5293,10 +5400,10 @@ defun_catch_5: {
|
|||||||
throw 42;
|
throw 42;
|
||||||
} catch (a) {
|
} catch (a) {
|
||||||
console.log(a);
|
console.log(a);
|
||||||
|
function a() {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect_stdout: "42"
|
expect_stdout: true
|
||||||
node_version: "<=4"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
defun_catch_6: {
|
defun_catch_6: {
|
||||||
@@ -5483,7 +5590,7 @@ lvalues_def_1: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var b = 1;
|
var b = 1;
|
||||||
var a = b++, b = NaN;
|
var a = +b, b = NaN;
|
||||||
console.log(a, b);
|
console.log(a, b);
|
||||||
}
|
}
|
||||||
expect_stdout: "1 NaN"
|
expect_stdout: "1 NaN"
|
||||||
|
|||||||
@@ -245,6 +245,31 @@ unsafe_builtin_2: {
|
|||||||
expect_stdout: "object PASS PASS"
|
expect_stdout: "object PASS PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe_builtin_3: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {};
|
||||||
|
if (42 < Math.random())
|
||||||
|
o.p = "FAIL";
|
||||||
|
else
|
||||||
|
o.p = "PASS";
|
||||||
|
for (var k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {};
|
||||||
|
o.p = 42 < Math.random() ? "FAIL" : "PASS";
|
||||||
|
for (var k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect_stdout: "p PASS"
|
||||||
|
}
|
||||||
|
|
||||||
unsafe_string_replace: {
|
unsafe_string_replace: {
|
||||||
options = {
|
options = {
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
|
|||||||
@@ -1,11 +1,47 @@
|
|||||||
require("../../tools/exit");
|
|
||||||
|
|
||||||
var get = require("https").get;
|
var get = require("https").get;
|
||||||
var parse = require("url").parse;
|
var parse = require("url").parse;
|
||||||
var base = process.argv[2];
|
|
||||||
var token = process.argv[3];
|
var base, token, run_number, eldest = true;
|
||||||
|
exports.init = function(url, auth, num) {
|
||||||
|
base = url;
|
||||||
|
token = auth;
|
||||||
|
run_number = num;
|
||||||
|
};
|
||||||
|
exports.should_stop = function(callback) {
|
||||||
|
read(base + "/actions/runs?per_page=100", function(reply) {
|
||||||
|
if (!reply || !Array.isArray(reply.workflow_runs)) return;
|
||||||
|
var runs = reply.workflow_runs.filter(function(workflow) {
|
||||||
|
return workflow.status != "completed";
|
||||||
|
}).sort(function(a, b) {
|
||||||
|
return b.run_number - a.run_number;
|
||||||
|
});
|
||||||
|
var found = false, remaining = 20;
|
||||||
|
(function next() {
|
||||||
|
if (!runs.length) return;
|
||||||
|
var workflow = runs.pop();
|
||||||
|
if (workflow.event == "schedule" && workflow.run_number == run_number) found = true;
|
||||||
|
read(workflow.jobs_url, function(reply) {
|
||||||
|
if (!reply || !Array.isArray(reply.jobs)) return;
|
||||||
|
if (!reply.jobs.every(function(job) {
|
||||||
|
if (job.status == "completed") return true;
|
||||||
|
remaining--;
|
||||||
|
return found || workflow.event != "schedule";
|
||||||
|
})) return;
|
||||||
|
if (remaining >= 0) {
|
||||||
|
next();
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
function read(url, callback) {
|
function read(url, callback) {
|
||||||
|
var done = function(reply) {
|
||||||
|
done = function() {};
|
||||||
|
callback(reply);
|
||||||
|
};
|
||||||
var options = parse(url);
|
var options = parse(url);
|
||||||
options.headers = {
|
options.headers = {
|
||||||
"Authorization": "Token " + token,
|
"Authorization": "Token " + token,
|
||||||
@@ -17,33 +53,15 @@ function read(url, callback) {
|
|||||||
response.on("data", function(chunk) {
|
response.on("data", function(chunk) {
|
||||||
chunks.push(chunk);
|
chunks.push(chunk);
|
||||||
}).on("end", function() {
|
}).on("end", function() {
|
||||||
callback(JSON.parse(chunks.join("")));
|
var reply;
|
||||||
|
try {
|
||||||
|
reply = JSON.parse(chunks.join(""))
|
||||||
|
} catch (e) {}
|
||||||
|
done(reply);
|
||||||
|
}).on("error", function() {
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
|
}).on("error", function() {
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var queued = 0, total = 0, earliest, now = Date.now();
|
|
||||||
process.on("beforeExit", function() {
|
|
||||||
if (queued > 3) {
|
|
||||||
process.stdout.write("0");
|
|
||||||
} else if (now - earliest > 0 && total > 1) {
|
|
||||||
process.stdout.write(Math.min(20 * (now - earliest) / (total - 1), 18000000).toFixed(0));
|
|
||||||
} else {
|
|
||||||
process.stdout.write("3600000");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
read(base + "/actions/workflows/ufuzz.yml/runs?event=schedule", function(reply) {
|
|
||||||
reply.workflow_runs.filter(function(workflow) {
|
|
||||||
return /^(in_progress|queued|)$/.test(workflow.status);
|
|
||||||
}).forEach(function(workflow) {
|
|
||||||
read(workflow.jobs_url, function(reply) {
|
|
||||||
reply.jobs.forEach(function(job) {
|
|
||||||
if (job.status == "queued") queued++;
|
|
||||||
total++;
|
|
||||||
if (!job.started_at) return;
|
|
||||||
var start = new Date(job.started_at);
|
|
||||||
if (!(earliest < start)) earliest = start;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -1,39 +1,69 @@
|
|||||||
|
var actions = require("./actions");
|
||||||
var child_process = require("child_process");
|
var child_process = require("child_process");
|
||||||
|
|
||||||
var ping = 5 * 60 * 1000;
|
var args = [
|
||||||
var period = +process.argv[2];
|
"--max-old-space-size=2048",
|
||||||
var endTime = Date.now() + period;
|
"test/ufuzz",
|
||||||
for (var i = 0; i < 2; i++) spawn(endTime);
|
];
|
||||||
|
var iterations;
|
||||||
function spawn(endTime) {
|
switch (process.argv.length) {
|
||||||
var child = child_process.spawn("node", [
|
case 3:
|
||||||
"--max-old-space-size=2048",
|
iterations = +process.argv[2];
|
||||||
"test/ufuzz"
|
args.push(iterations);
|
||||||
], {
|
break;
|
||||||
stdio: [ "ignore", "pipe", "pipe" ]
|
case 5:
|
||||||
}).on("exit", respawn);
|
actions.init(process.argv[2], process.argv[3], +process.argv[4]);
|
||||||
var stdout = "";
|
break;
|
||||||
child.stdout.on("data", function(data) {
|
default:
|
||||||
stdout += data;
|
throw new Error("invalid parameters");
|
||||||
|
}
|
||||||
|
var tasks = [ run(), run() ];
|
||||||
|
if (iterations) return;
|
||||||
|
var alive = setInterval(function() {
|
||||||
|
actions.should_stop(function() {
|
||||||
|
clearInterval(alive);
|
||||||
|
tasks.forEach(function(kill) {
|
||||||
|
kill();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
var stderr = "";
|
}, 8 * 60 * 1000);
|
||||||
child.stderr.on("data", trap).pipe(process.stdout);
|
|
||||||
var keepAlive = setInterval(function() {
|
function run() {
|
||||||
var end = stdout.lastIndexOf("\r");
|
var child, stdout, stderr, log;
|
||||||
console.log(stdout.slice(stdout.lastIndexOf("\r", end - 1) + 1, end));
|
spawn();
|
||||||
stdout = stdout.slice(end + 1);
|
return function() {
|
||||||
}, ping);
|
clearInterval(log);
|
||||||
var timer = setTimeout(function() {
|
|
||||||
clearInterval(keepAlive);
|
|
||||||
child.removeListener("exit", respawn);
|
child.removeListener("exit", respawn);
|
||||||
child.kill();
|
child.kill();
|
||||||
}, endTime - Date.now());
|
};
|
||||||
|
|
||||||
|
function spawn() {
|
||||||
|
child = child_process.spawn("node", args, {
|
||||||
|
stdio: [ "ignore", "pipe", "pipe" ]
|
||||||
|
}).on("exit", respawn);
|
||||||
|
stdout = "";
|
||||||
|
child.stdout.on("data", function(data) {
|
||||||
|
stdout += data;
|
||||||
|
});
|
||||||
|
stderr = "";
|
||||||
|
child.stderr.on("data", trap).pipe(process.stdout);
|
||||||
|
log = setInterval(function() {
|
||||||
|
var end = stdout.lastIndexOf("\r");
|
||||||
|
console.log(stdout.slice(stdout.lastIndexOf("\r", end - 1) + 1, end));
|
||||||
|
stdout = stdout.slice(end + 1);
|
||||||
|
}, 5 * 60 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
function respawn() {
|
function respawn() {
|
||||||
console.log(stdout.replace(/[^\r\n]*\r/g, ""));
|
console.log(stdout.replace(/[^\r\n]*\r/g, ""));
|
||||||
clearInterval(keepAlive);
|
clearInterval(log);
|
||||||
clearTimeout(timer);
|
if (!iterations) {
|
||||||
spawn(endTime);
|
spawn();
|
||||||
|
} else if (process.exitCode) {
|
||||||
|
tasks.forEach(function(kill) {
|
||||||
|
kill();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function trap(data) {
|
function trap(data) {
|
||||||
|
|||||||
Reference in New Issue
Block a user