Compare commits
78 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 | ||
|
|
30761eede5 | ||
|
|
fb30aeccaf | ||
|
|
226aa1f76b | ||
|
|
6e235602fb | ||
|
|
980fcbb56b | ||
|
|
375ebe316d | ||
|
|
2500930234 | ||
|
|
2f0da2ff05 | ||
|
|
83a3cbf151 | ||
|
|
da8d154571 | ||
|
|
e33c727e8b | ||
|
|
f886b3fb2b | ||
|
|
b1cc15e85b | ||
|
|
3aa765e429 | ||
|
|
93d084a1d1 | ||
|
|
c7a3e09407 | ||
|
|
09525c7530 | ||
|
|
a7e15fe73c | ||
|
|
a31c27c7cf | ||
|
|
1caf7c7bd2 | ||
|
|
0eb0c9b388 | ||
|
|
7dc61cdc89 |
9
.github/workflows/ufuzz.yml
vendored
9
.github/workflows/ufuzz.yml
vendored
@@ -6,6 +6,7 @@ on:
|
||||
env:
|
||||
BASE_URL: https://api.github.com/repos/${{ github.repository }}
|
||||
CAUSE: ${{ github.event_name }}
|
||||
RUN_NUM: ${{ github.run_number }}
|
||||
TOKEN: ${{ github.token }}
|
||||
jobs:
|
||||
ufuzz:
|
||||
@@ -36,12 +37,8 @@ jobs:
|
||||
npm config set update-notifier false
|
||||
npm --version
|
||||
while !(npm install); do echo "'npm install' failed - retrying..."; done
|
||||
PERIOD=1800000
|
||||
if [[ $CAUSE == "schedule" ]]; then
|
||||
PERIOD=`node test/ufuzz/actions $BASE_URL $TOKEN`
|
||||
fi
|
||||
if (( $PERIOD == 0 )); then
|
||||
echo "too many jobs in queue - skipping..."
|
||||
node test/ufuzz/job $BASE_URL $TOKEN $RUN_NUM
|
||||
else
|
||||
node test/ufuzz/job $PERIOD
|
||||
node test/ufuzz/job 5000
|
||||
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
|
||||
when we can statically determine the condition.
|
||||
|
||||
- `merge_vars` (default: `true`) -- combine and reuse variables.
|
||||
|
||||
- `negate_iife` (default: `true`) -- negate "Immediately-Called Function Expressions"
|
||||
where the return value is discarded, to avoid the parens that the
|
||||
code generator would insert.
|
||||
|
||||
13
bin/uglifyjs
13
bin/uglifyjs
@@ -342,7 +342,18 @@ function run() {
|
||||
}
|
||||
fatal(ex);
|
||||
} 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) {
|
||||
if (value) switch (key) {
|
||||
case "thedef":
|
||||
|
||||
53
lib/ast.js
53
lib/ast.js
@@ -288,10 +288,13 @@ var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
|
||||
var label = node.label;
|
||||
var def = this.label;
|
||||
node.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_LoopControl && node.label && node.label.thedef === def) {
|
||||
if (node instanceof AST_LoopControl) {
|
||||
if (!node.label || node.label.thedef !== def) return;
|
||||
node.label.thedef = label;
|
||||
label.references.push(node);
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Scope) return true;
|
||||
}));
|
||||
}
|
||||
return node;
|
||||
@@ -409,33 +412,46 @@ var AST_With = DEFNODE("With", "expression", {
|
||||
|
||||
/* -----[ scope and functions ]----- */
|
||||
|
||||
var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent_scope enclosed cname", {
|
||||
var AST_BlockScope = DEFNODE("BlockScope", "enclosed functions make_def parent_scope variables", {
|
||||
$documentation: "Base class for all statements introducing a lexical scope",
|
||||
$propdoc: {
|
||||
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
|
||||
functions: "[Object/S] like `variables`, but only lists function declarations",
|
||||
uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
|
||||
uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`",
|
||||
parent_scope: "[AST_Scope?/S] link to the parent scope",
|
||||
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
|
||||
cname: "[integer/S] current index for mangling variables (used internally by the mangler)",
|
||||
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",
|
||||
},
|
||||
clone: function(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.functions) node.functions = this.functions.clone();
|
||||
if (this.variables) node.variables = this.variables.clone();
|
||||
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() {
|
||||
return this.uses_eval || this.uses_with;
|
||||
},
|
||||
_validate: function() {
|
||||
if (this.parent_scope != null) {
|
||||
if (!(this.parent_scope instanceof AST_Scope)) throw new Error("parent_scope must be AST_Scope");
|
||||
}
|
||||
},
|
||||
}, AST_Block);
|
||||
resolve: return_this,
|
||||
}, AST_BlockScope);
|
||||
|
||||
var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
||||
$documentation: "The toplevel scope",
|
||||
@@ -628,6 +644,9 @@ var AST_Switch = DEFNODE("Switch", "expression", {
|
||||
},
|
||||
_validate: function() {
|
||||
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);
|
||||
|
||||
@@ -697,7 +716,7 @@ var AST_Catch = DEFNODE("Catch", "argname", {
|
||||
_validate: function() {
|
||||
if (!(this.argname instanceof AST_SymbolCatch)) throw new Error("argname must be AST_SymbolCatch");
|
||||
},
|
||||
}, AST_Block);
|
||||
}, AST_BlockScope);
|
||||
|
||||
var AST_Finally = DEFNODE("Finally", null, {
|
||||
$documentation: "A `finally` node; only makes sense as part of a `try` statement"
|
||||
|
||||
982
lib/compress.js
982
lib/compress.js
File diff suppressed because it is too large
Load Diff
379
lib/output.js
379
lib/output.js
@@ -100,7 +100,7 @@ function OutputStream(options) {
|
||||
}
|
||||
}
|
||||
|
||||
var indentation = 0;
|
||||
var indentation = options.indent_start;
|
||||
var current_col = 0;
|
||||
var current_line = 1;
|
||||
var current_pos = 0;
|
||||
@@ -191,10 +191,6 @@ function OutputStream(options) {
|
||||
return name;
|
||||
}
|
||||
|
||||
function make_indent(back) {
|
||||
return repeat_string(" ", options.indent_start + indentation - back * options.indent_level);
|
||||
}
|
||||
|
||||
/* -----[ beautification/minification ]----- */
|
||||
|
||||
var has_parens = false;
|
||||
@@ -345,9 +341,7 @@ function OutputStream(options) {
|
||||
};
|
||||
|
||||
var indent = options.beautify ? function(half) {
|
||||
if (options.beautify) {
|
||||
print(make_indent(half ? 0.5 : 0));
|
||||
}
|
||||
print(repeat_string(" ", half ? indentation - (options.indent_level >> 1) : indentation));
|
||||
} : noop;
|
||||
|
||||
var with_indent = options.beautify ? function(col, cont) {
|
||||
@@ -575,9 +569,9 @@ function OutputStream(options) {
|
||||
get : get,
|
||||
toString : get,
|
||||
indent : indent,
|
||||
indentation : function() { return indentation },
|
||||
current_width : function() { return current_col - indentation },
|
||||
should_break : function() { return options.width && this.current_width() >= options.width },
|
||||
should_break : readonly ? noop : function() {
|
||||
return options.width && current_col - indentation >= options.width;
|
||||
},
|
||||
has_parens : function() { return has_parens },
|
||||
newline : newline,
|
||||
print : print,
|
||||
@@ -630,13 +624,7 @@ function OutputStream(options) {
|
||||
var use_asm = false;
|
||||
|
||||
AST_Node.DEFMETHOD("print", function(stream, force_parens) {
|
||||
var self = this, generator = self._codegen;
|
||||
function doit() {
|
||||
stream.prepend_comments(self);
|
||||
self.add_source_map(stream);
|
||||
generator(self, stream);
|
||||
stream.append_comments(self);
|
||||
}
|
||||
var self = this;
|
||||
stream.push_node(self);
|
||||
if (force_parens || self.needs_parens(stream)) {
|
||||
stream.with_parens(doit);
|
||||
@@ -644,9 +632,14 @@ function OutputStream(options) {
|
||||
doit();
|
||||
}
|
||||
stream.pop_node();
|
||||
});
|
||||
AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
|
||||
|
||||
function doit() {
|
||||
stream.prepend_comments(self);
|
||||
self.add_source_map(stream);
|
||||
self._codegen(stream);
|
||||
stream.append_comments(self);
|
||||
}
|
||||
});
|
||||
AST_Node.DEFMETHOD("print_to_string", function(options) {
|
||||
var s = OutputStream(options);
|
||||
this.print(s);
|
||||
@@ -689,78 +682,66 @@ function OutputStream(options) {
|
||||
|
||||
PARENS(AST_Unary, function(output) {
|
||||
var p = output.parent();
|
||||
return p instanceof AST_PropAccess && p.expression === this
|
||||
|| p instanceof AST_Call && p.expression === this;
|
||||
return (p instanceof AST_Call || p instanceof AST_PropAccess) && p.expression === this;
|
||||
});
|
||||
|
||||
PARENS(AST_Sequence, function(output) {
|
||||
var p = output.parent();
|
||||
// (foo, bar)() or foo(1, (2, 3), 4)
|
||||
return p instanceof AST_Call
|
||||
// !(foo, bar, baz)
|
||||
|| p instanceof AST_Unary
|
||||
// [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
|
||||
return p instanceof AST_Array
|
||||
// 1 + (2, 3) + 4 ==> 8
|
||||
|| p instanceof AST_Binary
|
||||
// var a = (1, 2), b = a + a; ==> b == 4
|
||||
|| p instanceof AST_VarDef
|
||||
// (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|
||||
|| p instanceof AST_PropAccess && p.expression === this
|
||||
// [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
|
||||
|| p instanceof AST_Array
|
||||
// { foo: (1, 2) }.foo ==> 2
|
||||
|| p instanceof AST_ObjectProperty
|
||||
// new (foo, bar) or foo(1, (2, 3), 4)
|
||||
|| p instanceof AST_Call
|
||||
// (false, true) ? (a = 10, b = 20) : (c = 30)
|
||||
// ==> 20 (side effect, set a := 10 and b := 20)
|
||||
|| p instanceof AST_Conditional;
|
||||
|| p instanceof AST_Conditional
|
||||
// { foo: (1, 2) }.foo ==> 2
|
||||
|| p instanceof AST_ObjectProperty
|
||||
// (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|
||||
|| p instanceof AST_PropAccess && p.expression === this
|
||||
// !(foo, bar, baz)
|
||||
|| p instanceof AST_Unary
|
||||
// var a = (1, 2), b = a + a; ==> b == 4
|
||||
|| p instanceof AST_VarDef;
|
||||
});
|
||||
|
||||
PARENS(AST_Binary, function(output) {
|
||||
var p = output.parent();
|
||||
// (foo && bar)()
|
||||
if (p instanceof AST_Call && p.expression === this)
|
||||
return true;
|
||||
// typeof (foo && bar)
|
||||
if (p instanceof AST_Unary)
|
||||
return true;
|
||||
// (foo && bar)["prop"], (foo && bar).prop
|
||||
if (p instanceof AST_PropAccess && p.expression === this)
|
||||
return true;
|
||||
// this deals with precedence: 3 * (2 + 1)
|
||||
if (p instanceof AST_Binary) {
|
||||
var po = p.operator, pp = PRECEDENCE[po];
|
||||
var so = this.operator, sp = PRECEDENCE[so];
|
||||
if (pp > sp
|
||||
|| (pp == sp
|
||||
&& this === p.right)) {
|
||||
return true;
|
||||
}
|
||||
return pp > sp || (pp == sp && this === p.right);
|
||||
}
|
||||
// (foo && bar)()
|
||||
if (p instanceof AST_Call) return p.expression === this;
|
||||
// (foo && bar)["prop"], (foo && bar).prop
|
||||
if (p instanceof AST_PropAccess) return p.expression === this;
|
||||
// typeof (foo && bar)
|
||||
if (p instanceof AST_Unary) return true;
|
||||
});
|
||||
|
||||
PARENS(AST_PropAccess, function(output) {
|
||||
var node = this;
|
||||
var p = output.parent();
|
||||
if (p instanceof AST_New && p.expression === this) {
|
||||
// i.e. new (foo.bar().baz)
|
||||
if (p instanceof AST_New && p.expression === node) {
|
||||
// i.e. new (foo().bar)
|
||||
//
|
||||
// if there's one call into this subtree, then we need
|
||||
// parens around it too, otherwise the call will be
|
||||
// interpreted as passing the arguments to the upper New
|
||||
// expression.
|
||||
var parens = false;
|
||||
this.walk(new TreeWalker(function(node) {
|
||||
if (parens || node instanceof AST_Scope) return true;
|
||||
if (node instanceof AST_Call) {
|
||||
parens = true;
|
||||
return true;
|
||||
}
|
||||
}));
|
||||
return parens;
|
||||
do {
|
||||
node = node.expression;
|
||||
} while (node instanceof AST_PropAccess);
|
||||
return node.TYPE == "Call";
|
||||
}
|
||||
});
|
||||
|
||||
PARENS(AST_Call, function(output) {
|
||||
var p = output.parent();
|
||||
if (p instanceof AST_New && p.expression === this) return true;
|
||||
if (p instanceof AST_New) return p.expression === this;
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=123506
|
||||
if (output.option('webkit')) {
|
||||
var g = output.parent(1);
|
||||
@@ -773,11 +754,12 @@ function OutputStream(options) {
|
||||
});
|
||||
|
||||
PARENS(AST_New, function(output) {
|
||||
if (need_constructor_parens(this, output)) return false;
|
||||
var p = output.parent();
|
||||
if (!need_constructor_parens(this, output)
|
||||
&& (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]()
|
||||
|| p instanceof AST_Call && p.expression === this)) // (new foo)(bar)
|
||||
return true;
|
||||
// (new foo)(bar)
|
||||
if (p instanceof AST_Call) return p.expression === this;
|
||||
// (new Date).getTime(), (new Date)["getTime"]()
|
||||
return p instanceof AST_PropAccess;
|
||||
});
|
||||
|
||||
PARENS(AST_Number, function(output) {
|
||||
@@ -786,36 +768,29 @@ function OutputStream(options) {
|
||||
var value = this.value;
|
||||
// https://github.com/mishoo/UglifyJS/issues/115
|
||||
// https://github.com/mishoo/UglifyJS/pull/1009
|
||||
if (value < 0 || /^0/.test(make_num(value))) {
|
||||
return true;
|
||||
}
|
||||
return value < 0 || /^0/.test(make_num(value));
|
||||
}
|
||||
});
|
||||
|
||||
PARENS([ AST_Assign, AST_Conditional ], function(output) {
|
||||
var p = output.parent();
|
||||
// !(a = false) → true
|
||||
if (p instanceof AST_Unary)
|
||||
return true;
|
||||
// 1 + (a = 2) + 3 → 6, side effect setting a = 2
|
||||
if (p instanceof AST_Binary && !(p instanceof AST_Assign))
|
||||
return true;
|
||||
if (p instanceof AST_Binary) return !(p instanceof AST_Assign);
|
||||
// (a = func)() —or— new (a = Object)()
|
||||
if (p instanceof AST_Call && p.expression === this)
|
||||
return true;
|
||||
if (p instanceof AST_Call) return p.expression === this;
|
||||
// (a = foo) ? bar : baz
|
||||
if (p instanceof AST_Conditional && p.condition === this)
|
||||
return true;
|
||||
if (p instanceof AST_Conditional) return p.condition === this;
|
||||
// (a = foo)["prop"] —or— (a = foo).prop
|
||||
if (p instanceof AST_PropAccess && p.expression === this)
|
||||
return true;
|
||||
if (p instanceof AST_PropAccess) return p.expression === this;
|
||||
// !(a = false) → true
|
||||
if (p instanceof AST_Unary) return true;
|
||||
});
|
||||
|
||||
/* -----[ PRINTERS ]----- */
|
||||
|
||||
DEFPRINT(AST_Directive, function(self, output) {
|
||||
var quote = self.quote;
|
||||
var value = self.value;
|
||||
DEFPRINT(AST_Directive, function(output) {
|
||||
var quote = this.quote;
|
||||
var value = this.value;
|
||||
switch (output.option("quote_style")) {
|
||||
case 0:
|
||||
case 2:
|
||||
@@ -828,7 +803,7 @@ function OutputStream(options) {
|
||||
output.print(quote + value + quote);
|
||||
output.semicolon();
|
||||
});
|
||||
DEFPRINT(AST_Debugger, function(self, output) {
|
||||
DEFPRINT(AST_Debugger, function(output) {
|
||||
output.print("debugger");
|
||||
output.semicolon();
|
||||
});
|
||||
@@ -864,21 +839,21 @@ function OutputStream(options) {
|
||||
force_statement(this.body, output);
|
||||
});
|
||||
|
||||
DEFPRINT(AST_Statement, function(self, output) {
|
||||
self.body.print(output);
|
||||
DEFPRINT(AST_Statement, function(output) {
|
||||
this.body.print(output);
|
||||
output.semicolon();
|
||||
});
|
||||
DEFPRINT(AST_Toplevel, function(self, output) {
|
||||
display_body(self.body, true, output, true);
|
||||
DEFPRINT(AST_Toplevel, function(output) {
|
||||
display_body(this.body, true, output, true);
|
||||
output.print("");
|
||||
});
|
||||
DEFPRINT(AST_LabeledStatement, function(self, output) {
|
||||
self.label.print(output);
|
||||
DEFPRINT(AST_LabeledStatement, function(output) {
|
||||
this.label.print(output);
|
||||
output.colon();
|
||||
self.body.print(output);
|
||||
this.body.print(output);
|
||||
});
|
||||
DEFPRINT(AST_SimpleStatement, function(self, output) {
|
||||
self.body.print(output);
|
||||
DEFPRINT(AST_SimpleStatement, function(output) {
|
||||
this.body.print(output);
|
||||
output.semicolon();
|
||||
});
|
||||
function print_braced_empty(self, output) {
|
||||
@@ -895,13 +870,14 @@ function OutputStream(options) {
|
||||
});
|
||||
} else print_braced_empty(self, output);
|
||||
}
|
||||
DEFPRINT(AST_BlockStatement, function(self, output) {
|
||||
print_braced(self, output);
|
||||
DEFPRINT(AST_BlockStatement, function(output) {
|
||||
print_braced(this, output);
|
||||
});
|
||||
DEFPRINT(AST_EmptyStatement, function(self, output) {
|
||||
DEFPRINT(AST_EmptyStatement, function(output) {
|
||||
output.semicolon();
|
||||
});
|
||||
DEFPRINT(AST_Do, function(self, output) {
|
||||
DEFPRINT(AST_Do, function(output) {
|
||||
var self = this;
|
||||
output.print("do");
|
||||
output.space();
|
||||
make_block(self.body, output);
|
||||
@@ -913,7 +889,8 @@ function OutputStream(options) {
|
||||
});
|
||||
output.semicolon();
|
||||
});
|
||||
DEFPRINT(AST_While, function(self, output) {
|
||||
DEFPRINT(AST_While, function(output) {
|
||||
var self = this;
|
||||
output.print("while");
|
||||
output.space();
|
||||
output.with_parens(function() {
|
||||
@@ -922,7 +899,8 @@ function OutputStream(options) {
|
||||
output.space();
|
||||
self._do_print_body(output);
|
||||
});
|
||||
DEFPRINT(AST_For, function(self, output) {
|
||||
DEFPRINT(AST_For, function(output) {
|
||||
var self = this;
|
||||
output.print("for");
|
||||
output.space();
|
||||
output.with_parens(function() {
|
||||
@@ -951,7 +929,8 @@ function OutputStream(options) {
|
||||
output.space();
|
||||
self._do_print_body(output);
|
||||
});
|
||||
DEFPRINT(AST_ForIn, function(self, output) {
|
||||
DEFPRINT(AST_ForIn, function(output) {
|
||||
var self = this;
|
||||
output.print("for");
|
||||
output.space();
|
||||
output.with_parens(function() {
|
||||
@@ -964,7 +943,8 @@ function OutputStream(options) {
|
||||
output.space();
|
||||
self._do_print_body(output);
|
||||
});
|
||||
DEFPRINT(AST_With, function(self, output) {
|
||||
DEFPRINT(AST_With, function(output) {
|
||||
var self = this;
|
||||
output.print("with");
|
||||
output.space();
|
||||
output.with_parens(function() {
|
||||
@@ -975,7 +955,7 @@ function OutputStream(options) {
|
||||
});
|
||||
|
||||
/* -----[ functions ]----- */
|
||||
AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword) {
|
||||
DEFPRINT(AST_Lambda, function(output, nokeyword) {
|
||||
var self = this;
|
||||
if (!nokeyword) {
|
||||
output.print("function");
|
||||
@@ -993,32 +973,23 @@ function OutputStream(options) {
|
||||
output.space();
|
||||
print_braced(self, output, true);
|
||||
});
|
||||
DEFPRINT(AST_Lambda, function(self, output) {
|
||||
self._do_print(output);
|
||||
});
|
||||
|
||||
/* -----[ jumps ]----- */
|
||||
function print_jump(output, kind, target) {
|
||||
output.print(kind);
|
||||
if (target) {
|
||||
output.space();
|
||||
target.print(output);
|
||||
}
|
||||
output.semicolon();
|
||||
function print_jump(kind, prop) {
|
||||
return function(output) {
|
||||
output.print(kind);
|
||||
var target = this[prop];
|
||||
if (target) {
|
||||
output.space();
|
||||
target.print(output);
|
||||
}
|
||||
output.semicolon();
|
||||
};
|
||||
}
|
||||
|
||||
DEFPRINT(AST_Return, function(self, output) {
|
||||
print_jump(output, "return", self.value);
|
||||
});
|
||||
DEFPRINT(AST_Throw, function(self, output) {
|
||||
print_jump(output, "throw", self.value);
|
||||
});
|
||||
DEFPRINT(AST_Break, function(self, output) {
|
||||
print_jump(output, "break", self.label);
|
||||
});
|
||||
DEFPRINT(AST_Continue, function(self, output) {
|
||||
print_jump(output, "continue", self.label);
|
||||
});
|
||||
DEFPRINT(AST_Return, print_jump("return", "value"));
|
||||
DEFPRINT(AST_Throw, print_jump("throw", "value"));
|
||||
DEFPRINT(AST_Break, print_jump("break", "label"));
|
||||
DEFPRINT(AST_Continue, print_jump("continue", "label"));
|
||||
|
||||
/* -----[ if ]----- */
|
||||
function make_then(self, output) {
|
||||
@@ -1047,7 +1018,8 @@ function OutputStream(options) {
|
||||
}
|
||||
force_statement(self.body, output);
|
||||
}
|
||||
DEFPRINT(AST_If, function(self, output) {
|
||||
DEFPRINT(AST_If, function(output) {
|
||||
var self = this;
|
||||
output.print("if");
|
||||
output.space();
|
||||
output.with_parens(function() {
|
||||
@@ -1069,7 +1041,8 @@ function OutputStream(options) {
|
||||
});
|
||||
|
||||
/* -----[ switch ]----- */
|
||||
DEFPRINT(AST_Switch, function(self, output) {
|
||||
DEFPRINT(AST_Switch, function(output) {
|
||||
var self = this;
|
||||
output.print("switch");
|
||||
output.space();
|
||||
output.with_parens(function() {
|
||||
@@ -1087,28 +1060,30 @@ function OutputStream(options) {
|
||||
});
|
||||
});
|
||||
});
|
||||
AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output) {
|
||||
function print_branch_body(self, output) {
|
||||
output.newline();
|
||||
this.body.forEach(function(stmt) {
|
||||
self.body.forEach(function(stmt) {
|
||||
output.indent();
|
||||
stmt.print(output);
|
||||
output.newline();
|
||||
});
|
||||
});
|
||||
DEFPRINT(AST_Default, function(self, output) {
|
||||
}
|
||||
DEFPRINT(AST_Default, function(output) {
|
||||
output.print("default:");
|
||||
self._do_print_body(output);
|
||||
print_branch_body(this, output);
|
||||
});
|
||||
DEFPRINT(AST_Case, function(self, output) {
|
||||
DEFPRINT(AST_Case, function(output) {
|
||||
var self = this;
|
||||
output.print("case");
|
||||
output.space();
|
||||
self.expression.print(output);
|
||||
output.print(":");
|
||||
self._do_print_body(output);
|
||||
print_branch_body(self, output);
|
||||
});
|
||||
|
||||
/* -----[ exceptions ]----- */
|
||||
DEFPRINT(AST_Try, function(self, output) {
|
||||
DEFPRINT(AST_Try, function(output) {
|
||||
var self = this;
|
||||
output.print("try");
|
||||
output.space();
|
||||
print_braced(self, output);
|
||||
@@ -1121,7 +1096,8 @@ function OutputStream(options) {
|
||||
self.bfinally.print(output);
|
||||
}
|
||||
});
|
||||
DEFPRINT(AST_Catch, function(self, output) {
|
||||
DEFPRINT(AST_Catch, function(output) {
|
||||
var self = this;
|
||||
output.print("catch");
|
||||
output.space();
|
||||
output.with_parens(function() {
|
||||
@@ -1130,13 +1106,14 @@ function OutputStream(options) {
|
||||
output.space();
|
||||
print_braced(self, output);
|
||||
});
|
||||
DEFPRINT(AST_Finally, function(self, output) {
|
||||
DEFPRINT(AST_Finally, function(output) {
|
||||
output.print("finally");
|
||||
output.space();
|
||||
print_braced(self, output);
|
||||
print_braced(this, output);
|
||||
});
|
||||
|
||||
DEFPRINT(AST_Var, function(self, output) {
|
||||
DEFPRINT(AST_Var, function(output) {
|
||||
var self = this;
|
||||
output.print("var");
|
||||
output.space();
|
||||
self.definitions.forEach(function(def, i) {
|
||||
@@ -1161,7 +1138,8 @@ function OutputStream(options) {
|
||||
node.print(output, parens);
|
||||
}
|
||||
|
||||
DEFPRINT(AST_VarDef, function(self, output) {
|
||||
DEFPRINT(AST_VarDef, function(output) {
|
||||
var self = this;
|
||||
self.name.print(output);
|
||||
if (self.value) {
|
||||
output.space();
|
||||
@@ -1185,18 +1163,19 @@ function OutputStream(options) {
|
||||
});
|
||||
});
|
||||
}
|
||||
DEFPRINT(AST_Call, function(self, output) {
|
||||
self.expression.print(output);
|
||||
print_call_args(self, output);
|
||||
DEFPRINT(AST_Call, function(output) {
|
||||
this.expression.print(output);
|
||||
print_call_args(this, output);
|
||||
});
|
||||
DEFPRINT(AST_New, function(self, output) {
|
||||
DEFPRINT(AST_New, function(output) {
|
||||
var self = this;
|
||||
output.print("new");
|
||||
output.space();
|
||||
self.expression.print(output);
|
||||
if (need_constructor_parens(self, output)) print_call_args(self, output);
|
||||
});
|
||||
DEFPRINT(AST_Sequence, function(self, output) {
|
||||
self.expressions.forEach(function(node, index) {
|
||||
DEFPRINT(AST_Sequence, function(output) {
|
||||
this.expressions.forEach(function(node, index) {
|
||||
if (index > 0) {
|
||||
output.comma();
|
||||
if (output.should_break()) {
|
||||
@@ -1207,7 +1186,8 @@ function OutputStream(options) {
|
||||
node.print(output);
|
||||
});
|
||||
});
|
||||
DEFPRINT(AST_Dot, function(self, output) {
|
||||
DEFPRINT(AST_Dot, function(output) {
|
||||
var self = this;
|
||||
var expr = self.expression;
|
||||
expr.print(output);
|
||||
var prop = self.property;
|
||||
@@ -1228,35 +1208,38 @@ function OutputStream(options) {
|
||||
output.print_name(prop);
|
||||
}
|
||||
});
|
||||
DEFPRINT(AST_Sub, function(self, output) {
|
||||
self.expression.print(output);
|
||||
DEFPRINT(AST_Sub, function(output) {
|
||||
this.expression.print(output);
|
||||
output.print("[");
|
||||
self.property.print(output);
|
||||
this.property.print(output);
|
||||
output.print("]");
|
||||
});
|
||||
DEFPRINT(AST_UnaryPrefix, function(self, output) {
|
||||
var op = self.operator;
|
||||
DEFPRINT(AST_UnaryPrefix, function(output) {
|
||||
var op = this.operator;
|
||||
var exp = this.expression;
|
||||
output.print(op);
|
||||
if (/^[a-z]/i.test(op)
|
||||
|| (/[+-]$/.test(op)
|
||||
&& self.expression instanceof AST_UnaryPrefix
|
||||
&& /^[+-]/.test(self.expression.operator))) {
|
||||
&& exp instanceof AST_UnaryPrefix
|
||||
&& /^[+-]/.test(exp.operator))) {
|
||||
output.space();
|
||||
}
|
||||
self.expression.print(output);
|
||||
exp.print(output);
|
||||
});
|
||||
DEFPRINT(AST_UnaryPostfix, function(self, output) {
|
||||
self.expression.print(output);
|
||||
output.print(self.operator);
|
||||
DEFPRINT(AST_UnaryPostfix, function(output) {
|
||||
this.expression.print(output);
|
||||
output.print(this.operator);
|
||||
});
|
||||
DEFPRINT(AST_Binary, function(self, output) {
|
||||
DEFPRINT(AST_Binary, function(output) {
|
||||
var self = this;
|
||||
self.left.print(output);
|
||||
output.space();
|
||||
output.print(self.operator);
|
||||
output.space();
|
||||
self.right.print(output);
|
||||
});
|
||||
DEFPRINT(AST_Conditional, function(self, output) {
|
||||
DEFPRINT(AST_Conditional, function(output) {
|
||||
var self = this;
|
||||
self.condition.print(output);
|
||||
output.space();
|
||||
output.print("?");
|
||||
@@ -1268,10 +1251,10 @@ function OutputStream(options) {
|
||||
});
|
||||
|
||||
/* -----[ literals ]----- */
|
||||
DEFPRINT(AST_Array, function(self, output) {
|
||||
output.with_square(function() {
|
||||
var a = self.elements, len = a.length;
|
||||
if (len > 0) output.space();
|
||||
DEFPRINT(AST_Array, function(output) {
|
||||
var a = this.elements, len = a.length;
|
||||
output.with_square(len > 0 ? function() {
|
||||
output.space();
|
||||
a.forEach(function(exp, i) {
|
||||
if (i) output.comma();
|
||||
exp.print(output);
|
||||
@@ -1281,12 +1264,13 @@ function OutputStream(options) {
|
||||
if (i === len - 1 && exp instanceof AST_Hole)
|
||||
output.comma();
|
||||
});
|
||||
if (len > 0) output.space();
|
||||
});
|
||||
output.space();
|
||||
} : noop);
|
||||
});
|
||||
DEFPRINT(AST_Object, function(self, output) {
|
||||
if (self.properties.length > 0) output.with_block(function() {
|
||||
self.properties.forEach(function(prop, i) {
|
||||
DEFPRINT(AST_Object, function(output) {
|
||||
var props = this.properties;
|
||||
if (props.length > 0) output.with_block(function() {
|
||||
props.forEach(function(prop, i) {
|
||||
if (i) {
|
||||
output.print(",");
|
||||
output.newline();
|
||||
@@ -1296,7 +1280,7 @@ function OutputStream(options) {
|
||||
});
|
||||
output.newline();
|
||||
});
|
||||
else print_braced_empty(self, output);
|
||||
else print_braced_empty(this, output);
|
||||
});
|
||||
|
||||
function print_property_name(key, quote, output) {
|
||||
@@ -1315,47 +1299,48 @@ function OutputStream(options) {
|
||||
}
|
||||
}
|
||||
|
||||
DEFPRINT(AST_ObjectKeyVal, function(self, output) {
|
||||
DEFPRINT(AST_ObjectKeyVal, function(output) {
|
||||
var self = this;
|
||||
print_property_name(self.key, self.quote, output);
|
||||
output.colon();
|
||||
self.value.print(output);
|
||||
});
|
||||
AST_ObjectProperty.DEFMETHOD("_print_getter_setter", function(type, output) {
|
||||
output.print(type);
|
||||
output.space();
|
||||
print_property_name(this.key.name, this.quote, output);
|
||||
this.value._do_print(output, true);
|
||||
});
|
||||
DEFPRINT(AST_ObjectSetter, function(self, output) {
|
||||
self._print_getter_setter("set", output);
|
||||
});
|
||||
DEFPRINT(AST_ObjectGetter, function(self, output) {
|
||||
self._print_getter_setter("get", output);
|
||||
});
|
||||
DEFPRINT(AST_Symbol, function(self, output) {
|
||||
var def = self.definition();
|
||||
output.print_name(def && def.mangled_name || self.name);
|
||||
function print_accessor(type) {
|
||||
return function(output) {
|
||||
var self = this;
|
||||
output.print(type);
|
||||
output.space();
|
||||
print_property_name(self.key.name, self.quote, output);
|
||||
self.value._codegen(output, true);
|
||||
};
|
||||
}
|
||||
DEFPRINT(AST_ObjectGetter, print_accessor("get"));
|
||||
DEFPRINT(AST_ObjectSetter, print_accessor("set"));
|
||||
DEFPRINT(AST_Symbol, function(output) {
|
||||
var def = this.definition();
|
||||
output.print_name(def && def.mangled_name || this.name);
|
||||
});
|
||||
DEFPRINT(AST_Hole, noop);
|
||||
DEFPRINT(AST_This, function(self, output) {
|
||||
DEFPRINT(AST_This, function(output) {
|
||||
output.print("this");
|
||||
});
|
||||
DEFPRINT(AST_Constant, function(self, output) {
|
||||
output.print(self.value);
|
||||
DEFPRINT(AST_Constant, function(output) {
|
||||
output.print(this.value);
|
||||
});
|
||||
DEFPRINT(AST_String, function(self, output) {
|
||||
output.print_string(self.value, self.quote);
|
||||
DEFPRINT(AST_String, function(output) {
|
||||
output.print_string(this.value, this.quote);
|
||||
});
|
||||
DEFPRINT(AST_Number, function(self, output) {
|
||||
if (use_asm && self.start && self.start.raw != null) {
|
||||
output.print(self.start.raw);
|
||||
DEFPRINT(AST_Number, function(output) {
|
||||
var start = this.start;
|
||||
if (use_asm && start && start.raw != null) {
|
||||
output.print(start.raw);
|
||||
} else {
|
||||
output.print(make_num(self.value));
|
||||
output.print(make_num(this.value));
|
||||
}
|
||||
});
|
||||
|
||||
DEFPRINT(AST_RegExp, function(self, output) {
|
||||
var regexp = self.value;
|
||||
DEFPRINT(AST_RegExp, function(output) {
|
||||
var regexp = this.value;
|
||||
var str = regexp.toString();
|
||||
var end = str.lastIndexOf("/");
|
||||
if (regexp.raw_source) {
|
||||
@@ -1389,7 +1374,7 @@ function OutputStream(options) {
|
||||
}
|
||||
}));
|
||||
var p = output.parent();
|
||||
if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self)
|
||||
if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === this)
|
||||
output.print(" ");
|
||||
});
|
||||
|
||||
|
||||
15
lib/parse.js
15
lib/parse.js
@@ -44,11 +44,14 @@
|
||||
|
||||
"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_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'
|
||||
+ " " + KEYWORDS_ATOM + " " + KEYWORDS;
|
||||
var KEYWORDS_BEFORE_EXPRESSION = 'return new delete throw else case';
|
||||
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 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",
|
||||
KEYWORDS_ATOM,
|
||||
KEYWORDS,
|
||||
].join(" ");
|
||||
var KEYWORDS_BEFORE_EXPRESSION = "return new delete throw else case";
|
||||
|
||||
KEYWORDS = makePredicate(KEYWORDS);
|
||||
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 regex_allowed = S.regex_allowed;
|
||||
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
|
||||
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));
|
||||
|
||||
@@ -110,7 +110,6 @@ function mangle_properties(ast, options) {
|
||||
cache: null,
|
||||
debug: false,
|
||||
keep_quoted: false,
|
||||
only_cache: false,
|
||||
regex: null,
|
||||
reserved: null,
|
||||
}, true);
|
||||
@@ -213,7 +212,6 @@ function mangle_properties(ast, options) {
|
||||
|
||||
function can_mangle(name) {
|
||||
if (unmangleable[name]) return false;
|
||||
if (options.only_cache) return cache.has(name);
|
||||
if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
178
lib/scope.js
178
lib/scope.js
@@ -59,13 +59,9 @@ function SymbolDef(id, scope, orig, init) {
|
||||
}
|
||||
|
||||
SymbolDef.prototype = {
|
||||
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);
|
||||
forEach: function(fn) {
|
||||
this.orig.forEach(fn);
|
||||
this.references.forEach(fn);
|
||||
},
|
||||
mangle: function(options) {
|
||||
var cache = options.cache && options.cache.props;
|
||||
@@ -85,7 +81,15 @@ SymbolDef.prototype = {
|
||||
},
|
||||
redefined: function() {
|
||||
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) {
|
||||
@@ -96,25 +100,22 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
|
||||
// pass 1: setup scope chaining and handle definitions
|
||||
var self = this;
|
||||
var scope = self.parent_scope = null;
|
||||
var defun = null;
|
||||
var next_def_id = 0;
|
||||
var scope = self.parent_scope = null;
|
||||
var tw = new TreeWalker(function(node, descend) {
|
||||
if (node instanceof AST_Catch) {
|
||||
var save_scope = scope;
|
||||
scope = new AST_Scope(node);
|
||||
scope.init_scope_vars(save_scope);
|
||||
descend();
|
||||
scope = save_scope;
|
||||
if (node instanceof AST_Defun) {
|
||||
node.name.walk(tw);
|
||||
walk_scope(function() {
|
||||
node.argnames.forEach(function(argname) {
|
||||
argname.walk(tw);
|
||||
});
|
||||
walk_body(node, tw);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Scope) {
|
||||
node.init_scope_vars(scope);
|
||||
var save_scope = scope;
|
||||
var save_defun = defun;
|
||||
defun = scope = node;
|
||||
descend();
|
||||
scope = save_scope;
|
||||
defun = save_defun;
|
||||
if (node instanceof AST_BlockScope) {
|
||||
walk_scope(descend);
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_With) {
|
||||
@@ -128,28 +129,46 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
node.thedef = node;
|
||||
node.references = [];
|
||||
}
|
||||
if (node instanceof AST_SymbolDefun) {
|
||||
// This should be defined in the parent scope, as we encounter the
|
||||
// AST_Defun node before getting to its AST_Symbol.
|
||||
(node.scope = defun.parent_scope.resolve()).def_function(node, defun);
|
||||
if (node instanceof AST_SymbolCatch) {
|
||||
scope.def_variable(node).defun = defun;
|
||||
} else if (node instanceof AST_SymbolDefun) {
|
||||
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) {
|
||||
var def = defun.def_function(node, node.name == "arguments" ? undefined : defun);
|
||||
if (options.ie8) def.defun = defun.parent_scope.resolve();
|
||||
} else if (node instanceof AST_SymbolVar) {
|
||||
defun.def_variable(node, node.TYPE == "SymbolVar" ? null : undefined);
|
||||
if (defun !== scope) {
|
||||
node.mark_enclosed(options);
|
||||
var def = scope.find_variable(node);
|
||||
if (node.thedef !== def) {
|
||||
node.thedef = def;
|
||||
}
|
||||
node.reference(options);
|
||||
}
|
||||
} else if (node instanceof AST_SymbolCatch) {
|
||||
scope.def_variable(node).defun = defun;
|
||||
defun.def_variable(node, null);
|
||||
entangle(defun, scope);
|
||||
}
|
||||
|
||||
function walk_scope(descend) {
|
||||
node.init_scope_vars(scope);
|
||||
var save_defun = defun;
|
||||
var save_scope = scope;
|
||||
if (node instanceof AST_Scope) defun = node;
|
||||
scope = node;
|
||||
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.next_def_id = 0;
|
||||
self.make_def = function(orig, init) {
|
||||
return new SymbolDef(++next_def_id, this, orig, init);
|
||||
};
|
||||
self.walk(tw);
|
||||
|
||||
// pass 2: find back references and eval
|
||||
@@ -231,7 +250,8 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
new_def = scope.def_variable(node);
|
||||
}
|
||||
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.reference(options);
|
||||
});
|
||||
@@ -240,12 +260,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
}
|
||||
});
|
||||
|
||||
AST_Scope.DEFMETHOD("make_def", function(orig, init) {
|
||||
var top = this;
|
||||
while (top.parent_scope) top = top.parent_scope;
|
||||
return new SymbolDef(++top.next_def_id, this, orig, init);
|
||||
});
|
||||
|
||||
AST_Toplevel.DEFMETHOD("def_global", function(node) {
|
||||
var globals = this.globals, name = node.name;
|
||||
if (globals.has(name)) {
|
||||
@@ -259,24 +273,30 @@ AST_Toplevel.DEFMETHOD("def_global", function(node) {
|
||||
}
|
||||
});
|
||||
|
||||
AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope) {
|
||||
this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
|
||||
this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
|
||||
this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
|
||||
this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
|
||||
this.parent_scope = parent_scope; // the parent scope
|
||||
this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes
|
||||
this.cname = -1; // the current index for mangling functions/variables
|
||||
function init_scope_vars(scope, parent) {
|
||||
scope.cname = -1; // the current index for mangling functions/variables
|
||||
scope.enclosed = []; // variables from this or outer scope(s) that are referenced from this or inner scopes
|
||||
scope.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
|
||||
scope.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
|
||||
scope.parent_scope = parent; // the parent scope (null if this is the top level)
|
||||
scope.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
|
||||
scope.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
|
||||
if (parent) scope.make_def = parent.make_def; // top-level tracking of SymbolDef instances
|
||||
}
|
||||
|
||||
AST_BlockScope.DEFMETHOD("init_scope_vars", function(parent_scope) {
|
||||
init_scope_vars(this, parent_scope);
|
||||
});
|
||||
|
||||
AST_Lambda.DEFMETHOD("init_scope_vars", function() {
|
||||
AST_Scope.prototype.init_scope_vars.apply(this, arguments);
|
||||
AST_Lambda.DEFMETHOD("init_scope_vars", function(parent_scope) {
|
||||
init_scope_vars(this, parent_scope);
|
||||
this.uses_arguments = false;
|
||||
this.def_variable(new AST_SymbolFunarg({
|
||||
name: "arguments",
|
||||
start: this.start,
|
||||
end: this.end
|
||||
end: this.end,
|
||||
}));
|
||||
return this;
|
||||
});
|
||||
|
||||
AST_Symbol.DEFMETHOD("mark_enclosed", function(options) {
|
||||
@@ -297,20 +317,20 @@ AST_Symbol.DEFMETHOD("reference", function(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;
|
||||
return this.variables.get(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);
|
||||
if (!def.init || def.init instanceof AST_Defun) def.init = init;
|
||||
this.functions.set(symbol.name, 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);
|
||||
if (def) {
|
||||
def.orig.push(symbol);
|
||||
@@ -323,16 +343,10 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
|
||||
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) {
|
||||
var names = scope.names_in_use;
|
||||
if (!names) {
|
||||
scope.names_in_use = names = Object.create(scope.mangled_names || null);
|
||||
scope.names_in_use = names = Object.create(null);
|
||||
scope.cname_holes = [];
|
||||
var cache = options.cache && options.cache.props;
|
||||
scope.enclosed.forEach(function(def) {
|
||||
@@ -350,7 +364,7 @@ function next_mangled_name(scope, options, def) {
|
||||
var holes = scope.cname_holes;
|
||||
var names = Object.create(null);
|
||||
var scopes = [ scope ];
|
||||
def.references.forEach(function(sym) {
|
||||
def.forEach(function(sym) {
|
||||
var scope = sym.scope;
|
||||
do {
|
||||
if (scopes.indexOf(scope) < 0) {
|
||||
@@ -366,7 +380,7 @@ function next_mangled_name(scope, options, def) {
|
||||
name = base54(holes[i]);
|
||||
if (names[name]) continue;
|
||||
holes.splice(i, 1);
|
||||
scope.names_in_use[name] = true;
|
||||
in_use[name] = true;
|
||||
return name;
|
||||
}
|
||||
while (true) {
|
||||
@@ -375,7 +389,7 @@ function next_mangled_name(scope, options, def) {
|
||||
if (!names[name]) break;
|
||||
holes.push(scope.cname);
|
||||
}
|
||||
scope.names_in_use[name] = true;
|
||||
in_use[name] = true;
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -387,18 +401,10 @@ AST_Symbol.DEFMETHOD("unmangleable", function(options) {
|
||||
// labels are always mangleable
|
||||
AST_Label.DEFMETHOD("unmangleable", return_false);
|
||||
|
||||
AST_Symbol.DEFMETHOD("unreferenced", function() {
|
||||
return !this.definition().references.length && !this.scope.pinned();
|
||||
});
|
||||
|
||||
AST_Symbol.DEFMETHOD("definition", function() {
|
||||
return this.thedef;
|
||||
});
|
||||
|
||||
AST_Symbol.DEFMETHOD("global", function() {
|
||||
return this.definition().global;
|
||||
});
|
||||
|
||||
function _default_mangler_options(options) {
|
||||
options = defaults(options, {
|
||||
eval : false,
|
||||
@@ -424,7 +430,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
||||
var lname = -1;
|
||||
|
||||
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) {
|
||||
mangled_names[mangled_name] = true;
|
||||
});
|
||||
@@ -496,12 +502,11 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
||||
|
||||
AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) {
|
||||
var cache = options.cache && options.cache.props;
|
||||
var avoid = Object.create(null);
|
||||
var avoid = Object.create(RESERVED_WORDS);
|
||||
options.reserved.forEach(to_avoid);
|
||||
this.globals.each(add_def);
|
||||
this.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_Scope) node.variables.each(add_def);
|
||||
if (node instanceof AST_SymbolCatch) add_def(node.definition());
|
||||
if (node instanceof AST_BlockScope) node.variables.each(add_def);
|
||||
}));
|
||||
return avoid;
|
||||
|
||||
@@ -525,15 +530,14 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
|
||||
var cname = 0;
|
||||
this.globals.each(rename);
|
||||
this.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_Scope) node.variables.each(rename);
|
||||
if (node instanceof AST_SymbolCatch) rename(node.definition());
|
||||
if (node instanceof AST_BlockScope) node.variables.each(rename);
|
||||
}));
|
||||
|
||||
function next_name() {
|
||||
var name;
|
||||
do {
|
||||
name = base54(cname++);
|
||||
} while (avoid[name] || RESERVED_WORDS[name]);
|
||||
} while (avoid[name]);
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -544,7 +548,7 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
|
||||
var redef = def.redefined();
|
||||
var name = redef ? redef.rename || redef.name : next_name();
|
||||
def.rename = name;
|
||||
def.orig.concat(def.references).forEach(function(sym) {
|
||||
def.forEach(function(sym) {
|
||||
if (sym.definition() === def) sym.name = name;
|
||||
});
|
||||
}
|
||||
@@ -558,8 +562,8 @@ AST_Sequence.DEFMETHOD("tail_node", function() {
|
||||
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) {
|
||||
options = _default_mangler_options(options);
|
||||
base54.reset();
|
||||
var fn = AST_Symbol.prototype.add_source_map;
|
||||
try {
|
||||
var fn = AST_Symbol.prototype.add_source_map;
|
||||
AST_Symbol.prototype.add_source_map = function() {
|
||||
if (!this.unmangleable(options)) base54.consider(this.name, -1);
|
||||
};
|
||||
|
||||
52
lib/utils.js
52
lib/utils.js
@@ -112,51 +112,29 @@ function return_this() { return this; }
|
||||
function return_null() { return null; }
|
||||
|
||||
var List = (function() {
|
||||
function List(a, f, backwards) {
|
||||
var ret = [], top = [], i;
|
||||
function doit() {
|
||||
function List(a, f) {
|
||||
var ret = [];
|
||||
for (var i = 0; i < a.length; i++) {
|
||||
var val = f(a[i], i);
|
||||
var is_last = val instanceof Last;
|
||||
if (is_last) val = val.v;
|
||||
if (val instanceof AtTop) {
|
||||
val = val.v;
|
||||
if (val instanceof Splice) {
|
||||
top.push.apply(top, backwards ? val.v.slice().reverse() : val.v);
|
||||
} else {
|
||||
top.push(val);
|
||||
}
|
||||
} else if (val !== skip) {
|
||||
if (val instanceof Splice) {
|
||||
ret.push.apply(ret, backwards ? val.v.slice().reverse() : val.v);
|
||||
} else {
|
||||
ret.push(val);
|
||||
}
|
||||
}
|
||||
return is_last;
|
||||
}
|
||||
if (Array.isArray(a)) {
|
||||
if (backwards) {
|
||||
for (i = a.length; --i >= 0;) if (doit()) break;
|
||||
ret.reverse();
|
||||
top.reverse();
|
||||
if (val === skip) continue;
|
||||
if (val instanceof Splice) {
|
||||
ret.push.apply(ret, val.v);
|
||||
} else {
|
||||
for (i = 0; i < a.length; ++i) if (doit()) break;
|
||||
ret.push(val);
|
||||
}
|
||||
} else {
|
||||
for (i in a) if (HOP(a, i)) if (doit()) break;
|
||||
}
|
||||
return top.concat(ret);
|
||||
return ret;
|
||||
}
|
||||
List.is_op = function(val) {
|
||||
return val === skip || val instanceof AtTop || val instanceof Last || val instanceof Splice;
|
||||
return val === skip || val instanceof Splice;
|
||||
};
|
||||
List.splice = function(val) {
|
||||
return new Splice(val);
|
||||
};
|
||||
List.at_top = function(val) { return new AtTop(val); };
|
||||
List.splice = function(val) { return new Splice(val); };
|
||||
List.last = function(val) { return new Last(val); };
|
||||
var skip = List.skip = {};
|
||||
function AtTop(val) { this.v = val; }
|
||||
function Splice(val) { this.v = val; }
|
||||
function Last(val) { this.v = val; }
|
||||
function Splice(val) {
|
||||
this.v = val;
|
||||
}
|
||||
return List;
|
||||
})();
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||
"license": "BSD-2-Clause",
|
||||
"version": "3.10.2",
|
||||
"version": "3.11.1",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
|
||||
@@ -95,7 +95,7 @@ asm_mixed: {
|
||||
return +sum;
|
||||
}
|
||||
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);
|
||||
return { geometricMean: geometricMean };
|
||||
|
||||
@@ -62,18 +62,18 @@ collapse_vars_side_effects_1: {
|
||||
expect: {
|
||||
function f1() {
|
||||
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() {
|
||||
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() {
|
||||
var s = "abcdef",
|
||||
i = 2,
|
||||
log = console.log.bind(console),
|
||||
x = s.charAt(i++),
|
||||
y = s.charAt(i++);
|
||||
y = s.charAt(+i);
|
||||
log(x, s.charAt(4), y, 7);
|
||||
}
|
||||
function f4() {
|
||||
@@ -3073,7 +3073,6 @@ issue_2298: {
|
||||
expect: {
|
||||
!function() {
|
||||
(function() {
|
||||
0;
|
||||
try {
|
||||
!function(b) {
|
||||
(void 0)[1] = "foo";
|
||||
@@ -8538,3 +8537,25 @@ issue_4051: {
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_4070: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function f() {
|
||||
function g() {}
|
||||
g.p++;
|
||||
return f.p = g.p;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function f() {
|
||||
function g() {}
|
||||
return f.p = ++g.p;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "NaN"
|
||||
}
|
||||
|
||||
@@ -238,6 +238,41 @@ concat_8: {
|
||||
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: {
|
||||
options = {
|
||||
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: {
|
||||
options = {
|
||||
booleans: true,
|
||||
|
||||
@@ -1730,7 +1730,7 @@ chained_3: {
|
||||
expect: {
|
||||
console.log(function(a, b) {
|
||||
var c = b;
|
||||
b++;
|
||||
+b;
|
||||
return c;
|
||||
}(0, 2));
|
||||
}
|
||||
@@ -1997,7 +1997,7 @@ issue_3146_4: {
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3192: {
|
||||
issue_3192_1: {
|
||||
options = {
|
||||
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: {
|
||||
options = {
|
||||
pure_getters: "strict",
|
||||
@@ -2161,8 +2181,7 @@ issue_3515_1: {
|
||||
expect: {
|
||||
var c = 0;
|
||||
(function() {
|
||||
this[c++] = 0;
|
||||
for (var key20 in !0);
|
||||
for (var key20 in !(this[c++] = 0));
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
@@ -2718,7 +2737,7 @@ issue_3962_1: {
|
||||
0..toString();
|
||||
} while (0);
|
||||
if (c) console.log("PASS");
|
||||
}((a--, 1)), 0);
|
||||
}(1), 0);
|
||||
void 0;
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
@@ -2751,7 +2770,7 @@ issue_3962_2: {
|
||||
0..toString();
|
||||
} while (0);
|
||||
if (c) console.log("PASS");
|
||||
}((a--, 1)), 0);
|
||||
}(1), 0);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
@@ -2834,11 +2853,11 @@ issue_4025: {
|
||||
console.log(a, b, d);
|
||||
}
|
||||
expect: {
|
||||
var d, c = 0;
|
||||
var c = 0;
|
||||
try {
|
||||
console.log(c);
|
||||
} finally {
|
||||
d = c + 1;
|
||||
var d = c + 1;
|
||||
c = 0;
|
||||
}
|
||||
console.log(1, 1, d);
|
||||
@@ -2848,3 +2867,159 @@ issue_4025: {
|
||||
"1 1 1",
|
||||
]
|
||||
}
|
||||
|
||||
forin_var_1: {
|
||||
options = {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var k;
|
||||
for (k in [ 1, 2 ])
|
||||
console.log(k);
|
||||
for (k in { PASS: 3 })
|
||||
console.log(k);
|
||||
console.log(k);
|
||||
}
|
||||
expect: {
|
||||
for (var k in [ 1, 2 ])
|
||||
console.log(k);
|
||||
for (k in { PASS: 3 })
|
||||
console.log(k);
|
||||
console.log(k);
|
||||
}
|
||||
expect_stdout: [
|
||||
"0",
|
||||
"1",
|
||||
"PASS",
|
||||
"PASS",
|
||||
]
|
||||
}
|
||||
|
||||
forin_var_2: {
|
||||
options = {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
switch (0) {
|
||||
case function() {
|
||||
for (a in 0);
|
||||
}:
|
||||
var b = 0;
|
||||
}
|
||||
for (var c = 0; a;);
|
||||
var a;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
switch (0) {
|
||||
case function() {
|
||||
for (a in 0);
|
||||
}:
|
||||
}
|
||||
for (; a;);
|
||||
var a;
|
||||
}());
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -2869,3 +2869,148 @@ issue_4035: {
|
||||
"true",
|
||||
]
|
||||
}
|
||||
|
||||
issue_4067: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
(function(a) {
|
||||
(function(b) {
|
||||
b[0] += 0;
|
||||
console.log(+a);
|
||||
})(a);
|
||||
})([]);
|
||||
}
|
||||
expect: {
|
||||
(function(a) {
|
||||
(function(b) {
|
||||
b[0] += 0;
|
||||
console.log(+a);
|
||||
})(a);
|
||||
})([]);
|
||||
}
|
||||
expect_stdout: "NaN"
|
||||
}
|
||||
|
||||
issue_4077: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
console.log((a = []) - (a[0]++, 1) || "PASS");
|
||||
}
|
||||
expect: {
|
||||
console.log((a = []) - (a[0]++, 1) || "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"
|
||||
}
|
||||
|
||||
@@ -1483,8 +1483,7 @@ issue_2663_2: {
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
var i;
|
||||
for (i in { a: 1, b: 2, c: 3 })
|
||||
for (var i in { a: 1, b: 2, c: 3 })
|
||||
j = i, console.log(j);
|
||||
var j;
|
||||
})();
|
||||
@@ -2677,7 +2676,7 @@ cross_references_3: {
|
||||
};
|
||||
return Math.square(n) + Math.cube(n);
|
||||
};
|
||||
}(Math)(2));
|
||||
}()(2));
|
||||
console.log(Math.square(3), Math.cube(3));
|
||||
}
|
||||
expect_stdout: [
|
||||
@@ -4778,3 +4777,213 @@ issue_4006: {
|
||||
}
|
||||
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"
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
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() {
|
||||
// NOTE: other compression steps will reduce this
|
||||
// down to just `window`.
|
||||
if ( window );
|
||||
if ( !window );
|
||||
function f() {}
|
||||
function g() {}
|
||||
} )();
|
||||
@@ -38,7 +38,7 @@ single_function: {
|
||||
}
|
||||
expect: {
|
||||
( function() {
|
||||
if ( window );
|
||||
if ( !window );
|
||||
function f() {}
|
||||
} )();
|
||||
}
|
||||
@@ -67,7 +67,7 @@ deeply_nested: {
|
||||
// NOTE: other compression steps will reduce this
|
||||
// down to just `window`.
|
||||
if ( window )
|
||||
if (document);
|
||||
if ( !document );
|
||||
function f() {}
|
||||
function g() {}
|
||||
function h() {}
|
||||
|
||||
@@ -277,8 +277,8 @@ join_object_assignments_forin: {
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
var o = { a: "PASS" };
|
||||
for (var a in o)
|
||||
var o = { a: "PASS" }, a;
|
||||
for (a in o)
|
||||
return o[a];
|
||||
}());
|
||||
}
|
||||
|
||||
@@ -306,7 +306,6 @@ issue_2298: {
|
||||
expect: {
|
||||
!function() {
|
||||
(function() {
|
||||
0;
|
||||
try {
|
||||
!function() {
|
||||
(void 0)[1] = "foo";
|
||||
|
||||
@@ -756,7 +756,37 @@ empty_for_in_side_effects: {
|
||||
expect_warnings: [
|
||||
"WARN: Dropping unused variable b [test/compress/loops.js:4,16]",
|
||||
"INFO: Dropping unused loop variable a [test/compress/loops.js:1,17]",
|
||||
"WARN: Side effects in object of for-in loop [test/compress/loops.js:1,17]",
|
||||
"WARN: Side effects in object of for-in loop [test/compress/loops.js:2,17]",
|
||||
]
|
||||
}
|
||||
|
||||
empty_for_in_prop_init: {
|
||||
options = {
|
||||
loops: true,
|
||||
pure_getters: "strict",
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function f() {
|
||||
var a = "bar";
|
||||
for ((a, f)[a] in console.log("foo"));
|
||||
return a;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
var a = "bar";
|
||||
console.log("foo");
|
||||
return a;
|
||||
}());
|
||||
}
|
||||
expect_stdout: [
|
||||
"foo",
|
||||
"bar",
|
||||
]
|
||||
expect_warnings: [
|
||||
"INFO: Dropping unused loop variable f [test/compress/loops.js:3,21]",
|
||||
"WARN: Side effects in object of for-in loop [test/compress/loops.js:3,30]",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -933,3 +963,128 @@ issue_3634_2: {
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_4075: {
|
||||
options = {
|
||||
loops: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
(function() {
|
||||
for (a in { PASS: 0 });
|
||||
})()
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "FAIL";
|
||||
(function() {
|
||||
for (a in { PASS: 0 });
|
||||
})()
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4082: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
loops: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = "PASS";
|
||||
(function(a) {
|
||||
for (a in "foo")
|
||||
var b;
|
||||
})();
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "PASS";
|
||||
(function(a) {
|
||||
for (a in "foo");
|
||||
})();
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4084: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
loops: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
function f(a) {
|
||||
var b = a++;
|
||||
for (a in "foo");
|
||||
}
|
||||
f();
|
||||
return typeof a;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
(function() {
|
||||
0;
|
||||
})();
|
||||
return typeof a;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_4091_1: {
|
||||
options = {
|
||||
loops: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
throw "FAIL";
|
||||
} catch (e) {
|
||||
for (var e in 42);
|
||||
}
|
||||
console.log(e && e);
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
throw "FAIL";
|
||||
} catch (e) {
|
||||
var e;
|
||||
}
|
||||
console.log(e && e);
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_4091_2: {
|
||||
options = {
|
||||
loops: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
throw "FAIL";
|
||||
} catch (e) {
|
||||
for (e in 42);
|
||||
var e;
|
||||
}
|
||||
console.log(e && e);
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
throw "FAIL";
|
||||
} catch (e) {
|
||||
var e;
|
||||
}
|
||||
console.log(e && e);
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
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: {
|
||||
console.log(
|
||||
x + 1 + 2,
|
||||
2 * x,
|
||||
2 * +x,
|
||||
+x + 1 + 2,
|
||||
1 + x + 2 + 3,
|
||||
3 | x,
|
||||
@@ -130,7 +130,7 @@ evaluate_1_unsafe_math: {
|
||||
expect: {
|
||||
console.log(
|
||||
x + 1 + 2,
|
||||
2 * x,
|
||||
2 * +x,
|
||||
+x + 3,
|
||||
1 + x + 2 + 3,
|
||||
3 | x,
|
||||
@@ -148,45 +148,52 @@ evaluate_1_unsafe_math: {
|
||||
evaluate_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unsafe_math: false,
|
||||
}
|
||||
input: {
|
||||
var x = "42", y = null;
|
||||
[
|
||||
x + 1 + 2,
|
||||
x * 1 * 2,
|
||||
+x + 1 + 2,
|
||||
1 + x + 2 + 3,
|
||||
1 | x | 2 | 3,
|
||||
1 + x-- + 2 + 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 |= 0) + 3),
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
function f(num) {
|
||||
var x = "" + num, y = null;
|
||||
[
|
||||
x + 1 + 2,
|
||||
x * 1 * 2,
|
||||
+x + 1 + 2,
|
||||
1 + x + 2 + 3,
|
||||
1 | x | 2 | 3,
|
||||
1 + x-- + 2 + 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 |= 0) + 3),
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
}
|
||||
f(42);
|
||||
}
|
||||
expect: {
|
||||
var x = "42", y = null;
|
||||
[
|
||||
x + 1 + 2,
|
||||
2 * x,
|
||||
+x + 1 + 2,
|
||||
1 + x + 2 + 3,
|
||||
3 | x,
|
||||
1 + x-- + 2 + 3,
|
||||
x*y + 2 + 1 + 3,
|
||||
1 + (2 + x + 3),
|
||||
2 + ~x + 3 + 1,
|
||||
2 + ~x + 3 - y,
|
||||
0 & x,
|
||||
2 + (x |= 0) + 3 + 1,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
function f(num) {
|
||||
var x = "" + num, y = null;
|
||||
[
|
||||
x + "12",
|
||||
2 * x,
|
||||
+x + 1 + 2,
|
||||
1 + x + "23",
|
||||
3 | x,
|
||||
1 + x-- + 2 + 3,
|
||||
x*y + 2 + 1 + 3,
|
||||
2 + x + 3 + 1,
|
||||
2 + ~x + 3 + 1,
|
||||
2 + ~x + 3,
|
||||
0 & x,
|
||||
2 + (x |= 0) + 3 + 1,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
}
|
||||
f(42);
|
||||
}
|
||||
expect_stdout: [
|
||||
"string 4212",
|
||||
@@ -207,45 +214,52 @@ evaluate_2: {
|
||||
evaluate_2_unsafe_math: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unsafe_math: true,
|
||||
}
|
||||
input: {
|
||||
var x = "42", y = null;
|
||||
[
|
||||
x + 1 + 2,
|
||||
x * 1 * 2,
|
||||
+x + 1 + 2,
|
||||
1 + x + 2 + 3,
|
||||
1 | x | 2 | 3,
|
||||
1 + x-- + 2 + 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 |= 0) + 3),
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
function f(num) {
|
||||
var x = "" + num, y = null;
|
||||
[
|
||||
x + 1 + 2,
|
||||
x * 1 * 2,
|
||||
+x + 1 + 2,
|
||||
1 + x + 2 + 3,
|
||||
1 | x | 2 | 3,
|
||||
1 + x-- + 2 + 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 |= 0) + 3),
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
}
|
||||
f(42);
|
||||
}
|
||||
expect: {
|
||||
var x = "42", y = null;
|
||||
[
|
||||
x + 1 + 2,
|
||||
2 * x,
|
||||
+x + 3,
|
||||
1 + x + 2 + 3,
|
||||
3 | x,
|
||||
6 + x--,
|
||||
x*y + 6,
|
||||
1 + (2 + x + 3),
|
||||
6 + ~x,
|
||||
5 + ~x - y,
|
||||
0 & x,
|
||||
6 + (x |= 0),
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
function f(num) {
|
||||
var x = "" + num, y = null;
|
||||
[
|
||||
x + "12",
|
||||
2 * x,
|
||||
+x + 3,
|
||||
1 + x + "23",
|
||||
3 | x,
|
||||
6 + x--,
|
||||
x*y + 6,
|
||||
6 + x,
|
||||
6 + ~x,
|
||||
5 + ~x,
|
||||
0 & x,
|
||||
6 + (x |= 0),
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
}
|
||||
f(42);
|
||||
}
|
||||
expect_stdout: [
|
||||
"string 4212",
|
||||
@@ -310,45 +324,52 @@ evaluate_4: {
|
||||
evaluate_5: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unsafe_math: false,
|
||||
}
|
||||
input: {
|
||||
var a = "1";
|
||||
[
|
||||
+a + 2 + 3,
|
||||
+a + 2 - 3,
|
||||
+a - 2 + 3,
|
||||
+a - 2 - 3,
|
||||
2 + +a + 3,
|
||||
2 + +a - 3,
|
||||
2 - +a + 3,
|
||||
2 - +a - 3,
|
||||
2 + 3 + +a,
|
||||
2 + 3 - +a,
|
||||
2 - 3 + +a,
|
||||
2 - 3 - +a,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
function f(num) {
|
||||
var a = "" + num;
|
||||
[
|
||||
+a + 2 + 3,
|
||||
+a + 2 - 3,
|
||||
+a - 2 + 3,
|
||||
+a - 2 - 3,
|
||||
2 + +a + 3,
|
||||
2 + +a - 3,
|
||||
2 - +a + 3,
|
||||
2 - +a - 3,
|
||||
2 + 3 + +a,
|
||||
2 + 3 - +a,
|
||||
2 - 3 + +a,
|
||||
2 - 3 - +a,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
}
|
||||
f(1);
|
||||
}
|
||||
expect: {
|
||||
var a = "1";
|
||||
[
|
||||
+a + 2 + 3,
|
||||
+a + 2 - 3,
|
||||
a - 2 + 3,
|
||||
a - 2 - 3,
|
||||
+a + 2 + 3,
|
||||
+a + 2 - 3,
|
||||
2 - a + 3,
|
||||
2 - a - 3,
|
||||
+a + 5,
|
||||
5 - a,
|
||||
+a - 1,
|
||||
-1 - a,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
function f(num) {
|
||||
var a = "" + num;
|
||||
[
|
||||
+a + 2 + 3,
|
||||
+a + 2 - 3,
|
||||
a - 2 + 3,
|
||||
a - 2 - 3,
|
||||
+a + 2 + 3,
|
||||
+a + 2 - 3,
|
||||
2 - a + 3,
|
||||
2 - a - 3,
|
||||
+a + 5,
|
||||
5 - a,
|
||||
+a - 1,
|
||||
-1 - a,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
}
|
||||
f(1);
|
||||
}
|
||||
expect_stdout: [
|
||||
"number 6",
|
||||
@@ -369,45 +390,52 @@ evaluate_5: {
|
||||
evaluate_5_unsafe_math: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unsafe_math: true,
|
||||
}
|
||||
input: {
|
||||
var a = "1";
|
||||
[
|
||||
+a + 2 + 3,
|
||||
+a + 2 - 3,
|
||||
+a - 2 + 3,
|
||||
+a - 2 - 3,
|
||||
2 + +a + 3,
|
||||
2 + +a - 3,
|
||||
2 - +a + 3,
|
||||
2 - +a - 3,
|
||||
2 + 3 + +a,
|
||||
2 + 3 - +a,
|
||||
2 - 3 + +a,
|
||||
2 - 3 - +a,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
function f(num) {
|
||||
var a = "" + num;
|
||||
[
|
||||
+a + 2 + 3,
|
||||
+a + 2 - 3,
|
||||
+a - 2 + 3,
|
||||
+a - 2 - 3,
|
||||
2 + +a + 3,
|
||||
2 + +a - 3,
|
||||
2 - +a + 3,
|
||||
2 - +a - 3,
|
||||
2 + 3 + +a,
|
||||
2 + 3 - +a,
|
||||
2 - 3 + +a,
|
||||
2 - 3 - +a,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
}
|
||||
f(1);
|
||||
}
|
||||
expect: {
|
||||
var a = "1";
|
||||
[
|
||||
+a + 5,
|
||||
+a + -1,
|
||||
a - -1,
|
||||
a - 5,
|
||||
+a + 5,
|
||||
+a + -1,
|
||||
5 - a,
|
||||
-1 - a,
|
||||
+a + 5,
|
||||
5 - a,
|
||||
+a - 1,
|
||||
-1 - a,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
function f(num) {
|
||||
var a = "" + num;
|
||||
[
|
||||
+a + 5,
|
||||
+a + -1,
|
||||
a - -1,
|
||||
a - 5,
|
||||
+a + 5,
|
||||
+a + -1,
|
||||
5 - a,
|
||||
-1 - a,
|
||||
+a + 5,
|
||||
5 - a,
|
||||
+a - 1,
|
||||
-1 - a,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
}
|
||||
f(1);
|
||||
}
|
||||
expect_stdout: [
|
||||
"number 6",
|
||||
@@ -546,37 +574,44 @@ evaluate_6_unsafe_math: {
|
||||
evaluate_7: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unsafe_math: false,
|
||||
}
|
||||
input: {
|
||||
var x = "42", 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) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
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),
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
}
|
||||
f(42);
|
||||
}
|
||||
expect: {
|
||||
var x = "42", 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) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
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),
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
}
|
||||
f(42);
|
||||
}
|
||||
expect_stdout: [
|
||||
"number 48",
|
||||
@@ -593,37 +628,44 @@ evaluate_7: {
|
||||
evaluate_7_unsafe_math: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unsafe_math: true,
|
||||
}
|
||||
input: {
|
||||
var x = "42", 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) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
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),
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
}
|
||||
f(42);
|
||||
}
|
||||
expect: {
|
||||
var x = "42", y;
|
||||
[
|
||||
+x + 5 + !y,
|
||||
+x + 5 - !y,
|
||||
+x + -1 - !y,
|
||||
+x + -1 + !y,
|
||||
x - -1 + !y,
|
||||
x - -1 - !y,
|
||||
x - 5 - !y,
|
||||
x - 5 + !y,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
function f(num, y) {
|
||||
var x = "" + num;
|
||||
[
|
||||
+x + 5 + !y,
|
||||
+x + 5 - !y,
|
||||
+x + -1 - !y,
|
||||
+x + -1 + !y,
|
||||
x - -1 + !y,
|
||||
x - -1 - !y,
|
||||
x - 5 - !y,
|
||||
x - 5 + !y,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
}
|
||||
f(42);
|
||||
}
|
||||
expect_stdout: [
|
||||
"number 48",
|
||||
@@ -637,6 +679,22 @@ evaluate_7_unsafe_math: {
|
||||
]
|
||||
}
|
||||
|
||||
evaluate_8_unsafe_math: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe_math: true,
|
||||
}
|
||||
input: {
|
||||
var a = [ "42" ];
|
||||
console.log(a * (1 / 7));
|
||||
}
|
||||
expect: {
|
||||
var a = [ "42" ];
|
||||
console.log(+a / 7);
|
||||
}
|
||||
expect_stdout: "6"
|
||||
}
|
||||
|
||||
NaN_redefined: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
@@ -1251,3 +1309,29 @@ issue_3695: {
|
||||
}
|
||||
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: {
|
||||
function f0() {
|
||||
var b = 2;
|
||||
b++;
|
||||
+b;
|
||||
console.log(2);
|
||||
console.log(4);
|
||||
}
|
||||
@@ -1624,7 +1624,7 @@ defun_label: {
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
double_reference: {
|
||||
double_reference_1: {
|
||||
options = {
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
@@ -1638,6 +1638,32 @@ double_reference: {
|
||||
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: {
|
||||
function f() {
|
||||
(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: {
|
||||
options = {
|
||||
reduce_funcs: true,
|
||||
@@ -1686,8 +1766,35 @@ iife_arguments_2: {
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
console.log(function f() {
|
||||
var x = function 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]);
|
||||
})();
|
||||
}
|
||||
@@ -2069,6 +2176,7 @@ issue_1670_6: {
|
||||
keep_fargs: false,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
switches: true,
|
||||
unused: true,
|
||||
@@ -2086,10 +2194,9 @@ issue_1670_6: {
|
||||
})(1);
|
||||
}
|
||||
expect: {
|
||||
(function(a) {
|
||||
a = 1;
|
||||
console.log(a);
|
||||
})(1);
|
||||
(function() {
|
||||
console.log(1);
|
||||
})();
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
@@ -2308,7 +2415,7 @@ redefine_farg_2: {
|
||||
console.log(typeof [], "number",function(a, b) {
|
||||
a = b;
|
||||
return typeof a;
|
||||
}([]));
|
||||
}());
|
||||
}
|
||||
expect_stdout: "object number undefined"
|
||||
}
|
||||
@@ -5267,11 +5374,11 @@ defun_catch_4: {
|
||||
try {
|
||||
throw 42;
|
||||
} catch (a) {
|
||||
function a() {}
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect_stdout: "42"
|
||||
node_version: "<=4"
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
defun_catch_5: {
|
||||
@@ -5293,10 +5400,10 @@ defun_catch_5: {
|
||||
throw 42;
|
||||
} catch (a) {
|
||||
console.log(a);
|
||||
function a() {}
|
||||
}
|
||||
}
|
||||
expect_stdout: "42"
|
||||
node_version: "<=4"
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
defun_catch_6: {
|
||||
@@ -5483,7 +5590,7 @@ lvalues_def_1: {
|
||||
}
|
||||
expect: {
|
||||
var b = 1;
|
||||
var a = b++, b = NaN;
|
||||
var a = +b, b = NaN;
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "1 NaN"
|
||||
|
||||
@@ -877,7 +877,7 @@ for_init_var: {
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
forin: {
|
||||
forin_1: {
|
||||
options = {
|
||||
sequences: true,
|
||||
}
|
||||
@@ -895,6 +895,49 @@ forin: {
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
forin_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
p: 1,
|
||||
q: 2,
|
||||
};
|
||||
var k = "k";
|
||||
for ((console.log("exp"), o)[function() {
|
||||
console.log("prop");
|
||||
return k;
|
||||
}()] in function() {
|
||||
console.log("obj");
|
||||
return o;
|
||||
}())
|
||||
console.log(o.k, o[o.k]);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
p: 1,
|
||||
q: 2,
|
||||
};
|
||||
for ((console.log("exp"), o)[console.log("prop"), "k"] in console.log("obj"), o)
|
||||
console.log(o.k, o[o.k]);
|
||||
}
|
||||
expect_stdout: [
|
||||
"obj",
|
||||
"exp",
|
||||
"prop",
|
||||
"p 1",
|
||||
"exp",
|
||||
"prop",
|
||||
"q 2",
|
||||
]
|
||||
}
|
||||
|
||||
call: {
|
||||
options = {
|
||||
sequences: true,
|
||||
@@ -1112,3 +1155,25 @@ issue_3703: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4079: {
|
||||
options = {
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
typeof (0, A);
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
A;
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -245,6 +245,31 @@ unsafe_builtin_2: {
|
||||
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: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
var o = this;
|
||||
|
||||
for (var k in o) L17060: {
|
||||
a++;
|
||||
UNUSED: {
|
||||
console.log(0 - .1 - .1 - .1);
|
||||
}
|
||||
|
||||
var a;
|
||||
|
||||
console.log(k);
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
// (beautified)
|
||||
var o = this;
|
||||
|
||||
for (var k in o) {}
|
||||
|
||||
var a;
|
||||
|
||||
console.log(k);
|
||||
// output: a
|
||||
console.log(0 - 1 - .1 - .1);
|
||||
// output: -1.2000000000000002
|
||||
//
|
||||
// minify: k
|
||||
// minify: -1.2
|
||||
//
|
||||
// options: {
|
||||
// "compress": {
|
||||
// "unsafe_math": true
|
||||
// },
|
||||
// "mangle": false
|
||||
// }
|
||||
@@ -24,6 +24,9 @@ describe("test/reduce.js", function() {
|
||||
});
|
||||
it("Should eliminate unreferenced labels", function() {
|
||||
var result = reduce_test(read("test/input/reduce/label.js"), {
|
||||
compress: {
|
||||
unsafe_math: true,
|
||||
},
|
||||
mangle: false,
|
||||
}, {
|
||||
verbose: false,
|
||||
|
||||
@@ -112,19 +112,18 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
// no structural AST changes before this point.
|
||||
if (node.start._permute >= REPLACEMENTS.length) return;
|
||||
|
||||
if (parent instanceof U.AST_Assign
|
||||
&& parent.left === node
|
||||
|| parent instanceof U.AST_Unary
|
||||
&& parent.expression === node
|
||||
&& ["++", "--", "delete"].indexOf(parent.operator) >= 0) {
|
||||
// ignore lvalues
|
||||
// ignore lvalues
|
||||
if (parent instanceof U.AST_Assign && parent.left === node) return;
|
||||
if (parent instanceof U.AST_Unary && parent.expression === node) switch (parent.operator) {
|
||||
case "++":
|
||||
case "--":
|
||||
case "delete":
|
||||
return;
|
||||
}
|
||||
if ((parent instanceof U.AST_For || parent instanceof U.AST_ForIn)
|
||||
&& parent.init === node && node instanceof U.AST_Var) {
|
||||
// preserve for (var ...)
|
||||
return node;
|
||||
}
|
||||
// preserve for (var xxx; ...)
|
||||
if (parent instanceof U.AST_For && parent.init === node && node instanceof U.AST_Var) return node;
|
||||
// preserve for (xxx in ...)
|
||||
if (parent instanceof U.AST_ForIn && parent.init === node) return node;
|
||||
|
||||
// node specific permutations with no parent logic
|
||||
|
||||
@@ -452,6 +451,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
node.start = JSON.parse(JSON.stringify(node.start));
|
||||
node.start._permute = 0;
|
||||
}));
|
||||
var before_iterations = testcase;
|
||||
for (var c = 0; c < max_iterations; ++c) {
|
||||
if (verbose && pass == 1 && c % 25 == 0) {
|
||||
log("// reduce test pass " + pass + ", iteration " + c + ": " + testcase.length + " bytes");
|
||||
@@ -494,7 +494,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (c == 0) break;
|
||||
if (before_iterations === testcase) break;
|
||||
if (verbose) {
|
||||
log("// reduce test pass " + pass + ": " + testcase.length + " bytes");
|
||||
}
|
||||
@@ -557,7 +557,7 @@ function try_beautify(testcase, minify_options, expected, result_cache, timeout)
|
||||
code: testcase,
|
||||
};
|
||||
} else {
|
||||
var actual = run_code(result.code, toplevel, result_cache, timeout);
|
||||
var actual = run_code(result.code, toplevel, result_cache, timeout).result;
|
||||
if (!sandbox.same_stdout(expected, actual)) return {
|
||||
code: testcase,
|
||||
};
|
||||
@@ -650,7 +650,15 @@ function wrap_with_console_log(node) {
|
||||
|
||||
function run_code(code, toplevel, result_cache, timeout) {
|
||||
var key = crypto.createHash("sha1").update(code).digest("base64");
|
||||
return result_cache[key] || (result_cache[key] = sandbox.run_code(code, toplevel, timeout));
|
||||
var value = result_cache[key];
|
||||
if (!value) {
|
||||
var start = Date.now();
|
||||
result_cache[key] = value = {
|
||||
result: sandbox.run_code(code, toplevel, timeout),
|
||||
elapsed: Date.now() - start,
|
||||
};
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function compare_run_code(code, minify_options, result_cache, max_timeout) {
|
||||
@@ -658,21 +666,19 @@ function compare_run_code(code, minify_options, result_cache, max_timeout) {
|
||||
if (minified.error) return minified;
|
||||
|
||||
var toplevel = sandbox.has_toplevel(minify_options);
|
||||
var elapsed = Date.now();
|
||||
var unminified_result = run_code(code, toplevel, result_cache, max_timeout);
|
||||
elapsed = Date.now() - elapsed;
|
||||
var timeout = Math.min(100 * elapsed, max_timeout);
|
||||
var minified_result = run_code(minified.code, toplevel, result_cache, timeout);
|
||||
var unminified = run_code(code, toplevel, result_cache, max_timeout);
|
||||
var timeout = Math.min(100 * unminified.elapsed, max_timeout);
|
||||
var minified_result = run_code(minified.code, toplevel, result_cache, timeout).result;
|
||||
|
||||
if (sandbox.same_stdout(unminified_result, minified_result)) {
|
||||
return is_timed_out(unminified_result) && is_timed_out(minified_result) && {
|
||||
if (sandbox.same_stdout(unminified.result, minified_result)) {
|
||||
return is_timed_out(unminified.result) && is_timed_out(minified_result) && {
|
||||
timed_out: true,
|
||||
};
|
||||
}
|
||||
return {
|
||||
unminified_result: unminified_result,
|
||||
unminified_result: unminified.result,
|
||||
minified_result: minified_result,
|
||||
elapsed: elapsed,
|
||||
elapsed: unminified.elapsed,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,47 @@
|
||||
require("../../tools/exit");
|
||||
|
||||
var get = require("https").get;
|
||||
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) {
|
||||
var done = function(reply) {
|
||||
done = function() {};
|
||||
callback(reply);
|
||||
};
|
||||
var options = parse(url);
|
||||
options.headers = {
|
||||
"Authorization": "Token " + token,
|
||||
@@ -17,33 +53,15 @@ function read(url, callback) {
|
||||
response.on("data", function(chunk) {
|
||||
chunks.push(chunk);
|
||||
}).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), 6300000).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;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -496,11 +496,16 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
||||
var label = createLabel(canBreak, canContinue);
|
||||
canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK);
|
||||
canContinue = label.continue || enableLoopControl(canContinue, CAN_CONTINUE);
|
||||
var optElementVar = "";
|
||||
if (rng(5) > 1) {
|
||||
optElementVar = "c = 1 + c; var " + createVarName(MANDATORY) + " = expr" + loop + "[key" + loop + "]; ";
|
||||
}
|
||||
return "{var expr" + loop + " = " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "; " + label.target + " for (var key" + loop + " in expr" + loop + ") {" + optElementVar + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + "}}";
|
||||
var key = rng(10) ? "key" + loop : getVarName();
|
||||
return [
|
||||
"{var expr" + loop + " = " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "; ",
|
||||
label.target + " for (",
|
||||
/^key/.test(key) ? "var " : "",
|
||||
key + " in expr" + loop + ") {",
|
||||
rng(5) > 1 ? "c = 1 + c; var " + createVarName(MANDATORY) + " = expr" + loop + "[" + key + "]; " : "",
|
||||
createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth),
|
||||
"}}",
|
||||
].join("");
|
||||
case STMT_SEMI:
|
||||
return use_strict && rng(20) === 0 ? '"use strict";' : ";";
|
||||
case STMT_EXPR:
|
||||
|
||||
@@ -1,39 +1,69 @@
|
||||
var actions = require("./actions");
|
||||
var child_process = require("child_process");
|
||||
|
||||
var ping = 5 * 60 * 1000;
|
||||
var period = +process.argv[2];
|
||||
var endTime = Date.now() + period;
|
||||
for (var i = 0; i < 2; i++) spawn(endTime);
|
||||
|
||||
function spawn(endTime) {
|
||||
var child = child_process.spawn("node", [
|
||||
"--max-old-space-size=2048",
|
||||
"test/ufuzz"
|
||||
], {
|
||||
stdio: [ "ignore", "pipe", "pipe" ]
|
||||
}).on("exit", respawn);
|
||||
var stdout = "";
|
||||
child.stdout.on("data", function(data) {
|
||||
stdout += data;
|
||||
var args = [
|
||||
"--max-old-space-size=2048",
|
||||
"test/ufuzz",
|
||||
];
|
||||
var iterations;
|
||||
switch (process.argv.length) {
|
||||
case 3:
|
||||
iterations = +process.argv[2];
|
||||
args.push(iterations);
|
||||
break;
|
||||
case 5:
|
||||
actions.init(process.argv[2], process.argv[3], +process.argv[4]);
|
||||
break;
|
||||
default:
|
||||
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 = "";
|
||||
child.stderr.on("data", trap).pipe(process.stdout);
|
||||
var keepAlive = setInterval(function() {
|
||||
var end = stdout.lastIndexOf("\r");
|
||||
console.log(stdout.slice(stdout.lastIndexOf("\r", end - 1) + 1, end));
|
||||
stdout = stdout.slice(end + 1);
|
||||
}, ping);
|
||||
var timer = setTimeout(function() {
|
||||
clearInterval(keepAlive);
|
||||
}, 8 * 60 * 1000);
|
||||
|
||||
function run() {
|
||||
var child, stdout, stderr, log;
|
||||
spawn();
|
||||
return function() {
|
||||
clearInterval(log);
|
||||
child.removeListener("exit", respawn);
|
||||
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() {
|
||||
console.log(stdout.replace(/[^\r\n]*\r/g, ""));
|
||||
clearInterval(keepAlive);
|
||||
clearTimeout(timer);
|
||||
spawn(endTime);
|
||||
clearInterval(log);
|
||||
if (!iterations) {
|
||||
spawn();
|
||||
} else if (process.exitCode) {
|
||||
tasks.forEach(function(kill) {
|
||||
kill();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function trap(data) {
|
||||
|
||||
Reference in New Issue
Block a user