This commit is contained in:
Alex Lam S.L 2017-02-26 22:31:01 +00:00 committed by GitHub
commit dcd015cbe9
4 changed files with 85 additions and 69 deletions

View File

@ -591,10 +591,20 @@ var AST_New = DEFNODE("New", null, {
var AST_Seq = DEFNODE("Seq", "car cdr", { var AST_Seq = DEFNODE("Seq", "car cdr", {
$documentation: "A sequence expression (two comma-separated expressions)", $documentation: "A sequence expression (two comma-separated expressions)",
$propdoc: { $propdoc: {
car: "[AST_Node] first element in sequence", car: "[AST_Node] first element in sequence (should not be instanceof AST_Seq or null)",
cdr: "[AST_Node] second element in sequence" cdr: "[AST_Node] second element in sequence (should not be null)"
}, },
$cons: function(x, y) { $cons: function(x, y) {
// TODO: Remove these sanity checks at the end of PR
if (!x) {
throw new Error('AST_Seq.car missing');
}
if (!y) {
throw new Error('AST_Seq.cdr missing');
}
if (x instanceof AST_Seq) {
throw new Error('AST_Seq.car cannot be AST_Seq');
}
var seq = new AST_Seq(x); var seq = new AST_Seq(x);
seq.car = x; seq.car = x;
seq.cdr = y; seq.cdr = y;
@ -603,53 +613,53 @@ var AST_Seq = DEFNODE("Seq", "car cdr", {
$from_array: function(array) { $from_array: function(array) {
if (array.length == 0) return null; if (array.length == 0) return null;
if (array.length == 1) return array[0].clone(); if (array.length == 1) return array[0].clone();
var list = null; var i = array.length - 1;
for (var i = array.length; --i >= 0;) { var list = array[i];
while (--i >= 0) {
var node = array[i];
if (node instanceof AST_Seq) {
node.add(list);
list = node;
} else {
list = AST_Seq.cons(array[i], list); 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; return list;
}, },
to_array: function() { to_array: function() {
var p = this, a = []; var a = [];
while (p) { var p = this;
do {
a.push(p.car); a.push(p.car);
if (p.cdr && !(p.cdr instanceof AST_Seq)) {
a.push(p.cdr);
break;
}
p = p.cdr; p = p.cdr;
} } while (p instanceof AST_Seq);
a.push(p);
return a; return a;
}, },
add: function(node) { tail: function() {
var p = this; var p = this;
while (p) { while (p.cdr instanceof AST_Seq) {
if (!(p.cdr instanceof AST_Seq)) {
var cell = AST_Seq.cons(p.cdr, node);
return p.cdr = cell;
}
p = p.cdr; p = p.cdr;
} }
return p;
},
add: function(node) {
var p = this.tail();
p.cdr = AST_Seq.cons(p.cdr, node);
}, },
len: function() { len: function() {
if (this.cdr instanceof AST_Seq) { var i = 2;
return this.cdr.len() + 1; var p = this.cdr;
} else { while (p instanceof AST_Seq) {
return 2; p = p.cdr;
i++;
} }
return i;
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function(){
this.car._walk(visitor); this.car._walk(visitor);
if (this.cdr) this.cdr._walk(visitor); this.cdr._walk(visitor);
}); });
} }
}); });

View File

@ -959,7 +959,7 @@ merge(Compressor.prototype, {
return this.operator == "=" && this.right.is_boolean(); return this.operator == "=" && this.right.is_boolean();
}); });
def(AST_Seq, function(){ def(AST_Seq, function(){
return this.cdr.is_boolean(); return this.tail().cdr.is_boolean();
}); });
def(AST_True, return_true); def(AST_True, return_true);
def(AST_False, return_true); def(AST_False, return_true);
@ -982,7 +982,7 @@ merge(Compressor.prototype, {
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_Seq, function(compressor){
return this.cdr.is_string(compressor); return this.tail().cdr.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);
@ -1459,8 +1459,12 @@ merge(Compressor.prototype, {
return !compressor.option("pure_getters"); return !compressor.option("pure_getters");
}); });
def(AST_Seq, function(compressor){ def(AST_Seq, function(compressor){
return this.car.has_side_effects(compressor) var p = this;
|| this.cdr.has_side_effects(compressor); do {
if (p.car.has_side_effects(compressor)) return true;
p = p.cdr;
} while (p instanceof AST_Seq);
return p.has_side_effects(compressor);
}); });
})(function(node, func){ })(function(node, func){
node.DEFMETHOD("has_side_effects", func); node.DEFMETHOD("has_side_effects", func);
@ -2669,12 +2673,11 @@ merge(Compressor.prototype, {
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) {
var seq = this.expression; var seq = this.expression;
var x = seq.to_array(); if (seq instanceof AST_Seq) {
this.expression = x.pop(); var p = seq.tail();
x.push(this); this.expression = p.cdr;
seq = AST_Seq.from_array(x).transform(compressor); p.cdr = this.transform(compressor);
return seq; return seq;
} }
} }
@ -2687,8 +2690,9 @@ merge(Compressor.prototype, {
OPT(AST_UnaryPrefix, function(self, compressor){ OPT(AST_UnaryPrefix, function(self, compressor){
self = self.lift_sequences(compressor); self = self.lift_sequences(compressor);
var e = self.expression; if (!(self instanceof AST_UnaryPrefix)) return self;
if (compressor.option("booleans") && compressor.in_boolean_context()) { if (compressor.option("booleans") && compressor.in_boolean_context()) {
var e = self.expression;
switch (self.operator) { switch (self.operator) {
case "!": case "!":
if (e instanceof AST_UnaryPrefix && e.operator == "!") { if (e instanceof AST_UnaryPrefix && e.operator == "!") {
@ -2726,22 +2730,20 @@ 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) {
var seq = this.left; var seq = this.left;
var x = seq.to_array(); if (seq instanceof AST_Seq) {
this.left = x.pop(); var p = seq.tail();
x.push(this); this.left = p.cdr;
seq = AST_Seq.from_array(x).transform(compressor); p.cdr = this.transform(compressor);
return seq; return seq;
} }
if (this.right instanceof AST_Seq seq = this.right;
if (seq instanceof AST_Seq
&& this instanceof AST_Assign && this instanceof AST_Assign
&& !has_side_effects_or_prop_access(this.left, compressor)) { && !has_side_effects_or_prop_access(this.left, compressor)) {
var seq = this.right; var p = seq.tail();
var x = seq.to_array(); this.right = p.cdr;
this.right = x.pop(); p.cdr = this.transform(compressor);
x.push(this);
seq = AST_Seq.from_array(x).transform(compressor);
return seq; return seq;
} }
} }
@ -2809,6 +2811,7 @@ merge(Compressor.prototype, {
} }
} }
self = self.lift_sequences(compressor); self = self.lift_sequences(compressor);
if (!(self instanceof AST_Binary)) return self;
if (compressor.option("comparisons")) switch (self.operator) { if (compressor.option("comparisons")) switch (self.operator) {
case "===": case "===":
case "!==": case "!==":
@ -3078,6 +3081,7 @@ merge(Compressor.prototype, {
var ASSIGN_OPS_COMMUTATIVE = [ '*', '|', '^', '&' ]; var ASSIGN_OPS_COMMUTATIVE = [ '*', '|', '^', '&' ];
OPT(AST_Assign, function(self, compressor){ OPT(AST_Assign, function(self, compressor){
self = self.lift_sequences(compressor); self = self.lift_sequences(compressor);
if (!(self instanceof AST_Assign)) return self;
if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) { if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) {
// x = expr1 OP expr2 // x = expr1 OP expr2
if (self.right.left instanceof AST_SymbolRef if (self.right.left instanceof AST_SymbolRef
@ -3100,12 +3104,16 @@ merge(Compressor.prototype, {
}); });
OPT(AST_Conditional, function(self, compressor){ OPT(AST_Conditional, function(self, compressor){
if (!compressor.option("conditionals")) return self; if (compressor.option("sequences")) {
if (self.condition instanceof AST_Seq) { var seq = self.condition;
var car = self.condition.car; if (seq instanceof AST_Seq) {
self.condition = self.condition.cdr; var p = seq.tail();
return AST_Seq.cons(car, self); self.condition = p.cdr;
p.cdr = self.transform(compressor);
return seq;
} }
}
if (!compressor.option("conditionals")) return self;
var cond = self.condition.evaluate(compressor); var cond = self.condition.evaluate(compressor);
if (cond.length > 1) { if (cond.length > 1) {
if (cond[1]) { if (cond[1]) {
@ -3188,7 +3196,7 @@ merge(Compressor.prototype, {
&& consequent.equivalent_to(alternative)) { && consequent.equivalent_to(alternative)) {
var consequent_value = consequent.evaluate(compressor)[0]; var consequent_value = consequent.evaluate(compressor)[0];
if (self.condition.has_side_effects(compressor)) { if (self.condition.has_side_effects(compressor)) {
return AST_Seq.from_array([self.condition, consequent_value]); return AST_Seq.cons(self.condition, consequent_value);
} else { } else {
return consequent_value; return consequent_value;
} }

View File

@ -1106,14 +1106,12 @@ function OutputStream(options) {
AST_Seq.DEFMETHOD("_do_print", function(output){ AST_Seq.DEFMETHOD("_do_print", function(output){
this.car.print(output); this.car.print(output);
if (this.cdr) {
output.comma(); output.comma();
if (output.should_break()) { if (output.should_break()) {
output.newline(); output.newline();
output.indent(); output.indent();
} }
this.cdr.print(output); this.cdr.print(output);
}
}); });
DEFPRINT(AST_Seq, function(self, output){ DEFPRINT(AST_Seq, function(self, output){
self._do_print(output); self._do_print(output);

View File

@ -29,6 +29,7 @@ typeof_in_boolean_context: {
booleans : true, booleans : true,
evaluate : true, evaluate : true,
conditionals : true, conditionals : true,
sequences : true,
}; };
input: { input: {
function f1(x) { return typeof x ? "yes" : "no"; } function f1(x) { return typeof x ? "yes" : "no"; }
@ -40,8 +41,7 @@ typeof_in_boolean_context: {
expect: { expect: {
function f1(x) { return "yes"; } function f1(x) { return "yes"; }
function f2() { return g(), "Yes"; } function f2() { return g(), "Yes"; }
foo(); foo(), console.log(1), !1;
!(console.log(1), !0); var a = (console.log(2), !1);
var a = !(console.log(2), !0);
} }
} }