uglifier 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of uglifier might be problematic. Click here for more details.
- data/Gemfile +2 -2
- data/Rakefile +3 -9
- data/VERSION +1 -1
- data/lib/uglifier.rb +5 -14
- data/lib/uglifier/cli.rb +0 -4
- data/spec/uglifier_spec.rb +4 -4
- data/uglifier.gemspec +10 -26
- data/vendor/uglifyjs/lib/parse-js.js +185 -99
- data/vendor/uglifyjs/lib/process.js +335 -301
- metadata +20 -99
@@ -69,139 +69,135 @@ var jsp = require("./parse-js"),
|
|
69
69
|
|
70
70
|
function ast_walker(ast) {
|
71
71
|
function _vardefs(defs) {
|
72
|
-
return MAP(defs, function(def){
|
72
|
+
return [ this[0], MAP(defs, function(def){
|
73
73
|
var a = [ def[0] ];
|
74
74
|
if (def.length > 1)
|
75
75
|
a[1] = walk(def[1]);
|
76
76
|
return a;
|
77
|
-
});
|
77
|
+
}) ];
|
78
78
|
};
|
79
79
|
var walkers = {
|
80
80
|
"string": function(str) {
|
81
|
-
return [
|
81
|
+
return [ this[0], str ];
|
82
82
|
},
|
83
83
|
"num": function(num) {
|
84
|
-
return [
|
84
|
+
return [ this[0], num ];
|
85
85
|
},
|
86
86
|
"name": function(name) {
|
87
|
-
return [
|
87
|
+
return [ this[0], name ];
|
88
88
|
},
|
89
89
|
"toplevel": function(statements) {
|
90
|
-
return [
|
90
|
+
return [ this[0], MAP(statements, walk) ];
|
91
91
|
},
|
92
92
|
"block": function(statements) {
|
93
|
-
var out = [
|
93
|
+
var out = [ this[0] ];
|
94
94
|
if (statements != null)
|
95
95
|
out.push(MAP(statements, walk));
|
96
96
|
return out;
|
97
97
|
},
|
98
|
-
"var":
|
99
|
-
|
100
|
-
},
|
101
|
-
"const": function(defs) {
|
102
|
-
return [ "const", _vardefs(defs) ];
|
103
|
-
},
|
98
|
+
"var": _vardefs,
|
99
|
+
"const": _vardefs,
|
104
100
|
"try": function(t, c, f) {
|
105
101
|
return [
|
106
|
-
|
102
|
+
this[0],
|
107
103
|
MAP(t, walk),
|
108
104
|
c != null ? [ c[0], MAP(c[1], walk) ] : null,
|
109
105
|
f != null ? MAP(f, walk) : null
|
110
106
|
];
|
111
107
|
},
|
112
108
|
"throw": function(expr) {
|
113
|
-
return [
|
109
|
+
return [ this[0], walk(expr) ];
|
114
110
|
},
|
115
111
|
"new": function(ctor, args) {
|
116
|
-
return [
|
112
|
+
return [ this[0], walk(ctor), MAP(args, walk) ];
|
117
113
|
},
|
118
114
|
"switch": function(expr, body) {
|
119
|
-
return [
|
115
|
+
return [ this[0], walk(expr), MAP(body, function(branch){
|
120
116
|
return [ branch[0] ? walk(branch[0]) : null,
|
121
117
|
MAP(branch[1], walk) ];
|
122
118
|
}) ];
|
123
119
|
},
|
124
120
|
"break": function(label) {
|
125
|
-
return [
|
121
|
+
return [ this[0], label ];
|
126
122
|
},
|
127
123
|
"continue": function(label) {
|
128
|
-
return [
|
124
|
+
return [ this[0], label ];
|
129
125
|
},
|
130
126
|
"conditional": function(cond, t, e) {
|
131
|
-
return [
|
127
|
+
return [ this[0], walk(cond), walk(t), walk(e) ];
|
132
128
|
},
|
133
129
|
"assign": function(op, lvalue, rvalue) {
|
134
|
-
return [
|
130
|
+
return [ this[0], op, walk(lvalue), walk(rvalue) ];
|
135
131
|
},
|
136
132
|
"dot": function(expr) {
|
137
|
-
return [
|
133
|
+
return [ this[0], walk(expr) ].concat(slice(arguments, 1));
|
138
134
|
},
|
139
135
|
"call": function(expr, args) {
|
140
|
-
return [
|
136
|
+
return [ this[0], walk(expr), MAP(args, walk) ];
|
141
137
|
},
|
142
138
|
"function": function(name, args, body) {
|
143
|
-
return [
|
139
|
+
return [ this[0], name, args.slice(), MAP(body, walk) ];
|
144
140
|
},
|
145
141
|
"defun": function(name, args, body) {
|
146
|
-
return [
|
142
|
+
return [ this[0], name, args.slice(), MAP(body, walk) ];
|
147
143
|
},
|
148
144
|
"if": function(conditional, t, e) {
|
149
|
-
return [
|
145
|
+
return [ this[0], walk(conditional), walk(t), walk(e) ];
|
150
146
|
},
|
151
147
|
"for": function(init, cond, step, block) {
|
152
|
-
return [
|
148
|
+
return [ this[0], walk(init), walk(cond), walk(step), walk(block) ];
|
153
149
|
},
|
154
|
-
"for-in": function(
|
155
|
-
return [
|
150
|
+
"for-in": function(vvar, key, hash, block) {
|
151
|
+
return [ this[0], walk(vvar), walk(key), walk(hash), walk(block) ];
|
156
152
|
},
|
157
153
|
"while": function(cond, block) {
|
158
|
-
return [
|
154
|
+
return [ this[0], walk(cond), walk(block) ];
|
159
155
|
},
|
160
156
|
"do": function(cond, block) {
|
161
|
-
return [
|
157
|
+
return [ this[0], walk(cond), walk(block) ];
|
162
158
|
},
|
163
159
|
"return": function(expr) {
|
164
|
-
return [
|
160
|
+
return [ this[0], walk(expr) ];
|
165
161
|
},
|
166
162
|
"binary": function(op, left, right) {
|
167
|
-
return [
|
163
|
+
return [ this[0], op, walk(left), walk(right) ];
|
168
164
|
},
|
169
165
|
"unary-prefix": function(op, expr) {
|
170
|
-
return [
|
166
|
+
return [ this[0], op, walk(expr) ];
|
171
167
|
},
|
172
168
|
"unary-postfix": function(op, expr) {
|
173
|
-
return [
|
169
|
+
return [ this[0], op, walk(expr) ];
|
174
170
|
},
|
175
171
|
"sub": function(expr, subscript) {
|
176
|
-
return [
|
172
|
+
return [ this[0], walk(expr), walk(subscript) ];
|
177
173
|
},
|
178
174
|
"object": function(props) {
|
179
|
-
return [
|
175
|
+
return [ this[0], MAP(props, function(p){
|
180
176
|
return p.length == 2
|
181
177
|
? [ p[0], walk(p[1]) ]
|
182
178
|
: [ p[0], walk(p[1]), p[2] ]; // get/set-ter
|
183
179
|
}) ];
|
184
180
|
},
|
185
181
|
"regexp": function(rx, mods) {
|
186
|
-
return [
|
182
|
+
return [ this[0], rx, mods ];
|
187
183
|
},
|
188
184
|
"array": function(elements) {
|
189
|
-
return [
|
185
|
+
return [ this[0], MAP(elements, walk) ];
|
190
186
|
},
|
191
187
|
"stat": function(stat) {
|
192
|
-
return [
|
188
|
+
return [ this[0], walk(stat) ];
|
193
189
|
},
|
194
190
|
"seq": function() {
|
195
|
-
return [
|
191
|
+
return [ this[0] ].concat(MAP(slice(arguments), walk));
|
196
192
|
},
|
197
193
|
"label": function(name, block) {
|
198
|
-
return [
|
194
|
+
return [ this[0], name, walk(block) ];
|
199
195
|
},
|
200
196
|
"with": function(expr, block) {
|
201
|
-
return [
|
197
|
+
return [ this[0], walk(expr), walk(block) ];
|
202
198
|
},
|
203
199
|
"atom": function(name) {
|
204
|
-
return [
|
200
|
+
return [ this[0], name ];
|
205
201
|
}
|
206
202
|
};
|
207
203
|
|
@@ -405,7 +401,7 @@ function ast_add_scope(ast) {
|
|
405
401
|
},
|
406
402
|
"try": function(t, c, f) {
|
407
403
|
if (c != null) return [
|
408
|
-
|
404
|
+
this[0],
|
409
405
|
MAP(t, walk),
|
410
406
|
[ define(c[0]), MAP(c[1], walk) ],
|
411
407
|
f != null ? MAP(f, walk) : null
|
@@ -415,10 +411,6 @@ function ast_add_scope(ast) {
|
|
415
411
|
if (name == "eval")
|
416
412
|
having_eval.push(current_scope);
|
417
413
|
reference(name);
|
418
|
-
},
|
419
|
-
"for-in": function(has_var, name) {
|
420
|
-
if (has_var) define(name);
|
421
|
-
else reference(name);
|
422
414
|
}
|
423
415
|
}, function(){
|
424
416
|
return walk(ast);
|
@@ -461,11 +453,14 @@ function ast_add_scope(ast) {
|
|
461
453
|
|
462
454
|
/* -----[ mangle names ]----- */
|
463
455
|
|
464
|
-
function ast_mangle(ast,
|
456
|
+
function ast_mangle(ast, options) {
|
465
457
|
var w = ast_walker(), walk = w.walk, scope;
|
458
|
+
options = options || {};
|
466
459
|
|
467
460
|
function get_mangled(name, newMangle) {
|
468
|
-
if (!
|
461
|
+
if (!options.toplevel && !scope.parent) return name; // don't mangle toplevel
|
462
|
+
if (options.except && member(name, options.except))
|
463
|
+
return name;
|
469
464
|
return scope.get_mangled(name, newMangle);
|
470
465
|
};
|
471
466
|
|
@@ -491,9 +486,9 @@ function ast_mangle(ast, do_toplevel) {
|
|
491
486
|
};
|
492
487
|
|
493
488
|
function _vardefs(defs) {
|
494
|
-
return MAP(defs, function(d){
|
489
|
+
return [ this[0], MAP(defs, function(d){
|
495
490
|
return [ get_mangled(d[0]), walk(d[1]) ];
|
496
|
-
});
|
491
|
+
}) ];
|
497
492
|
};
|
498
493
|
|
499
494
|
return w.with_walkers({
|
@@ -510,28 +505,22 @@ function ast_mangle(ast, do_toplevel) {
|
|
510
505
|
}
|
511
506
|
return ast;
|
512
507
|
},
|
513
|
-
"var":
|
514
|
-
|
515
|
-
},
|
516
|
-
"const": function(defs) {
|
517
|
-
return [ "const", _vardefs(defs) ];
|
518
|
-
},
|
508
|
+
"var": _vardefs,
|
509
|
+
"const": _vardefs,
|
519
510
|
"name": function(name) {
|
520
|
-
return [
|
511
|
+
return [ this[0], get_mangled(name) ];
|
521
512
|
},
|
522
513
|
"try": function(t, c, f) {
|
523
|
-
return [
|
514
|
+
return [ this[0],
|
524
515
|
MAP(t, walk),
|
525
516
|
c != null ? [ get_mangled(c[0]), MAP(c[1], walk) ] : null,
|
526
517
|
f != null ? MAP(f, walk) : null ];
|
527
518
|
},
|
528
519
|
"toplevel": function(body) {
|
529
|
-
|
530
|
-
|
520
|
+
var self = this;
|
521
|
+
return with_scope(self.scope, function(){
|
522
|
+
return [ self[0], MAP(body, walk) ];
|
531
523
|
});
|
532
|
-
},
|
533
|
-
"for-in": function(has_var, name, obj, stat) {
|
534
|
-
return [ "for-in", has_var, get_mangled(name), walk(obj), walk(stat) ];
|
535
524
|
}
|
536
525
|
}, function() {
|
537
526
|
return walk(ast_add_scope(ast));
|
@@ -569,28 +558,29 @@ function aborts(t) {
|
|
569
558
|
}
|
570
559
|
};
|
571
560
|
|
572
|
-
function
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
561
|
+
function boolean_expr(expr) {
|
562
|
+
return ( (expr[0] == "unary-prefix"
|
563
|
+
&& member(expr[1], [ "!", "delete" ])) ||
|
564
|
+
|
565
|
+
(expr[0] == "binary"
|
566
|
+
&& member(expr[1], [ "in", "instanceof", "==", "!=", "===", "!==", "<", "<=", ">=", ">" ])) ||
|
567
|
+
|
568
|
+
(expr[0] == "binary"
|
569
|
+
&& member(expr[1], [ "&&", "||" ])
|
570
|
+
&& boolean_expr(expr[2])
|
571
|
+
&& boolean_expr(expr[3])) ||
|
572
|
+
|
573
|
+
(expr[0] == "conditional"
|
574
|
+
&& boolean_expr(expr[2])
|
575
|
+
&& boolean_expr(expr[3])) ||
|
576
|
+
|
577
|
+
(expr[0] == "assign"
|
578
|
+
&& expr[1] === true
|
579
|
+
&& boolean_expr(expr[3])) ||
|
580
|
+
|
581
|
+
(expr[0] == "seq"
|
582
|
+
&& boolean_expr(expr[expr.length - 1]))
|
583
|
+
);
|
594
584
|
};
|
595
585
|
|
596
586
|
function make_conditional(c, t, e) {
|
@@ -605,16 +595,143 @@ function empty(b) {
|
|
605
595
|
return !b || (b[0] == "block" && (!b[1] || b[1].length == 0));
|
606
596
|
};
|
607
597
|
|
598
|
+
function is_string(node) {
|
599
|
+
return (node[0] == "string" ||
|
600
|
+
node[0] == "unary-prefix" && node[1] == "typeof" ||
|
601
|
+
node[0] == "binary" && node[1] == "+" &&
|
602
|
+
(is_string(node[2]) || is_string(node[3])));
|
603
|
+
};
|
604
|
+
|
605
|
+
var when_constant = (function(){
|
606
|
+
|
607
|
+
var $NOT_CONSTANT = {};
|
608
|
+
|
609
|
+
// this can only evaluate constant expressions. If it finds anything
|
610
|
+
// not constant, it throws $NOT_CONSTANT.
|
611
|
+
function evaluate(expr) {
|
612
|
+
switch (expr[0]) {
|
613
|
+
case "string":
|
614
|
+
case "num":
|
615
|
+
return expr[1];
|
616
|
+
case "name":
|
617
|
+
case "atom":
|
618
|
+
switch (expr[1]) {
|
619
|
+
case "true": return true;
|
620
|
+
case "false": return false;
|
621
|
+
}
|
622
|
+
break;
|
623
|
+
case "unary-prefix":
|
624
|
+
switch (expr[1]) {
|
625
|
+
case "!": return !evaluate(expr[2]);
|
626
|
+
case "typeof": return typeof evaluate(expr[2]);
|
627
|
+
case "~": return ~evaluate(expr[2]);
|
628
|
+
case "-": return -evaluate(expr[2]);
|
629
|
+
case "+": return +evaluate(expr[2]);
|
630
|
+
}
|
631
|
+
break;
|
632
|
+
case "binary":
|
633
|
+
var left = expr[2], right = expr[3];
|
634
|
+
switch (expr[1]) {
|
635
|
+
case "&&" : return evaluate(left) && evaluate(right);
|
636
|
+
case "||" : return evaluate(left) || evaluate(right);
|
637
|
+
case "|" : return evaluate(left) | evaluate(right);
|
638
|
+
case "&" : return evaluate(left) & evaluate(right);
|
639
|
+
case "^" : return evaluate(left) ^ evaluate(right);
|
640
|
+
case "+" : return evaluate(left) + evaluate(right);
|
641
|
+
case "*" : return evaluate(left) * evaluate(right);
|
642
|
+
case "/" : return evaluate(left) / evaluate(right);
|
643
|
+
case "-" : return evaluate(left) - evaluate(right);
|
644
|
+
case "<<" : return evaluate(left) << evaluate(right);
|
645
|
+
case ">>" : return evaluate(left) >> evaluate(right);
|
646
|
+
case ">>>" : return evaluate(left) >>> evaluate(right);
|
647
|
+
case "==" : return evaluate(left) == evaluate(right);
|
648
|
+
case "===" : return evaluate(left) === evaluate(right);
|
649
|
+
case "!=" : return evaluate(left) != evaluate(right);
|
650
|
+
case "!==" : return evaluate(left) !== evaluate(right);
|
651
|
+
case "<" : return evaluate(left) < evaluate(right);
|
652
|
+
case "<=" : return evaluate(left) <= evaluate(right);
|
653
|
+
case ">" : return evaluate(left) > evaluate(right);
|
654
|
+
case ">=" : return evaluate(left) >= evaluate(right);
|
655
|
+
case "in" : return evaluate(left) in evaluate(right);
|
656
|
+
case "instanceof" : return evaluate(left) instanceof evaluate(right);
|
657
|
+
}
|
658
|
+
}
|
659
|
+
throw $NOT_CONSTANT;
|
660
|
+
};
|
661
|
+
|
662
|
+
return function(expr, yes, no) {
|
663
|
+
try {
|
664
|
+
var val = evaluate(expr), ast;
|
665
|
+
switch (typeof val) {
|
666
|
+
case "string": ast = [ "string", val ]; break;
|
667
|
+
case "number": ast = [ "num", val ]; break;
|
668
|
+
case "boolean": ast = [ "name", String(val) ]; break;
|
669
|
+
default: throw new Error("Can't handle constant of type: " + (typeof val));
|
670
|
+
}
|
671
|
+
return yes.call(expr, ast, val);
|
672
|
+
} catch(ex) {
|
673
|
+
if (ex === $NOT_CONSTANT) {
|
674
|
+
if (expr[0] == "binary"
|
675
|
+
&& (expr[1] == "===" || expr[1] == "!==")
|
676
|
+
&& ((is_string(expr[2]) && is_string(expr[3]))
|
677
|
+
|| (boolean_expr(expr[2]) && boolean_expr(expr[3])))) {
|
678
|
+
expr[1] = expr[1].substr(0, 2);
|
679
|
+
}
|
680
|
+
return no ? no.call(expr, expr) : null;
|
681
|
+
}
|
682
|
+
else throw ex;
|
683
|
+
}
|
684
|
+
};
|
685
|
+
|
686
|
+
})();
|
687
|
+
|
688
|
+
function warn_unreachable(ast) {
|
689
|
+
if (!empty(ast))
|
690
|
+
warn("Dropping unreachable code: " + gen_code(ast, true));
|
691
|
+
};
|
692
|
+
|
608
693
|
function ast_squeeze(ast, options) {
|
609
694
|
options = defaults(options, {
|
610
695
|
make_seqs : true,
|
611
696
|
dead_code : true,
|
612
|
-
|
613
|
-
|
697
|
+
keep_comps : true,
|
698
|
+
no_warnings : false
|
614
699
|
});
|
615
700
|
|
616
701
|
var w = ast_walker(), walk = w.walk, scope;
|
617
702
|
|
703
|
+
function negate(c) {
|
704
|
+
var not_c = [ "unary-prefix", "!", c ];
|
705
|
+
switch (c[0]) {
|
706
|
+
case "unary-prefix":
|
707
|
+
return c[1] == "!" && boolean_expr(c[2]) ? c[2] : not_c;
|
708
|
+
case "seq":
|
709
|
+
c = slice(c);
|
710
|
+
c[c.length - 1] = negate(c[c.length - 1]);
|
711
|
+
return c;
|
712
|
+
case "conditional":
|
713
|
+
return best_of(not_c, [ "conditional", c[1], negate(c[2]), negate(c[3]) ]);
|
714
|
+
case "binary":
|
715
|
+
var op = c[1], left = c[2], right = c[3];
|
716
|
+
if (!options.keep_comps) switch (op) {
|
717
|
+
case "<=" : return [ "binary", ">", left, right ];
|
718
|
+
case "<" : return [ "binary", ">=", left, right ];
|
719
|
+
case ">=" : return [ "binary", "<", left, right ];
|
720
|
+
case ">" : return [ "binary", "<=", left, right ];
|
721
|
+
}
|
722
|
+
switch (op) {
|
723
|
+
case "==" : return [ "binary", "!=", left, right ];
|
724
|
+
case "!=" : return [ "binary", "==", left, right ];
|
725
|
+
case "===" : return [ "binary", "!==", left, right ];
|
726
|
+
case "!==" : return [ "binary", "===", left, right ];
|
727
|
+
case "&&" : return best_of(not_c, [ "binary", "||", negate(left), negate(right) ]);
|
728
|
+
case "||" : return best_of(not_c, [ "binary", "&&", negate(left), negate(right) ]);
|
729
|
+
}
|
730
|
+
break;
|
731
|
+
}
|
732
|
+
return not_c;
|
733
|
+
};
|
734
|
+
|
618
735
|
function with_scope(s, cont) {
|
619
736
|
var _scope = scope;
|
620
737
|
scope = s;
|
@@ -624,89 +741,14 @@ function ast_squeeze(ast, options) {
|
|
624
741
|
return ret;
|
625
742
|
};
|
626
743
|
|
627
|
-
function is_constant(node) {
|
628
|
-
return node[0] == "string" || node[0] == "num";
|
629
|
-
};
|
630
|
-
|
631
|
-
function find_first_execute(node) {
|
632
|
-
if (!node)
|
633
|
-
return false;
|
634
|
-
|
635
|
-
switch (node[0]) {
|
636
|
-
case "num":
|
637
|
-
case "string":
|
638
|
-
case "name":
|
639
|
-
return node;
|
640
|
-
case "call":
|
641
|
-
case "conditional":
|
642
|
-
case "for":
|
643
|
-
case "if":
|
644
|
-
case "new":
|
645
|
-
case "return":
|
646
|
-
case "stat":
|
647
|
-
case "switch":
|
648
|
-
case "throw":
|
649
|
-
return find_first_execute(node[1]);
|
650
|
-
case "binary":
|
651
|
-
return find_first_execute(node[2]);
|
652
|
-
case "assign":
|
653
|
-
if (node[1] === true)
|
654
|
-
return find_first_execute(node[3]);
|
655
|
-
break;
|
656
|
-
case "var":
|
657
|
-
if (node[1][0].length > 1)
|
658
|
-
return find_first_execute(node[1][0][1]);
|
659
|
-
break;
|
660
|
-
}
|
661
|
-
return null;
|
662
|
-
}
|
663
|
-
|
664
|
-
function find_assign_recursive(p, v) {
|
665
|
-
if (p[0] == "assign" && p[1] != true || p[0] == "unary-prefix") {
|
666
|
-
if (p[2][0] == "name" && v[0] == "name" && p[2][1] == v[1])
|
667
|
-
return true;
|
668
|
-
return false;
|
669
|
-
}
|
670
|
-
|
671
|
-
if (p[0] != "assign" || p[1] !== true)
|
672
|
-
return false;
|
673
|
-
|
674
|
-
if ((is_constant(p[3]) && p[3][0] == v[0] && p[3][1] == v[1]) ||
|
675
|
-
(p[3][0] == "name" && v[0] == "name" && p[3][1] == v[1]) ||
|
676
|
-
(p[2][0] == "name" && v[0] == "name" && p[2][1] == v[1]))
|
677
|
-
return true;
|
678
|
-
|
679
|
-
return find_assign_recursive(p[3], v);
|
680
|
-
};
|
681
|
-
|
682
744
|
function rmblock(block) {
|
683
|
-
if (block != null && block[0] == "block" && block[1]
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
function clone(obj) {
|
689
|
-
if (obj && obj.constructor == Array)
|
690
|
-
return MAP(obj, clone);
|
691
|
-
return obj;
|
692
|
-
};
|
693
|
-
|
694
|
-
function make_seq_to_statements(node) {
|
695
|
-
if (node[0] != "seq") {
|
696
|
-
switch (node[0]) {
|
697
|
-
case "var":
|
698
|
-
case "const":
|
699
|
-
return [ node ];
|
700
|
-
default:
|
701
|
-
return [ [ "stat", node ] ];
|
702
|
-
}
|
745
|
+
if (block != null && block[0] == "block" && block[1]) {
|
746
|
+
if (block[1].length == 1)
|
747
|
+
block = block[1][0];
|
748
|
+
else if (block[1].length == 0)
|
749
|
+
block = [ "block" ];
|
703
750
|
}
|
704
|
-
|
705
|
-
var ret = [];
|
706
|
-
for (var i = 1; i < node.length; i++)
|
707
|
-
ret.push.apply(ret, make_seq_to_statements(node[i]));
|
708
|
-
|
709
|
-
return ret;
|
751
|
+
return block;
|
710
752
|
};
|
711
753
|
|
712
754
|
function _lambda(name, args, body) {
|
@@ -734,64 +776,6 @@ function ast_squeeze(ast, options) {
|
|
734
776
|
return a;
|
735
777
|
}, []);
|
736
778
|
|
737
|
-
if (options.extra) {
|
738
|
-
// Detightening things. We do this because then we can assume that the
|
739
|
-
// statements are structured in a specific way.
|
740
|
-
statements = (function(a, prev) {
|
741
|
-
statements.forEach(function(cur) {
|
742
|
-
switch (cur[0]) {
|
743
|
-
case "for":
|
744
|
-
if (cur[1] != null) {
|
745
|
-
a.push.apply(a, make_seq_to_statements(cur[1]));
|
746
|
-
cur[1] = null;
|
747
|
-
}
|
748
|
-
a.push(cur);
|
749
|
-
break;
|
750
|
-
case "stat":
|
751
|
-
var stats = make_seq_to_statements(cur[1]);
|
752
|
-
stats.forEach(function(s) {
|
753
|
-
if (s[1][0] == "unary-postfix")
|
754
|
-
s[1][0] = "unary-prefix";
|
755
|
-
});
|
756
|
-
a.push.apply(a, stats);
|
757
|
-
break;
|
758
|
-
default:
|
759
|
-
a.push(cur);
|
760
|
-
}
|
761
|
-
});
|
762
|
-
return a;
|
763
|
-
})([]);
|
764
|
-
|
765
|
-
statements = (function(a, prev) {
|
766
|
-
statements.forEach(function(cur) {
|
767
|
-
if (!(prev && prev[0] == "stat")) {
|
768
|
-
a.push(cur);
|
769
|
-
prev = cur;
|
770
|
-
return;
|
771
|
-
}
|
772
|
-
|
773
|
-
var p = prev[1];
|
774
|
-
var c = find_first_execute(cur);
|
775
|
-
if (c && find_assign_recursive(p, c)) {
|
776
|
-
var old_cur = clone(cur);
|
777
|
-
c.splice(0, c.length);
|
778
|
-
c.push.apply(c, p);
|
779
|
-
var tmp_cur = best_of(cur, [ "toplevel", [ prev, old_cur ] ]);
|
780
|
-
if (tmp_cur == cur) {
|
781
|
-
a[a.length -1] = cur;
|
782
|
-
} else {
|
783
|
-
cur = old_cur;
|
784
|
-
a.push(cur);
|
785
|
-
}
|
786
|
-
} else {
|
787
|
-
a.push(cur);
|
788
|
-
}
|
789
|
-
prev = cur;
|
790
|
-
});
|
791
|
-
return a;
|
792
|
-
})([]);
|
793
|
-
}
|
794
|
-
|
795
779
|
statements = (function(a, prev){
|
796
780
|
statements.forEach(function(cur){
|
797
781
|
if (prev && ((cur[0] == "var" && prev[0] == "var") ||
|
@@ -812,7 +796,7 @@ function ast_squeeze(ast, options) {
|
|
812
796
|
a.push(st);
|
813
797
|
}
|
814
798
|
else if (!options.no_warnings)
|
815
|
-
|
799
|
+
warn_unreachable(st);
|
816
800
|
}
|
817
801
|
else {
|
818
802
|
a.push(st);
|
@@ -835,22 +819,6 @@ function ast_squeeze(ast, options) {
|
|
835
819
|
return a;
|
836
820
|
})([]);
|
837
821
|
|
838
|
-
if (options.extra) {
|
839
|
-
statements = (function(a, prev){
|
840
|
-
statements.forEach(function(cur){
|
841
|
-
var replaced = false;
|
842
|
-
if (prev && cur[0] == "for" && cur[1] == null && (prev[0] == "var" || prev[0] == "const" || prev[0] == "stat")) {
|
843
|
-
cur[1] = prev;
|
844
|
-
a[a.length - 1] = cur;
|
845
|
-
} else {
|
846
|
-
a.push(cur);
|
847
|
-
}
|
848
|
-
prev = cur;
|
849
|
-
});
|
850
|
-
return a;
|
851
|
-
})([]);
|
852
|
-
}
|
853
|
-
|
854
822
|
if (block_type == "lambda") statements = (function(i, a, stat){
|
855
823
|
while (i < statements.length) {
|
856
824
|
stat = statements[i++];
|
@@ -874,6 +842,20 @@ function ast_squeeze(ast, options) {
|
|
874
842
|
};
|
875
843
|
|
876
844
|
function make_if(c, t, e) {
|
845
|
+
return when_constant(c, function(ast, val){
|
846
|
+
if (val) {
|
847
|
+
warn_unreachable(e);
|
848
|
+
return t;
|
849
|
+
} else {
|
850
|
+
warn_unreachable(t);
|
851
|
+
return e;
|
852
|
+
}
|
853
|
+
}, function() {
|
854
|
+
return make_real_if(c, t, e);
|
855
|
+
});
|
856
|
+
};
|
857
|
+
|
858
|
+
function make_real_if(c, t, e) {
|
877
859
|
c = walk(c);
|
878
860
|
t = walk(t);
|
879
861
|
e = walk(e);
|
@@ -901,7 +883,10 @@ function ast_squeeze(ast, options) {
|
|
901
883
|
if (empty(e) && empty(t))
|
902
884
|
return [ "stat", c ];
|
903
885
|
var ret = [ "if", c, t, e ];
|
904
|
-
if (t[0] == "
|
886
|
+
if (t[0] == "if" && empty(t[3]) && empty(e)) {
|
887
|
+
ret = best_of(ret, walk([ "if", [ "binary", "&&", c, t[1] ], t[2] ]));
|
888
|
+
}
|
889
|
+
else if (t[0] == "stat") {
|
905
890
|
if (e) {
|
906
891
|
if (e[0] == "stat") {
|
907
892
|
ret = best_of(ret, [ "stat", make_conditional(c, t[1], e[1]) ]);
|
@@ -911,7 +896,7 @@ function ast_squeeze(ast, options) {
|
|
911
896
|
ret = best_of(ret, [ "stat", make_conditional(c, t[1]) ]);
|
912
897
|
}
|
913
898
|
}
|
914
|
-
else if (e && t[0] == e[0] && (t[0] == "return" || t[0] == "throw")) {
|
899
|
+
else if (e && t[0] == e[0] && (t[0] == "return" || t[0] == "throw") && t[1] && e[1]) {
|
915
900
|
ret = best_of(ret, [ t[0], make_conditional(c, t[1], e[1] ) ]);
|
916
901
|
}
|
917
902
|
else if (e && aborts(t)) {
|
@@ -936,6 +921,17 @@ function ast_squeeze(ast, options) {
|
|
936
921
|
return ret;
|
937
922
|
};
|
938
923
|
|
924
|
+
function _do_while(cond, body) {
|
925
|
+
return when_constant(cond, function(cond, val){
|
926
|
+
if (!val) {
|
927
|
+
warn_unreachable(body);
|
928
|
+
return [ "block" ];
|
929
|
+
} else {
|
930
|
+
return [ "for", null, null, null, walk(body) ];
|
931
|
+
}
|
932
|
+
});
|
933
|
+
};
|
934
|
+
|
939
935
|
return w.with_walkers({
|
940
936
|
"sub": function(expr, subscript) {
|
941
937
|
if (subscript[0] == "string") {
|
@@ -963,35 +959,23 @@ function ast_squeeze(ast, options) {
|
|
963
959
|
return [ branch[0] ? walk(branch[0]) : null, block ];
|
964
960
|
}) ];
|
965
961
|
},
|
966
|
-
"function":
|
962
|
+
"function": function() {
|
963
|
+
var ret = _lambda.apply(this, arguments);
|
964
|
+
if (ret[1] && !HOP(scope.refs, ret[1])) {
|
965
|
+
ret[1] = null;
|
966
|
+
}
|
967
|
+
return ret;
|
968
|
+
},
|
967
969
|
"defun": _lambda,
|
968
970
|
"block": function(body) {
|
969
971
|
if (body) return rmblock([ "block", tighten(MAP(body, walk)) ]);
|
970
972
|
},
|
971
973
|
"binary": function(op, left, right) {
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
var val = null;
|
978
|
-
switch (op) {
|
979
|
-
case "+": val = left[1] + right[1]; break;
|
980
|
-
case "*": val = left[1] * right[1]; break;
|
981
|
-
case "/": val = left[1] / right[1]; break;
|
982
|
-
case "-": val = left[1] - right[1]; break;
|
983
|
-
case "<<": val = left[1] << right[1]; break;
|
984
|
-
case ">>": val = left[1] >> right[1]; break;
|
985
|
-
case ">>>": val = left[1] >>> right[1]; break;
|
986
|
-
}
|
987
|
-
if (val != null) {
|
988
|
-
best = best_of(best, [ typeof val == "string" ? "string" : "num", val ]);
|
989
|
-
}
|
990
|
-
} else if (left[0] == "binary" && left[1] == "+" && left[3][0] == "string") {
|
991
|
-
best = best_of(best, [ "binary", "+", left[2], [ "string", left[3][1] + right[1] ] ]);
|
992
|
-
}
|
993
|
-
}
|
994
|
-
return best;
|
974
|
+
return when_constant([ "binary", op, walk(left), walk(right) ], function yes(c){
|
975
|
+
return best_of(walk(c), this);
|
976
|
+
}, function no() {
|
977
|
+
return this;
|
978
|
+
});
|
995
979
|
},
|
996
980
|
"conditional": function(c, t, e) {
|
997
981
|
return make_conditional(walk(c), walk(t), walk(e));
|
@@ -1004,17 +988,14 @@ function ast_squeeze(ast, options) {
|
|
1004
988
|
f != null ? tighten(MAP(f, walk)) : null
|
1005
989
|
];
|
1006
990
|
},
|
1007
|
-
"unary-prefix": function(op,
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
}
|
1016
|
-
return best_of(this, negate(cond));
|
1017
|
-
}
|
991
|
+
"unary-prefix": function(op, expr) {
|
992
|
+
expr = walk(expr);
|
993
|
+
var ret = [ "unary-prefix", op, expr ];
|
994
|
+
if (op == "!")
|
995
|
+
ret = best_of(ret, negate(expr));
|
996
|
+
return when_constant(ret, function(ast, val){
|
997
|
+
return walk(ast); // it's either true or false, so minifies to !0 or !1
|
998
|
+
}, function() { return ret });
|
1018
999
|
},
|
1019
1000
|
"name": function(name) {
|
1020
1001
|
switch (name) {
|
@@ -1035,7 +1016,9 @@ function ast_squeeze(ast, options) {
|
|
1035
1016
|
if (expr[0] == "name" && expr[1] == "Array" && args.length != 1 && !scope.has("Array")) {
|
1036
1017
|
return [ "array", args ];
|
1037
1018
|
}
|
1038
|
-
}
|
1019
|
+
},
|
1020
|
+
"while": _do_while,
|
1021
|
+
"do": _do_while
|
1039
1022
|
}, function() {
|
1040
1023
|
return walk(ast_add_scope(ast));
|
1041
1024
|
});
|
@@ -1253,7 +1236,9 @@ function gen_code(ast, beautify) {
|
|
1253
1236
|
},
|
1254
1237
|
"dot": function(expr) {
|
1255
1238
|
var out = make(expr), i = 1;
|
1256
|
-
if (
|
1239
|
+
if (expr[0] == "num")
|
1240
|
+
out += ".";
|
1241
|
+
else if (needs_parens(expr))
|
1257
1242
|
out = "(" + out + ")";
|
1258
1243
|
while (i < arguments.length)
|
1259
1244
|
out += "." + make_name(arguments[i++]);
|
@@ -1286,12 +1271,11 @@ function gen_code(ast, beautify) {
|
|
1286
1271
|
out.push("(" + args + ")", make(block));
|
1287
1272
|
return add_spaces(out);
|
1288
1273
|
},
|
1289
|
-
"for-in": function(
|
1290
|
-
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
return out;
|
1274
|
+
"for-in": function(vvar, key, hash, block) {
|
1275
|
+
return add_spaces([ "for", "(" +
|
1276
|
+
(vvar ? make(vvar).replace(/;+$/, "") : make(key)),
|
1277
|
+
"in",
|
1278
|
+
make(hash) + ")", make(block) ]);
|
1295
1279
|
},
|
1296
1280
|
"while": function(condition, block) {
|
1297
1281
|
return add_spaces([ "while", "(" + make(condition) + ")", make(block) ]);
|
@@ -1314,7 +1298,8 @@ function gen_code(ast, beautify) {
|
|
1314
1298
|
left = "(" + left + ")";
|
1315
1299
|
}
|
1316
1300
|
if (member(rvalue[0], [ "assign", "conditional", "seq" ]) ||
|
1317
|
-
rvalue[0] == "binary" && PRECEDENCE[operator] >= PRECEDENCE[rvalue[1]]
|
1301
|
+
rvalue[0] == "binary" && PRECEDENCE[operator] >= PRECEDENCE[rvalue[1]] &&
|
1302
|
+
!(rvalue[1] == operator && member(operator, [ "&&", "||", "*" ]))) {
|
1318
1303
|
right = "(" + right + ")";
|
1319
1304
|
}
|
1320
1305
|
return add_spaces([ left, operator, right ]);
|
@@ -1350,7 +1335,8 @@ function gen_code(ast, beautify) {
|
|
1350
1335
|
var key = p[0], val = make(p[1]);
|
1351
1336
|
if (beautify && beautify.quote_keys) {
|
1352
1337
|
key = make_string(key);
|
1353
|
-
} else if (typeof key == "number" || !beautify && +key + "" == key)
|
1338
|
+
} else if ((typeof key == "number" || !beautify && +key + "" == key)
|
1339
|
+
&& parseFloat(key) >= 0) {
|
1354
1340
|
key = make_num(+key);
|
1355
1341
|
} else if (!is_identifier(key)) {
|
1356
1342
|
key = make_string(key);
|
@@ -1367,6 +1353,7 @@ function gen_code(ast, beautify) {
|
|
1367
1353
|
"array": function(elements) {
|
1368
1354
|
if (elements.length == 0) return "[]";
|
1369
1355
|
return add_spaces([ "[", add_commas(MAP(elements, function(el){
|
1356
|
+
if (!beautify && el[0] == "atom" && el[1] == "undefined") return "";
|
1370
1357
|
return parenthesize(el, "seq");
|
1371
1358
|
})), "]" ]);
|
1372
1359
|
},
|
@@ -1384,12 +1371,6 @@ function gen_code(ast, beautify) {
|
|
1384
1371
|
},
|
1385
1372
|
"atom": function(name) {
|
1386
1373
|
return make_name(name);
|
1387
|
-
},
|
1388
|
-
"comment1": function(text) {
|
1389
|
-
return "//" + text + "\n";
|
1390
|
-
},
|
1391
|
-
"comment2": function(text) {
|
1392
|
-
return "/*" + text + "*/";
|
1393
1374
|
}
|
1394
1375
|
};
|
1395
1376
|
|
@@ -1442,8 +1423,16 @@ function gen_code(ast, beautify) {
|
|
1442
1423
|
var stat = statements[i];
|
1443
1424
|
var code = make(stat);
|
1444
1425
|
if (code != ";") {
|
1445
|
-
if (!beautify && i == last)
|
1446
|
-
|
1426
|
+
if (!beautify && i == last) {
|
1427
|
+
if ((stat[0] == "while" && empty(stat[2])) ||
|
1428
|
+
(member(stat[0], [ "for", "for-in"] ) && empty(stat[4])) ||
|
1429
|
+
(stat[0] == "if" && empty(stat[2]) && !stat[3]) ||
|
1430
|
+
(stat[0] == "if" && stat[3] && empty(stat[3]))) {
|
1431
|
+
code = code.replace(/;*\s*$/, ";");
|
1432
|
+
} else {
|
1433
|
+
code = code.replace(/;+\s*$/, "");
|
1434
|
+
}
|
1435
|
+
}
|
1447
1436
|
a.push(code);
|
1448
1437
|
}
|
1449
1438
|
}
|
@@ -1498,6 +1487,49 @@ function gen_code(ast, beautify) {
|
|
1498
1487
|
return make(ast);
|
1499
1488
|
};
|
1500
1489
|
|
1490
|
+
function split_lines(code, max_line_length) {
|
1491
|
+
var splits = [ 0 ];
|
1492
|
+
jsp.parse(function(){
|
1493
|
+
var next_token = jsp.tokenizer(code);
|
1494
|
+
var last_split = 0;
|
1495
|
+
var prev_token;
|
1496
|
+
function current_length(tok) {
|
1497
|
+
return tok.pos - last_split;
|
1498
|
+
};
|
1499
|
+
function split_here(tok) {
|
1500
|
+
last_split = tok.pos;
|
1501
|
+
splits.push(last_split);
|
1502
|
+
};
|
1503
|
+
function custom(){
|
1504
|
+
var tok = next_token.apply(this, arguments);
|
1505
|
+
out: {
|
1506
|
+
if (prev_token) {
|
1507
|
+
if (prev_token.type == "keyword") break out;
|
1508
|
+
}
|
1509
|
+
if (current_length(tok) > max_line_length) {
|
1510
|
+
switch (tok.type) {
|
1511
|
+
case "keyword":
|
1512
|
+
case "atom":
|
1513
|
+
case "name":
|
1514
|
+
case "punc":
|
1515
|
+
split_here(tok);
|
1516
|
+
break out;
|
1517
|
+
}
|
1518
|
+
}
|
1519
|
+
}
|
1520
|
+
prev_token = tok;
|
1521
|
+
return tok;
|
1522
|
+
};
|
1523
|
+
custom.context = function() {
|
1524
|
+
return next_token.context.apply(this, arguments);
|
1525
|
+
};
|
1526
|
+
return custom;
|
1527
|
+
}());
|
1528
|
+
return splits.map(function(pos, i){
|
1529
|
+
return code.substring(pos, splits[i + 1] || code.length);
|
1530
|
+
}).join("\n");
|
1531
|
+
};
|
1532
|
+
|
1501
1533
|
/* -----[ Utilities ]----- */
|
1502
1534
|
|
1503
1535
|
function repeat_string(str, i) {
|
@@ -1558,3 +1590,5 @@ exports.gen_code = gen_code;
|
|
1558
1590
|
exports.ast_add_scope = ast_add_scope;
|
1559
1591
|
exports.ast_squeeze_more = require("./squeeze-more").ast_squeeze_more;
|
1560
1592
|
exports.set_logger = function(logger) { warn = logger };
|
1593
|
+
exports.make_string = make_string;
|
1594
|
+
exports.split_lines = split_lines;
|