@@ -54,6 +54,7 @@ function Compressor(options, false_by_default) {
54
54
drop_debugger : ! false_by_default ,
55
55
unsafe : false ,
56
56
unsafe_comps : false ,
57
+ unsafe_math : false ,
57
58
unsafe_proto : false ,
58
59
conditionals : ! false_by_default ,
59
60
comparisons : ! false_by_default ,
@@ -1043,6 +1044,34 @@ merge(Compressor.prototype, {
1043
1044
node . DEFMETHOD ( "is_boolean" , func ) ;
1044
1045
} ) ;
1045
1046
1047
+ // methods to determine if an expression has a numeric result type
1048
+ ( function ( def ) {
1049
+ def ( AST_Node , return_false ) ;
1050
+ def ( AST_Number , return_true ) ;
1051
+ var unary = makePredicate ( "+ - ~ ++ --" ) ;
1052
+ def ( AST_Unary , function ( ) {
1053
+ return unary ( this . operator ) ;
1054
+ } ) ;
1055
+ var binary = makePredicate ( "- * / % & | ^ << >> >>>" ) ;
1056
+ def ( AST_Binary , function ( compressor ) {
1057
+ return binary ( this . operator ) || this . operator == "+"
1058
+ && this . left . is_number ( compressor )
1059
+ && this . right . is_number ( compressor ) ;
1060
+ } ) ;
1061
+ var assign = makePredicate ( "-= *= /= %= &= |= ^= <<= >>= >>>=" ) ;
1062
+ def ( AST_Assign , function ( compressor ) {
1063
+ return assign ( this . operator ) || this . right . is_number ( compressor ) ;
1064
+ } ) ;
1065
+ def ( AST_Seq , function ( compressor ) {
1066
+ return this . cdr . is_number ( compressor ) ;
1067
+ } ) ;
1068
+ def ( AST_Conditional , function ( compressor ) {
1069
+ return this . consequent . is_number ( compressor ) && this . alternative . is_number ( compressor ) ;
1070
+ } ) ;
1071
+ } ) ( function ( node , func ) {
1072
+ node . DEFMETHOD ( "is_number" , func ) ;
1073
+ } ) ;
1074
+
1046
1075
// methods to determine if an expression has a string result type
1047
1076
( function ( def ) {
1048
1077
def ( AST_Node , return_false ) ;
@@ -2867,8 +2896,14 @@ merge(Compressor.prototype, {
2867
2896
right : rhs [ 0 ]
2868
2897
} ) . optimize ( compressor ) ;
2869
2898
}
2870
- function reverse ( op , force ) {
2871
- if ( force || ! ( self . left . has_side_effects ( compressor ) || self . right . has_side_effects ( compressor ) ) ) {
2899
+ function reversible ( ) {
2900
+ return self . left instanceof AST_Constant
2901
+ || self . right instanceof AST_Constant
2902
+ || ! self . left . has_side_effects ( compressor )
2903
+ && ! self . right . has_side_effects ( compressor ) ;
2904
+ }
2905
+ function reverse ( op ) {
2906
+ if ( reversible ( ) ) {
2872
2907
if ( op ) self . operator = op ;
2873
2908
var tmp = self . left ;
2874
2909
self . left = self . right ;
@@ -2884,7 +2919,7 @@ merge(Compressor.prototype, {
2884
2919
2885
2920
if ( ! ( self . left instanceof AST_Binary
2886
2921
&& PRECEDENCE [ self . left . operator ] >= PRECEDENCE [ self . operator ] ) ) {
2887
- reverse ( null , true ) ;
2922
+ reverse ( ) ;
2888
2923
}
2889
2924
}
2890
2925
if ( / ^ [ ! = ] = = ? $ / . test ( self . operator ) ) {
@@ -2919,6 +2954,7 @@ merge(Compressor.prototype, {
2919
2954
case "===" :
2920
2955
case "!==" :
2921
2956
if ( ( self . left . is_string ( compressor ) && self . right . is_string ( compressor ) ) ||
2957
+ ( self . left . is_number ( compressor ) && self . right . is_number ( compressor ) ) ||
2922
2958
( self . left . is_boolean ( ) && self . right . is_boolean ( ) ) ) {
2923
2959
self . operator = self . operator . substr ( 0 , 2 ) ;
2924
2960
}
@@ -3056,22 +3092,26 @@ merge(Compressor.prototype, {
3056
3092
}
3057
3093
break ;
3058
3094
}
3059
- if ( self . operator == "+" ) {
3095
+ var associative = true ;
3096
+ switch ( self . operator ) {
3097
+ case "+" :
3098
+ // "foo" + ("bar" + x) => "foobar" + x
3060
3099
if ( self . left instanceof AST_Constant
3061
3100
&& self . right instanceof AST_Binary
3062
3101
&& self . right . operator == "+"
3063
3102
&& self . right . left instanceof AST_Constant
3064
3103
&& self . right . is_string ( compressor ) ) {
3065
3104
self = make_node ( AST_Binary , self , {
3066
3105
operator : "+" ,
3067
- left : make_node ( AST_String , null , {
3106
+ left : make_node ( AST_String , self . left , {
3068
3107
value : "" + self . left . getValue ( ) + self . right . left . getValue ( ) ,
3069
3108
start : self . left . start ,
3070
3109
end : self . right . left . end
3071
3110
} ) ,
3072
3111
right : self . right . right
3073
3112
} ) ;
3074
3113
}
3114
+ // (x + "foo") + "bar" => x + "foobar"
3075
3115
if ( self . right instanceof AST_Constant
3076
3116
&& self . left instanceof AST_Binary
3077
3117
&& self . left . operator == "+"
@@ -3080,13 +3120,14 @@ merge(Compressor.prototype, {
3080
3120
self = make_node ( AST_Binary , self , {
3081
3121
operator : "+" ,
3082
3122
left : self . left . left ,
3083
- right : make_node ( AST_String , null , {
3123
+ right : make_node ( AST_String , self . right , {
3084
3124
value : "" + self . left . right . getValue ( ) + self . right . getValue ( ) ,
3085
3125
start : self . left . right . start ,
3086
3126
end : self . right . end
3087
3127
} )
3088
3128
} ) ;
3089
3129
}
3130
+ // (x + "foo") + ("bar" + y) => (x + "foobar") + y
3090
3131
if ( self . left instanceof AST_Binary
3091
3132
&& self . left . operator == "+"
3092
3133
&& self . left . is_string ( compressor )
@@ -3100,7 +3141,7 @@ merge(Compressor.prototype, {
3100
3141
left : make_node ( AST_Binary , self . left , {
3101
3142
operator : "+" ,
3102
3143
left : self . left . left ,
3103
- right : make_node ( AST_String , null , {
3144
+ right : make_node ( AST_String , self . left . right , {
3104
3145
value : "" + self . left . right . getValue ( ) + self . right . left . getValue ( ) ,
3105
3146
start : self . left . right . start ,
3106
3147
end : self . right . left . end
@@ -3109,6 +3150,122 @@ merge(Compressor.prototype, {
3109
3150
right : self . right . right
3110
3151
} ) ;
3111
3152
}
3153
+ // a + -b => a - b
3154
+ if ( self . right instanceof AST_UnaryPrefix
3155
+ && self . right . operator == "-"
3156
+ && self . left . is_number ( compressor ) ) {
3157
+ self = make_node ( AST_Binary , self , {
3158
+ operator : "-" ,
3159
+ left : self . left ,
3160
+ right : self . right . expression
3161
+ } ) ;
3162
+ }
3163
+ // -a + b => b - a
3164
+ if ( self . left instanceof AST_UnaryPrefix
3165
+ && self . left . operator == "-"
3166
+ && reversible ( )
3167
+ && self . right . is_number ( compressor ) ) {
3168
+ self = make_node ( AST_Binary , self , {
3169
+ operator : "-" ,
3170
+ left : self . right ,
3171
+ right : self . left . expression
3172
+ } ) ;
3173
+ }
3174
+ case "*" :
3175
+ associative = compressor . option ( "unsafe_math" ) ;
3176
+ case "&" :
3177
+ case "|" :
3178
+ case "^" :
3179
+ // a + +b => +b + a
3180
+ if ( self . left . is_number ( compressor )
3181
+ && self . right . is_number ( compressor )
3182
+ && reversible ( )
3183
+ && ! ( self . left instanceof AST_Binary
3184
+ && self . left . operator != self . operator
3185
+ && PRECEDENCE [ self . left . operator ] >= PRECEDENCE [ self . operator ] ) ) {
3186
+ var reversed = make_node ( AST_Binary , self , {
3187
+ operator : self . operator ,
3188
+ left : self . right ,
3189
+ right : self . left
3190
+ } ) ;
3191
+ if ( self . right instanceof AST_Constant
3192
+ && ! ( self . left instanceof AST_Constant ) ) {
3193
+ self = best_of ( reversed , self ) ;
3194
+ } else {
3195
+ self = best_of ( self , reversed ) ;
3196
+ }
3197
+ }
3198
+ if ( associative && self . is_number ( compressor ) ) {
3199
+ // a + (b + c) => (a + b) + c
3200
+ if ( self . right instanceof AST_Binary
3201
+ && self . right . operator == self . operator ) {
3202
+ self = make_node ( AST_Binary , self , {
3203
+ operator : self . operator ,
3204
+ left : make_node ( AST_Binary , self . left , {
3205
+ operator : self . operator ,
3206
+ left : self . left ,
3207
+ right : self . right . left ,
3208
+ start : self . left . start ,
3209
+ end : self . right . left . end
3210
+ } ) ,
3211
+ right : self . right . right
3212
+ } ) ;
3213
+ }
3214
+ // (n + 2) + 3 => 5 + n
3215
+ // (2 * n) * 3 => 6 + n
3216
+ if ( self . right instanceof AST_Constant
3217
+ && self . left instanceof AST_Binary
3218
+ && self . left . operator == self . operator ) {
3219
+ if ( self . left . left instanceof AST_Constant ) {
3220
+ self = make_node ( AST_Binary , self , {
3221
+ operator : self . operator ,
3222
+ left : make_node ( AST_Binary , self . left , {
3223
+ operator : self . operator ,
3224
+ left : self . left . left ,
3225
+ right : self . right ,
3226
+ start : self . left . left . start ,
3227
+ end : self . right . end
3228
+ } ) ,
3229
+ right : self . left . right
3230
+ } ) ;
3231
+ } else if ( self . left . right instanceof AST_Constant ) {
3232
+ self = make_node ( AST_Binary , self , {
3233
+ operator : self . operator ,
3234
+ left : make_node ( AST_Binary , self . left , {
3235
+ operator : self . operator ,
3236
+ left : self . left . right ,
3237
+ right : self . right ,
3238
+ start : self . left . right . start ,
3239
+ end : self . right . end
3240
+ } ) ,
3241
+ right : self . left . left
3242
+ } ) ;
3243
+ }
3244
+ }
3245
+ // (a | 1) | (2 | d) => (3 | a) | b
3246
+ if ( self . left instanceof AST_Binary
3247
+ && self . left . operator == self . operator
3248
+ && self . left . right instanceof AST_Constant
3249
+ && self . right instanceof AST_Binary
3250
+ && self . right . operator == self . operator
3251
+ && self . right . left instanceof AST_Constant ) {
3252
+ self = make_node ( AST_Binary , self , {
3253
+ operator : self . operator ,
3254
+ left : make_node ( AST_Binary , self . left , {
3255
+ operator : self . operator ,
3256
+ left : make_node ( AST_Binary , self . left . left , {
3257
+ operator : self . operator ,
3258
+ left : self . left . right ,
3259
+ right : self . right . left ,
3260
+ start : self . left . right . start ,
3261
+ end : self . right . left . end
3262
+ } ) ,
3263
+ right : self . left . left
3264
+ } ) ,
3265
+ right : self . right . right
3266
+ } ) ;
3267
+ }
3268
+ }
3112
3269
}
3113
3270
}
3114
3271
// x && (y && z) ==> x && y && z
0 commit comments