[79a0317] | 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 | import {
|
---|
| 45 | HOP,
|
---|
| 46 | makePredicate,
|
---|
| 47 | return_this,
|
---|
| 48 | string_template,
|
---|
| 49 | regexp_source_fix,
|
---|
| 50 | regexp_is_safe,
|
---|
| 51 | } from "../utils/index.js";
|
---|
| 52 | import {
|
---|
| 53 | AST_Array,
|
---|
| 54 | AST_BigInt,
|
---|
| 55 | AST_Binary,
|
---|
| 56 | AST_Call,
|
---|
| 57 | AST_Chain,
|
---|
| 58 | AST_Class,
|
---|
| 59 | AST_Conditional,
|
---|
| 60 | AST_Constant,
|
---|
| 61 | AST_Dot,
|
---|
| 62 | AST_Expansion,
|
---|
| 63 | AST_Function,
|
---|
| 64 | AST_Lambda,
|
---|
| 65 | AST_New,
|
---|
| 66 | AST_Node,
|
---|
| 67 | AST_Object,
|
---|
| 68 | AST_PropAccess,
|
---|
| 69 | AST_RegExp,
|
---|
| 70 | AST_Statement,
|
---|
| 71 | AST_Symbol,
|
---|
| 72 | AST_SymbolRef,
|
---|
| 73 | AST_TemplateString,
|
---|
| 74 | AST_UnaryPrefix,
|
---|
| 75 | AST_With,
|
---|
| 76 | } from "../ast.js";
|
---|
| 77 | import { is_undeclared_ref} from "./inference.js";
|
---|
| 78 | import { is_pure_native_value, is_pure_native_fn, is_pure_native_method } from "./native-objects.js";
|
---|
| 79 |
|
---|
| 80 | // methods to evaluate a constant expression
|
---|
| 81 |
|
---|
| 82 | function def_eval(node, func) {
|
---|
| 83 | node.DEFMETHOD("_eval", func);
|
---|
| 84 | }
|
---|
| 85 |
|
---|
| 86 | // Used to propagate a nullish short-circuit signal upwards through the chain.
|
---|
| 87 | export const nullish = Symbol("This AST_Chain is nullish");
|
---|
| 88 |
|
---|
| 89 | // If the node has been successfully reduced to a constant,
|
---|
| 90 | // then its value is returned; otherwise the element itself
|
---|
| 91 | // is returned.
|
---|
| 92 | // They can be distinguished as constant value is never a
|
---|
| 93 | // descendant of AST_Node.
|
---|
| 94 | AST_Node.DEFMETHOD("evaluate", function (compressor) {
|
---|
| 95 | if (!compressor.option("evaluate"))
|
---|
| 96 | return this;
|
---|
| 97 | var val = this._eval(compressor, 1);
|
---|
| 98 | if (!val || val instanceof RegExp)
|
---|
| 99 | return val;
|
---|
| 100 | if (typeof val == "function" || typeof val == "object" || val == nullish)
|
---|
| 101 | return this;
|
---|
| 102 |
|
---|
| 103 | // Evaluated strings can be larger than the original expression
|
---|
| 104 | if (typeof val === "string") {
|
---|
| 105 | const unevaluated_size = this.size(compressor);
|
---|
| 106 | if (val.length + 2 > unevaluated_size) return this;
|
---|
| 107 | }
|
---|
| 108 |
|
---|
| 109 | return val;
|
---|
| 110 | });
|
---|
| 111 |
|
---|
| 112 | var unaryPrefix = makePredicate("! ~ - + void");
|
---|
| 113 | AST_Node.DEFMETHOD("is_constant", function () {
|
---|
| 114 | // Accomodate when compress option evaluate=false
|
---|
| 115 | // as well as the common constant expressions !0 and -1
|
---|
| 116 | if (this instanceof AST_Constant) {
|
---|
| 117 | return !(this instanceof AST_RegExp);
|
---|
| 118 | } else {
|
---|
| 119 | return this instanceof AST_UnaryPrefix
|
---|
| 120 | && this.expression instanceof AST_Constant
|
---|
| 121 | && unaryPrefix.has(this.operator);
|
---|
| 122 | }
|
---|
| 123 | });
|
---|
| 124 |
|
---|
| 125 | def_eval(AST_Statement, function () {
|
---|
| 126 | throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
|
---|
| 127 | });
|
---|
| 128 |
|
---|
| 129 | def_eval(AST_Lambda, return_this);
|
---|
| 130 | def_eval(AST_Class, return_this);
|
---|
| 131 | def_eval(AST_Node, return_this);
|
---|
| 132 | def_eval(AST_Constant, function () {
|
---|
| 133 | return this.getValue();
|
---|
| 134 | });
|
---|
| 135 |
|
---|
| 136 | const supports_bigint = typeof BigInt === "function";
|
---|
| 137 | def_eval(AST_BigInt, function () {
|
---|
| 138 | if (supports_bigint) {
|
---|
| 139 | return BigInt(this.value);
|
---|
| 140 | } else {
|
---|
| 141 | return this;
|
---|
| 142 | }
|
---|
| 143 | });
|
---|
| 144 |
|
---|
| 145 | def_eval(AST_RegExp, function (compressor) {
|
---|
| 146 | let evaluated = compressor.evaluated_regexps.get(this.value);
|
---|
| 147 | if (evaluated === undefined && regexp_is_safe(this.value.source)) {
|
---|
| 148 | try {
|
---|
| 149 | const { source, flags } = this.value;
|
---|
| 150 | evaluated = new RegExp(source, flags);
|
---|
| 151 | } catch (e) {
|
---|
| 152 | evaluated = null;
|
---|
| 153 | }
|
---|
| 154 | compressor.evaluated_regexps.set(this.value, evaluated);
|
---|
| 155 | }
|
---|
| 156 | return evaluated || this;
|
---|
| 157 | });
|
---|
| 158 |
|
---|
| 159 | def_eval(AST_TemplateString, function () {
|
---|
| 160 | if (this.segments.length !== 1) return this;
|
---|
| 161 | return this.segments[0].value;
|
---|
| 162 | });
|
---|
| 163 |
|
---|
| 164 | def_eval(AST_Function, function (compressor) {
|
---|
| 165 | if (compressor.option("unsafe")) {
|
---|
| 166 | var fn = function () { };
|
---|
| 167 | fn.node = this;
|
---|
| 168 | fn.toString = () => this.print_to_string();
|
---|
| 169 | return fn;
|
---|
| 170 | }
|
---|
| 171 | return this;
|
---|
| 172 | });
|
---|
| 173 |
|
---|
| 174 | def_eval(AST_Array, function (compressor, depth) {
|
---|
| 175 | if (compressor.option("unsafe")) {
|
---|
| 176 | var elements = [];
|
---|
| 177 | for (var i = 0, len = this.elements.length; i < len; i++) {
|
---|
| 178 | var element = this.elements[i];
|
---|
| 179 | var value = element._eval(compressor, depth);
|
---|
| 180 | if (element === value)
|
---|
| 181 | return this;
|
---|
| 182 | elements.push(value);
|
---|
| 183 | }
|
---|
| 184 | return elements;
|
---|
| 185 | }
|
---|
| 186 | return this;
|
---|
| 187 | });
|
---|
| 188 |
|
---|
| 189 | def_eval(AST_Object, function (compressor, depth) {
|
---|
| 190 | if (compressor.option("unsafe")) {
|
---|
| 191 | var val = {};
|
---|
| 192 | for (var i = 0, len = this.properties.length; i < len; i++) {
|
---|
| 193 | var prop = this.properties[i];
|
---|
| 194 | if (prop instanceof AST_Expansion)
|
---|
| 195 | return this;
|
---|
| 196 | var key = prop.key;
|
---|
| 197 | if (key instanceof AST_Symbol) {
|
---|
| 198 | key = key.name;
|
---|
| 199 | } else if (key instanceof AST_Node) {
|
---|
| 200 | key = key._eval(compressor, depth);
|
---|
| 201 | if (key === prop.key)
|
---|
| 202 | return this;
|
---|
| 203 | }
|
---|
| 204 | if (typeof Object.prototype[key] === "function") {
|
---|
| 205 | return this;
|
---|
| 206 | }
|
---|
| 207 | if (prop.value instanceof AST_Function)
|
---|
| 208 | continue;
|
---|
| 209 | val[key] = prop.value._eval(compressor, depth);
|
---|
| 210 | if (val[key] === prop.value)
|
---|
| 211 | return this;
|
---|
| 212 | }
|
---|
| 213 | return val;
|
---|
| 214 | }
|
---|
| 215 | return this;
|
---|
| 216 | });
|
---|
| 217 |
|
---|
| 218 | var non_converting_unary = makePredicate("! typeof void");
|
---|
| 219 | def_eval(AST_UnaryPrefix, function (compressor, depth) {
|
---|
| 220 | var e = this.expression;
|
---|
| 221 | if (compressor.option("typeofs")
|
---|
| 222 | && this.operator == "typeof") {
|
---|
| 223 | // Function would be evaluated to an array and so typeof would
|
---|
| 224 | // incorrectly return 'object'. Hence making is a special case.
|
---|
| 225 | if (e instanceof AST_Lambda
|
---|
| 226 | || e instanceof AST_SymbolRef
|
---|
| 227 | && e.fixed_value() instanceof AST_Lambda) {
|
---|
| 228 | return typeof function () { };
|
---|
| 229 | }
|
---|
| 230 | if (
|
---|
| 231 | (e instanceof AST_Object
|
---|
| 232 | || e instanceof AST_Array
|
---|
| 233 | || (e instanceof AST_SymbolRef
|
---|
| 234 | && (e.fixed_value() instanceof AST_Object
|
---|
| 235 | || e.fixed_value() instanceof AST_Array)))
|
---|
| 236 | && !e.has_side_effects(compressor)
|
---|
| 237 | ) {
|
---|
| 238 | return typeof {};
|
---|
| 239 | }
|
---|
| 240 | }
|
---|
| 241 | if (!non_converting_unary.has(this.operator))
|
---|
| 242 | depth++;
|
---|
| 243 | e = e._eval(compressor, depth);
|
---|
| 244 | if (e === this.expression)
|
---|
| 245 | return this;
|
---|
| 246 | switch (this.operator) {
|
---|
| 247 | case "!": return !e;
|
---|
| 248 | case "typeof":
|
---|
| 249 | // typeof <RegExp> returns "object" or "function" on different platforms
|
---|
| 250 | // so cannot evaluate reliably
|
---|
| 251 | if (e instanceof RegExp)
|
---|
| 252 | return this;
|
---|
| 253 | return typeof e;
|
---|
| 254 | case "void": return void e;
|
---|
| 255 | case "~": return ~e;
|
---|
| 256 | case "-": return -e;
|
---|
| 257 | case "+": return +e;
|
---|
| 258 | }
|
---|
| 259 | return this;
|
---|
| 260 | });
|
---|
| 261 |
|
---|
| 262 | var non_converting_binary = makePredicate("&& || ?? === !==");
|
---|
| 263 | const identity_comparison = makePredicate("== != === !==");
|
---|
| 264 | const has_identity = value => typeof value === "object"
|
---|
| 265 | || typeof value === "function"
|
---|
| 266 | || typeof value === "symbol";
|
---|
| 267 |
|
---|
| 268 | def_eval(AST_Binary, function (compressor, depth) {
|
---|
| 269 | if (!non_converting_binary.has(this.operator))
|
---|
| 270 | depth++;
|
---|
| 271 |
|
---|
| 272 | var left = this.left._eval(compressor, depth);
|
---|
| 273 | if (left === this.left)
|
---|
| 274 | return this;
|
---|
| 275 | var right = this.right._eval(compressor, depth);
|
---|
| 276 | if (right === this.right)
|
---|
| 277 | return this;
|
---|
| 278 |
|
---|
| 279 | if (left != null
|
---|
| 280 | && right != null
|
---|
| 281 | && identity_comparison.has(this.operator)
|
---|
| 282 | && has_identity(left)
|
---|
| 283 | && has_identity(right)
|
---|
| 284 | && typeof left === typeof right) {
|
---|
| 285 | // Do not compare by reference
|
---|
| 286 | return this;
|
---|
| 287 | }
|
---|
| 288 |
|
---|
| 289 | // Do not mix BigInt and Number; Don't use `>>>` on BigInt or `/ 0n`
|
---|
| 290 | if (
|
---|
| 291 | (typeof left === "bigint") !== (typeof right === "bigint")
|
---|
| 292 | || typeof left === "bigint"
|
---|
| 293 | && (this.operator === ">>>"
|
---|
| 294 | || this.operator === "/" && Number(right) === 0)
|
---|
| 295 | ) {
|
---|
| 296 | return this;
|
---|
| 297 | }
|
---|
| 298 |
|
---|
| 299 | var result;
|
---|
| 300 | switch (this.operator) {
|
---|
| 301 | case "&&": result = left && right; break;
|
---|
| 302 | case "||": result = left || right; break;
|
---|
| 303 | case "??": result = left != null ? left : right; break;
|
---|
| 304 | case "|": result = left | right; break;
|
---|
| 305 | case "&": result = left & right; break;
|
---|
| 306 | case "^": result = left ^ right; break;
|
---|
| 307 | case "+": result = left + right; break;
|
---|
| 308 | case "*": result = left * right; break;
|
---|
| 309 | case "**": result = left ** right; break;
|
---|
| 310 | case "/": result = left / right; break;
|
---|
| 311 | case "%": result = left % right; break;
|
---|
| 312 | case "-": result = left - right; break;
|
---|
| 313 | case "<<": result = left << right; break;
|
---|
| 314 | case ">>": result = left >> right; break;
|
---|
| 315 | case ">>>": result = left >>> right; break;
|
---|
| 316 | case "==": result = left == right; break;
|
---|
| 317 | case "===": result = left === right; break;
|
---|
| 318 | case "!=": result = left != right; break;
|
---|
| 319 | case "!==": result = left !== right; break;
|
---|
| 320 | case "<": result = left < right; break;
|
---|
| 321 | case "<=": result = left <= right; break;
|
---|
| 322 | case ">": result = left > right; break;
|
---|
| 323 | case ">=": result = left >= right; break;
|
---|
| 324 | default:
|
---|
| 325 | return this;
|
---|
| 326 | }
|
---|
| 327 | if (typeof result === "number" && isNaN(result) && compressor.find_parent(AST_With)) {
|
---|
| 328 | // leave original expression as is
|
---|
| 329 | return this;
|
---|
| 330 | }
|
---|
| 331 | return result;
|
---|
| 332 | });
|
---|
| 333 |
|
---|
| 334 | def_eval(AST_Conditional, function (compressor, depth) {
|
---|
| 335 | var condition = this.condition._eval(compressor, depth);
|
---|
| 336 | if (condition === this.condition)
|
---|
| 337 | return this;
|
---|
| 338 | var node = condition ? this.consequent : this.alternative;
|
---|
| 339 | var value = node._eval(compressor, depth);
|
---|
| 340 | return value === node ? this : value;
|
---|
| 341 | });
|
---|
| 342 |
|
---|
| 343 | // Set of AST_SymbolRef which are currently being evaluated.
|
---|
| 344 | // Avoids infinite recursion of ._eval()
|
---|
| 345 | const reentrant_ref_eval = new Set();
|
---|
| 346 | def_eval(AST_SymbolRef, function (compressor, depth) {
|
---|
| 347 | if (reentrant_ref_eval.has(this))
|
---|
| 348 | return this;
|
---|
| 349 |
|
---|
| 350 | var fixed = this.fixed_value();
|
---|
| 351 | if (!fixed)
|
---|
| 352 | return this;
|
---|
| 353 |
|
---|
| 354 | reentrant_ref_eval.add(this);
|
---|
| 355 | const value = fixed._eval(compressor, depth);
|
---|
| 356 | reentrant_ref_eval.delete(this);
|
---|
| 357 |
|
---|
| 358 | if (value === fixed)
|
---|
| 359 | return this;
|
---|
| 360 |
|
---|
| 361 | if (value && typeof value == "object") {
|
---|
| 362 | var escaped = this.definition().escaped;
|
---|
| 363 | if (escaped && depth > escaped)
|
---|
| 364 | return this;
|
---|
| 365 | }
|
---|
| 366 | return value;
|
---|
| 367 | });
|
---|
| 368 |
|
---|
| 369 | const global_objs = { Array, Math, Number, Object, String };
|
---|
| 370 |
|
---|
| 371 | const regexp_flags = new Set([
|
---|
| 372 | "dotAll",
|
---|
| 373 | "global",
|
---|
| 374 | "ignoreCase",
|
---|
| 375 | "multiline",
|
---|
| 376 | "sticky",
|
---|
| 377 | "unicode",
|
---|
| 378 | ]);
|
---|
| 379 |
|
---|
| 380 | def_eval(AST_PropAccess, function (compressor, depth) {
|
---|
| 381 | let obj = this.expression._eval(compressor, depth + 1);
|
---|
| 382 | if (obj === nullish || (this.optional && obj == null)) return nullish;
|
---|
| 383 |
|
---|
| 384 | // `.length` of strings and arrays is always safe
|
---|
| 385 | if (this.property === "length") {
|
---|
| 386 | if (typeof obj === "string") {
|
---|
| 387 | return obj.length;
|
---|
| 388 | }
|
---|
| 389 |
|
---|
| 390 | const is_spreadless_array =
|
---|
| 391 | obj instanceof AST_Array
|
---|
| 392 | && obj.elements.every(el => !(el instanceof AST_Expansion));
|
---|
| 393 |
|
---|
| 394 | if (
|
---|
| 395 | is_spreadless_array
|
---|
| 396 | && obj.elements.every(el => !el.has_side_effects(compressor))
|
---|
| 397 | ) {
|
---|
| 398 | return obj.elements.length;
|
---|
| 399 | }
|
---|
| 400 | }
|
---|
| 401 |
|
---|
| 402 | if (compressor.option("unsafe")) {
|
---|
| 403 | var key = this.property;
|
---|
| 404 | if (key instanceof AST_Node) {
|
---|
| 405 | key = key._eval(compressor, depth);
|
---|
| 406 | if (key === this.property)
|
---|
| 407 | return this;
|
---|
| 408 | }
|
---|
| 409 |
|
---|
| 410 | var exp = this.expression;
|
---|
| 411 | if (is_undeclared_ref(exp)) {
|
---|
| 412 | var aa;
|
---|
| 413 | var first_arg = exp.name === "hasOwnProperty"
|
---|
| 414 | && key === "call"
|
---|
| 415 | && (aa = compressor.parent() && compressor.parent().args)
|
---|
| 416 | && (aa && aa[0]
|
---|
| 417 | && aa[0].evaluate(compressor));
|
---|
| 418 |
|
---|
| 419 | first_arg = first_arg instanceof AST_Dot ? first_arg.expression : first_arg;
|
---|
| 420 |
|
---|
| 421 | if (first_arg == null || first_arg.thedef && first_arg.thedef.undeclared) {
|
---|
| 422 | return this.clone();
|
---|
| 423 | }
|
---|
| 424 | if (!is_pure_native_value(exp.name, key))
|
---|
| 425 | return this;
|
---|
| 426 | obj = global_objs[exp.name];
|
---|
| 427 | } else {
|
---|
| 428 | if (obj instanceof RegExp) {
|
---|
| 429 | if (key == "source") {
|
---|
| 430 | return regexp_source_fix(obj.source);
|
---|
| 431 | } else if (key == "flags" || regexp_flags.has(key)) {
|
---|
| 432 | return obj[key];
|
---|
| 433 | }
|
---|
| 434 | }
|
---|
| 435 | if (!obj || obj === exp || !HOP(obj, key))
|
---|
| 436 | return this;
|
---|
| 437 |
|
---|
| 438 | if (typeof obj == "function")
|
---|
| 439 | switch (key) {
|
---|
| 440 | case "name":
|
---|
| 441 | return obj.node.name ? obj.node.name.name : "";
|
---|
| 442 | case "length":
|
---|
| 443 | return obj.node.length_property();
|
---|
| 444 | default:
|
---|
| 445 | return this;
|
---|
| 446 | }
|
---|
| 447 | }
|
---|
| 448 | return obj[key];
|
---|
| 449 | }
|
---|
| 450 | return this;
|
---|
| 451 | });
|
---|
| 452 |
|
---|
| 453 | def_eval(AST_Chain, function (compressor, depth) {
|
---|
| 454 | const evaluated = this.expression._eval(compressor, depth);
|
---|
| 455 | return evaluated === nullish
|
---|
| 456 | ? undefined
|
---|
| 457 | : evaluated === this.expression
|
---|
| 458 | ? this
|
---|
| 459 | : evaluated;
|
---|
| 460 | });
|
---|
| 461 |
|
---|
| 462 | def_eval(AST_Call, function (compressor, depth) {
|
---|
| 463 | var exp = this.expression;
|
---|
| 464 |
|
---|
| 465 | const callee = exp._eval(compressor, depth);
|
---|
| 466 | if (callee === nullish || (this.optional && callee == null)) return nullish;
|
---|
| 467 |
|
---|
| 468 | if (compressor.option("unsafe") && exp instanceof AST_PropAccess) {
|
---|
| 469 | var key = exp.property;
|
---|
| 470 | if (key instanceof AST_Node) {
|
---|
| 471 | key = key._eval(compressor, depth);
|
---|
| 472 | if (key === exp.property)
|
---|
| 473 | return this;
|
---|
| 474 | }
|
---|
| 475 | var val;
|
---|
| 476 | var e = exp.expression;
|
---|
| 477 | if (is_undeclared_ref(e)) {
|
---|
| 478 | var first_arg = e.name === "hasOwnProperty" &&
|
---|
| 479 | key === "call" &&
|
---|
| 480 | (this.args[0] && this.args[0].evaluate(compressor));
|
---|
| 481 |
|
---|
| 482 | first_arg = first_arg instanceof AST_Dot ? first_arg.expression : first_arg;
|
---|
| 483 |
|
---|
| 484 | if ((first_arg == null || first_arg.thedef && first_arg.thedef.undeclared)) {
|
---|
| 485 | return this.clone();
|
---|
| 486 | }
|
---|
| 487 | if (!is_pure_native_fn(e.name, key)) return this;
|
---|
| 488 | val = global_objs[e.name];
|
---|
| 489 | } else {
|
---|
| 490 | val = e._eval(compressor, depth + 1);
|
---|
| 491 | if (val === e || !val)
|
---|
| 492 | return this;
|
---|
| 493 | if (!is_pure_native_method(val.constructor.name, key))
|
---|
| 494 | return this;
|
---|
| 495 | }
|
---|
| 496 | var args = [];
|
---|
| 497 | for (var i = 0, len = this.args.length; i < len; i++) {
|
---|
| 498 | var arg = this.args[i];
|
---|
| 499 | var value = arg._eval(compressor, depth);
|
---|
| 500 | if (arg === value)
|
---|
| 501 | return this;
|
---|
| 502 | if (arg instanceof AST_Lambda)
|
---|
| 503 | return this;
|
---|
| 504 | args.push(value);
|
---|
| 505 | }
|
---|
| 506 | try {
|
---|
| 507 | return val[key].apply(val, args);
|
---|
| 508 | } catch (ex) {
|
---|
| 509 | // We don't really care
|
---|
| 510 | }
|
---|
| 511 | }
|
---|
| 512 | return this;
|
---|
| 513 | });
|
---|
| 514 |
|
---|
| 515 | // Also a subclass of AST_Call
|
---|
| 516 | def_eval(AST_New, return_this);
|
---|