convert AST_Seq from binary tree to array (#1460)
- rename `AST_Seq` to `AST_Sequence` - raise default sequences_limit from 200 to 800
This commit is contained in:
@@ -50,8 +50,8 @@ function getProps(filename) {
|
|||||||
try {
|
try {
|
||||||
(function walk(node){
|
(function walk(node){
|
||||||
node.walk(new U2.TreeWalker(function(node){
|
node.walk(new U2.TreeWalker(function(node){
|
||||||
if (node instanceof U2.AST_Seq) {
|
if (node instanceof U2.AST_Sequence) {
|
||||||
walk(node.cdr);
|
walk(node.expressions[node.expressions.length - 1]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof U2.AST_String) {
|
if (node instanceof U2.AST_String) {
|
||||||
|
|||||||
@@ -569,7 +569,7 @@ function getOptions(flag, constants) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.walk(new UglifyJS.TreeWalker(function(node){
|
ast.walk(new UglifyJS.TreeWalker(function(node){
|
||||||
if (node instanceof UglifyJS.AST_Seq) return; // descend
|
if (node instanceof UglifyJS.AST_Sequence) return; // descend
|
||||||
if (node instanceof UglifyJS.AST_Assign) {
|
if (node instanceof UglifyJS.AST_Assign) {
|
||||||
var name = node.left.print_to_string().replace(/-/g, "_");
|
var name = node.left.print_to_string().replace(/-/g, "_");
|
||||||
var value = node.right;
|
var value = node.right;
|
||||||
@@ -583,7 +583,7 @@ function getOptions(flag, constants) {
|
|||||||
ret[name] = true;
|
ret[name] = true;
|
||||||
return true; // no descend
|
return true; // no descend
|
||||||
}
|
}
|
||||||
print_error(node.TYPE)
|
print_error(node.TYPE);
|
||||||
print_error("Error parsing arguments for flag `" + flag + "': " + x);
|
print_error("Error parsing arguments for flag `" + flag + "': " + x);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}));
|
}));
|
||||||
|
|||||||
64
lib/ast.js
64
lib/ast.js
@@ -613,68 +613,16 @@ var AST_New = DEFNODE("New", null, {
|
|||||||
$documentation: "An object instantiation. Derives from a function call since it has exactly the same properties"
|
$documentation: "An object instantiation. Derives from a function call since it has exactly the same properties"
|
||||||
}, AST_Call);
|
}, AST_Call);
|
||||||
|
|
||||||
var AST_Seq = DEFNODE("Seq", "car cdr", {
|
var AST_Sequence = DEFNODE("Sequence", "expressions", {
|
||||||
$documentation: "A sequence expression (two comma-separated expressions)",
|
$documentation: "A sequence expression (comma-separated expressions)",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
car: "[AST_Node] first element in sequence",
|
expressions: "[AST_Node*] array of expressions (at least two)"
|
||||||
cdr: "[AST_Node] second element in sequence"
|
|
||||||
},
|
|
||||||
$cons: function(x, y) {
|
|
||||||
var seq = new AST_Seq(x);
|
|
||||||
seq.car = x;
|
|
||||||
seq.cdr = y;
|
|
||||||
return seq;
|
|
||||||
},
|
|
||||||
$from_array: function(array) {
|
|
||||||
if (array.length == 0) return null;
|
|
||||||
if (array.length == 1) return array[0].clone();
|
|
||||||
var list = null;
|
|
||||||
for (var i = array.length; --i >= 0;) {
|
|
||||||
list = AST_Seq.cons(array[i], list);
|
|
||||||
}
|
|
||||||
var p = list;
|
|
||||||
while (p) {
|
|
||||||
if (p.cdr && !p.cdr.cdr) {
|
|
||||||
p.cdr = p.cdr.car;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
p = p.cdr;
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
},
|
|
||||||
to_array: function() {
|
|
||||||
var p = this, a = [];
|
|
||||||
while (p) {
|
|
||||||
a.push(p.car);
|
|
||||||
if (p.cdr && !(p.cdr instanceof AST_Seq)) {
|
|
||||||
a.push(p.cdr);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
p = p.cdr;
|
|
||||||
}
|
|
||||||
return a;
|
|
||||||
},
|
|
||||||
add: function(node) {
|
|
||||||
var p = this;
|
|
||||||
while (p) {
|
|
||||||
if (!(p.cdr instanceof AST_Seq)) {
|
|
||||||
var cell = AST_Seq.cons(p.cdr, node);
|
|
||||||
return p.cdr = cell;
|
|
||||||
}
|
|
||||||
p = p.cdr;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
len: function() {
|
|
||||||
if (this.cdr instanceof AST_Seq) {
|
|
||||||
return this.cdr.len() + 1;
|
|
||||||
} else {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
_walk: function(visitor) {
|
_walk: function(visitor) {
|
||||||
return visitor._visit(this, function(){
|
return visitor._visit(this, function(){
|
||||||
this.car._walk(visitor);
|
this.expressions.forEach(function(node) {
|
||||||
if (this.cdr) this.cdr._walk(visitor);
|
node._walk(visitor);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
369
lib/compress.js
369
lib/compress.js
@@ -111,7 +111,7 @@ function Compressor(options, false_by_default) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
var sequences = this.options["sequences"];
|
var sequences = this.options["sequences"];
|
||||||
this.sequences_limit = sequences == 1 ? 200 : sequences | 0;
|
this.sequences_limit = sequences == 1 ? 800 : sequences | 0;
|
||||||
this.warnings_produced = {};
|
this.warnings_produced = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -440,6 +440,13 @@ merge(Compressor.prototype, {
|
|||||||
return new ctor(props);
|
return new ctor(props);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function make_sequence(orig, expressions) {
|
||||||
|
if (expressions.length == 1) return expressions[0];
|
||||||
|
return make_node(AST_Sequence, orig, {
|
||||||
|
expressions: expressions
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function make_node_from_constant(val, orig) {
|
function make_node_from_constant(val, orig) {
|
||||||
switch (typeof val) {
|
switch (typeof val) {
|
||||||
case "string":
|
case "string":
|
||||||
@@ -482,16 +489,19 @@ merge(Compressor.prototype, {
|
|||||||
if (parent instanceof AST_UnaryPrefix && parent.operator == "delete"
|
if (parent instanceof AST_UnaryPrefix && parent.operator == "delete"
|
||||||
|| parent instanceof AST_Call && parent.expression === orig
|
|| parent instanceof AST_Call && parent.expression === orig
|
||||||
&& (val instanceof AST_PropAccess || val instanceof AST_SymbolRef && val.name == "eval")) {
|
&& (val instanceof AST_PropAccess || val instanceof AST_SymbolRef && val.name == "eval")) {
|
||||||
return make_node(AST_Seq, orig, {
|
return make_sequence(orig, [ make_node(AST_Number, orig, { value: 0 }), val ]);
|
||||||
car: make_node(AST_Number, orig, {
|
|
||||||
value: 0
|
|
||||||
}),
|
|
||||||
cdr: val
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function merge_sequence(array, node) {
|
||||||
|
if (node instanceof AST_Sequence) {
|
||||||
|
array.push.apply(array, node.expressions);
|
||||||
|
} else {
|
||||||
|
array.push(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function as_statement_array(thing) {
|
function as_statement_array(thing) {
|
||||||
if (thing === null) return [];
|
if (thing === null) return [];
|
||||||
if (thing instanceof AST_BlockStatement) return thing.body;
|
if (thing instanceof AST_BlockStatement) return thing.body;
|
||||||
@@ -1000,18 +1010,17 @@ merge(Compressor.prototype, {
|
|||||||
if (statements.length < 2) return statements;
|
if (statements.length < 2) return statements;
|
||||||
var seq = [], ret = [];
|
var seq = [], ret = [];
|
||||||
function push_seq() {
|
function push_seq() {
|
||||||
seq = AST_Seq.from_array(seq);
|
if (!seq.length) return;
|
||||||
if (seq) ret.push(make_node(AST_SimpleStatement, seq, {
|
var body = make_sequence(seq[0], seq);
|
||||||
body: seq
|
ret.push(make_node(AST_SimpleStatement, body, { body: body }));
|
||||||
}));
|
|
||||||
seq = [];
|
seq = [];
|
||||||
};
|
};
|
||||||
statements.forEach(function(stat){
|
statements.forEach(function(stat){
|
||||||
if (stat instanceof AST_SimpleStatement) {
|
if (stat instanceof AST_SimpleStatement) {
|
||||||
if (seqLength(seq) >= compressor.sequences_limit) push_seq();
|
if (seq.length >= compressor.sequences_limit) push_seq();
|
||||||
var body = stat.body;
|
var body = stat.body;
|
||||||
if (seq.length > 0) body = body.drop_side_effect_free(compressor);
|
if (seq.length > 0) body = body.drop_side_effect_free(compressor);
|
||||||
if (body) seq.push(body);
|
if (body) merge_sequence(seq, body);
|
||||||
} else {
|
} else {
|
||||||
push_seq();
|
push_seq();
|
||||||
ret.push(stat);
|
ret.push(stat);
|
||||||
@@ -1023,27 +1032,16 @@ merge(Compressor.prototype, {
|
|||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
function seqLength(a) {
|
|
||||||
for (var len = 0, i = 0; i < a.length; ++i) {
|
|
||||||
var stat = a[i];
|
|
||||||
if (stat instanceof AST_Seq) {
|
|
||||||
len += stat.len();
|
|
||||||
} else {
|
|
||||||
len++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return len;
|
|
||||||
};
|
|
||||||
|
|
||||||
function sequencesize_2(statements, compressor) {
|
function sequencesize_2(statements, compressor) {
|
||||||
function cons_seq(right) {
|
function cons_seq(right) {
|
||||||
ret.pop();
|
ret.pop();
|
||||||
var left = prev.body;
|
var left = prev.body;
|
||||||
if (left instanceof AST_Seq) {
|
if (!(left instanceof AST_Sequence)) {
|
||||||
left.add(right);
|
left = make_node(AST_Sequence, left, {
|
||||||
} else {
|
expressions: [ left ]
|
||||||
left = AST_Seq.cons(left, right);
|
});
|
||||||
}
|
}
|
||||||
|
merge_sequence(left.expressions, right);
|
||||||
return left.transform(compressor);
|
return left.transform(compressor);
|
||||||
};
|
};
|
||||||
var ret = [], prev = null;
|
var ret = [], prev = null;
|
||||||
@@ -1202,8 +1200,8 @@ merge(Compressor.prototype, {
|
|||||||
return this.consequent._eq_null(pure_getters)
|
return this.consequent._eq_null(pure_getters)
|
||||||
|| this.alternative._eq_null(pure_getters);
|
|| this.alternative._eq_null(pure_getters);
|
||||||
})
|
})
|
||||||
def(AST_Seq, function(pure_getters) {
|
def(AST_Sequence, function(pure_getters) {
|
||||||
return this.cdr._eq_null(pure_getters);
|
return this.expressions[this.expressions.length - 1]._eq_null(pure_getters);
|
||||||
});
|
});
|
||||||
def(AST_SymbolRef, function(pure_getters) {
|
def(AST_SymbolRef, function(pure_getters) {
|
||||||
if (this.is_undefined) return true;
|
if (this.is_undefined) return true;
|
||||||
@@ -1236,8 +1234,8 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Assign, function(){
|
def(AST_Assign, function(){
|
||||||
return this.operator == "=" && this.right.is_boolean();
|
return this.operator == "=" && this.right.is_boolean();
|
||||||
});
|
});
|
||||||
def(AST_Seq, function(){
|
def(AST_Sequence, function(){
|
||||||
return this.cdr.is_boolean();
|
return this.expressions[this.expressions.length - 1].is_boolean();
|
||||||
});
|
});
|
||||||
def(AST_True, return_true);
|
def(AST_True, return_true);
|
||||||
def(AST_False, return_true);
|
def(AST_False, return_true);
|
||||||
@@ -1263,8 +1261,8 @@ merge(Compressor.prototype, {
|
|||||||
return binary(this.operator.slice(0, -1))
|
return binary(this.operator.slice(0, -1))
|
||||||
|| this.operator == "=" && this.right.is_number(compressor);
|
|| this.operator == "=" && this.right.is_number(compressor);
|
||||||
});
|
});
|
||||||
def(AST_Seq, function(compressor){
|
def(AST_Sequence, function(compressor){
|
||||||
return this.cdr.is_number(compressor);
|
return this.expressions[this.expressions.length - 1].is_number(compressor);
|
||||||
});
|
});
|
||||||
def(AST_Conditional, function(compressor){
|
def(AST_Conditional, function(compressor){
|
||||||
return this.consequent.is_number(compressor) && this.alternative.is_number(compressor);
|
return this.consequent.is_number(compressor) && this.alternative.is_number(compressor);
|
||||||
@@ -1287,8 +1285,8 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Assign, function(compressor){
|
def(AST_Assign, function(compressor){
|
||||||
return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor);
|
return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor);
|
||||||
});
|
});
|
||||||
def(AST_Seq, function(compressor){
|
def(AST_Sequence, function(compressor){
|
||||||
return this.cdr.is_string(compressor);
|
return this.expressions[this.expressions.length - 1].is_string(compressor);
|
||||||
});
|
});
|
||||||
def(AST_Conditional, function(compressor){
|
def(AST_Conditional, function(compressor){
|
||||||
return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);
|
return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);
|
||||||
@@ -1616,10 +1614,10 @@ merge(Compressor.prototype, {
|
|||||||
return this.expression;
|
return this.expression;
|
||||||
return basic_negation(this);
|
return basic_negation(this);
|
||||||
});
|
});
|
||||||
def(AST_Seq, function(compressor){
|
def(AST_Sequence, function(compressor){
|
||||||
var self = this.clone();
|
var expressions = this.expressions.slice();
|
||||||
self.cdr = self.cdr.negate(compressor);
|
expressions.push(expressions.pop().negate(compressor));
|
||||||
return self;
|
return make_sequence(this, expressions);
|
||||||
});
|
});
|
||||||
def(AST_Conditional, function(compressor, first_in_statement){
|
def(AST_Conditional, function(compressor, first_in_statement){
|
||||||
var self = this.clone();
|
var self = this.clone();
|
||||||
@@ -1763,9 +1761,10 @@ merge(Compressor.prototype, {
|
|||||||
|| this.expression.has_side_effects(compressor)
|
|| this.expression.has_side_effects(compressor)
|
||||||
|| this.property.has_side_effects(compressor);
|
|| this.property.has_side_effects(compressor);
|
||||||
});
|
});
|
||||||
def(AST_Seq, function(compressor){
|
def(AST_Sequence, function(compressor){
|
||||||
return this.car.has_side_effects(compressor)
|
return this.expressions.some(function(expression, index) {
|
||||||
|| this.cdr.has_side_effects(compressor);
|
return expression.has_side_effects(compressor);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
})(function(node, func){
|
})(function(node, func){
|
||||||
node.DEFMETHOD("has_side_effects", func);
|
node.DEFMETHOD("has_side_effects", func);
|
||||||
@@ -2015,12 +2014,12 @@ merge(Compressor.prototype, {
|
|||||||
for (var i = 0; i < def.length;) {
|
for (var i = 0; i < def.length;) {
|
||||||
var x = def[i];
|
var x = def[i];
|
||||||
if (x._unused_side_effects) {
|
if (x._unused_side_effects) {
|
||||||
side_effects.push(x._unused_side_effects);
|
merge_sequence(side_effects, x._unused_side_effects);
|
||||||
def.splice(i, 1);
|
def.splice(i, 1);
|
||||||
} else {
|
} else {
|
||||||
if (side_effects.length > 0) {
|
if (side_effects.length > 0) {
|
||||||
side_effects.push(x.value);
|
merge_sequence(side_effects, x.value);
|
||||||
x.value = AST_Seq.from_array(side_effects);
|
x.value = make_sequence(x.value, side_effects);
|
||||||
side_effects = [];
|
side_effects = [];
|
||||||
}
|
}
|
||||||
++i;
|
++i;
|
||||||
@@ -2029,7 +2028,7 @@ merge(Compressor.prototype, {
|
|||||||
if (side_effects.length > 0) {
|
if (side_effects.length > 0) {
|
||||||
side_effects = make_node(AST_BlockStatement, node, {
|
side_effects = make_node(AST_BlockStatement, node, {
|
||||||
body: [ make_node(AST_SimpleStatement, node, {
|
body: [ make_node(AST_SimpleStatement, node, {
|
||||||
body: AST_Seq.from_array(side_effects)
|
body: make_sequence(node, side_effects)
|
||||||
}) ]
|
}) ]
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -2179,8 +2178,8 @@ merge(Compressor.prototype, {
|
|||||||
self.body.splice(i, 1);
|
self.body.splice(i, 1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (expr instanceof AST_Seq
|
if (expr instanceof AST_Sequence
|
||||||
&& (assign = expr.car) instanceof AST_Assign
|
&& (assign = expr.expressions[0]) instanceof AST_Assign
|
||||||
&& assign.operator == "="
|
&& assign.operator == "="
|
||||||
&& (sym = assign.left) instanceof AST_Symbol
|
&& (sym = assign.left) instanceof AST_Symbol
|
||||||
&& vars.has(sym.name))
|
&& vars.has(sym.name))
|
||||||
@@ -2190,7 +2189,7 @@ merge(Compressor.prototype, {
|
|||||||
def.value = assign.right;
|
def.value = assign.right;
|
||||||
remove(defs, def);
|
remove(defs, def);
|
||||||
defs.push(def);
|
defs.push(def);
|
||||||
self.body[i].body = expr.cdr;
|
self.body[i].body = make_sequence(expr, expr.expressions.slice(1));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2224,12 +2223,14 @@ merge(Compressor.prototype, {
|
|||||||
// if all elements were dropped. Note: original array may be
|
// if all elements were dropped. Note: original array may be
|
||||||
// returned if nothing changed.
|
// returned if nothing changed.
|
||||||
function trim(nodes, compressor, first_in_statement) {
|
function trim(nodes, compressor, first_in_statement) {
|
||||||
|
var len = nodes.length;
|
||||||
|
if (!len) return null;
|
||||||
var ret = [], changed = false;
|
var ret = [], changed = false;
|
||||||
for (var i = 0, len = nodes.length; i < len; i++) {
|
for (var i = 0; i < len; i++) {
|
||||||
var node = nodes[i].drop_side_effect_free(compressor, first_in_statement);
|
var node = nodes[i].drop_side_effect_free(compressor, first_in_statement);
|
||||||
changed |= node !== nodes[i];
|
changed |= node !== nodes[i];
|
||||||
if (node) {
|
if (node) {
|
||||||
ret.push(node);
|
merge_sequence(ret, node);
|
||||||
first_in_statement = false;
|
first_in_statement = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2254,7 +2255,7 @@ merge(Compressor.prototype, {
|
|||||||
this.pure.value = this.pure.value.replace(/[@#]__PURE__/g, ' ');
|
this.pure.value = this.pure.value.replace(/[@#]__PURE__/g, ' ');
|
||||||
}
|
}
|
||||||
var args = trim(this.args, compressor, first_in_statement);
|
var args = trim(this.args, compressor, first_in_statement);
|
||||||
return args && AST_Seq.from_array(args);
|
return args && make_sequence(this, args);
|
||||||
});
|
});
|
||||||
def(AST_Function, return_null);
|
def(AST_Function, return_null);
|
||||||
def(AST_Binary, function(compressor, first_in_statement){
|
def(AST_Binary, function(compressor, first_in_statement){
|
||||||
@@ -2270,10 +2271,7 @@ merge(Compressor.prototype, {
|
|||||||
default:
|
default:
|
||||||
var left = this.left.drop_side_effect_free(compressor, first_in_statement);
|
var left = this.left.drop_side_effect_free(compressor, first_in_statement);
|
||||||
if (!left) return this.right.drop_side_effect_free(compressor, first_in_statement);
|
if (!left) return this.right.drop_side_effect_free(compressor, first_in_statement);
|
||||||
return make_node(AST_Seq, this, {
|
return make_sequence(this, [ left, right ]);
|
||||||
car: left,
|
|
||||||
cdr: right
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
def(AST_Assign, return_this);
|
def(AST_Assign, return_this);
|
||||||
@@ -2316,14 +2314,14 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
def(AST_Object, function(compressor, first_in_statement){
|
def(AST_Object, function(compressor, first_in_statement){
|
||||||
var values = trim(this.properties, compressor, first_in_statement);
|
var values = trim(this.properties, compressor, first_in_statement);
|
||||||
return values && AST_Seq.from_array(values);
|
return values && make_sequence(this, values);
|
||||||
});
|
});
|
||||||
def(AST_ObjectProperty, function(compressor, first_in_statement){
|
def(AST_ObjectProperty, function(compressor, first_in_statement){
|
||||||
return this.value.drop_side_effect_free(compressor, first_in_statement);
|
return this.value.drop_side_effect_free(compressor, first_in_statement);
|
||||||
});
|
});
|
||||||
def(AST_Array, function(compressor, first_in_statement){
|
def(AST_Array, function(compressor, first_in_statement){
|
||||||
var values = trim(this.elements, compressor, first_in_statement);
|
var values = trim(this.elements, compressor, first_in_statement);
|
||||||
return values && AST_Seq.from_array(values);
|
return values && make_sequence(this, values);
|
||||||
});
|
});
|
||||||
def(AST_Dot, function(compressor, first_in_statement){
|
def(AST_Dot, function(compressor, first_in_statement){
|
||||||
if (this.expression.may_eq_null(compressor)) return this;
|
if (this.expression.may_eq_null(compressor)) return this;
|
||||||
@@ -2335,19 +2333,15 @@ merge(Compressor.prototype, {
|
|||||||
if (!expression) return this.property.drop_side_effect_free(compressor, first_in_statement);
|
if (!expression) return this.property.drop_side_effect_free(compressor, first_in_statement);
|
||||||
var property = this.property.drop_side_effect_free(compressor);
|
var property = this.property.drop_side_effect_free(compressor);
|
||||||
if (!property) return expression;
|
if (!property) return expression;
|
||||||
return make_node(AST_Seq, this, {
|
return make_sequence(this, [ expression, property ]);
|
||||||
car: expression,
|
|
||||||
cdr: property
|
|
||||||
});
|
|
||||||
});
|
|
||||||
def(AST_Seq, function(compressor){
|
|
||||||
var cdr = this.cdr.drop_side_effect_free(compressor);
|
|
||||||
if (cdr === this.cdr) return this;
|
|
||||||
if (!cdr) return this.car;
|
|
||||||
return make_node(AST_Seq, this, {
|
|
||||||
car: this.car,
|
|
||||||
cdr: cdr
|
|
||||||
});
|
});
|
||||||
|
def(AST_Sequence, function(compressor){
|
||||||
|
var last = this.expressions[this.expressions.length - 1];
|
||||||
|
var expr = last.drop_side_effect_free(compressor);
|
||||||
|
if (expr === last) return this;
|
||||||
|
var expressions = this.expressions.slice(0, -1);
|
||||||
|
if (expr) merge_sequence(expressions, expr);
|
||||||
|
return make_sequence(this, expressions);
|
||||||
});
|
});
|
||||||
})(function(node, func){
|
})(function(node, func){
|
||||||
node.DEFMETHOD("drop_side_effect_free", func);
|
node.DEFMETHOD("drop_side_effect_free", func);
|
||||||
@@ -2737,7 +2731,7 @@ merge(Compressor.prototype, {
|
|||||||
return a;
|
return a;
|
||||||
}, []);
|
}, []);
|
||||||
if (assignments.length == 0) return null;
|
if (assignments.length == 0) return null;
|
||||||
return AST_Seq.from_array(assignments);
|
return make_sequence(this, assignments);
|
||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Definitions, function(self, compressor){
|
OPT(AST_Definitions, function(self, compressor){
|
||||||
@@ -2979,12 +2973,12 @@ merge(Compressor.prototype, {
|
|||||||
var value = exp.body[0].value;
|
var value = exp.body[0].value;
|
||||||
if (!value || value.is_constant()) {
|
if (!value || value.is_constant()) {
|
||||||
var args = self.args.concat(value || make_node(AST_Undefined, self));
|
var args = self.args.concat(value || make_node(AST_Undefined, self));
|
||||||
return AST_Seq.from_array(args).transform(compressor);
|
return make_sequence(self, args).transform(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compressor.option("side_effects") && all(exp.body, is_empty)) {
|
if (compressor.option("side_effects") && all(exp.body, is_empty)) {
|
||||||
var args = self.args.concat(make_node(AST_Undefined, self));
|
var args = self.args.concat(make_node(AST_Undefined, self));
|
||||||
return AST_Seq.from_array(args).transform(compressor);
|
return make_sequence(self, args).transform(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compressor.option("drop_console")) {
|
if (compressor.option("drop_console")) {
|
||||||
@@ -3025,40 +3019,85 @@ merge(Compressor.prototype, {
|
|||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Seq, function(self, compressor){
|
OPT(AST_Sequence, function(self, compressor){
|
||||||
if (!compressor.option("side_effects"))
|
if (!compressor.option("side_effects")) return self;
|
||||||
|
var expressions = [];
|
||||||
|
filter_for_side_effects();
|
||||||
|
var end = expressions.length - 1;
|
||||||
|
trim_right_for_undefined();
|
||||||
|
if (end > 0 && compressor.option("cascade")) trim_left_for_assignment();
|
||||||
|
if (end == 0) {
|
||||||
|
self = maintain_this_binding(compressor.parent(), self, expressions[0]);
|
||||||
|
if (!(self instanceof AST_Sequence)) self = self.optimize(compressor);
|
||||||
return self;
|
return self;
|
||||||
self.car = self.car.drop_side_effect_free(compressor, first_in_statement(compressor));
|
|
||||||
if (!self.car) return maintain_this_binding(compressor.parent(), self, self.cdr);
|
|
||||||
if (compressor.option("cascade")) {
|
|
||||||
var left;
|
|
||||||
if (self.car instanceof AST_Assign
|
|
||||||
&& !self.car.left.has_side_effects(compressor)) {
|
|
||||||
left = self.car.left;
|
|
||||||
} else if (self.car instanceof AST_Unary
|
|
||||||
&& (self.car.operator == "++" || self.car.operator == "--")) {
|
|
||||||
left = self.car.expression;
|
|
||||||
}
|
}
|
||||||
if (left
|
self.expressions = expressions;
|
||||||
&& !(left instanceof AST_SymbolRef
|
return self;
|
||||||
&& left.definition().orig[0] instanceof AST_SymbolLambda)) {
|
|
||||||
var parent, field;
|
function filter_for_side_effects() {
|
||||||
var cdr = self.cdr;
|
var first = first_in_statement(compressor);
|
||||||
|
var last = self.expressions.length - 1;
|
||||||
|
self.expressions.forEach(function(expr, index) {
|
||||||
|
if (index < last) expr = expr.drop_side_effect_free(compressor, first);
|
||||||
|
if (expr) {
|
||||||
|
merge_sequence(expressions, expr);
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function trim_right_for_undefined() {
|
||||||
|
while (end > 0 && is_undefined(expressions[end], compressor)) end--;
|
||||||
|
if (end < expressions.length - 1) {
|
||||||
|
expressions[end] = make_node(AST_UnaryPrefix, self, {
|
||||||
|
operator : "void",
|
||||||
|
expression : expressions[end]
|
||||||
|
});
|
||||||
|
expressions.length = end + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function trim_left_for_assignment() {
|
||||||
|
for (var i = 0, j = 1; j <= end; j++) {
|
||||||
|
var left = expressions[i];
|
||||||
|
var cdr = expressions[j];
|
||||||
|
if (left instanceof AST_Assign
|
||||||
|
&& !left.left.has_side_effects(compressor)) {
|
||||||
|
left = left.left;
|
||||||
|
} else if (left instanceof AST_Unary
|
||||||
|
&& (left.operator == "++" || left.operator == "--")) {
|
||||||
|
left = left.expression;
|
||||||
|
} else left = null;
|
||||||
|
if (!left ||
|
||||||
|
left instanceof AST_SymbolRef
|
||||||
|
&& left.definition().orig[0] instanceof AST_SymbolLambda) {
|
||||||
|
expressions[++i] = cdr;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var parent = null, field;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (cdr.equivalent_to(left)) {
|
if (cdr.equivalent_to(left)) {
|
||||||
var car = self.car instanceof AST_UnaryPostfix ? make_node(AST_UnaryPrefix, self.car, {
|
var car = expressions[i];
|
||||||
operator: self.car.operator,
|
if (car instanceof AST_UnaryPostfix) {
|
||||||
|
car = make_node(AST_UnaryPrefix, car, {
|
||||||
|
operator: car.operator,
|
||||||
expression: left
|
expression: left
|
||||||
}) : self.car;
|
});
|
||||||
|
}
|
||||||
if (parent) {
|
if (parent) {
|
||||||
parent[field] = car;
|
parent[field] = car;
|
||||||
return self.cdr;
|
expressions[i] = expressions[j];
|
||||||
|
} else {
|
||||||
|
expressions[i] = car;
|
||||||
}
|
}
|
||||||
return car;
|
break;
|
||||||
}
|
}
|
||||||
if (cdr instanceof AST_Binary && !(cdr instanceof AST_Assign)) {
|
if (cdr instanceof AST_Binary && !(cdr instanceof AST_Assign)) {
|
||||||
if (cdr.left.is_constant()) {
|
if (cdr.left.is_constant()) {
|
||||||
if (cdr.operator == "||" || cdr.operator == "&&") break;
|
if (cdr.operator == "||" || cdr.operator == "&&") {
|
||||||
|
expressions[++i] = expressions[j];
|
||||||
|
break;
|
||||||
|
}
|
||||||
field = "right";
|
field = "right";
|
||||||
} else {
|
} else {
|
||||||
field = "left";
|
field = "left";
|
||||||
@@ -3066,31 +3105,27 @@ merge(Compressor.prototype, {
|
|||||||
} else if (cdr instanceof AST_Call
|
} else if (cdr instanceof AST_Call
|
||||||
|| cdr instanceof AST_Unary && !unary_side_effects(cdr.operator)) {
|
|| cdr instanceof AST_Unary && !unary_side_effects(cdr.operator)) {
|
||||||
field = "expression";
|
field = "expression";
|
||||||
} else break;
|
} else {
|
||||||
|
expressions[++i] = expressions[j];
|
||||||
|
break;
|
||||||
|
}
|
||||||
parent = cdr;
|
parent = cdr;
|
||||||
cdr = cdr[field];
|
cdr = cdr[field];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
end = i;
|
||||||
|
expressions.length = end + 1;
|
||||||
}
|
}
|
||||||
if (is_undefined(self.cdr, compressor)) {
|
|
||||||
return make_node(AST_UnaryPrefix, self, {
|
|
||||||
operator : "void",
|
|
||||||
expression : self.car
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Unary.DEFMETHOD("lift_sequences", function(compressor){
|
AST_Unary.DEFMETHOD("lift_sequences", function(compressor){
|
||||||
if (compressor.option("sequences")) {
|
if (compressor.option("sequences")) {
|
||||||
if (this.expression instanceof AST_Seq) {
|
if (this.expression instanceof AST_Sequence) {
|
||||||
var seq = this.expression;
|
var x = this.expression.expressions.slice();
|
||||||
var x = seq.to_array();
|
|
||||||
var e = this.clone();
|
var e = this.clone();
|
||||||
e.expression = x.pop();
|
e.expression = x.pop();
|
||||||
x.push(e);
|
x.push(e);
|
||||||
seq = AST_Seq.from_array(x).transform(compressor);
|
return make_sequence(this, x).optimize(compressor);
|
||||||
return seq;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
@@ -3108,15 +3143,12 @@ merge(Compressor.prototype, {
|
|||||||
|| e instanceof AST_NaN
|
|| e instanceof AST_NaN
|
||||||
|| e instanceof AST_Infinity
|
|| e instanceof AST_Infinity
|
||||||
|| e instanceof AST_Undefined)) {
|
|| e instanceof AST_Undefined)) {
|
||||||
if (e instanceof AST_Seq) {
|
if (e instanceof AST_Sequence) {
|
||||||
e = e.to_array();
|
e = e.expressions.slice();
|
||||||
e.push(make_node(AST_True, self));
|
e.push(make_node(AST_True, self));
|
||||||
return AST_Seq.from_array(e).optimize(compressor);
|
return make_sequence(self, e).optimize(compressor);
|
||||||
}
|
}
|
||||||
return make_node(AST_Seq, self, {
|
return make_sequence(self, [ e, make_node(AST_True, self) ]).optimize(compressor);
|
||||||
car: e,
|
|
||||||
cdr: make_node(AST_True, self)
|
|
||||||
}).optimize(compressor);
|
|
||||||
}
|
}
|
||||||
var seq = self.lift_sequences(compressor);
|
var seq = self.lift_sequences(compressor);
|
||||||
if (seq !== self) {
|
if (seq !== self) {
|
||||||
@@ -3146,10 +3178,10 @@ merge(Compressor.prototype, {
|
|||||||
// typeof always returns a non-empty string, thus it's
|
// typeof always returns a non-empty string, thus it's
|
||||||
// always true in booleans
|
// always true in booleans
|
||||||
compressor.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
|
compressor.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
|
||||||
return (e instanceof AST_SymbolRef ? make_node(AST_True, self) : make_node(AST_Seq, self, {
|
return (e instanceof AST_SymbolRef ? make_node(AST_True, self) : make_sequence(self, [
|
||||||
car: e,
|
e,
|
||||||
cdr: make_node(AST_True, self)
|
make_node(AST_True, self)
|
||||||
})).optimize(compressor);
|
])).optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (self.operator == "-" && e instanceof AST_Infinity) {
|
if (self.operator == "-" && e instanceof AST_Infinity) {
|
||||||
@@ -3181,29 +3213,32 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
AST_Binary.DEFMETHOD("lift_sequences", function(compressor){
|
AST_Binary.DEFMETHOD("lift_sequences", function(compressor){
|
||||||
if (compressor.option("sequences")) {
|
if (compressor.option("sequences")) {
|
||||||
if (this.left instanceof AST_Seq) {
|
if (this.left instanceof AST_Sequence) {
|
||||||
var seq = this.left;
|
var x = this.left.expressions.slice();
|
||||||
var x = seq.to_array();
|
|
||||||
var e = this.clone();
|
var e = this.clone();
|
||||||
e.left = x.pop();
|
e.left = x.pop();
|
||||||
x.push(e);
|
x.push(e);
|
||||||
return AST_Seq.from_array(x).optimize(compressor);
|
return make_sequence(this, x).optimize(compressor);
|
||||||
}
|
}
|
||||||
if (this.right instanceof AST_Seq && !this.left.has_side_effects(compressor)) {
|
if (this.right instanceof AST_Sequence && !this.left.has_side_effects(compressor)) {
|
||||||
var assign = this.operator == "=" && this.left instanceof AST_SymbolRef;
|
var assign = this.operator == "=" && this.left instanceof AST_SymbolRef;
|
||||||
var root = this.right.clone();
|
var x = this.right.expressions;
|
||||||
var cursor, seq = root;
|
var last = x.length - 1;
|
||||||
while (assign || !seq.car.has_side_effects(compressor)) {
|
for (var i = 0; i < last; i++) {
|
||||||
cursor = seq;
|
if (!assign && x[i].has_side_effects(compressor)) break;
|
||||||
if (seq.cdr instanceof AST_Seq) {
|
|
||||||
seq = seq.cdr = seq.cdr.clone();
|
|
||||||
} else break;
|
|
||||||
}
|
}
|
||||||
if (cursor) {
|
if (i == last) {
|
||||||
|
x = x.slice();
|
||||||
var e = this.clone();
|
var e = this.clone();
|
||||||
e.right = cursor.cdr;
|
e.right = x.pop();
|
||||||
cursor.cdr = e;
|
x.push(e);
|
||||||
return root.optimize(compressor);
|
return make_sequence(this, x).optimize(compressor);
|
||||||
|
} else if (i > 0) {
|
||||||
|
var e = this.clone();
|
||||||
|
e.right = make_sequence(this.right, x.slice(i));
|
||||||
|
x = x.slice(0, i);
|
||||||
|
x.push(e);
|
||||||
|
return make_sequence(this, x).optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3272,17 +3307,17 @@ merge(Compressor.prototype, {
|
|||||||
var rr = self.right.evaluate(compressor);
|
var rr = self.right.evaluate(compressor);
|
||||||
if (ll && typeof ll == "string") {
|
if (ll && typeof ll == "string") {
|
||||||
compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
|
compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
|
||||||
return make_node(AST_Seq, self, {
|
return make_sequence(self, [
|
||||||
car: self.right,
|
self.right,
|
||||||
cdr: make_node(AST_True, self)
|
make_node(AST_True, self)
|
||||||
}).optimize(compressor);
|
]).optimize(compressor);
|
||||||
}
|
}
|
||||||
if (rr && typeof rr == "string") {
|
if (rr && typeof rr == "string") {
|
||||||
compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
|
compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
|
||||||
return make_node(AST_Seq, self, {
|
return make_sequence(self, [
|
||||||
car: self.left,
|
self.left,
|
||||||
cdr: make_node(AST_True, self)
|
make_node(AST_True, self)
|
||||||
}).optimize(compressor);
|
]).optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compressor.option("comparisons") && self.is_boolean()) {
|
if (compressor.option("comparisons") && self.is_boolean()) {
|
||||||
@@ -3336,10 +3371,10 @@ merge(Compressor.prototype, {
|
|||||||
var rr = self.right.evaluate(compressor);
|
var rr = self.right.evaluate(compressor);
|
||||||
if (!rr) {
|
if (!rr) {
|
||||||
compressor.warn("Boolean && always false [{file}:{line},{col}]", self.start);
|
compressor.warn("Boolean && always false [{file}:{line},{col}]", self.start);
|
||||||
return make_node(AST_Seq, self, {
|
return make_sequence(self, [
|
||||||
car: self.left,
|
self.left,
|
||||||
cdr: make_node(AST_False, self)
|
make_node(AST_False, self)
|
||||||
}).optimize(compressor);
|
]).optimize(compressor);
|
||||||
} else if (rr !== self.right) {
|
} else if (rr !== self.right) {
|
||||||
compressor.warn("Dropping side-effect-free && in boolean context [{file}:{line},{col}]", self.start);
|
compressor.warn("Dropping side-effect-free && in boolean context [{file}:{line},{col}]", self.start);
|
||||||
return self.left.optimize(compressor);
|
return self.left.optimize(compressor);
|
||||||
@@ -3362,10 +3397,10 @@ merge(Compressor.prototype, {
|
|||||||
return self.left.optimize(compressor);
|
return self.left.optimize(compressor);
|
||||||
} else if (rr !== self.right) {
|
} else if (rr !== self.right) {
|
||||||
compressor.warn("Boolean || always true [{file}:{line},{col}]", self.start);
|
compressor.warn("Boolean || always true [{file}:{line},{col}]", self.start);
|
||||||
return make_node(AST_Seq, self, {
|
return make_sequence(self, [
|
||||||
car: self.left,
|
self.left,
|
||||||
cdr: make_node(AST_True, self)
|
make_node(AST_True, self)
|
||||||
}).optimize(compressor);
|
]).optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -3709,10 +3744,12 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
OPT(AST_Conditional, function(self, compressor){
|
OPT(AST_Conditional, function(self, compressor){
|
||||||
if (!compressor.option("conditionals")) return self;
|
if (!compressor.option("conditionals")) return self;
|
||||||
if (self.condition instanceof AST_Seq) {
|
// This looks like lift_sequences(), should probably be under "sequences"
|
||||||
var car = self.condition.car;
|
if (self.condition instanceof AST_Sequence) {
|
||||||
self.condition = self.condition.cdr;
|
var expressions = self.condition.expressions.slice();
|
||||||
return AST_Seq.cons(car, self);
|
self.condition = expressions.pop();
|
||||||
|
expressions.push(self);
|
||||||
|
return make_sequence(self, expressions);
|
||||||
}
|
}
|
||||||
var cond = self.condition.evaluate(compressor);
|
var cond = self.condition.evaluate(compressor);
|
||||||
if (cond !== self.condition) {
|
if (cond !== self.condition) {
|
||||||
@@ -3795,10 +3832,10 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
// x ? y : y --> x, y
|
// x ? y : y --> x, y
|
||||||
if (consequent.equivalent_to(alternative)) {
|
if (consequent.equivalent_to(alternative)) {
|
||||||
return make_node(AST_Seq, self, {
|
return make_sequence(self, [
|
||||||
car: self.condition,
|
self.condition,
|
||||||
cdr: consequent
|
consequent
|
||||||
}).optimize(compressor);
|
]).optimize(compressor);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_true(self.consequent)) {
|
if (is_true(self.consequent)) {
|
||||||
@@ -3968,10 +4005,10 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
function literals_in_boolean_context(self, compressor) {
|
function literals_in_boolean_context(self, compressor) {
|
||||||
if (compressor.option("booleans") && compressor.in_boolean_context()) {
|
if (compressor.option("booleans") && compressor.in_boolean_context()) {
|
||||||
return best_of(compressor, self, make_node(AST_Seq, self, {
|
return best_of(compressor, self, make_sequence(self, [
|
||||||
car: self,
|
self,
|
||||||
cdr: make_node(AST_True, self)
|
make_node(AST_True, self)
|
||||||
}).optimize(compressor));
|
]).optimize(compressor));
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -149,7 +149,11 @@
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
SequenceExpression: function(M) {
|
SequenceExpression: function(M) {
|
||||||
return AST_Seq.from_array(M.expressions.map(from_moz));
|
return new AST_Sequence({
|
||||||
|
start : my_start_token(M),
|
||||||
|
end : my_end_token(M),
|
||||||
|
expressions: M.expressions.map(from_moz)
|
||||||
|
});
|
||||||
},
|
},
|
||||||
MemberExpression: function(M) {
|
MemberExpression: function(M) {
|
||||||
return new (M.computed ? AST_Sub : AST_Dot)({
|
return new (M.computed ? AST_Sub : AST_Dot)({
|
||||||
@@ -332,10 +336,10 @@
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
def_to_moz(AST_Seq, function To_Moz_SequenceExpression(M) {
|
def_to_moz(AST_Sequence, function To_Moz_SequenceExpression(M) {
|
||||||
return {
|
return {
|
||||||
type: "SequenceExpression",
|
type: "SequenceExpression",
|
||||||
expressions: M.to_array().map(to_moz)
|
expressions: M.expressions.map(to_moz)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -592,7 +592,7 @@ function OutputStream(options) {
|
|||||||
|| p instanceof AST_Call && p.expression === this;
|
|| p instanceof AST_Call && p.expression === this;
|
||||||
});
|
});
|
||||||
|
|
||||||
PARENS(AST_Seq, function(output){
|
PARENS(AST_Sequence, function(output){
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
|
return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
|
||||||
|| p instanceof AST_Unary // !(foo, bar, baz)
|
|| p instanceof AST_Unary // !(foo, bar, baz)
|
||||||
@@ -1087,18 +1087,19 @@ function OutputStream(options) {
|
|||||||
AST_Call.prototype._codegen(self, output);
|
AST_Call.prototype._codegen(self, output);
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Seq.DEFMETHOD("_do_print", function(output){
|
AST_Sequence.DEFMETHOD("_do_print", function(output){
|
||||||
this.car.print(output);
|
this.expressions.forEach(function(node, index) {
|
||||||
if (this.cdr) {
|
if (index > 0) {
|
||||||
output.comma();
|
output.comma();
|
||||||
if (output.should_break()) {
|
if (output.should_break()) {
|
||||||
output.newline();
|
output.newline();
|
||||||
output.indent();
|
output.indent();
|
||||||
}
|
}
|
||||||
this.cdr.print(output);
|
|
||||||
}
|
}
|
||||||
|
node.print(output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Seq, function(self, output){
|
});
|
||||||
|
DEFPRINT(AST_Sequence, function(self, output){
|
||||||
self._do_print(output);
|
self._do_print(output);
|
||||||
// var p = output.parent();
|
// var p = output.parent();
|
||||||
// if (p instanceof AST_Statement) {
|
// if (p instanceof AST_Statement) {
|
||||||
|
|||||||
15
lib/parse.js
15
lib/parse.js
@@ -1527,17 +1527,18 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
var expression = function(commas, no_in) {
|
var expression = function(commas, no_in) {
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
var expr = maybe_assign(no_in);
|
var exprs = [];
|
||||||
if (commas && is("punc", ",")) {
|
while (true) {
|
||||||
|
exprs.push(maybe_assign(no_in));
|
||||||
|
if (!commas || !is("punc", ",")) break;
|
||||||
next();
|
next();
|
||||||
return new AST_Seq({
|
commas = true;
|
||||||
|
}
|
||||||
|
return exprs.length == 1 ? exprs[0] : new AST_Sequence({
|
||||||
start : start,
|
start : start,
|
||||||
car : expr,
|
expressions : exprs,
|
||||||
cdr : expression(true, no_in),
|
|
||||||
end : peek()
|
end : peek()
|
||||||
});
|
});
|
||||||
}
|
|
||||||
return expr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function in_loop(cont) {
|
function in_loop(cont) {
|
||||||
|
|||||||
@@ -224,8 +224,8 @@ function mangle_properties(ast, options) {
|
|||||||
try {
|
try {
|
||||||
(function walk(node){
|
(function walk(node){
|
||||||
node.walk(new TreeWalker(function(node){
|
node.walk(new TreeWalker(function(node){
|
||||||
if (node instanceof AST_Seq) {
|
if (node instanceof AST_Sequence) {
|
||||||
walk(node.cdr);
|
walk(node.expressions[node.expressions.length - 1]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_String) {
|
if (node instanceof AST_String) {
|
||||||
@@ -247,8 +247,9 @@ function mangle_properties(ast, options) {
|
|||||||
|
|
||||||
function mangleStrings(node) {
|
function mangleStrings(node) {
|
||||||
return node.transform(new TreeTransformer(function(node){
|
return node.transform(new TreeTransformer(function(node){
|
||||||
if (node instanceof AST_Seq) {
|
if (node instanceof AST_Sequence) {
|
||||||
node.cdr = mangleStrings(node.cdr);
|
var last = node.expressions.length - 1;
|
||||||
|
node.expressions[last] = mangleStrings(node.expressions[last]);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_String) {
|
else if (node instanceof AST_String) {
|
||||||
node.value = mangle(node.value);
|
node.value = mangle(node.value);
|
||||||
|
|||||||
@@ -174,9 +174,8 @@ TreeTransformer.prototype = new TreeWalker;
|
|||||||
self.args = do_list(self.args, tw);
|
self.args = do_list(self.args, tw);
|
||||||
});
|
});
|
||||||
|
|
||||||
_(AST_Seq, function(self, tw){
|
_(AST_Sequence, function(self, tw){
|
||||||
self.car = self.car.transform(tw);
|
self.expressions = do_list(self.expressions, tw);
|
||||||
self.cdr = self.cdr.transform(tw);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
_(AST_Dot, function(self, tw){
|
_(AST_Dot, function(self, tw){
|
||||||
|
|||||||
@@ -346,7 +346,7 @@ function first_in_statement(stack) {
|
|||||||
for (var i = 0, p; p = stack.parent(i); i++) {
|
for (var i = 0, p; p = stack.parent(i); i++) {
|
||||||
if (p instanceof AST_Statement && p.body === node)
|
if (p instanceof AST_Statement && p.body === node)
|
||||||
return true;
|
return true;
|
||||||
if ((p instanceof AST_Seq && p.car === node ) ||
|
if ((p instanceof AST_Sequence && p.expressions[0] === node) ||
|
||||||
(p instanceof AST_Call && p.expression === node && !(p instanceof AST_New) ) ||
|
(p instanceof AST_Call && p.expression === node && !(p instanceof AST_New) ) ||
|
||||||
(p instanceof AST_Dot && p.expression === node ) ||
|
(p instanceof AST_Dot && p.expression === node ) ||
|
||||||
(p instanceof AST_Sub && p.expression === node ) ||
|
(p instanceof AST_Sub && p.expression === node ) ||
|
||||||
|
|||||||
@@ -979,12 +979,12 @@ delete_conditional_1: {
|
|||||||
console.log(delete (1 ? 0 / 0 : x));
|
console.log(delete (1 ? 0 / 0 : x));
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log((void 0, !0));
|
console.log(!0);
|
||||||
console.log((void 0, !0));
|
console.log(!0);
|
||||||
console.log((1 / 0, !0));
|
console.log(!0);
|
||||||
console.log((1 / 0, !0));
|
console.log(!0);
|
||||||
console.log((NaN, !0));
|
console.log(!0);
|
||||||
console.log((NaN, !0));
|
console.log(!0);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
@@ -1006,12 +1006,12 @@ delete_conditional_2: {
|
|||||||
console.log(delete (0 ? x : 0 / 0));
|
console.log(delete (0 ? x : 0 / 0));
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log((void 0, !0));
|
console.log(!0);
|
||||||
console.log((void 0, !0));
|
console.log(!0);
|
||||||
console.log((Infinity, !0));
|
console.log(!0);
|
||||||
console.log((1 / 0, !0));
|
console.log(!0);
|
||||||
console.log((NaN, !0));
|
console.log(!0);
|
||||||
console.log((NaN, !0));
|
console.log(!0);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -922,12 +922,12 @@ delete_binary_1: {
|
|||||||
console.log(delete (true && (0 / 0)));
|
console.log(delete (true && (0 / 0)));
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log((void 0, !0));
|
console.log(!0);
|
||||||
console.log((void 0, !0));
|
console.log(!0);
|
||||||
console.log((1 / 0, !0));
|
console.log(!0);
|
||||||
console.log((1 / 0, !0));
|
console.log(!0);
|
||||||
console.log((NaN, !0));
|
console.log(!0);
|
||||||
console.log((NaN, !0));
|
console.log(!0);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
@@ -948,12 +948,12 @@ delete_binary_2: {
|
|||||||
console.log(delete (false || (0 / 0)));
|
console.log(delete (false || (0 / 0)));
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log((void 0, !0));
|
console.log(!0);
|
||||||
console.log((void 0, !0));
|
console.log(!0);
|
||||||
console.log((Infinity, !0));
|
console.log(!0);
|
||||||
console.log((1 / 0, !0));
|
console.log(!0);
|
||||||
console.log((NaN, !0));
|
console.log(!0);
|
||||||
console.log((NaN, !0));
|
console.log(!0);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ negate_iife_4: {
|
|||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
(function(){ return t })() ? console.log(true) : console.log(false), function(){
|
!function(){ return t }() ? console.log(false) : console.log(true), function(){
|
||||||
console.log("something");
|
console.log("something");
|
||||||
}();
|
}();
|
||||||
}
|
}
|
||||||
@@ -183,7 +183,7 @@ negate_iife_5: {
|
|||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
(function(){ return t })() ? foo(true) : bar(false), function(){
|
!function(){ return t }() ? bar(false) : foo(true), function(){
|
||||||
console.log("something");
|
console.log("something");
|
||||||
}();
|
}();
|
||||||
}
|
}
|
||||||
@@ -207,7 +207,7 @@ negate_iife_5_off: {
|
|||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
(function(){ return t })() ? foo(true) : bar(false), function(){
|
!function(){ return t }() ? bar(false) : foo(true), function(){
|
||||||
console.log("something");
|
console.log("something");
|
||||||
}();
|
}();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -460,7 +460,7 @@ issue_1758: {
|
|||||||
console.log(function(c) {
|
console.log(function(c) {
|
||||||
var undefined = 42;
|
var undefined = 42;
|
||||||
return function() {
|
return function() {
|
||||||
return c--, c--, c.toString(), void 0;
|
return c--, c--, void c.toString();
|
||||||
}();
|
}();
|
||||||
}());
|
}());
|
||||||
}
|
}
|
||||||
@@ -481,12 +481,12 @@ delete_seq_1: {
|
|||||||
console.log(delete (1, 0 / 0));
|
console.log(delete (1, 0 / 0));
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log((void 0, !0));
|
console.log(!0);
|
||||||
console.log((void 0, !0));
|
console.log(!0);
|
||||||
console.log((1 / 0, !0));
|
console.log(!0);
|
||||||
console.log((1 / 0, !0));
|
console.log(!0);
|
||||||
console.log((NaN, !0));
|
console.log(!0);
|
||||||
console.log((0 / 0, !0));
|
console.log(!0);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
@@ -505,12 +505,12 @@ delete_seq_2: {
|
|||||||
console.log(delete (1, 2, 0 / 0));
|
console.log(delete (1, 2, 0 / 0));
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log((void 0, !0));
|
console.log(!0);
|
||||||
console.log((void 0, !0));
|
console.log(!0);
|
||||||
console.log((1 / 0, !0));
|
console.log(!0);
|
||||||
console.log((1 / 0, !0));
|
console.log(!0);
|
||||||
console.log((NaN, !0));
|
console.log(!0);
|
||||||
console.log((0 / 0, !0));
|
console.log(!0);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
@@ -530,12 +530,12 @@ delete_seq_3: {
|
|||||||
console.log(delete (1, 2, 0 / 0));
|
console.log(delete (1, 2, 0 / 0));
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log((void 0, !0));
|
console.log(!0);
|
||||||
console.log((void 0, !0));
|
console.log(!0);
|
||||||
console.log((Infinity, !0));
|
console.log(!0);
|
||||||
console.log((1 / 0, !0));
|
console.log(!0);
|
||||||
console.log((NaN, !0));
|
console.log(!0);
|
||||||
console.log((0 / 0, !0));
|
console.log(!0);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
@@ -606,7 +606,85 @@ delete_seq_6: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var a;
|
var a;
|
||||||
console.log((a, !0));
|
console.log(!0);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
side_effects: {
|
||||||
|
options = {
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
0, a(), 1, b(), 2, c(), 3;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
a(), b(), c();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
side_effects_cascade_1: {
|
||||||
|
options = {
|
||||||
|
cascade: true,
|
||||||
|
conditionals: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b) {
|
||||||
|
a -= 42;
|
||||||
|
if (a < 0) a = 0;
|
||||||
|
b.a = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b) {
|
||||||
|
(a -= 42) < 0 && (a = 0), b.a = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
side_effects_cascade_2: {
|
||||||
|
options = {
|
||||||
|
cascade: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b) {
|
||||||
|
b = a,
|
||||||
|
!a + (b += a) || (b += a),
|
||||||
|
b = a,
|
||||||
|
b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b) {
|
||||||
|
b = a,
|
||||||
|
!a + (b += a) || (b += a),
|
||||||
|
b = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
side_effects_cascade_3: {
|
||||||
|
options = {
|
||||||
|
cascade: true,
|
||||||
|
conditionals: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b) {
|
||||||
|
"foo" ^ (b += a),
|
||||||
|
b ? false : (b = a) ? -1 : (b -= a) - (b ^= a),
|
||||||
|
a-- || !a,
|
||||||
|
a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b) {
|
||||||
|
!(b += a) && ((b = a) || (b -= a, b ^= a)),
|
||||||
|
--a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user