1 /***********************************************************************
3 A JavaScript tokenizer / parser / beautifier / compressor.
4 https://github.com/mishoo/UglifyJS2
6 -------------------------------- (C) ---------------------------------
9 <mihai.bazon@gmail.com>
10 http://mihai.bazon.net/blog
12 Distributed under the BSD license:
14 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
16 Redistribution and use in source and binary forms, with or without
17 modification, are permitted provided that the following conditions
20 * Redistributions of source code must retain the above
21 copyright notice, this list of conditions and the following
24 * Redistributions in binary form must reproduce the above
25 copyright notice, this list of conditions and the following
26 disclaimer in the documentation and/or other materials
27 provided with the distribution.
29 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
30 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
33 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
34 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
35 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
36 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
38 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
39 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 ***********************************************************************/
46 function array_to_hash(a) {
47 var ret = Object.create(null);
48 for (var i = 0; i < a.length; ++i)
53 function slice(a, start) {
54 return Array.prototype.slice.call(a, start || 0);
57 function characters(str) {
61 function member(name, array) {
62 return array.indexOf(name) >= 0;
65 function find_if(func, array) {
66 for (var i = 0, n = array.length; i < n; ++i) {
72 function repeat_string(str, i) {
73 if (i <= 0) return "";
74 if (i == 1) return str;
75 var d = repeat_string(str, i >> 1);
81 function configure_error_stack(fn) {
82 Object.defineProperty(fn.prototype, "stack", {
84 var err = new Error(this.message);
95 function DefaultsError(msg, defs) {
99 DefaultsError.prototype = Object.create(Error.prototype);
100 DefaultsError.prototype.constructor = DefaultsError;
101 DefaultsError.prototype.name = "DefaultsError";
102 configure_error_stack(DefaultsError);
104 DefaultsError.croak = function(msg, defs) {
105 throw new DefaultsError(msg, defs);
108 function defaults(args, defs, croak) {
111 var ret = args || {};
112 if (croak) for (var i in ret) if (HOP(ret, i) && !HOP(defs, i))
113 DefaultsError.croak("`" + i + "` is not a supported option", defs);
114 for (var i in defs) if (HOP(defs, i)) {
115 ret[i] = (args && HOP(args, i)) ? args[i] : defs[i];
120 function merge(obj, ext) {
122 for (var i in ext) if (HOP(ext, i)) {
130 function return_false() { return false; }
131 function return_true() { return true; }
133 var MAP = (function(){
134 function MAP(a, f, backwards) {
135 var ret = [], top = [], i;
137 var val = f(a[i], i);
138 var is_last = val instanceof Last;
139 if (is_last) val = val.v;
140 if (val instanceof AtTop) {
142 if (val instanceof Splice) {
143 top.push.apply(top, backwards ? val.v.slice().reverse() : val.v);
148 else if (val !== skip) {
149 if (val instanceof Splice) {
150 ret.push.apply(ret, backwards ? val.v.slice().reverse() : val.v);
157 if (a instanceof Array) {
159 for (i = a.length; --i >= 0;) if (doit()) break;
163 for (i = 0; i < a.length; ++i) if (doit()) break;
167 for (i in a) if (HOP(a, i)) if (doit()) break;
169 return top.concat(ret);
171 MAP.at_top = function(val) { return new AtTop(val) };
172 MAP.splice = function(val) { return new Splice(val) };
173 MAP.last = function(val) { return new Last(val) };
174 var skip = MAP.skip = {};
175 function AtTop(val) { this.v = val };
176 function Splice(val) { this.v = val };
177 function Last(val) { this.v = val };
181 function push_uniq(array, el) {
182 if (array.indexOf(el) < 0)
186 function string_template(text, props) {
187 return text.replace(/\{(.+?)\}/g, function(str, p){
188 return props && props[p];
192 function remove(array, el) {
193 for (var i = array.length; --i >= 0;) {
194 if (array[i] === el) array.splice(i, 1);
198 function mergeSort(array, cmp) {
199 if (array.length < 2) return array.slice();
200 function merge(a, b) {
201 var r = [], ai = 0, bi = 0, i = 0;
202 while (ai < a.length && bi < b.length) {
203 cmp(a[ai], b[bi]) <= 0
207 if (ai < a.length) r.push.apply(r, a.slice(ai));
208 if (bi < b.length) r.push.apply(r, b.slice(bi));
214 var m = Math.floor(a.length / 2), left = a.slice(0, m), right = a.slice(m);
217 return merge(left, right);
222 function set_difference(a, b) {
223 return a.filter(function(el){
224 return b.indexOf(el) < 0;
228 function set_intersection(a, b) {
229 return a.filter(function(el){
230 return b.indexOf(el) >= 0;
234 // this function is taken from Acorn [1], written by Marijn Haverbeke
235 // [1] https://github.com/marijnh/acorn
236 function makePredicate(words) {
237 if (!(words instanceof Array)) words = words.split(" ");
238 var f = "", cats = [];
239 out: for (var i = 0; i < words.length; ++i) {
240 for (var j = 0; j < cats.length; ++j)
241 if (cats[j][0].length == words[i].length) {
242 cats[j].push(words[i]);
245 cats.push([words[i]]);
247 function quote(word) {
248 return JSON.stringify(word).replace(/[\u2028\u2029]/g, function(s) {
250 case "\u2028": return "\\u2028";
251 case "\u2029": return "\\u2029";
256 function compareTo(arr) {
257 if (arr.length == 1) return f += "return str === " + quote(arr[0]) + ";";
259 for (var i = 0; i < arr.length; ++i) f += "case " + quote(arr[i]) + ":";
260 f += "return true}return false;";
262 // When there are more than three length categories, an outer
263 // switch first dispatches on the lengths, to save on comparisons.
264 if (cats.length > 3) {
265 cats.sort(function(a, b) {return b.length - a.length;});
266 f += "switch(str.length){";
267 for (var i = 0; i < cats.length; ++i) {
269 f += "case " + cat[0].length + ":";
273 // Otherwise, simply generate a flat `switch` statement.
277 return new Function("str", f);
280 function all(array, predicate) {
281 for (var i = array.length; --i >= 0;)
282 if (!predicate(array[i]))
287 function Dictionary() {
288 this._values = Object.create(null);
291 Dictionary.prototype = {
292 set: function(key, val) {
293 if (!this.has(key)) ++this._size;
294 this._values["$" + key] = val;
297 add: function(key, val) {
299 this.get(key).push(val);
301 this.set(key, [ val ]);
305 get: function(key) { return this._values["$" + key] },
309 delete this._values["$" + key];
313 has: function(key) { return ("$" + key) in this._values },
315 for (var i in this._values)
316 f(this._values[i], i.substr(1));
323 for (var i in this._values)
324 ret.push(f(this._values[i], i.substr(1)));
327 toObject: function() { return this._values }
329 Dictionary.fromObject = function(obj) {
330 var dict = new Dictionary();
331 dict._size = merge(dict._values, obj);
335 function HOP(obj, prop) {
336 return Object.prototype.hasOwnProperty.call(obj, prop);
339 // return true if the node at the top of the stack (that means the
340 // innermost node in the current output) is lexically the first in
342 function first_in_statement(stack) {
343 var node = stack.parent(-1);
344 for (var i = 0, p; p = stack.parent(i); i++) {
345 if (p instanceof AST_Statement && p.body === node)
347 if ((p instanceof AST_Seq && p.car === node ) ||
348 (p instanceof AST_Call && p.expression === node && !(p instanceof AST_New) ) ||
349 (p instanceof AST_Dot && p.expression === node ) ||
350 (p instanceof AST_Sub && p.expression === node ) ||
351 (p instanceof AST_Conditional && p.condition === node ) ||
352 (p instanceof AST_Binary && p.left === node ) ||
353 (p instanceof AST_UnaryPostfix && p.expression === node ))