1/***********************************************************************
2
3  A JavaScript tokenizer / parser / beautifier / compressor.
4  https://github.com/mishoo/UglifyJS2
5
6  -------------------------------- (C) ---------------------------------
7
8                           Author: Mihai Bazon
9                         <mihai.bazon@gmail.com>
10                       http://mihai.bazon.net/blog
11
12  Distributed under the BSD license:
13
14    Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
15
16    Redistribution and use in source and binary forms, with or without
17    modification, are permitted provided that the following conditions
18    are met:
19
20        * Redistributions of source code must retain the above
21          copyright notice, this list of conditions and the following
22          disclaimer.
23
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.
28
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
40    SUCH DAMAGE.
41
42 ***********************************************************************/
43
44"use strict";
45
46function array_to_hash(a) {
47    var ret = Object.create(null);
48    for (var i = 0; i < a.length; ++i)
49        ret[a[i]] = true;
50    return ret;
51};
52
53function slice(a, start) {
54    return Array.prototype.slice.call(a, start || 0);
55};
56
57function characters(str) {
58    return str.split("");
59};
60
61function member(name, array) {
62    return array.indexOf(name) >= 0;
63};
64
65function find_if(func, array) {
66    for (var i = 0, n = array.length; i < n; ++i) {
67        if (func(array[i]))
68            return array[i];
69    }
70};
71
72function repeat_string(str, i) {
73    if (i <= 0) return "";
74    if (i == 1) return str;
75    var d = repeat_string(str, i >> 1);
76    d += d;
77    if (i & 1) d += str;
78    return d;
79};
80
81function configure_error_stack(fn) {
82    Object.defineProperty(fn.prototype, "stack", {
83        get: function() {
84            var err = new Error(this.message);
85            err.name = this.name;
86            try {
87                throw err;
88            } catch(e) {
89                return e.stack;
90            }
91        }
92    });
93}
94
95function DefaultsError(msg, defs) {
96    this.message = msg;
97    this.defs = defs;
98};
99DefaultsError.prototype = Object.create(Error.prototype);
100DefaultsError.prototype.constructor = DefaultsError;
101DefaultsError.prototype.name = "DefaultsError";
102configure_error_stack(DefaultsError);
103
104DefaultsError.croak = function(msg, defs) {
105    throw new DefaultsError(msg, defs);
106};
107
108function defaults(args, defs, croak) {
109    if (args === true)
110        args = {};
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];
116    }
117    return ret;
118};
119
120function merge(obj, ext) {
121    var count = 0;
122    for (var i in ext) if (HOP(ext, i)) {
123        obj[i] = ext[i];
124        count++;
125    }
126    return count;
127};
128
129function noop() {}
130function return_false() { return false; }
131function return_true() { return true; }
132function return_this() { return this; }
133function return_null() { return null; }
134
135var MAP = (function(){
136    function MAP(a, f, backwards) {
137        var ret = [], top = [], i;
138        function doit() {
139            var val = f(a[i], i);
140            var is_last = val instanceof Last;
141            if (is_last) val = val.v;
142            if (val instanceof AtTop) {
143                val = val.v;
144                if (val instanceof Splice) {
145                    top.push.apply(top, backwards ? val.v.slice().reverse() : val.v);
146                } else {
147                    top.push(val);
148                }
149            }
150            else if (val !== skip) {
151                if (val instanceof Splice) {
152                    ret.push.apply(ret, backwards ? val.v.slice().reverse() : val.v);
153                } else {
154                    ret.push(val);
155                }
156            }
157            return is_last;
158        };
159        if (a instanceof Array) {
160            if (backwards) {
161                for (i = a.length; --i >= 0;) if (doit()) break;
162                ret.reverse();
163                top.reverse();
164            } else {
165                for (i = 0; i < a.length; ++i) if (doit()) break;
166            }
167        }
168        else {
169            for (i in a) if (HOP(a, i)) if (doit()) break;
170        }
171        return top.concat(ret);
172    };
173    MAP.at_top = function(val) { return new AtTop(val) };
174    MAP.splice = function(val) { return new Splice(val) };
175    MAP.last = function(val) { return new Last(val) };
176    var skip = MAP.skip = {};
177    function AtTop(val) { this.v = val };
178    function Splice(val) { this.v = val };
179    function Last(val) { this.v = val };
180    return MAP;
181})();
182
183function push_uniq(array, el) {
184    if (array.indexOf(el) < 0)
185        array.push(el);
186};
187
188function string_template(text, props) {
189    return text.replace(/\{(.+?)\}/g, function(str, p){
190        return props && props[p];
191    });
192};
193
194function remove(array, el) {
195    for (var i = array.length; --i >= 0;) {
196        if (array[i] === el) array.splice(i, 1);
197    }
198};
199
200function mergeSort(array, cmp) {
201    if (array.length < 2) return array.slice();
202    function merge(a, b) {
203        var r = [], ai = 0, bi = 0, i = 0;
204        while (ai < a.length && bi < b.length) {
205            cmp(a[ai], b[bi]) <= 0
206                ? r[i++] = a[ai++]
207                : r[i++] = b[bi++];
208        }
209        if (ai < a.length) r.push.apply(r, a.slice(ai));
210        if (bi < b.length) r.push.apply(r, b.slice(bi));
211        return r;
212    };
213    function _ms(a) {
214        if (a.length <= 1)
215            return a;
216        var m = Math.floor(a.length / 2), left = a.slice(0, m), right = a.slice(m);
217        left = _ms(left);
218        right = _ms(right);
219        return merge(left, right);
220    };
221    return _ms(array);
222};
223
224function set_difference(a, b) {
225    return a.filter(function(el){
226        return b.indexOf(el) < 0;
227    });
228};
229
230function set_intersection(a, b) {
231    return a.filter(function(el){
232        return b.indexOf(el) >= 0;
233    });
234};
235
236// this function is taken from Acorn [1], written by Marijn Haverbeke
237// [1] https://github.com/marijnh/acorn
238function makePredicate(words) {
239    if (!(words instanceof Array)) words = words.split(" ");
240    var f = "", cats = [];
241    out: for (var i = 0; i < words.length; ++i) {
242        for (var j = 0; j < cats.length; ++j)
243            if (cats[j][0].length == words[i].length) {
244                cats[j].push(words[i]);
245                continue out;
246            }
247        cats.push([words[i]]);
248    }
249    function quote(word) {
250        return JSON.stringify(word).replace(/[\u2028\u2029]/g, function(s) {
251            switch (s) {
252                case "\u2028": return "\\u2028";
253                case "\u2029": return "\\u2029";
254            }
255            return s;
256        });
257    }
258    function compareTo(arr) {
259        if (arr.length == 1) return f += "return str === " + quote(arr[0]) + ";";
260        f += "switch(str){";
261        for (var i = 0; i < arr.length; ++i) f += "case " + quote(arr[i]) + ":";
262        f += "return true}return false;";
263    }
264    // When there are more than three length categories, an outer
265    // switch first dispatches on the lengths, to save on comparisons.
266    if (cats.length > 3) {
267        cats.sort(function(a, b) {return b.length - a.length;});
268        f += "switch(str.length){";
269        for (var i = 0; i < cats.length; ++i) {
270            var cat = cats[i];
271            f += "case " + cat[0].length + ":";
272            compareTo(cat);
273        }
274        f += "}";
275        // Otherwise, simply generate a flat `switch` statement.
276    } else {
277        compareTo(words);
278    }
279    return new Function("str", f);
280};
281
282function all(array, predicate) {
283    for (var i = array.length; --i >= 0;)
284        if (!predicate(array[i]))
285            return false;
286    return true;
287};
288
289function Dictionary() {
290    this._values = Object.create(null);
291    this._size = 0;
292};
293Dictionary.prototype = {
294    set: function(key, val) {
295        if (!this.has(key)) ++this._size;
296        this._values["$" + key] = val;
297        return this;
298    },
299    add: function(key, val) {
300        if (this.has(key)) {
301            this.get(key).push(val);
302        } else {
303            this.set(key, [ val ]);
304        }
305        return this;
306    },
307    get: function(key) { return this._values["$" + key] },
308    del: function(key) {
309        if (this.has(key)) {
310            --this._size;
311            delete this._values["$" + key];
312        }
313        return this;
314    },
315    has: function(key) { return ("$" + key) in this._values },
316    each: function(f) {
317        for (var i in this._values)
318            f(this._values[i], i.substr(1));
319    },
320    size: function() {
321        return this._size;
322    },
323    map: function(f) {
324        var ret = [];
325        for (var i in this._values)
326            ret.push(f(this._values[i], i.substr(1)));
327        return ret;
328    },
329    toObject: function() { return this._values }
330};
331Dictionary.fromObject = function(obj) {
332    var dict = new Dictionary();
333    dict._size = merge(dict._values, obj);
334    return dict;
335};
336
337function HOP(obj, prop) {
338    return Object.prototype.hasOwnProperty.call(obj, prop);
339}
340
341// return true if the node at the top of the stack (that means the
342// innermost node in the current output) is lexically the first in
343// a statement.
344function first_in_statement(stack) {
345    var node = stack.parent(-1);
346    for (var i = 0, p; p = stack.parent(i); i++) {
347        if (p instanceof AST_Statement && p.body === node)
348            return true;
349        if ((p instanceof AST_Seq           && p.car === node        ) ||
350            (p instanceof AST_Call          && p.expression === node && !(p instanceof AST_New) ) ||
351            (p instanceof AST_Dot           && p.expression === node ) ||
352            (p instanceof AST_Sub           && p.expression === node ) ||
353            (p instanceof AST_Conditional   && p.condition === node  ) ||
354            (p instanceof AST_Binary        && p.left === node       ) ||
355            (p instanceof AST_UnaryPostfix  && p.expression === node ))
356        {
357            node = p;
358        } else {
359            return false;
360        }
361    }
362}
363