minor tweak to sequence manipulations
- loop through `AST_Seq` chain instead of recursion - avoid deep-cloning in `lift_sequences()` - `AST_Seq.car` should never be `null` or `AST_Seq` - `AST_Seq.cdr` should never be `null`
This commit is contained in:
parent
7f8d72d9d3
commit
7413899ad4
61
lib/ast.js
61
lib/ast.js
|
|
@ -589,6 +589,15 @@ var AST_Seq = DEFNODE("Seq", "car cdr", {
|
||||||
cdr: "[AST_Node] second element in sequence"
|
cdr: "[AST_Node] second element in sequence"
|
||||||
},
|
},
|
||||||
$cons: function(x, y) {
|
$cons: function(x, y) {
|
||||||
|
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;
|
||||||
|
|
@ -596,54 +605,48 @@ 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];
|
||||||
var list = null;
|
var i = array.length - 1;
|
||||||
for (var i = array.length; --i >= 0;) {
|
var list = array[i];
|
||||||
|
while (--i >= 0) {
|
||||||
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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -938,7 +938,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);
|
||||||
|
|
@ -961,7 +961,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);
|
||||||
|
|
@ -1340,8 +1340,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);
|
||||||
|
|
@ -2353,12 +2357,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;
|
if (seq instanceof AST_Seq) {
|
||||||
var x = seq.to_array();
|
var p = seq.tail();
|
||||||
this.expression = x.pop();
|
this.expression = p.cdr;
|
||||||
x.push(this);
|
p.cdr = this.transform(compressor);
|
||||||
seq = AST_Seq.from_array(x).transform(compressor);
|
|
||||||
return seq;
|
return seq;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2371,8 +2374,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 == "!") {
|
||||||
|
|
@ -2409,22 +2413,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;
|
if (seq instanceof AST_Seq) {
|
||||||
var x = seq.to_array();
|
var p = seq.tail();
|
||||||
this.left = x.pop();
|
this.left = p.cdr;
|
||||||
x.push(this);
|
p.cdr = this.transform(compressor);
|
||||||
seq = AST_Seq.from_array(x).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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2492,6 +2494,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 "!==":
|
||||||
|
|
@ -2735,6 +2738,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
|
||||||
|
|
@ -2757,12 +2761,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]) {
|
||||||
|
|
@ -2844,7 +2852,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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1082,14 +1082,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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user