1/*********************************************************************** 2 3 A JavaScript tokenizer / parser / beautifier / compressor. 4 https://github.com/mishoo/UglifyJS 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 characters(str) { 47 return str.split(""); 48} 49 50function member(name, array) { 51 return array.indexOf(name) >= 0; 52} 53 54function find_if(func, array) { 55 for (var i = array.length; --i >= 0;) if (func(array[i])) return array[i]; 56} 57 58function configure_error_stack(fn) { 59 Object.defineProperty(fn.prototype, "stack", { 60 get: function() { 61 var err = new Error(this.message); 62 err.name = this.name; 63 try { 64 throw err; 65 } catch (e) { 66 return e.stack; 67 } 68 } 69 }); 70} 71 72function DefaultsError(msg, defs) { 73 this.message = msg; 74 this.defs = defs; 75} 76DefaultsError.prototype = Object.create(Error.prototype); 77DefaultsError.prototype.constructor = DefaultsError; 78DefaultsError.prototype.name = "DefaultsError"; 79configure_error_stack(DefaultsError); 80 81function defaults(args, defs, croak) { 82 if (croak) for (var i in args) { 83 if (HOP(args, i) && !HOP(defs, i)) throw new DefaultsError("`" + i + "` is not a supported option", defs); 84 } 85 for (var i in args) { 86 if (HOP(args, i)) defs[i] = args[i]; 87 } 88 return defs; 89} 90 91function noop() {} 92function return_false() { return false; } 93function return_true() { return true; } 94function return_this() { return this; } 95function return_null() { return null; } 96 97var List = (function() { 98 function List(a, f) { 99 var ret = []; 100 for (var i = 0; i < a.length; i++) { 101 var val = f(a[i], i); 102 if (val === skip) continue; 103 if (val instanceof Splice) { 104 ret.push.apply(ret, val.v); 105 } else { 106 ret.push(val); 107 } 108 } 109 return ret; 110 } 111 List.is_op = function(val) { 112 return val === skip || val instanceof Splice; 113 }; 114 List.splice = function(val) { 115 return new Splice(val); 116 }; 117 var skip = List.skip = {}; 118 function Splice(val) { 119 this.v = val; 120 } 121 return List; 122})(); 123 124function push_uniq(array, el) { 125 if (array.indexOf(el) < 0) return array.push(el); 126} 127 128function string_template(text, props) { 129 return text.replace(/\{([^{}]+)\}/g, function(str, p) { 130 var value = p == "this" ? props : props[p]; 131 if (value instanceof AST_Node) return value.print_to_string(); 132 if (value instanceof AST_Token) return value.file + ":" + value.line + "," + value.col; 133 return value; 134 }); 135} 136 137function remove(array, el) { 138 var index = array.indexOf(el); 139 if (index >= 0) array.splice(index, 1); 140} 141 142function makePredicate(words) { 143 if (!Array.isArray(words)) words = words.split(" "); 144 var map = Object.create(null); 145 words.forEach(function(word) { 146 map[word] = true; 147 }); 148 return map; 149} 150 151function all(array, predicate) { 152 for (var i = array.length; --i >= 0;) 153 if (!predicate(array[i], i)) 154 return false; 155 return true; 156} 157 158function Dictionary() { 159 this.values = Object.create(null); 160} 161Dictionary.prototype = { 162 set: function(key, val) { 163 if (key == "__proto__") { 164 this.proto_value = val; 165 } else { 166 this.values[key] = val; 167 } 168 return this; 169 }, 170 add: function(key, val) { 171 var list = this.get(key); 172 if (list) { 173 list.push(val); 174 } else { 175 this.set(key, [ val ]); 176 } 177 return this; 178 }, 179 get: function(key) { 180 return key == "__proto__" ? this.proto_value : this.values[key]; 181 }, 182 del: function(key) { 183 if (key == "__proto__") { 184 delete this.proto_value; 185 } else { 186 delete this.values[key]; 187 } 188 return this; 189 }, 190 has: function(key) { 191 return key == "__proto__" ? "proto_value" in this : key in this.values; 192 }, 193 all: function(predicate) { 194 for (var i in this.values) 195 if (!predicate(this.values[i], i)) return false; 196 if ("proto_value" in this && !predicate(this.proto_value, "__proto__")) return false; 197 return true; 198 }, 199 each: function(f) { 200 for (var i in this.values) 201 f(this.values[i], i); 202 if ("proto_value" in this) f(this.proto_value, "__proto__"); 203 }, 204 size: function() { 205 return Object.keys(this.values).length + ("proto_value" in this); 206 }, 207 map: function(f) { 208 var ret = []; 209 for (var i in this.values) 210 ret.push(f(this.values[i], i)); 211 if ("proto_value" in this) ret.push(f(this.proto_value, "__proto__")); 212 return ret; 213 }, 214 clone: function() { 215 var ret = new Dictionary(); 216 this.each(function(value, i) { 217 ret.set(i, value); 218 }); 219 return ret; 220 }, 221 toObject: function() { 222 var obj = {}; 223 this.each(function(value, i) { 224 obj["$" + i] = value; 225 }); 226 return obj; 227 }, 228}; 229Dictionary.fromObject = function(obj) { 230 var dict = new Dictionary(); 231 for (var i in obj) 232 if (HOP(obj, i)) dict.set(i.slice(1), obj[i]); 233 return dict; 234}; 235 236function HOP(obj, prop) { 237 return Object.prototype.hasOwnProperty.call(obj, prop); 238} 239 240// return true if the node at the top of the stack (that means the 241// innermost node in the current output) is lexically the first in 242// a statement. 243function first_in_statement(stack, arrow, export_default) { 244 var node = stack.parent(-1); 245 for (var i = 0, p; p = stack.parent(i++); node = p) { 246 if (is_arrow(p)) { 247 return arrow && p.value === node; 248 } else if (p instanceof AST_Binary) { 249 if (p.left === node) continue; 250 } else if (p.TYPE == "Call") { 251 if (p.expression === node) continue; 252 } else if (p instanceof AST_Conditional) { 253 if (p.condition === node) continue; 254 } else if (p instanceof AST_ExportDefault) { 255 return export_default; 256 } else if (p instanceof AST_PropAccess) { 257 if (p.expression === node) continue; 258 } else if (p instanceof AST_Sequence) { 259 if (p.expressions[0] === node) continue; 260 } else if (p instanceof AST_SimpleStatement) { 261 return true; 262 } else if (p instanceof AST_Template) { 263 if (p.tag === node) continue; 264 } else if (p instanceof AST_UnaryPostfix) { 265 if (p.expression === node) continue; 266 } 267 return false; 268 } 269} 270 271function DEF_BITPROPS(ctor, props) { 272 if (props.length > 31) throw new Error("Too many properties: " + props.length + "\n" + props.join(", ")); 273 props.forEach(function(name, pos) { 274 var mask = 1 << pos; 275 Object.defineProperty(ctor.prototype, name, { 276 get: function() { 277 return !!(this._bits & mask); 278 }, 279 set: function(val) { 280 if (val) 281 this._bits |= mask; 282 else 283 this._bits &= ~mask; 284 }, 285 }); 286 }); 287} 288