diff --git a/lib/compress.js b/lib/compress.js index e3ae5bde..07e21f89 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -384,7 +384,7 @@ merge(Compressor.prototype, { return new ctor(props); }; - function make_node_from_constant(compressor, val, orig) { + function make_node_from_constant(val, orig) { switch (typeof val) { case "string": return make_node(AST_String, orig, { @@ -404,9 +404,9 @@ merge(Compressor.prototype, { return make_node(AST_Number, orig, { value: val }); case "boolean": - return make_node(val ? AST_True : AST_False, orig).optimize(compressor); + return make_node(val ? AST_True : AST_False, orig); case "undefined": - return make_node(AST_Undefined, orig).transform(compressor); + return make_node(AST_Undefined, orig); default: if (val === null) { return make_node(AST_Null, orig, { value: null }); @@ -1217,7 +1217,7 @@ merge(Compressor.prototype, { properties: props }); } - return make_node_from_constant(compressor, value, orig); + return make_node_from_constant(value, orig); } def(AST_Node, noop); def(AST_Dot, function(compressor, suffix){ @@ -1243,20 +1243,24 @@ merge(Compressor.prototype, { node.DEFMETHOD("_find_defs", func); }); - function best_of(ast1, ast2) { + function best_of_expression(ast1, ast2) { return ast1.print_to_string().length > ast2.print_to_string().length ? ast2 : ast1; } function best_of_statement(ast1, ast2) { - return best_of(make_node(AST_SimpleStatement, ast1, { + return best_of_expression(make_node(AST_SimpleStatement, ast1, { body: ast1 }), make_node(AST_SimpleStatement, ast2, { body: ast2 })).body; } + function best_of(compressor, ast1, ast2) { + return (first_in_statement(compressor) ? best_of_statement : best_of_expression)(ast1, ast2); + } + // methods to evaluate a constant expression (function (def){ // The evaluate method returns an array with one or two @@ -1277,11 +1281,18 @@ merge(Compressor.prototype, { } var node; try { - node = make_node_from_constant(compressor, val, this); + node = make_node_from_constant(val, this); } catch(ex) { return [ this ]; } - return [ best_of(node, this), val ]; + return [ node, val ]; + }); + AST_Node.DEFMETHOD("evaluate_self", function(compressor){ + var ev = this.evaluate(compressor); + if (ev.length > 1 && !ev[0].equivalent_to(this)) { + return best_of(compressor, ev[0].optimize(compressor), this); + } + return this; }); var unaryPrefix = makePredicate("! ~ - +"); AST_Node.DEFMETHOD("is_constant", function(){ @@ -1480,9 +1491,9 @@ merge(Compressor.prototype, { var stat = make_node(AST_SimpleStatement, alt, { body: alt }); - return best_of(negated, stat) === stat ? alt : negated; + return best_of_expression(negated, stat) === stat ? alt : negated; } - return best_of(negated, alt); + return best_of_expression(negated, alt); } def(AST_Node, function(){ return basic_negation(this); @@ -1678,7 +1689,7 @@ merge(Compressor.prototype, { OPT(AST_LabeledStatement, function(self, compressor){ if (self.body instanceof AST_Break - && compressor.loopcontrol_target(self.body.label) === self.body) { + && compressor.loopcontrol_target(self.body.label) === compressor.self().body) { return make_node(AST_EmptyStatement, self); } return self.label.references.length == 0 ? self.body : self; @@ -2242,7 +2253,9 @@ merge(Compressor.prototype, { OPT(AST_DWLoop, function(self, compressor){ var cond = self.condition.evaluate(compressor); - self.condition = cond[0]; + if (cond.length > 1) { + self.condition = best_of_expression(cond[0].transform(compressor), self.condition); + } if (!compressor.option("loops")) return self; if (cond.length > 1) { if (cond[1]) { @@ -2261,7 +2274,7 @@ merge(Compressor.prototype, { } } if (self instanceof AST_While) { - return make_node(AST_For, self, self).transform(compressor); + return make_node(AST_For, self, self).optimize(compressor); } return self; }); @@ -2283,7 +2296,7 @@ merge(Compressor.prototype, { var first = self.body instanceof AST_BlockStatement ? self.body.body[0] : self.body; if (first instanceof AST_If) { if (first.body instanceof AST_Break - && compressor.loopcontrol_target(first.body.label) === self) { + && compressor.loopcontrol_target(first.body.label) === compressor.self()) { if (self.condition) { self.condition = make_node(AST_Binary, self.condition, { left: self.condition, @@ -2296,7 +2309,7 @@ merge(Compressor.prototype, { drop_it(first.alternative); } else if (first.alternative instanceof AST_Break - && compressor.loopcontrol_target(first.alternative.label) === self) { + && compressor.loopcontrol_target(first.alternative.label) === compressor.self()) { if (self.condition) { self.condition = make_node(AST_Binary, self.condition, { left: self.condition, @@ -2315,7 +2328,9 @@ merge(Compressor.prototype, { var cond = self.condition; if (cond) { cond = cond.evaluate(compressor); - self.condition = cond[0]; + if (cond.length > 1) { + self.condition = best_of_expression(cond[0].transform(compressor), self.condition); + } } if (!compressor.option("loops")) return self; if (cond) { @@ -2348,7 +2363,6 @@ merge(Compressor.prototype, { // “has no side effects”; also it doesn't work for cases like // `x && true`, though it probably should. var cond = self.condition.evaluate(compressor); - self.condition = cond[0]; if (cond.length > 1) { if (cond[1]) { compressor.warn("Condition always true [{file}:{line},{col}]", self.condition.start); @@ -2358,7 +2372,7 @@ merge(Compressor.prototype, { extract_declarations_from_unreachable_code(compressor, self.alternative, a); } a.push(self.body); - return make_node(AST_BlockStatement, self, { body: a }).transform(compressor); + return make_node(AST_BlockStatement, self, { body: a }).optimize(compressor); } } else { compressor.warn("Condition always false [{file}:{line},{col}]", self.condition.start); @@ -2366,9 +2380,10 @@ merge(Compressor.prototype, { var a = []; extract_declarations_from_unreachable_code(compressor, self.body, a); if (self.alternative) a.push(self.alternative); - return make_node(AST_BlockStatement, self, { body: a }).transform(compressor); + return make_node(AST_BlockStatement, self, { body: a }).optimize(compressor); } } + self.condition = best_of_expression(cond[0].transform(compressor), self.condition); } var negated = self.condition.negate(compressor); var self_condition_length = self.condition.print_to_string().length; @@ -2386,7 +2401,7 @@ merge(Compressor.prototype, { if (is_empty(self.body) && is_empty(self.alternative)) { return make_node(AST_SimpleStatement, self.condition, { body: self.condition - }).transform(compressor); + }).optimize(compressor); } if (self.body instanceof AST_SimpleStatement && self.alternative instanceof AST_SimpleStatement) { @@ -2396,7 +2411,7 @@ merge(Compressor.prototype, { consequent : statement_to_expression(self.body), alternative : statement_to_expression(self.alternative) }) - }).transform(compressor); + }).optimize(compressor); } if (is_empty(self.alternative) && self.body instanceof AST_SimpleStatement) { if (self_condition_length === negated_length && !negated_is_best @@ -2412,14 +2427,14 @@ merge(Compressor.prototype, { left : negated, right : statement_to_expression(self.body) }) - }).transform(compressor); + }).optimize(compressor); return make_node(AST_SimpleStatement, self, { body: make_node(AST_Binary, self, { operator : "&&", left : self.condition, right : statement_to_expression(self.body) }) - }).transform(compressor); + }).optimize(compressor); } if (self.body instanceof AST_EmptyStatement && self.alternative @@ -2430,7 +2445,7 @@ merge(Compressor.prototype, { left : self.condition, right : statement_to_expression(self.alternative) }) - }).transform(compressor); + }).optimize(compressor); } if (self.body instanceof AST_Exit && self.alternative instanceof AST_Exit @@ -2441,7 +2456,7 @@ merge(Compressor.prototype, { consequent : self.body.value || make_node(AST_Undefined, self.body), alternative : self.alternative.value || make_node(AST_Undefined, self.alternative) }) - }).transform(compressor); + }).optimize(compressor); } if (self.body instanceof AST_If && !self.body.alternative @@ -2459,7 +2474,7 @@ merge(Compressor.prototype, { self.alternative = null; return make_node(AST_BlockStatement, self, { body: [ self, alt ] - }).transform(compressor); + }).optimize(compressor); } } if (aborts(self.alternative)) { @@ -2469,7 +2484,7 @@ merge(Compressor.prototype, { self.alternative = null; return make_node(AST_BlockStatement, self, { body: [ self, body ] - }).transform(compressor); + }).optimize(compressor); } return self; }); @@ -2478,13 +2493,13 @@ merge(Compressor.prototype, { if (self.body.length == 0 && compressor.option("conditionals")) { return make_node(AST_SimpleStatement, self, { body: self.expression - }).transform(compressor); + }).optimize(compressor); } for(;;) { var last_branch = self.body[self.body.length - 1]; if (last_branch) { var stat = last_branch.body[last_branch.body.length - 1]; // last statement - if (stat instanceof AST_Break && loop_body(compressor.loopcontrol_target(stat.label)) === self) + if (stat instanceof AST_Break && loop_body(compressor.loopcontrol_target(stat.label)) === compressor.self()) last_branch.body.pop(); if (last_branch instanceof AST_Default && last_branch.body.length == 0) { self.body.pop(); @@ -2496,7 +2511,7 @@ merge(Compressor.prototype, { var exp = self.expression.evaluate(compressor); out: if (exp.length == 2) try { // constant expression - self.expression = exp[0]; + self.expression = best_of_expression(exp[0].transform(compressor), self.expression); if (!compressor.option("dead_code")) break out; var value = exp[1]; var in_if = false; @@ -2509,14 +2524,14 @@ merge(Compressor.prototype, { // no need to descend these node types return node; } - else if (node instanceof AST_Switch && node === self) { + else if (node === self) { node = node.clone(); descend(node, this); return ruined ? node : make_node(AST_BlockStatement, node, { body: node.body.reduce(function(a, branch){ return a.concat(branch.body); }, []) - }).transform(compressor); + }).optimize(compressor); } else if (node instanceof AST_If || node instanceof AST_Try) { var save = in_if; @@ -2532,7 +2547,7 @@ merge(Compressor.prototype, { in_block = save; return node; } - else if (node instanceof AST_Break && this.loopcontrol_target(node.label) === self) { + else if (node instanceof AST_Break && this.loopcontrol_target(node.label) === compressor.self()) { if (in_if) { ruined = true; return node; @@ -2656,7 +2671,7 @@ merge(Compressor.prototype, { if (self.args.length != 1) { return make_node(AST_Array, self, { elements: self.args - }).transform(compressor); + }).optimize(compressor); } break; case "Object": @@ -2674,7 +2689,7 @@ merge(Compressor.prototype, { left: self.args[0], operator: "+", right: make_node(AST_String, self, { value: "" }) - }).transform(compressor); + }).optimize(compressor); break; case "Number": if (self.args.length == 0) return make_node(AST_Number, self, { @@ -2683,7 +2698,7 @@ merge(Compressor.prototype, { if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, { expression: self.args[0], operator: "+" - }).transform(compressor); + }).optimize(compressor); case "Boolean": if (self.args.length == 0) return make_node(AST_False, self); if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, { @@ -2692,7 +2707,7 @@ merge(Compressor.prototype, { operator: "!" }), operator: "!" - }).transform(compressor); + }).optimize(compressor); break; case "Function": // new Function() => function(){} @@ -2757,7 +2772,7 @@ merge(Compressor.prototype, { left: make_node(AST_String, self, { value: "" }), operator: "+", right: exp.expression - }).transform(compressor); + }).optimize(compressor); } else if (exp instanceof AST_Dot && exp.expression instanceof AST_Array && exp.property == "join") EXIT: { var separator; @@ -2769,9 +2784,9 @@ merge(Compressor.prototype, { var elements = []; var consts = []; exp.expression.elements.forEach(function(el) { - el = el.evaluate(compressor); - if (el.length > 1) { - consts.push(el[1]); + var ev = el.evaluate(compressor); + if (ev.length > 1) { + consts.push(ev[1]); } else { if (consts.length > 0) { elements.push(make_node(AST_String, self, { @@ -2779,7 +2794,7 @@ merge(Compressor.prototype, { })); consts.length = 0; } - elements.push(el[0]); + elements.push(el); } }); if (consts.length > 0) { @@ -2812,15 +2827,15 @@ merge(Compressor.prototype, { left : prev, right : el }); - }, first).transform(compressor); + }, first).optimize(compressor); } // need this awkward cloning to not affect original element - // best_of will decide which one to get through. + // best_of_expression will decide which one to get through. var node = self.clone(); node.expression = node.expression.clone(); node.expression.expression = node.expression.expression.clone(); node.expression.expression.elements = elements; - return best_of(self, node); + return best_of_expression(self, node); } } if (exp instanceof AST_Function) { @@ -2828,13 +2843,13 @@ merge(Compressor.prototype, { var value = exp.body[0].value; if (!value || value.is_constant()) { var args = self.args.concat(value || make_node(AST_Undefined, self)); - return AST_Seq.from_array(args).transform(compressor); + return AST_Seq.from_array(args).optimize(compressor); } } if (compressor.option("side_effects")) { if (!AST_Block.prototype.has_side_effects.call(exp, compressor)) { var args = self.args.concat(make_node(AST_Undefined, self)); - return AST_Seq.from_array(args).transform(compressor); + return AST_Seq.from_array(args).optimize(compressor); } } } @@ -2847,7 +2862,7 @@ merge(Compressor.prototype, { if (name instanceof AST_SymbolRef && name.name == "console" && name.undeclared()) { - return make_node(AST_Undefined, self).transform(compressor); + return make_node(AST_Undefined, self).optimize(compressor); } } } @@ -2869,7 +2884,7 @@ merge(Compressor.prototype, { case "Function": case "Error": case "Array": - return make_node(AST_Call, self, self).transform(compressor); + return make_node(AST_Call, self, self).optimize(compressor); } } } @@ -2932,7 +2947,7 @@ merge(Compressor.prototype, { var x = seq.to_array(); this.expression = x.pop(); x.push(this); - seq = AST_Seq.from_array(x).transform(compressor); + seq = AST_Seq.from_array(x); return seq; } } @@ -2940,13 +2955,14 @@ merge(Compressor.prototype, { }); OPT(AST_UnaryPostfix, function(self, compressor){ - return self.lift_sequences(compressor); + var seq = self.lift_sequences(compressor); + return seq !== self ? seq.optimize(compressor) : self; }); OPT(AST_UnaryPrefix, function(self, compressor){ var seq = self.lift_sequences(compressor); if (seq !== self) { - return seq; + return seq.optimize(compressor); } var e = self.expression; if (compressor.option("side_effects") && self.operator == "void") { @@ -2955,7 +2971,7 @@ merge(Compressor.prototype, { self.expression = e; return self; } else { - return make_node(AST_Undefined, self).transform(compressor); + return make_node(AST_Undefined, self).optimize(compressor); } } if (compressor.option("booleans") && compressor.in_boolean_context()) { @@ -2966,8 +2982,7 @@ merge(Compressor.prototype, { return e.expression; } if (e instanceof AST_Binary) { - var statement = first_in_statement(compressor); - self = (statement ? best_of_statement : best_of)(self, e.negate(compressor, statement)); + self = best_of(compressor, self, e.negate(compressor, first_in_statement(compressor))); } break; case "typeof": @@ -2980,7 +2995,7 @@ merge(Compressor.prototype, { }).optimize(compressor); } } - return self.evaluate(compressor)[0]; + return self.evaluate_self(compressor); }); function has_side_effects_or_prop_access(node, compressor) { @@ -2998,7 +3013,7 @@ merge(Compressor.prototype, { var x = seq.to_array(); this.left = x.pop(); x.push(this); - seq = AST_Seq.from_array(x).transform(compressor); + seq = AST_Seq.from_array(x); return seq; } if (this.right instanceof AST_Seq @@ -3008,7 +3023,7 @@ merge(Compressor.prototype, { var x = seq.to_array(); this.right = x.pop(); x.push(this); - seq = AST_Seq.from_array(x).transform(compressor); + seq = AST_Seq.from_array(x); return seq; } } @@ -3018,16 +3033,6 @@ merge(Compressor.prototype, { var commutativeOperators = makePredicate("== === != !== * & | ^"); OPT(AST_Binary, function(self, compressor){ - var lhs = self.left.evaluate(compressor); - var rhs = self.right.evaluate(compressor); - if (lhs.length > 1 && lhs[0].is_constant() !== self.left.is_constant() - || rhs.length > 1 && rhs[0].is_constant() !== self.right.is_constant()) { - return make_node(AST_Binary, self, { - operator: self.operator, - left: lhs[0], - right: rhs[0] - }).optimize(compressor); - } function reversible() { return self.left instanceof AST_Constant || self.right instanceof AST_Constant @@ -3081,7 +3086,10 @@ merge(Compressor.prototype, { } } } - self = self.lift_sequences(compressor); + var seq = self.lift_sequences(compressor); + if (seq !== self) { + return seq.optimize(compressor); + } if (compressor.option("comparisons")) switch (self.operator) { case "===": case "!==": @@ -3102,7 +3110,7 @@ merge(Compressor.prototype, { if (expr instanceof AST_SymbolRef ? !expr.undeclared() : !(expr instanceof AST_PropAccess) || compressor.option("screw_ie8")) { self.right = expr; - self.left = make_node(AST_Undefined, self.left).optimize(compressor); + self.left = make_node(AST_Undefined, self.left).transform(compressor); if (self.operator.length == 2) self.operator += "="; } } @@ -3115,15 +3123,15 @@ merge(Compressor.prototype, { if ((ll.length > 1 && !ll[1]) || (rr.length > 1 && !rr[1])) { compressor.warn("Boolean && always false [{file}:{line},{col}]", self.start); return make_node(AST_Seq, self, { - car: self.left, - cdr: make_node(AST_False, self) + car: self.left.transform(compressor), + cdr: make_node(AST_False, self).transform(compressor) }).optimize(compressor); } if (ll.length > 1 && ll[1]) { - return rr[0]; + return best_of(compressor, rr[0].optimize(compressor), self.right); } if (rr.length > 1 && rr[1]) { - return ll[0]; + return best_of(compressor, ll[0].optimize(compressor), self.left); } break; case "||": @@ -3132,15 +3140,15 @@ merge(Compressor.prototype, { if ((ll.length > 1 && ll[1]) || (rr.length > 1 && rr[1])) { compressor.warn("Boolean || always true [{file}:{line},{col}]", self.start); return make_node(AST_Seq, self, { - car: self.left, - cdr: make_node(AST_True, self) + car: self.left.transform(compressor), + cdr: make_node(AST_True, self).transform(compressor) }).optimize(compressor); } if (ll.length > 1 && !ll[1]) { - return rr[0]; + return best_of(compressor, rr[0].optimize(compressor), self.right); } if (rr.length > 1 && !rr[1]) { - return ll[0]; + return best_of(compressor, ll[0].optimize(compressor), self.left); } break; case "+": @@ -3149,15 +3157,15 @@ merge(Compressor.prototype, { if (ll.length > 1 && ll[0] instanceof AST_String && ll[1]) { compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start); return make_node(AST_Seq, self, { - car: self.right, - cdr: make_node(AST_True, self) + car: self.right.transform(compressor), + cdr: make_node(AST_True, self).transform(compressor) }).optimize(compressor); } if (rr.length > 1 && rr[0] instanceof AST_String && rr[1]) { compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start); return make_node(AST_Seq, self, { - car: self.left, - cdr: make_node(AST_True, self) + car: self.left.transform(compressor), + cdr: make_node(AST_True, self).transform(compressor) }).optimize(compressor); } break; @@ -3165,12 +3173,11 @@ merge(Compressor.prototype, { if (compressor.option("comparisons") && self.is_boolean()) { if (!(compressor.parent() instanceof AST_Binary) || compressor.parent() instanceof AST_Assign) { - var statement = first_in_statement(compressor); var negated = make_node(AST_UnaryPrefix, self, { operator: "!", - expression: self.negate(compressor, statement) + expression: self.negate(compressor, first_in_statement(compressor)) }); - self = (statement ? best_of_statement : best_of)(self, negated); + self = best_of(compressor, self, negated); } if (compressor.option("unsafe_comps")) { switch (self.operator) { @@ -3196,7 +3203,7 @@ merge(Compressor.prototype, { && self.left.left.getValue() == "" && self.right.is_string(compressor)) { self.left = self.left.right; - return self.transform(compressor); + return self.optimize(compressor); } } if (compressor.option("evaluate")) { @@ -3322,9 +3329,9 @@ merge(Compressor.prototype, { }); if (self.right instanceof AST_Constant && !(self.left instanceof AST_Constant)) { - self = best_of(reversed, self); + self = best_of(compressor, reversed, self); } else { - self = best_of(self, reversed); + self = best_of(compressor, self, reversed); } } if (associative && self.is_number(compressor)) { @@ -3417,11 +3424,10 @@ merge(Compressor.prototype, { operator : self.operator, left : self.left, right : self.right.left - }); - self.right = self.right.right; - return self.transform(compressor); + }).transform(compressor); + self.right = self.right.right.transform(compressor); } - return self.evaluate(compressor)[0]; + return self.evaluate_self(compressor); }); OPT(AST_SymbolRef, function(self, compressor){ @@ -3436,11 +3442,11 @@ merge(Compressor.prototype, { && (!self.scope.uses_with || !compressor.find_parent(AST_With))) { switch (self.name) { case "undefined": - return make_node(AST_Undefined, self).transform(compressor); + return make_node(AST_Undefined, self).optimize(compressor); case "NaN": - return make_node(AST_NaN, self).transform(compressor); + return make_node(AST_NaN, self).optimize(compressor); case "Infinity": - return make_node(AST_Infinity, self).transform(compressor); + return make_node(AST_Infinity, self).optimize(compressor); } } if (compressor.option("evaluate") && compressor.option("reduce_vars")) { @@ -3449,11 +3455,12 @@ merge(Compressor.prototype, { if (d.should_replace === undefined) { var init = d.fixed.evaluate(compressor); if (init.length > 1) { - var value = init[0].print_to_string().length; + init = best_of(compressor, init[0].optimize(compressor), d.fixed); + var value = init.print_to_string().length; var name = d.name.length; var freq = d.references.length; var overhead = d.global || !freq ? 0 : (name + 2 + value) / freq; - d.should_replace = value <= name + overhead ? init[0] : false; + d.should_replace = value <= name + overhead ? init : false; } else { d.should_replace = false; } @@ -3494,7 +3501,10 @@ merge(Compressor.prototype, { var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ]; var ASSIGN_OPS_COMMUTATIVE = [ '*', '|', '^', '&' ]; OPT(AST_Assign, function(self, compressor){ - self = self.lift_sequences(compressor); + var seq = self.lift_sequences(compressor); + if (seq !== self) { + return seq.optimize(compressor); + } if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) { // x = expr1 OP expr2 if (self.right.left instanceof AST_SymbolRef @@ -3532,10 +3542,10 @@ merge(Compressor.prototype, { compressor.warn("Condition always false [{file}:{line},{col}]", self.start); return maintain_this_binding(compressor.parent(), self, self.alternative); } + self.condition = best_of(compressor, cond[0].transform(compressor), self.condition); } - var statement = first_in_statement(compressor); - var negated = cond[0].negate(compressor, statement); - if ((statement ? best_of_statement : best_of)(cond[0], negated) === negated) { + var negated = self.condition.negate(compressor, first_in_statement(compressor)); + if (best_of(compressor, self.condition, negated) === negated) { self = make_node(AST_Conditional, self, { condition: negated, consequent: self.alternative, @@ -3715,7 +3725,7 @@ merge(Compressor.prototype, { }); } } - return self.evaluate(compressor)[0]; + return self.evaluate_self(compressor); }); OPT(AST_Dot, function(self, compressor){ @@ -3754,13 +3764,12 @@ merge(Compressor.prototype, { break; } } - return self.evaluate(compressor)[0]; + return self.evaluate_self(compressor); }); function literals_in_boolean_context(self, compressor) { if (compressor.option("booleans") && compressor.in_boolean_context()) { - var best = first_in_statement(compressor) ? best_of_statement : best_of; - return best(self, make_node(AST_Seq, self, { + return best_of(compressor, self, make_node(AST_Seq, self, { car: self, cdr: make_node(AST_True, self) }).optimize(compressor)); diff --git a/test/compress/functions.js b/test/compress/functions.js index a1a515a1..b22cad63 100644 --- a/test/compress/functions.js +++ b/test/compress/functions.js @@ -37,7 +37,7 @@ iifes_returning_constants_keep_fargs_true: { console.log(void 0); console.log(2); console.log(6); - console.log((a(), b(), 6)); + console.log((0, a(), b(), 6)); } } diff --git a/test/compress/transform-optimize.js b/test/compress/transform-optimize.js new file mode 100644 index 00000000..aa3c7ffc --- /dev/null +++ b/test/compress/transform-optimize.js @@ -0,0 +1,68 @@ +booleans_evaluate: { + options = { + booleans: true, + evaluate: true, + } + input: { + console.log(typeof void 0 != "undefined"); + console.log(1 == 1, 1 === 1) + console.log(1 != 1, 1 !== 1) + } + expect: { + console.log(!1); + console.log(!0, !0); + console.log(!1, !1); + } +} + +booleans_global_defs: { + options = { + booleans: true, + evaluate: true, + global_defs: { + A: true, + }, + } + input: { + console.log(A == 1); + } + expect: { + console.log(!0); + } +} + +condition_evaluate: { + options = { + booleans: true, + dead_code: false, + evaluate: true, + loops: false, + } + input: { + while (1 === 2); + for (; 1 == true;); + if (void 0 == null); + } + expect: { + while (!1); + for (; !0;); + if (!0); + } +} + +while_if_break: { + options = { + conditionals: true, + loops: true, + sequences: true, + } + input: { + while (a) { + if (b) if(c) d; + if (e) break; + } + } + expect: { + for(; a && (b && c && d, !e);); + } +}