|  |  |  |  | /*********************************************************************** | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   A JavaScript tokenizer / parser / beautifier / compressor. | 
					
						
							|  |  |  |  |   https://github.com/mishoo/UglifyJS2
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   -------------------------------- (C) --------------------------------- | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                            Author: Mihai Bazon | 
					
						
							|  |  |  |  |                          <mihai.bazon@gmail.com> | 
					
						
							|  |  |  |  |                        http://mihai.bazon.net/blog
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   Distributed under the BSD license: | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com> | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     Redistribution and use in source and binary forms, with or without | 
					
						
							|  |  |  |  |     modification, are permitted provided that the following conditions | 
					
						
							|  |  |  |  |     are met: | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         * Redistributions of source code must retain the above | 
					
						
							|  |  |  |  |           copyright notice, this list of conditions and the following | 
					
						
							|  |  |  |  |           disclaimer. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         * Redistributions in binary form must reproduce the above | 
					
						
							|  |  |  |  |           copyright notice, this list of conditions and the following | 
					
						
							|  |  |  |  |           disclaimer in the documentation and/or other materials | 
					
						
							|  |  |  |  |           provided with the distribution. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY | 
					
						
							|  |  |  |  |     EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
					
						
							|  |  |  |  |     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 
					
						
							|  |  |  |  |     PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE | 
					
						
							|  |  |  |  |     LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, | 
					
						
							|  |  |  |  |     OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 
					
						
							|  |  |  |  |     PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 
					
						
							|  |  |  |  |     PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
					
						
							|  |  |  |  |     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR | 
					
						
							|  |  |  |  |     TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF | 
					
						
							|  |  |  |  |     THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 
					
						
							|  |  |  |  |     SUCH DAMAGE. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |  ***********************************************************************/ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | import { | 
					
						
							|  |  |  |  |     AST_Accessor, | 
					
						
							|  |  |  |  |     AST_Array, | 
					
						
							|  |  |  |  |     AST_Arrow, | 
					
						
							|  |  |  |  |     AST_Assign, | 
					
						
							|  |  |  |  |     AST_BigInt, | 
					
						
							|  |  |  |  |     AST_Binary, | 
					
						
							|  |  |  |  |     AST_Block, | 
					
						
							|  |  |  |  |     AST_BlockStatement, | 
					
						
							|  |  |  |  |     AST_Boolean, | 
					
						
							|  |  |  |  |     AST_Break, | 
					
						
							|  |  |  |  |     AST_Call, | 
					
						
							|  |  |  |  |     AST_Catch, | 
					
						
							|  |  |  |  |     AST_Chain, | 
					
						
							|  |  |  |  |     AST_Class, | 
					
						
							|  |  |  |  |     AST_ClassProperty, | 
					
						
							|  |  |  |  |     AST_ClassStaticBlock, | 
					
						
							|  |  |  |  |     AST_ConciseMethod, | 
					
						
							|  |  |  |  |     AST_Conditional, | 
					
						
							|  |  |  |  |     AST_Const, | 
					
						
							|  |  |  |  |     AST_Constant, | 
					
						
							|  |  |  |  |     AST_Debugger, | 
					
						
							|  |  |  |  |     AST_Default, | 
					
						
							|  |  |  |  |     AST_DefaultAssign, | 
					
						
							|  |  |  |  |     AST_Definitions, | 
					
						
							|  |  |  |  |     AST_Defun, | 
					
						
							|  |  |  |  |     AST_Destructuring, | 
					
						
							|  |  |  |  |     AST_Directive, | 
					
						
							|  |  |  |  |     AST_Do, | 
					
						
							|  |  |  |  |     AST_Dot, | 
					
						
							|  |  |  |  |     AST_DWLoop, | 
					
						
							|  |  |  |  |     AST_EmptyStatement, | 
					
						
							|  |  |  |  |     AST_Exit, | 
					
						
							|  |  |  |  |     AST_Expansion, | 
					
						
							|  |  |  |  |     AST_Export, | 
					
						
							|  |  |  |  |     AST_False, | 
					
						
							|  |  |  |  |     AST_For, | 
					
						
							|  |  |  |  |     AST_ForIn, | 
					
						
							|  |  |  |  |     AST_Function, | 
					
						
							|  |  |  |  |     AST_Hole, | 
					
						
							|  |  |  |  |     AST_If, | 
					
						
							|  |  |  |  |     AST_Import, | 
					
						
							|  |  |  |  |     AST_Infinity, | 
					
						
							|  |  |  |  |     AST_LabeledStatement, | 
					
						
							|  |  |  |  |     AST_Lambda, | 
					
						
							|  |  |  |  |     AST_Let, | 
					
						
							|  |  |  |  |     AST_NaN, | 
					
						
							|  |  |  |  |     AST_New, | 
					
						
							|  |  |  |  |     AST_Node, | 
					
						
							|  |  |  |  |     AST_Null, | 
					
						
							|  |  |  |  |     AST_Number, | 
					
						
							|  |  |  |  |     AST_Object, | 
					
						
							|  |  |  |  |     AST_ObjectKeyVal, | 
					
						
							|  |  |  |  |     AST_ObjectProperty, | 
					
						
							|  |  |  |  |     AST_PrefixedTemplateString, | 
					
						
							|  |  |  |  |     AST_PropAccess, | 
					
						
							|  |  |  |  |     AST_RegExp, | 
					
						
							|  |  |  |  |     AST_Return, | 
					
						
							|  |  |  |  |     AST_Scope, | 
					
						
							|  |  |  |  |     AST_Sequence, | 
					
						
							|  |  |  |  |     AST_SimpleStatement, | 
					
						
							|  |  |  |  |     AST_Statement, | 
					
						
							|  |  |  |  |     AST_String, | 
					
						
							|  |  |  |  |     AST_Sub, | 
					
						
							|  |  |  |  |     AST_Switch, | 
					
						
							|  |  |  |  |     AST_SwitchBranch, | 
					
						
							|  |  |  |  |     AST_Symbol, | 
					
						
							|  |  |  |  |     AST_SymbolClassProperty, | 
					
						
							|  |  |  |  |     AST_SymbolDeclaration, | 
					
						
							|  |  |  |  |     AST_SymbolDefun, | 
					
						
							|  |  |  |  |     AST_SymbolExport, | 
					
						
							|  |  |  |  |     AST_SymbolFunarg, | 
					
						
							|  |  |  |  |     AST_SymbolLambda, | 
					
						
							|  |  |  |  |     AST_SymbolLet, | 
					
						
							|  |  |  |  |     AST_SymbolMethod, | 
					
						
							|  |  |  |  |     AST_SymbolRef, | 
					
						
							|  |  |  |  |     AST_TemplateString, | 
					
						
							|  |  |  |  |     AST_This, | 
					
						
							|  |  |  |  |     AST_Toplevel, | 
					
						
							|  |  |  |  |     AST_True, | 
					
						
							|  |  |  |  |     AST_Try, | 
					
						
							|  |  |  |  |     AST_Unary, | 
					
						
							|  |  |  |  |     AST_UnaryPostfix, | 
					
						
							|  |  |  |  |     AST_UnaryPrefix, | 
					
						
							|  |  |  |  |     AST_Undefined, | 
					
						
							|  |  |  |  |     AST_Var, | 
					
						
							|  |  |  |  |     AST_VarDef, | 
					
						
							|  |  |  |  |     AST_While, | 
					
						
							|  |  |  |  |     AST_With, | 
					
						
							|  |  |  |  |     AST_Yield, | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     TreeTransformer, | 
					
						
							|  |  |  |  |     TreeWalker, | 
					
						
							|  |  |  |  |     walk, | 
					
						
							|  |  |  |  |     walk_abort, | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     _INLINE, | 
					
						
							|  |  |  |  |     _NOINLINE, | 
					
						
							|  |  |  |  |     _PURE | 
					
						
							|  |  |  |  | } from "../ast.js"; | 
					
						
							|  |  |  |  | import { | 
					
						
							|  |  |  |  |     defaults, | 
					
						
							|  |  |  |  |     HOP, | 
					
						
							|  |  |  |  |     make_node, | 
					
						
							|  |  |  |  |     makePredicate, | 
					
						
							|  |  |  |  |     MAP, | 
					
						
							|  |  |  |  |     remove, | 
					
						
							|  |  |  |  |     return_false, | 
					
						
							|  |  |  |  |     return_true, | 
					
						
							|  |  |  |  |     regexp_source_fix, | 
					
						
							|  |  |  |  |     has_annotation, | 
					
						
							|  |  |  |  |     regexp_is_safe, | 
					
						
							|  |  |  |  | } from "../utils/index.js"; | 
					
						
							|  |  |  |  | import { first_in_statement } from "../utils/first_in_statement.js"; | 
					
						
							|  |  |  |  | import { equivalent_to } from "../equivalent-to.js"; | 
					
						
							|  |  |  |  | import { | 
					
						
							|  |  |  |  |     is_basic_identifier_string, | 
					
						
							|  |  |  |  |     JS_Parse_Error, | 
					
						
							|  |  |  |  |     parse, | 
					
						
							|  |  |  |  |     PRECEDENCE, | 
					
						
							|  |  |  |  | } from "../parse.js"; | 
					
						
							|  |  |  |  | import { OutputStream } from "../output.js"; | 
					
						
							|  |  |  |  | import { base54, format_mangler_options } from "../scope.js"; | 
					
						
							|  |  |  |  | import "../size.js"; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | import "./evaluate.js"; | 
					
						
							|  |  |  |  | import "./drop-side-effect-free.js"; | 
					
						
							|  |  |  |  | import "./drop-unused.js"; | 
					
						
							|  |  |  |  | import "./reduce-vars.js"; | 
					
						
							|  |  |  |  | import { | 
					
						
							|  |  |  |  |     is_undeclared_ref, | 
					
						
							|  |  |  |  |     lazy_op, | 
					
						
							|  |  |  |  |     is_nullish, | 
					
						
							|  |  |  |  |     is_undefined, | 
					
						
							|  |  |  |  |     is_lhs, | 
					
						
							|  |  |  |  |     aborts, | 
					
						
							|  |  |  |  | } from "./inference.js"; | 
					
						
							|  |  |  |  | import { | 
					
						
							|  |  |  |  |     SQUEEZED, | 
					
						
							|  |  |  |  |     OPTIMIZED, | 
					
						
							|  |  |  |  |     CLEAR_BETWEEN_PASSES, | 
					
						
							|  |  |  |  |     TOP, | 
					
						
							|  |  |  |  |     UNDEFINED, | 
					
						
							|  |  |  |  |     UNUSED, | 
					
						
							|  |  |  |  |     TRUTHY, | 
					
						
							|  |  |  |  |     FALSY, | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     has_flag, | 
					
						
							|  |  |  |  |     set_flag, | 
					
						
							|  |  |  |  |     clear_flag, | 
					
						
							|  |  |  |  | } from "./compressor-flags.js"; | 
					
						
							|  |  |  |  | import { | 
					
						
							|  |  |  |  |     make_sequence, | 
					
						
							|  |  |  |  |     best_of, | 
					
						
							|  |  |  |  |     best_of_expression, | 
					
						
							|  |  |  |  |     make_node_from_constant, | 
					
						
							|  |  |  |  |     merge_sequence, | 
					
						
							|  |  |  |  |     get_simple_key, | 
					
						
							|  |  |  |  |     has_break_or_continue, | 
					
						
							|  |  |  |  |     maintain_this_binding, | 
					
						
							|  |  |  |  |     is_empty, | 
					
						
							|  |  |  |  |     is_identifier_atom, | 
					
						
							|  |  |  |  |     is_reachable, | 
					
						
							|  |  |  |  |     can_be_evicted_from_block, | 
					
						
							|  |  |  |  |     as_statement_array, | 
					
						
							|  |  |  |  |     retain_top_func, | 
					
						
							|  |  |  |  |     is_func_expr, | 
					
						
							|  |  |  |  | } from "./common.js"; | 
					
						
							|  |  |  |  | import { tighten_body, trim_unreachable_code } from "./tighten-body.js"; | 
					
						
							|  |  |  |  | import { inline_into_symbolref, inline_into_call } from "./inline.js"; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | class Compressor extends TreeWalker { | 
					
						
							|  |  |  |  |     constructor(options, { false_by_default = false, mangle_options = false }) { | 
					
						
							|  |  |  |  |         super(); | 
					
						
							|  |  |  |  |         if (options.defaults !== undefined && !options.defaults) false_by_default = true; | 
					
						
							|  |  |  |  |         this.options = defaults(options, { | 
					
						
							|  |  |  |  |             arguments     : false, | 
					
						
							|  |  |  |  |             arrows        : !false_by_default, | 
					
						
							|  |  |  |  |             booleans      : !false_by_default, | 
					
						
							|  |  |  |  |             booleans_as_integers : false, | 
					
						
							|  |  |  |  |             collapse_vars : !false_by_default, | 
					
						
							|  |  |  |  |             comparisons   : !false_by_default, | 
					
						
							|  |  |  |  |             computed_props: !false_by_default, | 
					
						
							|  |  |  |  |             conditionals  : !false_by_default, | 
					
						
							|  |  |  |  |             dead_code     : !false_by_default, | 
					
						
							|  |  |  |  |             defaults      : true, | 
					
						
							|  |  |  |  |             directives    : !false_by_default, | 
					
						
							|  |  |  |  |             drop_console  : false, | 
					
						
							|  |  |  |  |             drop_debugger : !false_by_default, | 
					
						
							|  |  |  |  |             ecma          : 5, | 
					
						
							|  |  |  |  |             evaluate      : !false_by_default, | 
					
						
							|  |  |  |  |             expression    : false, | 
					
						
							|  |  |  |  |             global_defs   : false, | 
					
						
							|  |  |  |  |             hoist_funs    : false, | 
					
						
							|  |  |  |  |             hoist_props   : !false_by_default, | 
					
						
							|  |  |  |  |             hoist_vars    : false, | 
					
						
							|  |  |  |  |             ie8           : false, | 
					
						
							|  |  |  |  |             if_return     : !false_by_default, | 
					
						
							|  |  |  |  |             inline        : !false_by_default, | 
					
						
							|  |  |  |  |             join_vars     : !false_by_default, | 
					
						
							|  |  |  |  |             keep_classnames: false, | 
					
						
							|  |  |  |  |             keep_fargs    : true, | 
					
						
							|  |  |  |  |             keep_fnames   : false, | 
					
						
							|  |  |  |  |             keep_infinity : false, | 
					
						
							|  |  |  |  |             loops         : !false_by_default, | 
					
						
							|  |  |  |  |             module        : false, | 
					
						
							|  |  |  |  |             negate_iife   : !false_by_default, | 
					
						
							|  |  |  |  |             passes        : 1, | 
					
						
							|  |  |  |  |             properties    : !false_by_default, | 
					
						
							|  |  |  |  |             pure_getters  : !false_by_default && "strict", | 
					
						
							|  |  |  |  |             pure_funcs    : null, | 
					
						
							|  |  |  |  |             reduce_funcs  : !false_by_default, | 
					
						
							|  |  |  |  |             reduce_vars   : !false_by_default, | 
					
						
							|  |  |  |  |             sequences     : !false_by_default, | 
					
						
							|  |  |  |  |             side_effects  : !false_by_default, | 
					
						
							|  |  |  |  |             switches      : !false_by_default, | 
					
						
							|  |  |  |  |             top_retain    : null, | 
					
						
							|  |  |  |  |             toplevel      : !!(options && options["top_retain"]), | 
					
						
							|  |  |  |  |             typeofs       : !false_by_default, | 
					
						
							|  |  |  |  |             unsafe        : false, | 
					
						
							|  |  |  |  |             unsafe_arrows : false, | 
					
						
							|  |  |  |  |             unsafe_comps  : false, | 
					
						
							|  |  |  |  |             unsafe_Function: false, | 
					
						
							|  |  |  |  |             unsafe_math   : false, | 
					
						
							|  |  |  |  |             unsafe_symbols: false, | 
					
						
							|  |  |  |  |             unsafe_methods: false, | 
					
						
							|  |  |  |  |             unsafe_proto  : false, | 
					
						
							|  |  |  |  |             unsafe_regexp : false, | 
					
						
							|  |  |  |  |             unsafe_undefined: false, | 
					
						
							|  |  |  |  |             unused        : !false_by_default, | 
					
						
							|  |  |  |  |             warnings      : false  // legacy
 | 
					
						
							|  |  |  |  |         }, true); | 
					
						
							|  |  |  |  |         var global_defs = this.options["global_defs"]; | 
					
						
							|  |  |  |  |         if (typeof global_defs == "object") for (var key in global_defs) { | 
					
						
							|  |  |  |  |             if (key[0] === "@" && HOP(global_defs, key)) { | 
					
						
							|  |  |  |  |                 global_defs[key.slice(1)] = parse(global_defs[key], { | 
					
						
							|  |  |  |  |                     expression: true | 
					
						
							|  |  |  |  |                 }); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         if (this.options["inline"] === true) this.options["inline"] = 3; | 
					
						
							|  |  |  |  |         var pure_funcs = this.options["pure_funcs"]; | 
					
						
							|  |  |  |  |         if (typeof pure_funcs == "function") { | 
					
						
							|  |  |  |  |             this.pure_funcs = pure_funcs; | 
					
						
							|  |  |  |  |         } else { | 
					
						
							|  |  |  |  |             this.pure_funcs = pure_funcs ? function(node) { | 
					
						
							|  |  |  |  |                 return !pure_funcs.includes(node.expression.print_to_string()); | 
					
						
							|  |  |  |  |             } : return_true; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         var top_retain = this.options["top_retain"]; | 
					
						
							|  |  |  |  |         if (top_retain instanceof RegExp) { | 
					
						
							|  |  |  |  |             this.top_retain = function(def) { | 
					
						
							|  |  |  |  |                 return top_retain.test(def.name); | 
					
						
							|  |  |  |  |             }; | 
					
						
							|  |  |  |  |         } else if (typeof top_retain == "function") { | 
					
						
							|  |  |  |  |             this.top_retain = top_retain; | 
					
						
							|  |  |  |  |         } else if (top_retain) { | 
					
						
							|  |  |  |  |             if (typeof top_retain == "string") { | 
					
						
							|  |  |  |  |                 top_retain = top_retain.split(/,/); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             this.top_retain = function(def) { | 
					
						
							|  |  |  |  |                 return top_retain.includes(def.name); | 
					
						
							|  |  |  |  |             }; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         if (this.options["module"]) { | 
					
						
							|  |  |  |  |             this.directives["use strict"] = true; | 
					
						
							|  |  |  |  |             this.options["toplevel"] = true; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         var toplevel = this.options["toplevel"]; | 
					
						
							|  |  |  |  |         this.toplevel = typeof toplevel == "string" ? { | 
					
						
							|  |  |  |  |             funcs: /funcs/.test(toplevel), | 
					
						
							|  |  |  |  |             vars: /vars/.test(toplevel) | 
					
						
							|  |  |  |  |         } : { | 
					
						
							|  |  |  |  |             funcs: toplevel, | 
					
						
							|  |  |  |  |             vars: toplevel | 
					
						
							|  |  |  |  |         }; | 
					
						
							|  |  |  |  |         var sequences = this.options["sequences"]; | 
					
						
							|  |  |  |  |         this.sequences_limit = sequences == 1 ? 800 : sequences | 0; | 
					
						
							|  |  |  |  |         this.evaluated_regexps = new Map(); | 
					
						
							|  |  |  |  |         this._toplevel = undefined; | 
					
						
							|  |  |  |  |         this.mangle_options = mangle_options | 
					
						
							|  |  |  |  |             ? format_mangler_options(mangle_options) | 
					
						
							|  |  |  |  |             : mangle_options; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     option(key) { | 
					
						
							|  |  |  |  |         return this.options[key]; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     exposed(def) { | 
					
						
							|  |  |  |  |         if (def.export) return true; | 
					
						
							|  |  |  |  |         if (def.global) for (var i = 0, len = def.orig.length; i < len; i++) | 
					
						
							|  |  |  |  |             if (!this.toplevel[def.orig[i] instanceof AST_SymbolDefun ? "funcs" : "vars"]) | 
					
						
							|  |  |  |  |                 return true; | 
					
						
							|  |  |  |  |         return false; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     in_boolean_context() { | 
					
						
							|  |  |  |  |         if (!this.option("booleans")) return false; | 
					
						
							|  |  |  |  |         var self = this.self(); | 
					
						
							|  |  |  |  |         for (var i = 0, p; p = this.parent(i); i++) { | 
					
						
							|  |  |  |  |             if (p instanceof AST_SimpleStatement | 
					
						
							|  |  |  |  |                 || p instanceof AST_Conditional && p.condition === self | 
					
						
							|  |  |  |  |                 || p instanceof AST_DWLoop && p.condition === self | 
					
						
							|  |  |  |  |                 || p instanceof AST_For && p.condition === self | 
					
						
							|  |  |  |  |                 || p instanceof AST_If && p.condition === self | 
					
						
							|  |  |  |  |                 || p instanceof AST_UnaryPrefix && p.operator == "!" && p.expression === self) { | 
					
						
							|  |  |  |  |                 return true; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             if ( | 
					
						
							|  |  |  |  |                 p instanceof AST_Binary | 
					
						
							|  |  |  |  |                     && ( | 
					
						
							|  |  |  |  |                         p.operator == "&&" | 
					
						
							|  |  |  |  |                         || p.operator == "||" | 
					
						
							|  |  |  |  |                         || p.operator == "??" | 
					
						
							|  |  |  |  |                     ) | 
					
						
							|  |  |  |  |                 || p instanceof AST_Conditional | 
					
						
							|  |  |  |  |                 || p.tail_node() === self | 
					
						
							|  |  |  |  |             ) { | 
					
						
							|  |  |  |  |                 self = p; | 
					
						
							|  |  |  |  |             } else { | 
					
						
							|  |  |  |  |                 return false; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     get_toplevel() { | 
					
						
							|  |  |  |  |         return this._toplevel; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     compress(toplevel) { | 
					
						
							|  |  |  |  |         toplevel = toplevel.resolve_defines(this); | 
					
						
							|  |  |  |  |         this._toplevel = toplevel; | 
					
						
							|  |  |  |  |         if (this.option("expression")) { | 
					
						
							|  |  |  |  |             this._toplevel.process_expression(true); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         var passes = +this.options.passes || 1; | 
					
						
							|  |  |  |  |         var min_count = 1 / 0; | 
					
						
							|  |  |  |  |         var stopping = false; | 
					
						
							|  |  |  |  |         var nth_identifier = this.mangle_options && this.mangle_options.nth_identifier || base54; | 
					
						
							|  |  |  |  |         var mangle = { ie8: this.option("ie8"), nth_identifier: nth_identifier }; | 
					
						
							|  |  |  |  |         for (var pass = 0; pass < passes; pass++) { | 
					
						
							|  |  |  |  |             this._toplevel.figure_out_scope(mangle); | 
					
						
							|  |  |  |  |             if (pass === 0 && this.option("drop_console")) { | 
					
						
							|  |  |  |  |                 // must be run before reduce_vars and compress pass
 | 
					
						
							|  |  |  |  |                 this._toplevel = this._toplevel.drop_console(); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             if (pass > 0 || this.option("reduce_vars")) { | 
					
						
							|  |  |  |  |                 this._toplevel.reset_opt_flags(this); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             this._toplevel = this._toplevel.transform(this); | 
					
						
							|  |  |  |  |             if (passes > 1) { | 
					
						
							|  |  |  |  |                 let count = 0; | 
					
						
							|  |  |  |  |                 walk(this._toplevel, () => { count++; }); | 
					
						
							|  |  |  |  |                 if (count < min_count) { | 
					
						
							|  |  |  |  |                     min_count = count; | 
					
						
							|  |  |  |  |                     stopping = false; | 
					
						
							|  |  |  |  |                 } else if (stopping) { | 
					
						
							|  |  |  |  |                     break; | 
					
						
							|  |  |  |  |                 } else { | 
					
						
							|  |  |  |  |                     stopping = true; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         if (this.option("expression")) { | 
					
						
							|  |  |  |  |             this._toplevel.process_expression(false); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         toplevel = this._toplevel; | 
					
						
							|  |  |  |  |         this._toplevel = undefined; | 
					
						
							|  |  |  |  |         return toplevel; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     before(node, descend) { | 
					
						
							|  |  |  |  |         if (has_flag(node, SQUEEZED)) return node; | 
					
						
							|  |  |  |  |         var was_scope = false; | 
					
						
							|  |  |  |  |         if (node instanceof AST_Scope) { | 
					
						
							|  |  |  |  |             node = node.hoist_properties(this); | 
					
						
							|  |  |  |  |             node = node.hoist_declarations(this); | 
					
						
							|  |  |  |  |             was_scope = true; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         // Before https://github.com/mishoo/UglifyJS2/pull/1602 AST_Node.optimize()
 | 
					
						
							|  |  |  |  |         // would call AST_Node.transform() if a different instance of AST_Node is
 | 
					
						
							|  |  |  |  |         // produced after def_optimize().
 | 
					
						
							|  |  |  |  |         // This corrupts TreeWalker.stack, which cause AST look-ups to malfunction.
 | 
					
						
							|  |  |  |  |         // Migrate and defer all children's AST_Node.transform() to below, which
 | 
					
						
							|  |  |  |  |         // will now happen after this parent AST_Node has been properly substituted
 | 
					
						
							|  |  |  |  |         // thus gives a consistent AST snapshot.
 | 
					
						
							|  |  |  |  |         descend(node, this); | 
					
						
							|  |  |  |  |         // Existing code relies on how AST_Node.optimize() worked, and omitting the
 | 
					
						
							|  |  |  |  |         // following replacement call would result in degraded efficiency of both
 | 
					
						
							|  |  |  |  |         // output and performance.
 | 
					
						
							|  |  |  |  |         descend(node, this); | 
					
						
							|  |  |  |  |         var opt = node.optimize(this); | 
					
						
							|  |  |  |  |         if (was_scope && opt instanceof AST_Scope) { | 
					
						
							|  |  |  |  |             opt.drop_unused(this); | 
					
						
							|  |  |  |  |             descend(opt, this); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         if (opt === node) set_flag(opt, SQUEEZED); | 
					
						
							|  |  |  |  |         return opt; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function def_optimize(node, optimizer) { | 
					
						
							|  |  |  |  |     node.DEFMETHOD("optimize", function(compressor) { | 
					
						
							|  |  |  |  |         var self = this; | 
					
						
							|  |  |  |  |         if (has_flag(self, OPTIMIZED)) return self; | 
					
						
							|  |  |  |  |         if (compressor.has_directive("use asm")) return self; | 
					
						
							|  |  |  |  |         var opt = optimizer(self, compressor); | 
					
						
							|  |  |  |  |         set_flag(opt, OPTIMIZED); | 
					
						
							|  |  |  |  |         return opt; | 
					
						
							|  |  |  |  |     }); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Node, function(self) { | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | AST_Toplevel.DEFMETHOD("drop_console", function() { | 
					
						
							|  |  |  |  |     return this.transform(new TreeTransformer(function(self) { | 
					
						
							|  |  |  |  |         if (self.TYPE == "Call") { | 
					
						
							|  |  |  |  |             var exp = self.expression; | 
					
						
							|  |  |  |  |             if (exp instanceof AST_PropAccess) { | 
					
						
							|  |  |  |  |                 var name = exp.expression; | 
					
						
							|  |  |  |  |                 while (name.expression) { | 
					
						
							|  |  |  |  |                     name = name.expression; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |                 if (is_undeclared_ref(name) && name.name == "console") { | 
					
						
							|  |  |  |  |                     return make_node(AST_Undefined, self); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     })); | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | AST_Node.DEFMETHOD("equivalent_to", function(node) { | 
					
						
							|  |  |  |  |     return equivalent_to(this, node); | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | AST_Scope.DEFMETHOD("process_expression", function(insert, compressor) { | 
					
						
							|  |  |  |  |     var self = this; | 
					
						
							|  |  |  |  |     var tt = new TreeTransformer(function(node) { | 
					
						
							|  |  |  |  |         if (insert && node instanceof AST_SimpleStatement) { | 
					
						
							|  |  |  |  |             return make_node(AST_Return, node, { | 
					
						
							|  |  |  |  |                 value: node.body | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         if (!insert && node instanceof AST_Return) { | 
					
						
							|  |  |  |  |             if (compressor) { | 
					
						
							|  |  |  |  |                 var value = node.value && node.value.drop_side_effect_free(compressor, true); | 
					
						
							|  |  |  |  |                 return value | 
					
						
							|  |  |  |  |                     ? make_node(AST_SimpleStatement, node, { body: value }) | 
					
						
							|  |  |  |  |                     : make_node(AST_EmptyStatement, node); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             return make_node(AST_SimpleStatement, node, { | 
					
						
							|  |  |  |  |                 body: node.value || make_node(AST_UnaryPrefix, node, { | 
					
						
							|  |  |  |  |                     operator: "void", | 
					
						
							|  |  |  |  |                     expression: make_node(AST_Number, node, { | 
					
						
							|  |  |  |  |                         value: 0 | 
					
						
							|  |  |  |  |                     }) | 
					
						
							|  |  |  |  |                 }) | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         if (node instanceof AST_Class || node instanceof AST_Lambda && node !== self) { | 
					
						
							|  |  |  |  |             return node; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         if (node instanceof AST_Block) { | 
					
						
							|  |  |  |  |             var index = node.body.length - 1; | 
					
						
							|  |  |  |  |             if (index >= 0) { | 
					
						
							|  |  |  |  |                 node.body[index] = node.body[index].transform(tt); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } else if (node instanceof AST_If) { | 
					
						
							|  |  |  |  |             node.body = node.body.transform(tt); | 
					
						
							|  |  |  |  |             if (node.alternative) { | 
					
						
							|  |  |  |  |                 node.alternative = node.alternative.transform(tt); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } else if (node instanceof AST_With) { | 
					
						
							|  |  |  |  |             node.body = node.body.transform(tt); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         return node; | 
					
						
							|  |  |  |  |     }); | 
					
						
							|  |  |  |  |     self.transform(tt); | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | AST_Toplevel.DEFMETHOD("reset_opt_flags", function(compressor) { | 
					
						
							|  |  |  |  |     const self = this; | 
					
						
							|  |  |  |  |     const reduce_vars = compressor.option("reduce_vars"); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     const preparation = new TreeWalker(function(node, descend) { | 
					
						
							|  |  |  |  |         clear_flag(node, CLEAR_BETWEEN_PASSES); | 
					
						
							|  |  |  |  |         if (reduce_vars) { | 
					
						
							|  |  |  |  |             if (compressor.top_retain | 
					
						
							|  |  |  |  |                 && node instanceof AST_Defun  // Only functions are retained
 | 
					
						
							|  |  |  |  |                 && preparation.parent() === self | 
					
						
							|  |  |  |  |             ) { | 
					
						
							|  |  |  |  |                 set_flag(node, TOP); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             return node.reduce_vars(preparation, descend, compressor); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     }); | 
					
						
							|  |  |  |  |     // Stack of look-up tables to keep track of whether a `SymbolDef` has been
 | 
					
						
							|  |  |  |  |     // properly assigned before use:
 | 
					
						
							|  |  |  |  |     // - `push()` & `pop()` when visiting conditional branches
 | 
					
						
							|  |  |  |  |     preparation.safe_ids = Object.create(null); | 
					
						
							|  |  |  |  |     preparation.in_loop = null; | 
					
						
							|  |  |  |  |     preparation.loop_ids = new Map(); | 
					
						
							|  |  |  |  |     preparation.defs_to_safe_ids = new Map(); | 
					
						
							|  |  |  |  |     self.walk(preparation); | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | AST_Symbol.DEFMETHOD("fixed_value", function() { | 
					
						
							|  |  |  |  |     var fixed = this.thedef.fixed; | 
					
						
							|  |  |  |  |     if (!fixed || fixed instanceof AST_Node) return fixed; | 
					
						
							|  |  |  |  |     return fixed(); | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | AST_SymbolRef.DEFMETHOD("is_immutable", function() { | 
					
						
							|  |  |  |  |     var orig = this.definition().orig; | 
					
						
							|  |  |  |  |     return orig.length == 1 && orig[0] instanceof AST_SymbolLambda; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function find_variable(compressor, name) { | 
					
						
							|  |  |  |  |     var scope, i = 0; | 
					
						
							|  |  |  |  |     while (scope = compressor.parent(i++)) { | 
					
						
							|  |  |  |  |         if (scope instanceof AST_Scope) break; | 
					
						
							|  |  |  |  |         if (scope instanceof AST_Catch && scope.argname) { | 
					
						
							|  |  |  |  |             scope = scope.argname.definition().scope; | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return scope.find_variable(name); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | var global_names = makePredicate("Array Boolean clearInterval clearTimeout console Date decodeURI decodeURIComponent encodeURI encodeURIComponent Error escape eval EvalError Function isFinite isNaN JSON Math Number parseFloat parseInt RangeError ReferenceError RegExp Object setInterval setTimeout String SyntaxError TypeError unescape URIError"); | 
					
						
							|  |  |  |  | AST_SymbolRef.DEFMETHOD("is_declared", function(compressor) { | 
					
						
							|  |  |  |  |     return !this.definition().undeclared | 
					
						
							|  |  |  |  |         || compressor.option("unsafe") && global_names.has(this.name); | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* -----[ optimizers ]----- */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | var directives = new Set(["use asm", "use strict"]); | 
					
						
							|  |  |  |  | def_optimize(AST_Directive, function(self, compressor) { | 
					
						
							|  |  |  |  |     if (compressor.option("directives") | 
					
						
							|  |  |  |  |         && (!directives.has(self.value) || compressor.has_directive(self.value) !== self)) { | 
					
						
							|  |  |  |  |         return make_node(AST_EmptyStatement, self); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Debugger, function(self, compressor) { | 
					
						
							|  |  |  |  |     if (compressor.option("drop_debugger")) | 
					
						
							|  |  |  |  |         return make_node(AST_EmptyStatement, self); | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_LabeledStatement, function(self, compressor) { | 
					
						
							|  |  |  |  |     if (self.body instanceof AST_Break | 
					
						
							|  |  |  |  |         && compressor.loopcontrol_target(self.body) === self.body) { | 
					
						
							|  |  |  |  |         return make_node(AST_EmptyStatement, self); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self.label.references.length == 0 ? self.body : self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Block, function(self, compressor) { | 
					
						
							|  |  |  |  |     tighten_body(self.body, compressor); | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function can_be_extracted_from_if_block(node) { | 
					
						
							|  |  |  |  |     return !( | 
					
						
							|  |  |  |  |         node instanceof AST_Const | 
					
						
							|  |  |  |  |         || node instanceof AST_Let | 
					
						
							|  |  |  |  |         || node instanceof AST_Class | 
					
						
							|  |  |  |  |     ); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_BlockStatement, function(self, compressor) { | 
					
						
							|  |  |  |  |     tighten_body(self.body, compressor); | 
					
						
							|  |  |  |  |     switch (self.body.length) { | 
					
						
							|  |  |  |  |       case 1: | 
					
						
							|  |  |  |  |         if (!compressor.has_directive("use strict") | 
					
						
							|  |  |  |  |             && compressor.parent() instanceof AST_If | 
					
						
							|  |  |  |  |             && can_be_extracted_from_if_block(self.body[0]) | 
					
						
							|  |  |  |  |             || can_be_evicted_from_block(self.body[0])) { | 
					
						
							|  |  |  |  |             return self.body[0]; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         break; | 
					
						
							|  |  |  |  |       case 0: return make_node(AST_EmptyStatement, self); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function opt_AST_Lambda(self, compressor) { | 
					
						
							|  |  |  |  |     tighten_body(self.body, compressor); | 
					
						
							|  |  |  |  |     if (compressor.option("side_effects") | 
					
						
							|  |  |  |  |         && self.body.length == 1 | 
					
						
							|  |  |  |  |         && self.body[0] === compressor.has_directive("use strict")) { | 
					
						
							|  |  |  |  |         self.body.length = 0; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | def_optimize(AST_Lambda, opt_AST_Lambda); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | AST_Scope.DEFMETHOD("hoist_declarations", function(compressor) { | 
					
						
							|  |  |  |  |     var self = this; | 
					
						
							|  |  |  |  |     if (compressor.has_directive("use asm")) return self; | 
					
						
							|  |  |  |  |     // Hoisting makes no sense in an arrow func
 | 
					
						
							|  |  |  |  |     if (!Array.isArray(self.body)) return self; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     var hoist_funs = compressor.option("hoist_funs"); | 
					
						
							|  |  |  |  |     var hoist_vars = compressor.option("hoist_vars"); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (hoist_funs || hoist_vars) { | 
					
						
							|  |  |  |  |         var dirs = []; | 
					
						
							|  |  |  |  |         var hoisted = []; | 
					
						
							|  |  |  |  |         var vars = new Map(), vars_found = 0, var_decl = 0; | 
					
						
							|  |  |  |  |         // let's count var_decl first, we seem to waste a lot of
 | 
					
						
							|  |  |  |  |         // space if we hoist `var` when there's only one.
 | 
					
						
							|  |  |  |  |         walk(self, node => { | 
					
						
							|  |  |  |  |             if (node instanceof AST_Scope && node !== self) | 
					
						
							|  |  |  |  |                 return true; | 
					
						
							|  |  |  |  |             if (node instanceof AST_Var) { | 
					
						
							|  |  |  |  |                 ++var_decl; | 
					
						
							|  |  |  |  |                 return true; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |         hoist_vars = hoist_vars && var_decl > 1; | 
					
						
							|  |  |  |  |         var tt = new TreeTransformer( | 
					
						
							|  |  |  |  |             function before(node) { | 
					
						
							|  |  |  |  |                 if (node !== self) { | 
					
						
							|  |  |  |  |                     if (node instanceof AST_Directive) { | 
					
						
							|  |  |  |  |                         dirs.push(node); | 
					
						
							|  |  |  |  |                         return make_node(AST_EmptyStatement, node); | 
					
						
							|  |  |  |  |                     } | 
					
						
							|  |  |  |  |                     if (hoist_funs && node instanceof AST_Defun | 
					
						
							|  |  |  |  |                         && !(tt.parent() instanceof AST_Export) | 
					
						
							|  |  |  |  |                         && tt.parent() === self) { | 
					
						
							|  |  |  |  |                         hoisted.push(node); | 
					
						
							|  |  |  |  |                         return make_node(AST_EmptyStatement, node); | 
					
						
							|  |  |  |  |                     } | 
					
						
							|  |  |  |  |                     if ( | 
					
						
							|  |  |  |  |                         hoist_vars | 
					
						
							|  |  |  |  |                         && node instanceof AST_Var | 
					
						
							|  |  |  |  |                         && !node.definitions.some(def => def.name instanceof AST_Destructuring) | 
					
						
							|  |  |  |  |                     ) { | 
					
						
							|  |  |  |  |                         node.definitions.forEach(function(def) { | 
					
						
							|  |  |  |  |                             vars.set(def.name.name, def); | 
					
						
							|  |  |  |  |                             ++vars_found; | 
					
						
							|  |  |  |  |                         }); | 
					
						
							|  |  |  |  |                         var seq = node.to_assignments(compressor); | 
					
						
							|  |  |  |  |                         var p = tt.parent(); | 
					
						
							|  |  |  |  |                         if (p instanceof AST_ForIn && p.init === node) { | 
					
						
							|  |  |  |  |                             if (seq == null) { | 
					
						
							|  |  |  |  |                                 var def = node.definitions[0].name; | 
					
						
							|  |  |  |  |                                 return make_node(AST_SymbolRef, def, def); | 
					
						
							|  |  |  |  |                             } | 
					
						
							|  |  |  |  |                             return seq; | 
					
						
							|  |  |  |  |                         } | 
					
						
							|  |  |  |  |                         if (p instanceof AST_For && p.init === node) { | 
					
						
							|  |  |  |  |                             return seq; | 
					
						
							|  |  |  |  |                         } | 
					
						
							|  |  |  |  |                         if (!seq) return make_node(AST_EmptyStatement, node); | 
					
						
							|  |  |  |  |                         return make_node(AST_SimpleStatement, node, { | 
					
						
							|  |  |  |  |                             body: seq | 
					
						
							|  |  |  |  |                         }); | 
					
						
							|  |  |  |  |                     } | 
					
						
							|  |  |  |  |                     if (node instanceof AST_Scope) | 
					
						
							|  |  |  |  |                         return node; // to avoid descending in nested scopes
 | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         ); | 
					
						
							|  |  |  |  |         self = self.transform(tt); | 
					
						
							|  |  |  |  |         if (vars_found > 0) { | 
					
						
							|  |  |  |  |             // collect only vars which don't show up in self's arguments list
 | 
					
						
							|  |  |  |  |             var defs = []; | 
					
						
							|  |  |  |  |             const is_lambda = self instanceof AST_Lambda; | 
					
						
							|  |  |  |  |             const args_as_names = is_lambda ? self.args_as_names() : null; | 
					
						
							|  |  |  |  |             vars.forEach((def, name) => { | 
					
						
							|  |  |  |  |                 if (is_lambda && args_as_names.some((x) => x.name === def.name.name)) { | 
					
						
							|  |  |  |  |                     vars.delete(name); | 
					
						
							|  |  |  |  |                 } else { | 
					
						
							|  |  |  |  |                     def = def.clone(); | 
					
						
							|  |  |  |  |                     def.value = null; | 
					
						
							|  |  |  |  |                     defs.push(def); | 
					
						
							|  |  |  |  |                     vars.set(name, def); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |             if (defs.length > 0) { | 
					
						
							|  |  |  |  |                 // try to merge in assignments
 | 
					
						
							|  |  |  |  |                 for (var i = 0; i < self.body.length;) { | 
					
						
							|  |  |  |  |                     if (self.body[i] instanceof AST_SimpleStatement) { | 
					
						
							|  |  |  |  |                         var expr = self.body[i].body, sym, assign; | 
					
						
							|  |  |  |  |                         if (expr instanceof AST_Assign | 
					
						
							|  |  |  |  |                             && expr.operator == "=" | 
					
						
							|  |  |  |  |                             && (sym = expr.left) instanceof AST_Symbol | 
					
						
							|  |  |  |  |                             && vars.has(sym.name) | 
					
						
							|  |  |  |  |                         ) { | 
					
						
							|  |  |  |  |                             var def = vars.get(sym.name); | 
					
						
							|  |  |  |  |                             if (def.value) break; | 
					
						
							|  |  |  |  |                             def.value = expr.right; | 
					
						
							|  |  |  |  |                             remove(defs, def); | 
					
						
							|  |  |  |  |                             defs.push(def); | 
					
						
							|  |  |  |  |                             self.body.splice(i, 1); | 
					
						
							|  |  |  |  |                             continue; | 
					
						
							|  |  |  |  |                         } | 
					
						
							|  |  |  |  |                         if (expr instanceof AST_Sequence | 
					
						
							|  |  |  |  |                             && (assign = expr.expressions[0]) instanceof AST_Assign | 
					
						
							|  |  |  |  |                             && assign.operator == "=" | 
					
						
							|  |  |  |  |                             && (sym = assign.left) instanceof AST_Symbol | 
					
						
							|  |  |  |  |                             && vars.has(sym.name) | 
					
						
							|  |  |  |  |                         ) { | 
					
						
							|  |  |  |  |                             var def = vars.get(sym.name); | 
					
						
							|  |  |  |  |                             if (def.value) break; | 
					
						
							|  |  |  |  |                             def.value = assign.right; | 
					
						
							|  |  |  |  |                             remove(defs, def); | 
					
						
							|  |  |  |  |                             defs.push(def); | 
					
						
							|  |  |  |  |                             self.body[i].body = make_sequence(expr, expr.expressions.slice(1)); | 
					
						
							|  |  |  |  |                             continue; | 
					
						
							|  |  |  |  |                         } | 
					
						
							|  |  |  |  |                     } | 
					
						
							|  |  |  |  |                     if (self.body[i] instanceof AST_EmptyStatement) { | 
					
						
							|  |  |  |  |                         self.body.splice(i, 1); | 
					
						
							|  |  |  |  |                         continue; | 
					
						
							|  |  |  |  |                     } | 
					
						
							|  |  |  |  |                     if (self.body[i] instanceof AST_BlockStatement) { | 
					
						
							|  |  |  |  |                         self.body.splice(i, 1, ...self.body[i].body); | 
					
						
							|  |  |  |  |                         continue; | 
					
						
							|  |  |  |  |                     } | 
					
						
							|  |  |  |  |                     break; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |                 defs = make_node(AST_Var, self, { | 
					
						
							|  |  |  |  |                     definitions: defs | 
					
						
							|  |  |  |  |                 }); | 
					
						
							|  |  |  |  |                 hoisted.push(defs); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         self.body = dirs.concat(hoisted, self.body); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | AST_Scope.DEFMETHOD("hoist_properties", function(compressor) { | 
					
						
							|  |  |  |  |     var self = this; | 
					
						
							|  |  |  |  |     if (!compressor.option("hoist_props") || compressor.has_directive("use asm")) return self; | 
					
						
							|  |  |  |  |     var top_retain = self instanceof AST_Toplevel && compressor.top_retain || return_false; | 
					
						
							|  |  |  |  |     var defs_by_id = new Map(); | 
					
						
							|  |  |  |  |     var hoister = new TreeTransformer(function(node, descend) { | 
					
						
							|  |  |  |  |         if (node instanceof AST_VarDef) { | 
					
						
							|  |  |  |  |             const sym = node.name; | 
					
						
							|  |  |  |  |             let def; | 
					
						
							|  |  |  |  |             let value; | 
					
						
							|  |  |  |  |             if (sym.scope === self | 
					
						
							|  |  |  |  |                 && (def = sym.definition()).escaped != 1 | 
					
						
							|  |  |  |  |                 && !def.assignments | 
					
						
							|  |  |  |  |                 && !def.direct_access | 
					
						
							|  |  |  |  |                 && !def.single_use | 
					
						
							|  |  |  |  |                 && !compressor.exposed(def) | 
					
						
							|  |  |  |  |                 && !top_retain(def) | 
					
						
							|  |  |  |  |                 && (value = sym.fixed_value()) === node.value | 
					
						
							|  |  |  |  |                 && value instanceof AST_Object | 
					
						
							|  |  |  |  |                 && !value.properties.some(prop => | 
					
						
							|  |  |  |  |                     prop instanceof AST_Expansion || prop.computed_key() | 
					
						
							|  |  |  |  |                 ) | 
					
						
							|  |  |  |  |             ) { | 
					
						
							|  |  |  |  |                 descend(node, this); | 
					
						
							|  |  |  |  |                 const defs = new Map(); | 
					
						
							|  |  |  |  |                 const assignments = []; | 
					
						
							|  |  |  |  |                 value.properties.forEach(({ key, value }) => { | 
					
						
							|  |  |  |  |                     const scope = hoister.find_scope(); | 
					
						
							|  |  |  |  |                     const symbol = self.create_symbol(sym.CTOR, { | 
					
						
							|  |  |  |  |                         source: sym, | 
					
						
							|  |  |  |  |                         scope, | 
					
						
							|  |  |  |  |                         conflict_scopes: new Set([ | 
					
						
							|  |  |  |  |                             scope, | 
					
						
							|  |  |  |  |                             ...sym.definition().references.map(ref => ref.scope) | 
					
						
							|  |  |  |  |                         ]), | 
					
						
							|  |  |  |  |                         tentative_name: sym.name + "_" + key | 
					
						
							|  |  |  |  |                     }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                     defs.set(String(key), symbol.definition()); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                     assignments.push(make_node(AST_VarDef, node, { | 
					
						
							|  |  |  |  |                         name: symbol, | 
					
						
							|  |  |  |  |                         value | 
					
						
							|  |  |  |  |                     })); | 
					
						
							|  |  |  |  |                 }); | 
					
						
							|  |  |  |  |                 defs_by_id.set(def.id, defs); | 
					
						
							|  |  |  |  |                 return MAP.splice(assignments); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } else if (node instanceof AST_PropAccess | 
					
						
							|  |  |  |  |             && node.expression instanceof AST_SymbolRef | 
					
						
							|  |  |  |  |         ) { | 
					
						
							|  |  |  |  |             const defs = defs_by_id.get(node.expression.definition().id); | 
					
						
							|  |  |  |  |             if (defs) { | 
					
						
							|  |  |  |  |                 const def = defs.get(String(get_simple_key(node.property))); | 
					
						
							|  |  |  |  |                 const sym = make_node(AST_SymbolRef, node, { | 
					
						
							|  |  |  |  |                     name: def.name, | 
					
						
							|  |  |  |  |                     scope: node.expression.scope, | 
					
						
							|  |  |  |  |                     thedef: def | 
					
						
							|  |  |  |  |                 }); | 
					
						
							|  |  |  |  |                 sym.reference({}); | 
					
						
							|  |  |  |  |                 return sym; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     }); | 
					
						
							|  |  |  |  |     return self.transform(hoister); | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_SimpleStatement, function(self, compressor) { | 
					
						
							|  |  |  |  |     if (compressor.option("side_effects")) { | 
					
						
							|  |  |  |  |         var body = self.body; | 
					
						
							|  |  |  |  |         var node = body.drop_side_effect_free(compressor, true); | 
					
						
							|  |  |  |  |         if (!node) { | 
					
						
							|  |  |  |  |             return make_node(AST_EmptyStatement, self); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         if (node !== body) { | 
					
						
							|  |  |  |  |             return make_node(AST_SimpleStatement, self, { body: node }); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_While, function(self, compressor) { | 
					
						
							|  |  |  |  |     return compressor.option("loops") ? make_node(AST_For, self, self).optimize(compressor) : self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Do, function(self, compressor) { | 
					
						
							|  |  |  |  |     if (!compressor.option("loops")) return self; | 
					
						
							|  |  |  |  |     var cond = self.condition.tail_node().evaluate(compressor); | 
					
						
							|  |  |  |  |     if (!(cond instanceof AST_Node)) { | 
					
						
							|  |  |  |  |         if (cond) return make_node(AST_For, self, { | 
					
						
							|  |  |  |  |             body: make_node(AST_BlockStatement, self.body, { | 
					
						
							|  |  |  |  |                 body: [ | 
					
						
							|  |  |  |  |                     self.body, | 
					
						
							|  |  |  |  |                     make_node(AST_SimpleStatement, self.condition, { | 
					
						
							|  |  |  |  |                         body: self.condition | 
					
						
							|  |  |  |  |                     }) | 
					
						
							|  |  |  |  |                 ] | 
					
						
							|  |  |  |  |             }) | 
					
						
							|  |  |  |  |         }).optimize(compressor); | 
					
						
							|  |  |  |  |         if (!has_break_or_continue(self, compressor.parent())) { | 
					
						
							|  |  |  |  |             return make_node(AST_BlockStatement, self.body, { | 
					
						
							|  |  |  |  |                 body: [ | 
					
						
							|  |  |  |  |                     self.body, | 
					
						
							|  |  |  |  |                     make_node(AST_SimpleStatement, self.condition, { | 
					
						
							|  |  |  |  |                         body: self.condition | 
					
						
							|  |  |  |  |                     }) | 
					
						
							|  |  |  |  |                 ] | 
					
						
							|  |  |  |  |             }).optimize(compressor); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function if_break_in_loop(self, compressor) { | 
					
						
							|  |  |  |  |     var first = self.body instanceof AST_BlockStatement ? self.body.body[0] : self.body; | 
					
						
							|  |  |  |  |     if (compressor.option("dead_code") && is_break(first)) { | 
					
						
							|  |  |  |  |         var body = []; | 
					
						
							|  |  |  |  |         if (self.init instanceof AST_Statement) { | 
					
						
							|  |  |  |  |             body.push(self.init); | 
					
						
							|  |  |  |  |         } else if (self.init) { | 
					
						
							|  |  |  |  |             body.push(make_node(AST_SimpleStatement, self.init, { | 
					
						
							|  |  |  |  |                 body: self.init | 
					
						
							|  |  |  |  |             })); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         if (self.condition) { | 
					
						
							|  |  |  |  |             body.push(make_node(AST_SimpleStatement, self.condition, { | 
					
						
							|  |  |  |  |                 body: self.condition | 
					
						
							|  |  |  |  |             })); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         trim_unreachable_code(compressor, self.body, body); | 
					
						
							|  |  |  |  |         return make_node(AST_BlockStatement, self, { | 
					
						
							|  |  |  |  |             body: body | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (first instanceof AST_If) { | 
					
						
							|  |  |  |  |         if (is_break(first.body)) { | 
					
						
							|  |  |  |  |             if (self.condition) { | 
					
						
							|  |  |  |  |                 self.condition = make_node(AST_Binary, self.condition, { | 
					
						
							|  |  |  |  |                     left: self.condition, | 
					
						
							|  |  |  |  |                     operator: "&&", | 
					
						
							|  |  |  |  |                     right: first.condition.negate(compressor), | 
					
						
							|  |  |  |  |                 }); | 
					
						
							|  |  |  |  |             } else { | 
					
						
							|  |  |  |  |                 self.condition = first.condition.negate(compressor); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             drop_it(first.alternative); | 
					
						
							|  |  |  |  |         } else if (is_break(first.alternative)) { | 
					
						
							|  |  |  |  |             if (self.condition) { | 
					
						
							|  |  |  |  |                 self.condition = make_node(AST_Binary, self.condition, { | 
					
						
							|  |  |  |  |                     left: self.condition, | 
					
						
							|  |  |  |  |                     operator: "&&", | 
					
						
							|  |  |  |  |                     right: first.condition, | 
					
						
							|  |  |  |  |                 }); | 
					
						
							|  |  |  |  |             } else { | 
					
						
							|  |  |  |  |                 self.condition = first.condition; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             drop_it(first.body); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     function is_break(node) { | 
					
						
							|  |  |  |  |         return node instanceof AST_Break | 
					
						
							|  |  |  |  |             && compressor.loopcontrol_target(node) === compressor.self(); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     function drop_it(rest) { | 
					
						
							|  |  |  |  |         rest = as_statement_array(rest); | 
					
						
							|  |  |  |  |         if (self.body instanceof AST_BlockStatement) { | 
					
						
							|  |  |  |  |             self.body = self.body.clone(); | 
					
						
							|  |  |  |  |             self.body.body = rest.concat(self.body.body.slice(1)); | 
					
						
							|  |  |  |  |             self.body = self.body.transform(compressor); | 
					
						
							|  |  |  |  |         } else { | 
					
						
							|  |  |  |  |             self.body = make_node(AST_BlockStatement, self.body, { | 
					
						
							|  |  |  |  |                 body: rest | 
					
						
							|  |  |  |  |             }).transform(compressor); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         self = if_break_in_loop(self, compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_For, function(self, compressor) { | 
					
						
							|  |  |  |  |     if (!compressor.option("loops")) return self; | 
					
						
							|  |  |  |  |     if (compressor.option("side_effects") && self.init) { | 
					
						
							|  |  |  |  |         self.init = self.init.drop_side_effect_free(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (self.condition) { | 
					
						
							|  |  |  |  |         var cond = self.condition.evaluate(compressor); | 
					
						
							|  |  |  |  |         if (!(cond instanceof AST_Node)) { | 
					
						
							|  |  |  |  |             if (cond) self.condition = null; | 
					
						
							|  |  |  |  |             else if (!compressor.option("dead_code")) { | 
					
						
							|  |  |  |  |                 var orig = self.condition; | 
					
						
							|  |  |  |  |                 self.condition = make_node_from_constant(cond, self.condition); | 
					
						
							|  |  |  |  |                 self.condition = best_of_expression(self.condition.transform(compressor), orig); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         if (compressor.option("dead_code")) { | 
					
						
							|  |  |  |  |             if (cond instanceof AST_Node) cond = self.condition.tail_node().evaluate(compressor); | 
					
						
							|  |  |  |  |             if (!cond) { | 
					
						
							|  |  |  |  |                 var body = []; | 
					
						
							|  |  |  |  |                 trim_unreachable_code(compressor, self.body, body); | 
					
						
							|  |  |  |  |                 if (self.init instanceof AST_Statement) { | 
					
						
							|  |  |  |  |                     body.push(self.init); | 
					
						
							|  |  |  |  |                 } else if (self.init) { | 
					
						
							|  |  |  |  |                     body.push(make_node(AST_SimpleStatement, self.init, { | 
					
						
							|  |  |  |  |                         body: self.init | 
					
						
							|  |  |  |  |                     })); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |                 body.push(make_node(AST_SimpleStatement, self.condition, { | 
					
						
							|  |  |  |  |                     body: self.condition | 
					
						
							|  |  |  |  |                 })); | 
					
						
							|  |  |  |  |                 return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return if_break_in_loop(self, compressor); | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_If, function(self, compressor) { | 
					
						
							|  |  |  |  |     if (is_empty(self.alternative)) self.alternative = null; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (!compressor.option("conditionals")) return self; | 
					
						
							|  |  |  |  |     // if condition can be statically determined, drop
 | 
					
						
							|  |  |  |  |     // one of the blocks.  note, statically determined implies
 | 
					
						
							|  |  |  |  |     // “has no side effects”; also it doesn't work for cases like
 | 
					
						
							|  |  |  |  |     // `x && true`, though it probably should.
 | 
					
						
							|  |  |  |  |     var cond = self.condition.evaluate(compressor); | 
					
						
							|  |  |  |  |     if (!compressor.option("dead_code") && !(cond instanceof AST_Node)) { | 
					
						
							|  |  |  |  |         var orig = self.condition; | 
					
						
							|  |  |  |  |         self.condition = make_node_from_constant(cond, orig); | 
					
						
							|  |  |  |  |         self.condition = best_of_expression(self.condition.transform(compressor), orig); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (compressor.option("dead_code")) { | 
					
						
							|  |  |  |  |         if (cond instanceof AST_Node) cond = self.condition.tail_node().evaluate(compressor); | 
					
						
							|  |  |  |  |         if (!cond) { | 
					
						
							|  |  |  |  |             var body = []; | 
					
						
							|  |  |  |  |             trim_unreachable_code(compressor, self.body, body); | 
					
						
							|  |  |  |  |             body.push(make_node(AST_SimpleStatement, self.condition, { | 
					
						
							|  |  |  |  |                 body: self.condition | 
					
						
							|  |  |  |  |             })); | 
					
						
							|  |  |  |  |             if (self.alternative) body.push(self.alternative); | 
					
						
							|  |  |  |  |             return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor); | 
					
						
							|  |  |  |  |         } else if (!(cond instanceof AST_Node)) { | 
					
						
							|  |  |  |  |             var body = []; | 
					
						
							|  |  |  |  |             body.push(make_node(AST_SimpleStatement, self.condition, { | 
					
						
							|  |  |  |  |                 body: self.condition | 
					
						
							|  |  |  |  |             })); | 
					
						
							|  |  |  |  |             body.push(self.body); | 
					
						
							|  |  |  |  |             if (self.alternative) { | 
					
						
							|  |  |  |  |                 trim_unreachable_code(compressor, self.alternative, body); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     var negated = self.condition.negate(compressor); | 
					
						
							|  |  |  |  |     var self_condition_length = self.condition.size(); | 
					
						
							|  |  |  |  |     var negated_length = negated.size(); | 
					
						
							|  |  |  |  |     var negated_is_best = negated_length < self_condition_length; | 
					
						
							|  |  |  |  |     if (self.alternative && negated_is_best) { | 
					
						
							|  |  |  |  |         negated_is_best = false; // because we already do the switch here.
 | 
					
						
							|  |  |  |  |         // no need to swap values of self_condition_length and negated_length
 | 
					
						
							|  |  |  |  |         // here because they are only used in an equality comparison later on.
 | 
					
						
							|  |  |  |  |         self.condition = negated; | 
					
						
							|  |  |  |  |         var tmp = self.body; | 
					
						
							|  |  |  |  |         self.body = self.alternative || make_node(AST_EmptyStatement, self); | 
					
						
							|  |  |  |  |         self.alternative = tmp; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (is_empty(self.body) && is_empty(self.alternative)) { | 
					
						
							|  |  |  |  |         return make_node(AST_SimpleStatement, self.condition, { | 
					
						
							|  |  |  |  |             body: self.condition.clone() | 
					
						
							|  |  |  |  |         }).optimize(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (self.body instanceof AST_SimpleStatement | 
					
						
							|  |  |  |  |         && self.alternative instanceof AST_SimpleStatement) { | 
					
						
							|  |  |  |  |         return make_node(AST_SimpleStatement, self, { | 
					
						
							|  |  |  |  |             body: make_node(AST_Conditional, self, { | 
					
						
							|  |  |  |  |                 condition   : self.condition, | 
					
						
							|  |  |  |  |                 consequent  : self.body.body, | 
					
						
							|  |  |  |  |                 alternative : self.alternative.body | 
					
						
							|  |  |  |  |             }) | 
					
						
							|  |  |  |  |         }).optimize(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (is_empty(self.alternative) && self.body instanceof AST_SimpleStatement) { | 
					
						
							|  |  |  |  |         if (self_condition_length === negated_length && !negated_is_best | 
					
						
							|  |  |  |  |             && self.condition instanceof AST_Binary && self.condition.operator == "||") { | 
					
						
							|  |  |  |  |             // although the code length of self.condition and negated are the same,
 | 
					
						
							|  |  |  |  |             // negated does not require additional surrounding parentheses.
 | 
					
						
							|  |  |  |  |             // see https://github.com/mishoo/UglifyJS2/issues/979
 | 
					
						
							|  |  |  |  |             negated_is_best = true; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         if (negated_is_best) return make_node(AST_SimpleStatement, self, { | 
					
						
							|  |  |  |  |             body: make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                 operator : "||", | 
					
						
							|  |  |  |  |                 left     : negated, | 
					
						
							|  |  |  |  |                 right    : self.body.body | 
					
						
							|  |  |  |  |             }) | 
					
						
							|  |  |  |  |         }).optimize(compressor); | 
					
						
							|  |  |  |  |         return make_node(AST_SimpleStatement, self, { | 
					
						
							|  |  |  |  |             body: make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                 operator : "&&", | 
					
						
							|  |  |  |  |                 left     : self.condition, | 
					
						
							|  |  |  |  |                 right    : self.body.body | 
					
						
							|  |  |  |  |             }) | 
					
						
							|  |  |  |  |         }).optimize(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (self.body instanceof AST_EmptyStatement | 
					
						
							|  |  |  |  |         && self.alternative instanceof AST_SimpleStatement) { | 
					
						
							|  |  |  |  |         return make_node(AST_SimpleStatement, self, { | 
					
						
							|  |  |  |  |             body: make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                 operator : "||", | 
					
						
							|  |  |  |  |                 left     : self.condition, | 
					
						
							|  |  |  |  |                 right    : self.alternative.body | 
					
						
							|  |  |  |  |             }) | 
					
						
							|  |  |  |  |         }).optimize(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (self.body instanceof AST_Exit | 
					
						
							|  |  |  |  |         && self.alternative instanceof AST_Exit | 
					
						
							|  |  |  |  |         && self.body.TYPE == self.alternative.TYPE) { | 
					
						
							|  |  |  |  |         return make_node(self.body.CTOR, self, { | 
					
						
							|  |  |  |  |             value: make_node(AST_Conditional, self, { | 
					
						
							|  |  |  |  |                 condition   : self.condition, | 
					
						
							|  |  |  |  |                 consequent  : self.body.value || make_node(AST_Undefined, self.body), | 
					
						
							|  |  |  |  |                 alternative : self.alternative.value || make_node(AST_Undefined, self.alternative) | 
					
						
							|  |  |  |  |             }).transform(compressor) | 
					
						
							|  |  |  |  |         }).optimize(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (self.body instanceof AST_If | 
					
						
							|  |  |  |  |         && !self.body.alternative | 
					
						
							|  |  |  |  |         && !self.alternative) { | 
					
						
							|  |  |  |  |         self = make_node(AST_If, self, { | 
					
						
							|  |  |  |  |             condition: make_node(AST_Binary, self.condition, { | 
					
						
							|  |  |  |  |                 operator: "&&", | 
					
						
							|  |  |  |  |                 left: self.condition, | 
					
						
							|  |  |  |  |                 right: self.body.condition | 
					
						
							|  |  |  |  |             }), | 
					
						
							|  |  |  |  |             body: self.body.body, | 
					
						
							|  |  |  |  |             alternative: null | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (aborts(self.body)) { | 
					
						
							|  |  |  |  |         if (self.alternative) { | 
					
						
							|  |  |  |  |             var alt = self.alternative; | 
					
						
							|  |  |  |  |             self.alternative = null; | 
					
						
							|  |  |  |  |             return make_node(AST_BlockStatement, self, { | 
					
						
							|  |  |  |  |                 body: [ self, alt ] | 
					
						
							|  |  |  |  |             }).optimize(compressor); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (aborts(self.alternative)) { | 
					
						
							|  |  |  |  |         var body = self.body; | 
					
						
							|  |  |  |  |         self.body = self.alternative; | 
					
						
							|  |  |  |  |         self.condition = negated_is_best ? negated : self.condition.negate(compressor); | 
					
						
							|  |  |  |  |         self.alternative = null; | 
					
						
							|  |  |  |  |         return make_node(AST_BlockStatement, self, { | 
					
						
							|  |  |  |  |             body: [ self, body ] | 
					
						
							|  |  |  |  |         }).optimize(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Switch, function(self, compressor) { | 
					
						
							|  |  |  |  |     if (!compressor.option("switches")) return self; | 
					
						
							|  |  |  |  |     var branch; | 
					
						
							|  |  |  |  |     var value = self.expression.evaluate(compressor); | 
					
						
							|  |  |  |  |     if (!(value instanceof AST_Node)) { | 
					
						
							|  |  |  |  |         var orig = self.expression; | 
					
						
							|  |  |  |  |         self.expression = make_node_from_constant(value, orig); | 
					
						
							|  |  |  |  |         self.expression = best_of_expression(self.expression.transform(compressor), orig); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (!compressor.option("dead_code")) return self; | 
					
						
							|  |  |  |  |     if (value instanceof AST_Node) { | 
					
						
							|  |  |  |  |         value = self.expression.tail_node().evaluate(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     var decl = []; | 
					
						
							|  |  |  |  |     var body = []; | 
					
						
							|  |  |  |  |     var default_branch; | 
					
						
							|  |  |  |  |     var exact_match; | 
					
						
							|  |  |  |  |     for (var i = 0, len = self.body.length; i < len && !exact_match; i++) { | 
					
						
							|  |  |  |  |         branch = self.body[i]; | 
					
						
							|  |  |  |  |         if (branch instanceof AST_Default) { | 
					
						
							|  |  |  |  |             if (!default_branch) { | 
					
						
							|  |  |  |  |                 default_branch = branch; | 
					
						
							|  |  |  |  |             } else { | 
					
						
							|  |  |  |  |                 eliminate_branch(branch, body[body.length - 1]); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } else if (!(value instanceof AST_Node)) { | 
					
						
							|  |  |  |  |             var exp = branch.expression.evaluate(compressor); | 
					
						
							|  |  |  |  |             if (!(exp instanceof AST_Node) && exp !== value) { | 
					
						
							|  |  |  |  |                 eliminate_branch(branch, body[body.length - 1]); | 
					
						
							|  |  |  |  |                 continue; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             if (exp instanceof AST_Node) exp = branch.expression.tail_node().evaluate(compressor); | 
					
						
							|  |  |  |  |             if (exp === value) { | 
					
						
							|  |  |  |  |                 exact_match = branch; | 
					
						
							|  |  |  |  |                 if (default_branch) { | 
					
						
							|  |  |  |  |                     var default_index = body.indexOf(default_branch); | 
					
						
							|  |  |  |  |                     body.splice(default_index, 1); | 
					
						
							|  |  |  |  |                     eliminate_branch(default_branch, body[default_index - 1]); | 
					
						
							|  |  |  |  |                     default_branch = null; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         body.push(branch); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     while (i < len) eliminate_branch(self.body[i++], body[body.length - 1]); | 
					
						
							|  |  |  |  |     self.body = body; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     let default_or_exact = default_branch || exact_match; | 
					
						
							|  |  |  |  |     default_branch = null; | 
					
						
							|  |  |  |  |     exact_match = null; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // group equivalent branches so they will be located next to each other,
 | 
					
						
							|  |  |  |  |     // that way the next micro-optimization will merge them.
 | 
					
						
							|  |  |  |  |     // ** bail micro-optimization if not a simple switch case with breaks
 | 
					
						
							|  |  |  |  |     if (body.every((branch, i) => | 
					
						
							|  |  |  |  |         (branch === default_or_exact || branch.expression instanceof AST_Constant) | 
					
						
							|  |  |  |  |         && (branch.body.length === 0 || aborts(branch) || body.length - 1 === i)) | 
					
						
							|  |  |  |  |     ) { | 
					
						
							|  |  |  |  |         for (let i = 0; i < body.length; i++) { | 
					
						
							|  |  |  |  |             const branch = body[i]; | 
					
						
							|  |  |  |  |             for (let j = i + 1; j < body.length; j++) { | 
					
						
							|  |  |  |  |                 const next = body[j]; | 
					
						
							|  |  |  |  |                 if (next.body.length === 0) continue; | 
					
						
							|  |  |  |  |                 const last_branch = j === (body.length - 1); | 
					
						
							|  |  |  |  |                 const equivalentBranch = branches_equivalent(next, branch, false); | 
					
						
							|  |  |  |  |                 if (equivalentBranch || (last_branch && branches_equivalent(next, branch, true))) { | 
					
						
							|  |  |  |  |                     if (!equivalentBranch && last_branch) { | 
					
						
							|  |  |  |  |                         next.body.push(make_node(AST_Break)); | 
					
						
							|  |  |  |  |                     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                     // let's find previous siblings with inert fallthrough...
 | 
					
						
							|  |  |  |  |                     let x = j - 1; | 
					
						
							|  |  |  |  |                     let fallthroughDepth = 0; | 
					
						
							|  |  |  |  |                     while (x > i) { | 
					
						
							|  |  |  |  |                         if (is_inert_body(body[x--])) { | 
					
						
							|  |  |  |  |                             fallthroughDepth++; | 
					
						
							|  |  |  |  |                         } else { | 
					
						
							|  |  |  |  |                             break; | 
					
						
							|  |  |  |  |                         } | 
					
						
							|  |  |  |  |                     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                     const plucked = body.splice(j - fallthroughDepth, 1 + fallthroughDepth); | 
					
						
							|  |  |  |  |                     body.splice(i + 1, 0, ...plucked); | 
					
						
							|  |  |  |  |                     i += plucked.length; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // merge equivalent branches in a row
 | 
					
						
							|  |  |  |  |     for (let i = 0; i < body.length; i++) { | 
					
						
							|  |  |  |  |         let branch = body[i]; | 
					
						
							|  |  |  |  |         if (branch.body.length === 0) continue; | 
					
						
							|  |  |  |  |         if (!aborts(branch)) continue; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         for (let j = i + 1; j < body.length; i++, j++) { | 
					
						
							|  |  |  |  |             let next = body[j]; | 
					
						
							|  |  |  |  |             if (next.body.length === 0) continue; | 
					
						
							|  |  |  |  |             if ( | 
					
						
							|  |  |  |  |                 branches_equivalent(next, branch, false) | 
					
						
							|  |  |  |  |                 || (j === body.length - 1 && branches_equivalent(next, branch, true)) | 
					
						
							|  |  |  |  |             ) { | 
					
						
							|  |  |  |  |                 branch.body = []; | 
					
						
							|  |  |  |  |                 branch = next; | 
					
						
							|  |  |  |  |                 continue; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // Prune any empty branches at the end of the switch statement.
 | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         let i = body.length - 1; | 
					
						
							|  |  |  |  |         for (; i >= 0; i--) { | 
					
						
							|  |  |  |  |             let bbody = body[i].body; | 
					
						
							|  |  |  |  |             if (is_break(bbody[bbody.length - 1], compressor)) bbody.pop(); | 
					
						
							|  |  |  |  |             if (!is_inert_body(body[i])) break; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         // i now points to the index of a branch that contains a body. By incrementing, it's
 | 
					
						
							|  |  |  |  |         // pointing to the first branch that's empty.
 | 
					
						
							|  |  |  |  |         i++; | 
					
						
							|  |  |  |  |         if (!default_or_exact || body.indexOf(default_or_exact) >= i) { | 
					
						
							|  |  |  |  |             // The default behavior is to do nothing. We can take advantage of that to
 | 
					
						
							|  |  |  |  |             // remove all case expressions that are side-effect free that also do
 | 
					
						
							|  |  |  |  |             // nothing, since they'll default to doing nothing. But we can't remove any
 | 
					
						
							|  |  |  |  |             // case expressions before one that would side-effect, since they may cause
 | 
					
						
							|  |  |  |  |             // the side-effect to be skipped.
 | 
					
						
							|  |  |  |  |             for (let j = body.length - 1; j >= i; j--) { | 
					
						
							|  |  |  |  |                 let branch = body[j]; | 
					
						
							|  |  |  |  |                 if (branch === default_or_exact) { | 
					
						
							|  |  |  |  |                     default_or_exact = null; | 
					
						
							|  |  |  |  |                     body.pop(); | 
					
						
							|  |  |  |  |                 } else if (!branch.expression.has_side_effects(compressor)) { | 
					
						
							|  |  |  |  |                     body.pop(); | 
					
						
							|  |  |  |  |                 } else { | 
					
						
							|  |  |  |  |                     break; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // Prune side-effect free branches that fall into default.
 | 
					
						
							|  |  |  |  |     DEFAULT: if (default_or_exact) { | 
					
						
							|  |  |  |  |         let default_index = body.indexOf(default_or_exact); | 
					
						
							|  |  |  |  |         let default_body_index = default_index; | 
					
						
							|  |  |  |  |         for (; default_body_index < body.length - 1; default_body_index++) { | 
					
						
							|  |  |  |  |             if (!is_inert_body(body[default_body_index])) break; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         if (default_body_index < body.length - 1) { | 
					
						
							|  |  |  |  |             break DEFAULT; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         let side_effect_index = body.length - 1; | 
					
						
							|  |  |  |  |         for (; side_effect_index >= 0; side_effect_index--) { | 
					
						
							|  |  |  |  |             let branch = body[side_effect_index]; | 
					
						
							|  |  |  |  |             if (branch === default_or_exact) continue; | 
					
						
							|  |  |  |  |             if (branch.expression.has_side_effects(compressor)) break; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         // If the default behavior comes after any side-effect case expressions,
 | 
					
						
							|  |  |  |  |         // then we can fold all side-effect free cases into the default branch.
 | 
					
						
							|  |  |  |  |         // If the side-effect case is after the default, then any side-effect
 | 
					
						
							|  |  |  |  |         // free cases could prevent the side-effect from occurring.
 | 
					
						
							|  |  |  |  |         if (default_body_index > side_effect_index) { | 
					
						
							|  |  |  |  |             let prev_body_index = default_index - 1; | 
					
						
							|  |  |  |  |             for (; prev_body_index >= 0; prev_body_index--) { | 
					
						
							|  |  |  |  |                 if (!is_inert_body(body[prev_body_index])) break; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             let before = Math.max(side_effect_index, prev_body_index) + 1; | 
					
						
							|  |  |  |  |             let after = default_index; | 
					
						
							|  |  |  |  |             if (side_effect_index > default_index) { | 
					
						
							|  |  |  |  |                 // If the default falls into the same body as a side-effect
 | 
					
						
							|  |  |  |  |                 // case, then we need preserve that case and only prune the
 | 
					
						
							|  |  |  |  |                 // cases after it.
 | 
					
						
							|  |  |  |  |                 after = side_effect_index; | 
					
						
							|  |  |  |  |                 body[side_effect_index].body = body[default_body_index].body; | 
					
						
							|  |  |  |  |             } else { | 
					
						
							|  |  |  |  |                 // The default will be the last branch.
 | 
					
						
							|  |  |  |  |                 default_or_exact.body = body[default_body_index].body; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // Prune everything after the default (or last side-effect case)
 | 
					
						
							|  |  |  |  |             // until the next case with a body.
 | 
					
						
							|  |  |  |  |             body.splice(after + 1, default_body_index - after); | 
					
						
							|  |  |  |  |             // Prune everything before the default that falls into it.
 | 
					
						
							|  |  |  |  |             body.splice(before, default_index - before); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // See if we can remove the switch entirely if all cases (the default) fall into the same case body.
 | 
					
						
							|  |  |  |  |     DEFAULT: if (default_or_exact) { | 
					
						
							|  |  |  |  |         let i = body.findIndex(branch => !is_inert_body(branch)); | 
					
						
							|  |  |  |  |         let caseBody; | 
					
						
							|  |  |  |  |         // `i` is equal to one of the following:
 | 
					
						
							|  |  |  |  |         // - `-1`, there is no body in the switch statement.
 | 
					
						
							|  |  |  |  |         // - `body.length - 1`, all cases fall into the same body.
 | 
					
						
							|  |  |  |  |         // - anything else, there are multiple bodies in the switch.
 | 
					
						
							|  |  |  |  |         if (i === body.length - 1) { | 
					
						
							|  |  |  |  |             // All cases fall into the case body.
 | 
					
						
							|  |  |  |  |             let branch = body[i]; | 
					
						
							|  |  |  |  |             if (has_nested_break(self)) break DEFAULT; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // This is the last case body, and we've already pruned any breaks, so it's
 | 
					
						
							|  |  |  |  |             // safe to hoist.
 | 
					
						
							|  |  |  |  |             caseBody = make_node(AST_BlockStatement, branch, { | 
					
						
							|  |  |  |  |                 body: branch.body | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |             branch.body = []; | 
					
						
							|  |  |  |  |         } else if (i !== -1) { | 
					
						
							|  |  |  |  |             // If there are multiple bodies, then we cannot optimize anything.
 | 
					
						
							|  |  |  |  |             break DEFAULT; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         let sideEffect = body.find(branch => { | 
					
						
							|  |  |  |  |             return ( | 
					
						
							|  |  |  |  |                 branch !== default_or_exact | 
					
						
							|  |  |  |  |                 && branch.expression.has_side_effects(compressor) | 
					
						
							|  |  |  |  |             ); | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |         // If no cases cause a side-effect, we can eliminate the switch entirely.
 | 
					
						
							|  |  |  |  |         if (!sideEffect) { | 
					
						
							|  |  |  |  |             return make_node(AST_BlockStatement, self, { | 
					
						
							|  |  |  |  |                 body: decl.concat( | 
					
						
							|  |  |  |  |                     statement(self.expression), | 
					
						
							|  |  |  |  |                     default_or_exact.expression ? statement(default_or_exact.expression) : [], | 
					
						
							|  |  |  |  |                     caseBody || [] | 
					
						
							|  |  |  |  |                 ) | 
					
						
							|  |  |  |  |             }).optimize(compressor); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // If we're this far, either there was no body or all cases fell into the same body.
 | 
					
						
							|  |  |  |  |         // If there was no body, then we don't need a default branch (because the default is
 | 
					
						
							|  |  |  |  |         // do nothing). If there was a body, we'll extract it to after the switch, so the
 | 
					
						
							|  |  |  |  |         // switch's new default is to do nothing and we can still prune it.
 | 
					
						
							|  |  |  |  |         const default_index = body.indexOf(default_or_exact); | 
					
						
							|  |  |  |  |         body.splice(default_index, 1); | 
					
						
							|  |  |  |  |         default_or_exact = null; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (caseBody) { | 
					
						
							|  |  |  |  |             // Recurse into switch statement one more time so that we can append the case body
 | 
					
						
							|  |  |  |  |             // outside of the switch. This recursion will only happen once since we've pruned
 | 
					
						
							|  |  |  |  |             // the default case.
 | 
					
						
							|  |  |  |  |             return make_node(AST_BlockStatement, self, { | 
					
						
							|  |  |  |  |                 body: decl.concat(self, caseBody) | 
					
						
							|  |  |  |  |             }).optimize(compressor); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         // If we fall here, there is a default branch somewhere, there are no case bodies,
 | 
					
						
							|  |  |  |  |         // and there's a side-effect somewhere. Just let the below paths take care of it.
 | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (body.length > 0) { | 
					
						
							|  |  |  |  |         body[0].body = decl.concat(body[0].body); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (body.length == 0) { | 
					
						
							|  |  |  |  |         return make_node(AST_BlockStatement, self, { | 
					
						
							|  |  |  |  |             body: decl.concat(statement(self.expression)) | 
					
						
							|  |  |  |  |         }).optimize(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (body.length == 1 && !has_nested_break(self)) { | 
					
						
							|  |  |  |  |         // This is the last case body, and we've already pruned any breaks, so it's
 | 
					
						
							|  |  |  |  |         // safe to hoist.
 | 
					
						
							|  |  |  |  |         let branch = body[0]; | 
					
						
							|  |  |  |  |         return make_node(AST_If, self, { | 
					
						
							|  |  |  |  |             condition: make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                 operator: "===", | 
					
						
							|  |  |  |  |                 left: self.expression, | 
					
						
							|  |  |  |  |                 right: branch.expression, | 
					
						
							|  |  |  |  |             }), | 
					
						
							|  |  |  |  |             body: make_node(AST_BlockStatement, branch, { | 
					
						
							|  |  |  |  |                 body: branch.body | 
					
						
							|  |  |  |  |             }), | 
					
						
							|  |  |  |  |             alternative: null | 
					
						
							|  |  |  |  |         }).optimize(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (body.length === 2 && default_or_exact && !has_nested_break(self)) { | 
					
						
							|  |  |  |  |         let branch = body[0] === default_or_exact ? body[1] : body[0]; | 
					
						
							|  |  |  |  |         let exact_exp = default_or_exact.expression && statement(default_or_exact.expression); | 
					
						
							|  |  |  |  |         if (aborts(body[0])) { | 
					
						
							|  |  |  |  |             // Only the first branch body could have a break (at the last statement)
 | 
					
						
							|  |  |  |  |             let first = body[0]; | 
					
						
							|  |  |  |  |             if (is_break(first.body[first.body.length - 1], compressor)) { | 
					
						
							|  |  |  |  |                 first.body.pop(); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             return make_node(AST_If, self, { | 
					
						
							|  |  |  |  |                 condition: make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                     operator: "===", | 
					
						
							|  |  |  |  |                     left: self.expression, | 
					
						
							|  |  |  |  |                     right: branch.expression, | 
					
						
							|  |  |  |  |                 }), | 
					
						
							|  |  |  |  |                 body: make_node(AST_BlockStatement, branch, { | 
					
						
							|  |  |  |  |                     body: branch.body | 
					
						
							|  |  |  |  |                 }), | 
					
						
							|  |  |  |  |                 alternative: make_node(AST_BlockStatement, default_or_exact, { | 
					
						
							|  |  |  |  |                     body: [].concat( | 
					
						
							|  |  |  |  |                         exact_exp || [], | 
					
						
							|  |  |  |  |                         default_or_exact.body | 
					
						
							|  |  |  |  |                     ) | 
					
						
							|  |  |  |  |                 }) | 
					
						
							|  |  |  |  |             }).optimize(compressor); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         let operator = "==="; | 
					
						
							|  |  |  |  |         let consequent = make_node(AST_BlockStatement, branch, { | 
					
						
							|  |  |  |  |             body: branch.body, | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |         let always = make_node(AST_BlockStatement, default_or_exact, { | 
					
						
							|  |  |  |  |             body: [].concat( | 
					
						
							|  |  |  |  |                 exact_exp || [], | 
					
						
							|  |  |  |  |                 default_or_exact.body | 
					
						
							|  |  |  |  |             ) | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |         if (body[0] === default_or_exact) { | 
					
						
							|  |  |  |  |             operator = "!=="; | 
					
						
							|  |  |  |  |             let tmp = always; | 
					
						
							|  |  |  |  |             always = consequent; | 
					
						
							|  |  |  |  |             consequent = tmp; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         return make_node(AST_BlockStatement, self, { | 
					
						
							|  |  |  |  |             body: [ | 
					
						
							|  |  |  |  |                 make_node(AST_If, self, { | 
					
						
							|  |  |  |  |                     condition: make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                         operator: operator, | 
					
						
							|  |  |  |  |                         left: self.expression, | 
					
						
							|  |  |  |  |                         right: branch.expression, | 
					
						
							|  |  |  |  |                     }), | 
					
						
							|  |  |  |  |                     body: consequent, | 
					
						
							|  |  |  |  |                     alternative: null | 
					
						
							|  |  |  |  |                 }) | 
					
						
							|  |  |  |  |             ].concat(always) | 
					
						
							|  |  |  |  |         }).optimize(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     function eliminate_branch(branch, prev) { | 
					
						
							|  |  |  |  |         if (prev && !aborts(prev)) { | 
					
						
							|  |  |  |  |             prev.body = prev.body.concat(branch.body); | 
					
						
							|  |  |  |  |         } else { | 
					
						
							|  |  |  |  |             trim_unreachable_code(compressor, branch, decl); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     function branches_equivalent(branch, prev, insertBreak) { | 
					
						
							|  |  |  |  |         let bbody = branch.body; | 
					
						
							|  |  |  |  |         let pbody = prev.body; | 
					
						
							|  |  |  |  |         if (insertBreak) { | 
					
						
							|  |  |  |  |             bbody = bbody.concat(make_node(AST_Break)); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         if (bbody.length !== pbody.length) return false; | 
					
						
							|  |  |  |  |         let bblock = make_node(AST_BlockStatement, branch, { body: bbody }); | 
					
						
							|  |  |  |  |         let pblock = make_node(AST_BlockStatement, prev, { body: pbody }); | 
					
						
							|  |  |  |  |         return bblock.equivalent_to(pblock); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     function statement(expression) { | 
					
						
							|  |  |  |  |         return make_node(AST_SimpleStatement, expression, { | 
					
						
							|  |  |  |  |             body: expression | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     function has_nested_break(root) { | 
					
						
							|  |  |  |  |         let has_break = false; | 
					
						
							|  |  |  |  |         let tw = new TreeWalker(node => { | 
					
						
							|  |  |  |  |             if (has_break) return true; | 
					
						
							|  |  |  |  |             if (node instanceof AST_Lambda) return true; | 
					
						
							|  |  |  |  |             if (node instanceof AST_SimpleStatement) return true; | 
					
						
							|  |  |  |  |             if (!is_break(node, tw)) return; | 
					
						
							|  |  |  |  |             let parent = tw.parent(); | 
					
						
							|  |  |  |  |             if ( | 
					
						
							|  |  |  |  |                 parent instanceof AST_SwitchBranch | 
					
						
							|  |  |  |  |                 && parent.body[parent.body.length - 1] === node | 
					
						
							|  |  |  |  |             ) { | 
					
						
							|  |  |  |  |                 return; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             has_break = true; | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |         root.walk(tw); | 
					
						
							|  |  |  |  |         return has_break; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     function is_break(node, stack) { | 
					
						
							|  |  |  |  |         return node instanceof AST_Break | 
					
						
							|  |  |  |  |             && stack.loopcontrol_target(node) === self; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     function is_inert_body(branch) { | 
					
						
							|  |  |  |  |         return !aborts(branch) && !make_node(AST_BlockStatement, branch, { | 
					
						
							|  |  |  |  |             body: branch.body | 
					
						
							|  |  |  |  |         }).has_side_effects(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Try, function(self, compressor) { | 
					
						
							|  |  |  |  |     tighten_body(self.body, compressor); | 
					
						
							|  |  |  |  |     if (self.bcatch && self.bfinally && self.bfinally.body.every(is_empty)) self.bfinally = null; | 
					
						
							|  |  |  |  |     if (compressor.option("dead_code") && self.body.every(is_empty)) { | 
					
						
							|  |  |  |  |         var body = []; | 
					
						
							|  |  |  |  |         if (self.bcatch) { | 
					
						
							|  |  |  |  |             trim_unreachable_code(compressor, self.bcatch, body); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         if (self.bfinally) body.push(...self.bfinally.body); | 
					
						
							|  |  |  |  |         return make_node(AST_BlockStatement, self, { | 
					
						
							|  |  |  |  |             body: body | 
					
						
							|  |  |  |  |         }).optimize(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | AST_Definitions.DEFMETHOD("remove_initializers", function() { | 
					
						
							|  |  |  |  |     var decls = []; | 
					
						
							|  |  |  |  |     this.definitions.forEach(function(def) { | 
					
						
							|  |  |  |  |         if (def.name instanceof AST_SymbolDeclaration) { | 
					
						
							|  |  |  |  |             def.value = null; | 
					
						
							|  |  |  |  |             decls.push(def); | 
					
						
							|  |  |  |  |         } else { | 
					
						
							|  |  |  |  |             walk(def.name, node => { | 
					
						
							|  |  |  |  |                 if (node instanceof AST_SymbolDeclaration) { | 
					
						
							|  |  |  |  |                     decls.push(make_node(AST_VarDef, def, { | 
					
						
							|  |  |  |  |                         name: node, | 
					
						
							|  |  |  |  |                         value: null | 
					
						
							|  |  |  |  |                     })); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     }); | 
					
						
							|  |  |  |  |     this.definitions = decls; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | AST_Definitions.DEFMETHOD("to_assignments", function(compressor) { | 
					
						
							|  |  |  |  |     var reduce_vars = compressor.option("reduce_vars"); | 
					
						
							|  |  |  |  |     var assignments = []; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     for (const def of this.definitions) { | 
					
						
							|  |  |  |  |         if (def.value) { | 
					
						
							|  |  |  |  |             var name = make_node(AST_SymbolRef, def.name, def.name); | 
					
						
							|  |  |  |  |             assignments.push(make_node(AST_Assign, def, { | 
					
						
							|  |  |  |  |                 operator : "=", | 
					
						
							|  |  |  |  |                 logical: false, | 
					
						
							|  |  |  |  |                 left     : name, | 
					
						
							|  |  |  |  |                 right    : def.value | 
					
						
							|  |  |  |  |             })); | 
					
						
							|  |  |  |  |             if (reduce_vars) name.definition().fixed = false; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         const thedef = def.name.definition(); | 
					
						
							|  |  |  |  |         thedef.eliminated++; | 
					
						
							|  |  |  |  |         thedef.replaced--; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (assignments.length == 0) return null; | 
					
						
							|  |  |  |  |     return make_sequence(this, assignments); | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Definitions, function(self) { | 
					
						
							|  |  |  |  |     if (self.definitions.length == 0) { | 
					
						
							|  |  |  |  |         return make_node(AST_EmptyStatement, self); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_VarDef, function(self, compressor) { | 
					
						
							|  |  |  |  |     if ( | 
					
						
							|  |  |  |  |         self.name instanceof AST_SymbolLet | 
					
						
							|  |  |  |  |         && self.value != null | 
					
						
							|  |  |  |  |         && is_undefined(self.value, compressor) | 
					
						
							|  |  |  |  |     ) { | 
					
						
							|  |  |  |  |         self.value = null; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Import, function(self) { | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Call, function(self, compressor) { | 
					
						
							|  |  |  |  |     var exp = self.expression; | 
					
						
							|  |  |  |  |     var fn = exp; | 
					
						
							|  |  |  |  |     inline_array_like_spread(self.args); | 
					
						
							|  |  |  |  |     var simple_args = self.args.every((arg) => | 
					
						
							|  |  |  |  |         !(arg instanceof AST_Expansion) | 
					
						
							|  |  |  |  |     ); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (compressor.option("reduce_vars") | 
					
						
							|  |  |  |  |         && fn instanceof AST_SymbolRef | 
					
						
							|  |  |  |  |         && !has_annotation(self, _NOINLINE) | 
					
						
							|  |  |  |  |     ) { | 
					
						
							|  |  |  |  |         const fixed = fn.fixed_value(); | 
					
						
							|  |  |  |  |         if (!retain_top_func(fixed, compressor)) { | 
					
						
							|  |  |  |  |             fn = fixed; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     var is_func = fn instanceof AST_Lambda; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (is_func && fn.pinned()) return self; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (compressor.option("unused") | 
					
						
							|  |  |  |  |         && simple_args | 
					
						
							|  |  |  |  |         && is_func | 
					
						
							|  |  |  |  |         && !fn.uses_arguments) { | 
					
						
							|  |  |  |  |         var pos = 0, last = 0; | 
					
						
							|  |  |  |  |         for (var i = 0, len = self.args.length; i < len; i++) { | 
					
						
							|  |  |  |  |             if (fn.argnames[i] instanceof AST_Expansion) { | 
					
						
							|  |  |  |  |                 if (has_flag(fn.argnames[i].expression, UNUSED)) while (i < len) { | 
					
						
							|  |  |  |  |                     var node = self.args[i++].drop_side_effect_free(compressor); | 
					
						
							|  |  |  |  |                     if (node) { | 
					
						
							|  |  |  |  |                         self.args[pos++] = node; | 
					
						
							|  |  |  |  |                     } | 
					
						
							|  |  |  |  |                 } else while (i < len) { | 
					
						
							|  |  |  |  |                     self.args[pos++] = self.args[i++]; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |                 last = pos; | 
					
						
							|  |  |  |  |                 break; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             var trim = i >= fn.argnames.length; | 
					
						
							|  |  |  |  |             if (trim || has_flag(fn.argnames[i], UNUSED)) { | 
					
						
							|  |  |  |  |                 var node = self.args[i].drop_side_effect_free(compressor); | 
					
						
							|  |  |  |  |                 if (node) { | 
					
						
							|  |  |  |  |                     self.args[pos++] = node; | 
					
						
							|  |  |  |  |                 } else if (!trim) { | 
					
						
							|  |  |  |  |                     self.args[pos++] = make_node(AST_Number, self.args[i], { | 
					
						
							|  |  |  |  |                         value: 0 | 
					
						
							|  |  |  |  |                     }); | 
					
						
							|  |  |  |  |                     continue; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } else { | 
					
						
							|  |  |  |  |                 self.args[pos++] = self.args[i]; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             last = pos; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         self.args.length = last; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (compressor.option("unsafe")) { | 
					
						
							|  |  |  |  |         if (exp instanceof AST_Dot && exp.start.value === "Array" && exp.property === "from" && self.args.length === 1) { | 
					
						
							|  |  |  |  |             const [argument] = self.args; | 
					
						
							|  |  |  |  |             if (argument instanceof AST_Array) { | 
					
						
							|  |  |  |  |                 return make_node(AST_Array, argument, { | 
					
						
							|  |  |  |  |                     elements: argument.elements | 
					
						
							|  |  |  |  |                 }).optimize(compressor); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         if (is_undeclared_ref(exp)) switch (exp.name) { | 
					
						
							|  |  |  |  |           case "Array": | 
					
						
							|  |  |  |  |             if (self.args.length != 1) { | 
					
						
							|  |  |  |  |                 return make_node(AST_Array, self, { | 
					
						
							|  |  |  |  |                     elements: self.args | 
					
						
							|  |  |  |  |                 }).optimize(compressor); | 
					
						
							|  |  |  |  |             } else if (self.args[0] instanceof AST_Number && self.args[0].value <= 11) { | 
					
						
							|  |  |  |  |                 const elements = []; | 
					
						
							|  |  |  |  |                 for (let i = 0; i < self.args[0].value; i++) elements.push(new AST_Hole); | 
					
						
							|  |  |  |  |                 return new AST_Array({ elements }); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |           case "Object": | 
					
						
							|  |  |  |  |             if (self.args.length == 0) { | 
					
						
							|  |  |  |  |                 return make_node(AST_Object, self, { | 
					
						
							|  |  |  |  |                     properties: [] | 
					
						
							|  |  |  |  |                 }); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |           case "String": | 
					
						
							|  |  |  |  |             if (self.args.length == 0) return make_node(AST_String, self, { | 
					
						
							|  |  |  |  |                 value: "" | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |             if (self.args.length <= 1) return make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                 left: self.args[0], | 
					
						
							|  |  |  |  |                 operator: "+", | 
					
						
							|  |  |  |  |                 right: make_node(AST_String, self, { value: "" }) | 
					
						
							|  |  |  |  |             }).optimize(compressor); | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |           case "Number": | 
					
						
							|  |  |  |  |             if (self.args.length == 0) return make_node(AST_Number, self, { | 
					
						
							|  |  |  |  |                 value: 0 | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |             if (self.args.length == 1 && compressor.option("unsafe_math")) { | 
					
						
							|  |  |  |  |                 return make_node(AST_UnaryPrefix, self, { | 
					
						
							|  |  |  |  |                     expression: self.args[0], | 
					
						
							|  |  |  |  |                     operator: "+" | 
					
						
							|  |  |  |  |                 }).optimize(compressor); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |           case "Symbol": | 
					
						
							|  |  |  |  |             if (self.args.length == 1 && self.args[0] instanceof AST_String && compressor.option("unsafe_symbols")) | 
					
						
							|  |  |  |  |                 self.args.length = 0; | 
					
						
							|  |  |  |  |                 break; | 
					
						
							|  |  |  |  |           case "Boolean": | 
					
						
							|  |  |  |  |             if (self.args.length == 0) return make_node(AST_False, self); | 
					
						
							|  |  |  |  |             if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, { | 
					
						
							|  |  |  |  |                 expression: make_node(AST_UnaryPrefix, self, { | 
					
						
							|  |  |  |  |                     expression: self.args[0], | 
					
						
							|  |  |  |  |                     operator: "!" | 
					
						
							|  |  |  |  |                 }), | 
					
						
							|  |  |  |  |                 operator: "!" | 
					
						
							|  |  |  |  |             }).optimize(compressor); | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |           case "RegExp": | 
					
						
							|  |  |  |  |             var params = []; | 
					
						
							|  |  |  |  |             if (self.args.length >= 1 | 
					
						
							|  |  |  |  |                 && self.args.length <= 2 | 
					
						
							|  |  |  |  |                 && self.args.every((arg) => { | 
					
						
							|  |  |  |  |                     var value = arg.evaluate(compressor); | 
					
						
							|  |  |  |  |                     params.push(value); | 
					
						
							|  |  |  |  |                     return arg !== value; | 
					
						
							|  |  |  |  |                 }) | 
					
						
							|  |  |  |  |                 && regexp_is_safe(params[0]) | 
					
						
							|  |  |  |  |             ) { | 
					
						
							|  |  |  |  |                 let [ source, flags ] = params; | 
					
						
							|  |  |  |  |                 source = regexp_source_fix(new RegExp(source).source); | 
					
						
							|  |  |  |  |                 const rx = make_node(AST_RegExp, self, { | 
					
						
							|  |  |  |  |                     value: { source, flags } | 
					
						
							|  |  |  |  |                 }); | 
					
						
							|  |  |  |  |                 if (rx._eval(compressor) !== rx) { | 
					
						
							|  |  |  |  |                     return rx; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |         } else if (exp instanceof AST_Dot) switch(exp.property) { | 
					
						
							|  |  |  |  |           case "toString": | 
					
						
							|  |  |  |  |             if (self.args.length == 0 && !exp.expression.may_throw_on_access(compressor)) { | 
					
						
							|  |  |  |  |                 return make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                     left: make_node(AST_String, self, { value: "" }), | 
					
						
							|  |  |  |  |                     operator: "+", | 
					
						
							|  |  |  |  |                     right: exp.expression | 
					
						
							|  |  |  |  |                 }).optimize(compressor); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |           case "join": | 
					
						
							|  |  |  |  |             if (exp.expression instanceof AST_Array) EXIT: { | 
					
						
							|  |  |  |  |                 var separator; | 
					
						
							|  |  |  |  |                 if (self.args.length > 0) { | 
					
						
							|  |  |  |  |                     separator = self.args[0].evaluate(compressor); | 
					
						
							|  |  |  |  |                     if (separator === self.args[0]) break EXIT; // not a constant
 | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |                 var elements = []; | 
					
						
							|  |  |  |  |                 var consts = []; | 
					
						
							|  |  |  |  |                 for (var i = 0, len = exp.expression.elements.length; i < len; i++) { | 
					
						
							|  |  |  |  |                     var el = exp.expression.elements[i]; | 
					
						
							|  |  |  |  |                     if (el instanceof AST_Expansion) break EXIT; | 
					
						
							|  |  |  |  |                     var value = el.evaluate(compressor); | 
					
						
							|  |  |  |  |                     if (value !== el) { | 
					
						
							|  |  |  |  |                         consts.push(value); | 
					
						
							|  |  |  |  |                     } else { | 
					
						
							|  |  |  |  |                         if (consts.length > 0) { | 
					
						
							|  |  |  |  |                             elements.push(make_node(AST_String, self, { | 
					
						
							|  |  |  |  |                                 value: consts.join(separator) | 
					
						
							|  |  |  |  |                             })); | 
					
						
							|  |  |  |  |                             consts.length = 0; | 
					
						
							|  |  |  |  |                         } | 
					
						
							|  |  |  |  |                         elements.push(el); | 
					
						
							|  |  |  |  |                     } | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |                 if (consts.length > 0) { | 
					
						
							|  |  |  |  |                     elements.push(make_node(AST_String, self, { | 
					
						
							|  |  |  |  |                         value: consts.join(separator) | 
					
						
							|  |  |  |  |                     })); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |                 if (elements.length == 0) return make_node(AST_String, self, { value: "" }); | 
					
						
							|  |  |  |  |                 if (elements.length == 1) { | 
					
						
							|  |  |  |  |                     if (elements[0].is_string(compressor)) { | 
					
						
							|  |  |  |  |                         return elements[0]; | 
					
						
							|  |  |  |  |                     } | 
					
						
							|  |  |  |  |                     return make_node(AST_Binary, elements[0], { | 
					
						
							|  |  |  |  |                         operator : "+", | 
					
						
							|  |  |  |  |                         left     : make_node(AST_String, self, { value: "" }), | 
					
						
							|  |  |  |  |                         right    : elements[0] | 
					
						
							|  |  |  |  |                     }); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |                 if (separator == "") { | 
					
						
							|  |  |  |  |                     var first; | 
					
						
							|  |  |  |  |                     if (elements[0].is_string(compressor) | 
					
						
							|  |  |  |  |                         || elements[1].is_string(compressor)) { | 
					
						
							|  |  |  |  |                         first = elements.shift(); | 
					
						
							|  |  |  |  |                     } else { | 
					
						
							|  |  |  |  |                         first = make_node(AST_String, self, { value: "" }); | 
					
						
							|  |  |  |  |                     } | 
					
						
							|  |  |  |  |                     return elements.reduce(function(prev, el) { | 
					
						
							|  |  |  |  |                         return make_node(AST_Binary, el, { | 
					
						
							|  |  |  |  |                             operator : "+", | 
					
						
							|  |  |  |  |                             left     : prev, | 
					
						
							|  |  |  |  |                             right    : el | 
					
						
							|  |  |  |  |                         }); | 
					
						
							|  |  |  |  |                     }, first).optimize(compressor); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |                 // need this awkward cloning to not affect original element
 | 
					
						
							|  |  |  |  |                 // best_of will decide which one to get through.
 | 
					
						
							|  |  |  |  |                 var node = self.clone(); | 
					
						
							|  |  |  |  |                 node.expression = node.expression.clone(); | 
					
						
							|  |  |  |  |                 node.expression.expression = node.expression.expression.clone(); | 
					
						
							|  |  |  |  |                 node.expression.expression.elements = elements; | 
					
						
							|  |  |  |  |                 return best_of(compressor, self, node); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |           case "charAt": | 
					
						
							|  |  |  |  |             if (exp.expression.is_string(compressor)) { | 
					
						
							|  |  |  |  |                 var arg = self.args[0]; | 
					
						
							|  |  |  |  |                 var index = arg ? arg.evaluate(compressor) : 0; | 
					
						
							|  |  |  |  |                 if (index !== arg) { | 
					
						
							|  |  |  |  |                     return make_node(AST_Sub, exp, { | 
					
						
							|  |  |  |  |                         expression: exp.expression, | 
					
						
							|  |  |  |  |                         property: make_node_from_constant(index | 0, arg || exp) | 
					
						
							|  |  |  |  |                     }).optimize(compressor); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |           case "apply": | 
					
						
							|  |  |  |  |             if (self.args.length == 2 && self.args[1] instanceof AST_Array) { | 
					
						
							|  |  |  |  |                 var args = self.args[1].elements.slice(); | 
					
						
							|  |  |  |  |                 args.unshift(self.args[0]); | 
					
						
							|  |  |  |  |                 return make_node(AST_Call, self, { | 
					
						
							|  |  |  |  |                     expression: make_node(AST_Dot, exp, { | 
					
						
							|  |  |  |  |                         expression: exp.expression, | 
					
						
							|  |  |  |  |                         optional: false, | 
					
						
							|  |  |  |  |                         property: "call" | 
					
						
							|  |  |  |  |                     }), | 
					
						
							|  |  |  |  |                     args: args | 
					
						
							|  |  |  |  |                 }).optimize(compressor); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |           case "call": | 
					
						
							|  |  |  |  |             var func = exp.expression; | 
					
						
							|  |  |  |  |             if (func instanceof AST_SymbolRef) { | 
					
						
							|  |  |  |  |                 func = func.fixed_value(); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             if (func instanceof AST_Lambda && !func.contains_this()) { | 
					
						
							|  |  |  |  |                 return (self.args.length ? make_sequence(this, [ | 
					
						
							|  |  |  |  |                     self.args[0], | 
					
						
							|  |  |  |  |                     make_node(AST_Call, self, { | 
					
						
							|  |  |  |  |                         expression: exp.expression, | 
					
						
							|  |  |  |  |                         args: self.args.slice(1) | 
					
						
							|  |  |  |  |                     }) | 
					
						
							|  |  |  |  |                 ]) : make_node(AST_Call, self, { | 
					
						
							|  |  |  |  |                     expression: exp.expression, | 
					
						
							|  |  |  |  |                     args: [] | 
					
						
							|  |  |  |  |                 })).optimize(compressor); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (compressor.option("unsafe_Function") | 
					
						
							|  |  |  |  |         && is_undeclared_ref(exp) | 
					
						
							|  |  |  |  |         && exp.name == "Function") { | 
					
						
							|  |  |  |  |         // new Function() => function(){}
 | 
					
						
							|  |  |  |  |         if (self.args.length == 0) return make_node(AST_Function, self, { | 
					
						
							|  |  |  |  |             argnames: [], | 
					
						
							|  |  |  |  |             body: [] | 
					
						
							|  |  |  |  |         }).optimize(compressor); | 
					
						
							|  |  |  |  |         var nth_identifier = compressor.mangle_options && compressor.mangle_options.nth_identifier || base54; | 
					
						
							|  |  |  |  |         if (self.args.every((x) => x instanceof AST_String)) { | 
					
						
							|  |  |  |  |             // quite a corner-case, but we can handle it:
 | 
					
						
							|  |  |  |  |             //   https://github.com/mishoo/UglifyJS2/issues/203
 | 
					
						
							|  |  |  |  |             // if the code argument is a constant, then we can minify it.
 | 
					
						
							|  |  |  |  |             try { | 
					
						
							|  |  |  |  |                 var code = "n(function(" + self.args.slice(0, -1).map(function(arg) { | 
					
						
							|  |  |  |  |                     return arg.value; | 
					
						
							|  |  |  |  |                 }).join(",") + "){" + self.args[self.args.length - 1].value + "})"; | 
					
						
							|  |  |  |  |                 var ast = parse(code); | 
					
						
							|  |  |  |  |                 var mangle = { ie8: compressor.option("ie8"), nth_identifier: nth_identifier }; | 
					
						
							|  |  |  |  |                 ast.figure_out_scope(mangle); | 
					
						
							|  |  |  |  |                 var comp = new Compressor(compressor.options, { | 
					
						
							|  |  |  |  |                     mangle_options: compressor.mangle_options | 
					
						
							|  |  |  |  |                 }); | 
					
						
							|  |  |  |  |                 ast = ast.transform(comp); | 
					
						
							|  |  |  |  |                 ast.figure_out_scope(mangle); | 
					
						
							|  |  |  |  |                 ast.compute_char_frequency(mangle); | 
					
						
							|  |  |  |  |                 ast.mangle_names(mangle); | 
					
						
							|  |  |  |  |                 var fun; | 
					
						
							|  |  |  |  |                 walk(ast, node => { | 
					
						
							|  |  |  |  |                     if (is_func_expr(node)) { | 
					
						
							|  |  |  |  |                         fun = node; | 
					
						
							|  |  |  |  |                         return walk_abort; | 
					
						
							|  |  |  |  |                     } | 
					
						
							|  |  |  |  |                 }); | 
					
						
							|  |  |  |  |                 var code = OutputStream(); | 
					
						
							|  |  |  |  |                 AST_BlockStatement.prototype._codegen.call(fun, fun, code); | 
					
						
							|  |  |  |  |                 self.args = [ | 
					
						
							|  |  |  |  |                     make_node(AST_String, self, { | 
					
						
							|  |  |  |  |                         value: fun.argnames.map(function(arg) { | 
					
						
							|  |  |  |  |                             return arg.print_to_string(); | 
					
						
							|  |  |  |  |                         }).join(",") | 
					
						
							|  |  |  |  |                     }), | 
					
						
							|  |  |  |  |                     make_node(AST_String, self.args[self.args.length - 1], { | 
					
						
							|  |  |  |  |                         value: code.get().replace(/^{|}$/g, "") | 
					
						
							|  |  |  |  |                     }) | 
					
						
							|  |  |  |  |                 ]; | 
					
						
							|  |  |  |  |                 return self; | 
					
						
							|  |  |  |  |             } catch (ex) { | 
					
						
							|  |  |  |  |                 if (!(ex instanceof JS_Parse_Error)) { | 
					
						
							|  |  |  |  |                     throw ex; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 // Otherwise, it crashes at runtime. Or maybe it's nonstandard syntax.
 | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     return inline_into_call(self, fn, compressor); | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_New, function(self, compressor) { | 
					
						
							|  |  |  |  |     if ( | 
					
						
							|  |  |  |  |         compressor.option("unsafe") && | 
					
						
							|  |  |  |  |         is_undeclared_ref(self.expression) && | 
					
						
							|  |  |  |  |         ["Object", "RegExp", "Function", "Error", "Array"].includes(self.expression.name) | 
					
						
							|  |  |  |  |     ) return make_node(AST_Call, self, self).transform(compressor); | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Sequence, function(self, compressor) { | 
					
						
							|  |  |  |  |     if (!compressor.option("side_effects")) return self; | 
					
						
							|  |  |  |  |     var expressions = []; | 
					
						
							|  |  |  |  |     filter_for_side_effects(); | 
					
						
							|  |  |  |  |     var end = expressions.length - 1; | 
					
						
							|  |  |  |  |     trim_right_for_undefined(); | 
					
						
							|  |  |  |  |     if (end == 0) { | 
					
						
							|  |  |  |  |         self = maintain_this_binding(compressor.parent(), compressor.self(), expressions[0]); | 
					
						
							|  |  |  |  |         if (!(self instanceof AST_Sequence)) self = self.optimize(compressor); | 
					
						
							|  |  |  |  |         return self; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     self.expressions = expressions; | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     function filter_for_side_effects() { | 
					
						
							|  |  |  |  |         var first = first_in_statement(compressor); | 
					
						
							|  |  |  |  |         var last = self.expressions.length - 1; | 
					
						
							|  |  |  |  |         self.expressions.forEach(function(expr, index) { | 
					
						
							|  |  |  |  |             if (index < last) expr = expr.drop_side_effect_free(compressor, first); | 
					
						
							|  |  |  |  |             if (expr) { | 
					
						
							|  |  |  |  |                 merge_sequence(expressions, expr); | 
					
						
							|  |  |  |  |                 first = false; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     function trim_right_for_undefined() { | 
					
						
							|  |  |  |  |         while (end > 0 && is_undefined(expressions[end], compressor)) end--; | 
					
						
							|  |  |  |  |         if (end < expressions.length - 1) { | 
					
						
							|  |  |  |  |             expressions[end] = make_node(AST_UnaryPrefix, self, { | 
					
						
							|  |  |  |  |                 operator   : "void", | 
					
						
							|  |  |  |  |                 expression : expressions[end] | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |             expressions.length = end + 1; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | AST_Unary.DEFMETHOD("lift_sequences", function(compressor) { | 
					
						
							|  |  |  |  |     if (compressor.option("sequences")) { | 
					
						
							|  |  |  |  |         if (this.expression instanceof AST_Sequence) { | 
					
						
							|  |  |  |  |             var x = this.expression.expressions.slice(); | 
					
						
							|  |  |  |  |             var e = this.clone(); | 
					
						
							|  |  |  |  |             e.expression = x.pop(); | 
					
						
							|  |  |  |  |             x.push(e); | 
					
						
							|  |  |  |  |             return make_sequence(this, x).optimize(compressor); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return this; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_UnaryPostfix, function(self, compressor) { | 
					
						
							|  |  |  |  |     return self.lift_sequences(compressor); | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_UnaryPrefix, function(self, compressor) { | 
					
						
							|  |  |  |  |     var e = self.expression; | 
					
						
							|  |  |  |  |     if ( | 
					
						
							|  |  |  |  |         self.operator == "delete" && | 
					
						
							|  |  |  |  |         !( | 
					
						
							|  |  |  |  |             e instanceof AST_SymbolRef || | 
					
						
							|  |  |  |  |             e instanceof AST_PropAccess || | 
					
						
							|  |  |  |  |             e instanceof AST_Chain || | 
					
						
							|  |  |  |  |             is_identifier_atom(e) | 
					
						
							|  |  |  |  |         ) | 
					
						
							|  |  |  |  |     ) { | 
					
						
							|  |  |  |  |         return make_sequence(self, [e, make_node(AST_True, self)]).optimize(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     var seq = self.lift_sequences(compressor); | 
					
						
							|  |  |  |  |     if (seq !== self) { | 
					
						
							|  |  |  |  |         return seq; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (compressor.option("side_effects") && self.operator == "void") { | 
					
						
							|  |  |  |  |         e = e.drop_side_effect_free(compressor); | 
					
						
							|  |  |  |  |         if (e) { | 
					
						
							|  |  |  |  |             self.expression = e; | 
					
						
							|  |  |  |  |             return self; | 
					
						
							|  |  |  |  |         } else { | 
					
						
							|  |  |  |  |             return make_node(AST_Undefined, self).optimize(compressor); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (compressor.in_boolean_context()) { | 
					
						
							|  |  |  |  |         switch (self.operator) { | 
					
						
							|  |  |  |  |           case "!": | 
					
						
							|  |  |  |  |             if (e instanceof AST_UnaryPrefix && e.operator == "!") { | 
					
						
							|  |  |  |  |                 // !!foo ==> foo, if we're in boolean context
 | 
					
						
							|  |  |  |  |                 return e.expression; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             if (e instanceof AST_Binary) { | 
					
						
							|  |  |  |  |                 self = best_of(compressor, self, e.negate(compressor, first_in_statement(compressor))); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |           case "typeof": | 
					
						
							|  |  |  |  |             // typeof always returns a non-empty string, thus it's
 | 
					
						
							|  |  |  |  |             // always true in booleans
 | 
					
						
							|  |  |  |  |             // And we don't need to check if it's undeclared, because in typeof, that's OK
 | 
					
						
							|  |  |  |  |             return (e instanceof AST_SymbolRef ? make_node(AST_True, self) : make_sequence(self, [ | 
					
						
							|  |  |  |  |                 e, | 
					
						
							|  |  |  |  |                 make_node(AST_True, self) | 
					
						
							|  |  |  |  |             ])).optimize(compressor); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (self.operator == "-" && e instanceof AST_Infinity) { | 
					
						
							|  |  |  |  |         e = e.transform(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (e instanceof AST_Binary | 
					
						
							|  |  |  |  |         && (self.operator == "+" || self.operator == "-") | 
					
						
							|  |  |  |  |         && (e.operator == "*" || e.operator == "/" || e.operator == "%")) { | 
					
						
							|  |  |  |  |         return make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |             operator: e.operator, | 
					
						
							|  |  |  |  |             left: make_node(AST_UnaryPrefix, e.left, { | 
					
						
							|  |  |  |  |                 operator: self.operator, | 
					
						
							|  |  |  |  |                 expression: e.left | 
					
						
							|  |  |  |  |             }), | 
					
						
							|  |  |  |  |             right: e.right | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     // avoids infinite recursion of numerals
 | 
					
						
							|  |  |  |  |     if (self.operator != "-" | 
					
						
							|  |  |  |  |         || !(e instanceof AST_Number || e instanceof AST_Infinity || e instanceof AST_BigInt)) { | 
					
						
							|  |  |  |  |         var ev = self.evaluate(compressor); | 
					
						
							|  |  |  |  |         if (ev !== self) { | 
					
						
							|  |  |  |  |             ev = make_node_from_constant(ev, self).optimize(compressor); | 
					
						
							|  |  |  |  |             return best_of(compressor, ev, self); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | AST_Binary.DEFMETHOD("lift_sequences", function(compressor) { | 
					
						
							|  |  |  |  |     if (compressor.option("sequences")) { | 
					
						
							|  |  |  |  |         if (this.left instanceof AST_Sequence) { | 
					
						
							|  |  |  |  |             var x = this.left.expressions.slice(); | 
					
						
							|  |  |  |  |             var e = this.clone(); | 
					
						
							|  |  |  |  |             e.left = x.pop(); | 
					
						
							|  |  |  |  |             x.push(e); | 
					
						
							|  |  |  |  |             return make_sequence(this, x).optimize(compressor); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         if (this.right instanceof AST_Sequence && !this.left.has_side_effects(compressor)) { | 
					
						
							|  |  |  |  |             var assign = this.operator == "=" && this.left instanceof AST_SymbolRef; | 
					
						
							|  |  |  |  |             var x = this.right.expressions; | 
					
						
							|  |  |  |  |             var last = x.length - 1; | 
					
						
							|  |  |  |  |             for (var i = 0; i < last; i++) { | 
					
						
							|  |  |  |  |                 if (!assign && x[i].has_side_effects(compressor)) break; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             if (i == last) { | 
					
						
							|  |  |  |  |                 x = x.slice(); | 
					
						
							|  |  |  |  |                 var e = this.clone(); | 
					
						
							|  |  |  |  |                 e.right = x.pop(); | 
					
						
							|  |  |  |  |                 x.push(e); | 
					
						
							|  |  |  |  |                 return make_sequence(this, x).optimize(compressor); | 
					
						
							|  |  |  |  |             } else if (i > 0) { | 
					
						
							|  |  |  |  |                 var e = this.clone(); | 
					
						
							|  |  |  |  |                 e.right = make_sequence(this.right, x.slice(i)); | 
					
						
							|  |  |  |  |                 x = x.slice(0, i); | 
					
						
							|  |  |  |  |                 x.push(e); | 
					
						
							|  |  |  |  |                 return make_sequence(this, x).optimize(compressor); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return this; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | var commutativeOperators = makePredicate("== === != !== * & | ^"); | 
					
						
							|  |  |  |  | function is_object(node) { | 
					
						
							|  |  |  |  |     return node instanceof AST_Array | 
					
						
							|  |  |  |  |         || node instanceof AST_Lambda | 
					
						
							|  |  |  |  |         || node instanceof AST_Object | 
					
						
							|  |  |  |  |         || node instanceof AST_Class; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Binary, function(self, compressor) { | 
					
						
							|  |  |  |  |     function reversible() { | 
					
						
							|  |  |  |  |         return self.left.is_constant() | 
					
						
							|  |  |  |  |             || self.right.is_constant() | 
					
						
							|  |  |  |  |             || !self.left.has_side_effects(compressor) | 
					
						
							|  |  |  |  |                 && !self.right.has_side_effects(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     function reverse(op) { | 
					
						
							|  |  |  |  |         if (reversible()) { | 
					
						
							|  |  |  |  |             if (op) self.operator = op; | 
					
						
							|  |  |  |  |             var tmp = self.left; | 
					
						
							|  |  |  |  |             self.left = self.right; | 
					
						
							|  |  |  |  |             self.right = tmp; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (commutativeOperators.has(self.operator)) { | 
					
						
							|  |  |  |  |         if (self.right.is_constant() | 
					
						
							|  |  |  |  |             && !self.left.is_constant()) { | 
					
						
							|  |  |  |  |             // if right is a constant, whatever side effects the
 | 
					
						
							|  |  |  |  |             // left side might have could not influence the
 | 
					
						
							|  |  |  |  |             // result.  hence, force switch.
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             if (!(self.left instanceof AST_Binary | 
					
						
							|  |  |  |  |                   && PRECEDENCE[self.left.operator] >= PRECEDENCE[self.operator])) { | 
					
						
							|  |  |  |  |                 reverse(); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     self = self.lift_sequences(compressor); | 
					
						
							|  |  |  |  |     if (compressor.option("comparisons")) switch (self.operator) { | 
					
						
							|  |  |  |  |       case "===": | 
					
						
							|  |  |  |  |       case "!==": | 
					
						
							|  |  |  |  |         var is_strict_comparison = true; | 
					
						
							|  |  |  |  |         if ((self.left.is_string(compressor) && self.right.is_string(compressor)) || | 
					
						
							|  |  |  |  |             (self.left.is_number(compressor) && self.right.is_number(compressor)) || | 
					
						
							|  |  |  |  |             (self.left.is_boolean() && self.right.is_boolean()) || | 
					
						
							|  |  |  |  |             self.left.equivalent_to(self.right)) { | 
					
						
							|  |  |  |  |             self.operator = self.operator.substr(0, 2); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         // XXX: intentionally falling down to the next case
 | 
					
						
							|  |  |  |  |       case "==": | 
					
						
							|  |  |  |  |       case "!=": | 
					
						
							|  |  |  |  |         // void 0 == x => null == x
 | 
					
						
							|  |  |  |  |         if (!is_strict_comparison && is_undefined(self.left, compressor)) { | 
					
						
							|  |  |  |  |             self.left = make_node(AST_Null, self.left); | 
					
						
							|  |  |  |  |         } else if (compressor.option("typeofs") | 
					
						
							|  |  |  |  |             // "undefined" == typeof x => undefined === x
 | 
					
						
							|  |  |  |  |             && self.left instanceof AST_String | 
					
						
							|  |  |  |  |             && self.left.value == "undefined" | 
					
						
							|  |  |  |  |             && self.right instanceof AST_UnaryPrefix | 
					
						
							|  |  |  |  |             && self.right.operator == "typeof") { | 
					
						
							|  |  |  |  |             var expr = self.right.expression; | 
					
						
							|  |  |  |  |             if (expr instanceof AST_SymbolRef ? expr.is_declared(compressor) | 
					
						
							|  |  |  |  |                 : !(expr instanceof AST_PropAccess && compressor.option("ie8"))) { | 
					
						
							|  |  |  |  |                 self.right = expr; | 
					
						
							|  |  |  |  |                 self.left = make_node(AST_Undefined, self.left).optimize(compressor); | 
					
						
							|  |  |  |  |                 if (self.operator.length == 2) self.operator += "="; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } else if (self.left instanceof AST_SymbolRef | 
					
						
							|  |  |  |  |             // obj !== obj => false
 | 
					
						
							|  |  |  |  |             && self.right instanceof AST_SymbolRef | 
					
						
							|  |  |  |  |             && self.left.definition() === self.right.definition() | 
					
						
							|  |  |  |  |             && is_object(self.left.fixed_value())) { | 
					
						
							|  |  |  |  |             return make_node(self.operator[0] == "=" ? AST_True : AST_False, self); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         break; | 
					
						
							|  |  |  |  |       case "&&": | 
					
						
							|  |  |  |  |       case "||": | 
					
						
							|  |  |  |  |         var lhs = self.left; | 
					
						
							|  |  |  |  |         if (lhs.operator == self.operator) { | 
					
						
							|  |  |  |  |             lhs = lhs.right; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         if (lhs instanceof AST_Binary | 
					
						
							|  |  |  |  |             && lhs.operator == (self.operator == "&&" ? "!==" : "===") | 
					
						
							|  |  |  |  |             && self.right instanceof AST_Binary | 
					
						
							|  |  |  |  |             && lhs.operator == self.right.operator | 
					
						
							|  |  |  |  |             && (is_undefined(lhs.left, compressor) && self.right.left instanceof AST_Null | 
					
						
							|  |  |  |  |                 || lhs.left instanceof AST_Null && is_undefined(self.right.left, compressor)) | 
					
						
							|  |  |  |  |             && !lhs.right.has_side_effects(compressor) | 
					
						
							|  |  |  |  |             && lhs.right.equivalent_to(self.right.right)) { | 
					
						
							|  |  |  |  |             var combined = make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                 operator: lhs.operator.slice(0, -1), | 
					
						
							|  |  |  |  |                 left: make_node(AST_Null, self), | 
					
						
							|  |  |  |  |                 right: lhs.right | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |             if (lhs !== self.left) { | 
					
						
							|  |  |  |  |                 combined = make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                     operator: self.operator, | 
					
						
							|  |  |  |  |                     left: self.left.left, | 
					
						
							|  |  |  |  |                     right: combined | 
					
						
							|  |  |  |  |                 }); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             return combined; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         break; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (self.operator == "+" && compressor.in_boolean_context()) { | 
					
						
							|  |  |  |  |         var ll = self.left.evaluate(compressor); | 
					
						
							|  |  |  |  |         var rr = self.right.evaluate(compressor); | 
					
						
							|  |  |  |  |         if (ll && typeof ll == "string") { | 
					
						
							|  |  |  |  |             return make_sequence(self, [ | 
					
						
							|  |  |  |  |                 self.right, | 
					
						
							|  |  |  |  |                 make_node(AST_True, self) | 
					
						
							|  |  |  |  |             ]).optimize(compressor); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         if (rr && typeof rr == "string") { | 
					
						
							|  |  |  |  |             return make_sequence(self, [ | 
					
						
							|  |  |  |  |                 self.left, | 
					
						
							|  |  |  |  |                 make_node(AST_True, self) | 
					
						
							|  |  |  |  |             ]).optimize(compressor); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (compressor.option("comparisons") && self.is_boolean()) { | 
					
						
							|  |  |  |  |         if (!(compressor.parent() instanceof AST_Binary) | 
					
						
							|  |  |  |  |             || compressor.parent() instanceof AST_Assign) { | 
					
						
							|  |  |  |  |             var negated = make_node(AST_UnaryPrefix, self, { | 
					
						
							|  |  |  |  |                 operator: "!", | 
					
						
							|  |  |  |  |                 expression: self.negate(compressor, first_in_statement(compressor)) | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |             self = best_of(compressor, self, negated); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         if (compressor.option("unsafe_comps")) { | 
					
						
							|  |  |  |  |             switch (self.operator) { | 
					
						
							|  |  |  |  |               case "<": reverse(">"); break; | 
					
						
							|  |  |  |  |               case "<=": reverse(">="); break; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (self.operator == "+") { | 
					
						
							|  |  |  |  |         if (self.right instanceof AST_String | 
					
						
							|  |  |  |  |             && self.right.getValue() == "" | 
					
						
							|  |  |  |  |             && self.left.is_string(compressor)) { | 
					
						
							|  |  |  |  |             return self.left; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         if (self.left instanceof AST_String | 
					
						
							|  |  |  |  |             && self.left.getValue() == "" | 
					
						
							|  |  |  |  |             && self.right.is_string(compressor)) { | 
					
						
							|  |  |  |  |             return self.right; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         if (self.left instanceof AST_Binary | 
					
						
							|  |  |  |  |             && self.left.operator == "+" | 
					
						
							|  |  |  |  |             && self.left.left instanceof AST_String | 
					
						
							|  |  |  |  |             && self.left.left.getValue() == "" | 
					
						
							|  |  |  |  |             && self.right.is_string(compressor)) { | 
					
						
							|  |  |  |  |             self.left = self.left.right; | 
					
						
							|  |  |  |  |             return self; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (compressor.option("evaluate")) { | 
					
						
							|  |  |  |  |         switch (self.operator) { | 
					
						
							|  |  |  |  |           case "&&": | 
					
						
							|  |  |  |  |             var ll = has_flag(self.left, TRUTHY) | 
					
						
							|  |  |  |  |                 ? true | 
					
						
							|  |  |  |  |                 : has_flag(self.left, FALSY) | 
					
						
							|  |  |  |  |                     ? false | 
					
						
							|  |  |  |  |                     : self.left.evaluate(compressor); | 
					
						
							|  |  |  |  |             if (!ll) { | 
					
						
							|  |  |  |  |                 return maintain_this_binding(compressor.parent(), compressor.self(), self.left).optimize(compressor); | 
					
						
							|  |  |  |  |             } else if (!(ll instanceof AST_Node)) { | 
					
						
							|  |  |  |  |                 return make_sequence(self, [ self.left, self.right ]).optimize(compressor); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             var rr = self.right.evaluate(compressor); | 
					
						
							|  |  |  |  |             if (!rr) { | 
					
						
							|  |  |  |  |                 if (compressor.in_boolean_context()) { | 
					
						
							|  |  |  |  |                     return make_sequence(self, [ | 
					
						
							|  |  |  |  |                         self.left, | 
					
						
							|  |  |  |  |                         make_node(AST_False, self) | 
					
						
							|  |  |  |  |                     ]).optimize(compressor); | 
					
						
							|  |  |  |  |                 } else { | 
					
						
							|  |  |  |  |                     set_flag(self, FALSY); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } else if (!(rr instanceof AST_Node)) { | 
					
						
							|  |  |  |  |                 var parent = compressor.parent(); | 
					
						
							|  |  |  |  |                 if (parent.operator == "&&" && parent.left === compressor.self() || compressor.in_boolean_context()) { | 
					
						
							|  |  |  |  |                     return self.left.optimize(compressor); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             // x || false && y ---> x ? y : false
 | 
					
						
							|  |  |  |  |             if (self.left.operator == "||") { | 
					
						
							|  |  |  |  |                 var lr = self.left.right.evaluate(compressor); | 
					
						
							|  |  |  |  |                 if (!lr) return make_node(AST_Conditional, self, { | 
					
						
							|  |  |  |  |                     condition: self.left.left, | 
					
						
							|  |  |  |  |                     consequent: self.right, | 
					
						
							|  |  |  |  |                     alternative: self.left.right | 
					
						
							|  |  |  |  |                 }).optimize(compressor); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |           case "||": | 
					
						
							|  |  |  |  |             var ll = has_flag(self.left, TRUTHY) | 
					
						
							|  |  |  |  |               ? true | 
					
						
							|  |  |  |  |               : has_flag(self.left, FALSY) | 
					
						
							|  |  |  |  |                 ? false | 
					
						
							|  |  |  |  |                 : self.left.evaluate(compressor); | 
					
						
							|  |  |  |  |             if (!ll) { | 
					
						
							|  |  |  |  |                 return make_sequence(self, [ self.left, self.right ]).optimize(compressor); | 
					
						
							|  |  |  |  |             } else if (!(ll instanceof AST_Node)) { | 
					
						
							|  |  |  |  |                 return maintain_this_binding(compressor.parent(), compressor.self(), self.left).optimize(compressor); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             var rr = self.right.evaluate(compressor); | 
					
						
							|  |  |  |  |             if (!rr) { | 
					
						
							|  |  |  |  |                 var parent = compressor.parent(); | 
					
						
							|  |  |  |  |                 if (parent.operator == "||" && parent.left === compressor.self() || compressor.in_boolean_context()) { | 
					
						
							|  |  |  |  |                     return self.left.optimize(compressor); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } else if (!(rr instanceof AST_Node)) { | 
					
						
							|  |  |  |  |                 if (compressor.in_boolean_context()) { | 
					
						
							|  |  |  |  |                     return make_sequence(self, [ | 
					
						
							|  |  |  |  |                         self.left, | 
					
						
							|  |  |  |  |                         make_node(AST_True, self) | 
					
						
							|  |  |  |  |                     ]).optimize(compressor); | 
					
						
							|  |  |  |  |                 } else { | 
					
						
							|  |  |  |  |                     set_flag(self, TRUTHY); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             if (self.left.operator == "&&") { | 
					
						
							|  |  |  |  |                 var lr = self.left.right.evaluate(compressor); | 
					
						
							|  |  |  |  |                 if (lr && !(lr instanceof AST_Node)) return make_node(AST_Conditional, self, { | 
					
						
							|  |  |  |  |                     condition: self.left.left, | 
					
						
							|  |  |  |  |                     consequent: self.left.right, | 
					
						
							|  |  |  |  |                     alternative: self.right | 
					
						
							|  |  |  |  |                 }).optimize(compressor); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |           case "??": | 
					
						
							|  |  |  |  |             if (is_nullish(self.left, compressor)) { | 
					
						
							|  |  |  |  |                 return self.right; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             var ll = self.left.evaluate(compressor); | 
					
						
							|  |  |  |  |             if (!(ll instanceof AST_Node)) { | 
					
						
							|  |  |  |  |                 // if we know the value for sure we can simply compute right away.
 | 
					
						
							|  |  |  |  |                 return ll == null ? self.right : self.left; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             if (compressor.in_boolean_context()) { | 
					
						
							|  |  |  |  |                 const rr = self.right.evaluate(compressor); | 
					
						
							|  |  |  |  |                 if (!(rr instanceof AST_Node) && !rr) { | 
					
						
							|  |  |  |  |                     return self.left; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         var associative = true; | 
					
						
							|  |  |  |  |         switch (self.operator) { | 
					
						
							|  |  |  |  |           case "+": | 
					
						
							|  |  |  |  |             // (x + "foo") + "bar" => x + "foobar"
 | 
					
						
							|  |  |  |  |             if (self.right instanceof AST_Constant | 
					
						
							|  |  |  |  |                 && self.left instanceof AST_Binary | 
					
						
							|  |  |  |  |                 && self.left.operator == "+" | 
					
						
							|  |  |  |  |                 && self.left.is_string(compressor)) { | 
					
						
							|  |  |  |  |                 var binary = make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                     operator: "+", | 
					
						
							|  |  |  |  |                     left: self.left.right, | 
					
						
							|  |  |  |  |                     right: self.right, | 
					
						
							|  |  |  |  |                 }); | 
					
						
							|  |  |  |  |                 var r = binary.optimize(compressor); | 
					
						
							|  |  |  |  |                 if (binary !== r) { | 
					
						
							|  |  |  |  |                     self = make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                         operator: "+", | 
					
						
							|  |  |  |  |                         left: self.left.left, | 
					
						
							|  |  |  |  |                         right: r | 
					
						
							|  |  |  |  |                     }); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             // (x + "foo") + ("bar" + y) => (x + "foobar") + y
 | 
					
						
							|  |  |  |  |             if (self.left instanceof AST_Binary | 
					
						
							|  |  |  |  |                 && self.left.operator == "+" | 
					
						
							|  |  |  |  |                 && self.left.is_string(compressor) | 
					
						
							|  |  |  |  |                 && self.right instanceof AST_Binary | 
					
						
							|  |  |  |  |                 && self.right.operator == "+" | 
					
						
							|  |  |  |  |                 && self.right.is_string(compressor)) { | 
					
						
							|  |  |  |  |                 var binary = make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                     operator: "+", | 
					
						
							|  |  |  |  |                     left: self.left.right, | 
					
						
							|  |  |  |  |                     right: self.right.left, | 
					
						
							|  |  |  |  |                 }); | 
					
						
							|  |  |  |  |                 var m = binary.optimize(compressor); | 
					
						
							|  |  |  |  |                 if (binary !== m) { | 
					
						
							|  |  |  |  |                     self = make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                         operator: "+", | 
					
						
							|  |  |  |  |                         left: make_node(AST_Binary, self.left, { | 
					
						
							|  |  |  |  |                             operator: "+", | 
					
						
							|  |  |  |  |                             left: self.left.left, | 
					
						
							|  |  |  |  |                             right: m | 
					
						
							|  |  |  |  |                         }), | 
					
						
							|  |  |  |  |                         right: self.right.right | 
					
						
							|  |  |  |  |                     }); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             // a + -b => a - b
 | 
					
						
							|  |  |  |  |             if (self.right instanceof AST_UnaryPrefix | 
					
						
							|  |  |  |  |                 && self.right.operator == "-" | 
					
						
							|  |  |  |  |                 && self.left.is_number(compressor)) { | 
					
						
							|  |  |  |  |                 self = make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                     operator: "-", | 
					
						
							|  |  |  |  |                     left: self.left, | 
					
						
							|  |  |  |  |                     right: self.right.expression | 
					
						
							|  |  |  |  |                 }); | 
					
						
							|  |  |  |  |                 break; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             // -a + b => b - a
 | 
					
						
							|  |  |  |  |             if (self.left instanceof AST_UnaryPrefix | 
					
						
							|  |  |  |  |                 && self.left.operator == "-" | 
					
						
							|  |  |  |  |                 && reversible() | 
					
						
							|  |  |  |  |                 && self.right.is_number(compressor)) { | 
					
						
							|  |  |  |  |                 self = make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                     operator: "-", | 
					
						
							|  |  |  |  |                     left: self.right, | 
					
						
							|  |  |  |  |                     right: self.left.expression | 
					
						
							|  |  |  |  |                 }); | 
					
						
							|  |  |  |  |                 break; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             // `foo${bar}baz` + 1 => `foo${bar}baz1`
 | 
					
						
							|  |  |  |  |             if (self.left instanceof AST_TemplateString) { | 
					
						
							|  |  |  |  |                 var l = self.left; | 
					
						
							|  |  |  |  |                 var r = self.right.evaluate(compressor); | 
					
						
							|  |  |  |  |                 if (r != self.right) { | 
					
						
							|  |  |  |  |                     l.segments[l.segments.length - 1].value += String(r); | 
					
						
							|  |  |  |  |                     return l; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             // 1 + `foo${bar}baz` => `1foo${bar}baz`
 | 
					
						
							|  |  |  |  |             if (self.right instanceof AST_TemplateString) { | 
					
						
							|  |  |  |  |                 var r = self.right; | 
					
						
							|  |  |  |  |                 var l = self.left.evaluate(compressor); | 
					
						
							|  |  |  |  |                 if (l != self.left) { | 
					
						
							|  |  |  |  |                     r.segments[0].value = String(l) + r.segments[0].value; | 
					
						
							|  |  |  |  |                     return r; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             // `1${bar}2` + `foo${bar}baz` => `1${bar}2foo${bar}baz`
 | 
					
						
							|  |  |  |  |             if (self.left instanceof AST_TemplateString | 
					
						
							|  |  |  |  |                 && self.right instanceof AST_TemplateString) { | 
					
						
							|  |  |  |  |                 var l = self.left; | 
					
						
							|  |  |  |  |                 var segments = l.segments; | 
					
						
							|  |  |  |  |                 var r = self.right; | 
					
						
							|  |  |  |  |                 segments[segments.length - 1].value += r.segments[0].value; | 
					
						
							|  |  |  |  |                 for (var i = 1; i < r.segments.length; i++) { | 
					
						
							|  |  |  |  |                     segments.push(r.segments[i]); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |                 return l; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |           case "*": | 
					
						
							|  |  |  |  |             associative = compressor.option("unsafe_math"); | 
					
						
							|  |  |  |  |           case "&": | 
					
						
							|  |  |  |  |           case "|": | 
					
						
							|  |  |  |  |           case "^": | 
					
						
							|  |  |  |  |             // a + +b => +b + a
 | 
					
						
							|  |  |  |  |             if (self.left.is_number(compressor) | 
					
						
							|  |  |  |  |                 && self.right.is_number(compressor) | 
					
						
							|  |  |  |  |                 && reversible() | 
					
						
							|  |  |  |  |                 && !(self.left instanceof AST_Binary | 
					
						
							|  |  |  |  |                     && self.left.operator != self.operator | 
					
						
							|  |  |  |  |                     && PRECEDENCE[self.left.operator] >= PRECEDENCE[self.operator])) { | 
					
						
							|  |  |  |  |                 var reversed = make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                     operator: self.operator, | 
					
						
							|  |  |  |  |                     left: self.right, | 
					
						
							|  |  |  |  |                     right: self.left | 
					
						
							|  |  |  |  |                 }); | 
					
						
							|  |  |  |  |                 if (self.right instanceof AST_Constant | 
					
						
							|  |  |  |  |                     && !(self.left instanceof AST_Constant)) { | 
					
						
							|  |  |  |  |                     self = best_of(compressor, reversed, self); | 
					
						
							|  |  |  |  |                 } else { | 
					
						
							|  |  |  |  |                     self = best_of(compressor, self, reversed); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             if (associative && self.is_number(compressor)) { | 
					
						
							|  |  |  |  |                 // a + (b + c) => (a + b) + c
 | 
					
						
							|  |  |  |  |                 if (self.right instanceof AST_Binary | 
					
						
							|  |  |  |  |                     && self.right.operator == self.operator) { | 
					
						
							|  |  |  |  |                     self = make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                         operator: self.operator, | 
					
						
							|  |  |  |  |                         left: make_node(AST_Binary, self.left, { | 
					
						
							|  |  |  |  |                             operator: self.operator, | 
					
						
							|  |  |  |  |                             left: self.left, | 
					
						
							|  |  |  |  |                             right: self.right.left, | 
					
						
							|  |  |  |  |                             start: self.left.start, | 
					
						
							|  |  |  |  |                             end: self.right.left.end | 
					
						
							|  |  |  |  |                         }), | 
					
						
							|  |  |  |  |                         right: self.right.right | 
					
						
							|  |  |  |  |                     }); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |                 // (n + 2) + 3 => 5 + n
 | 
					
						
							|  |  |  |  |                 // (2 * n) * 3 => 6 + n
 | 
					
						
							|  |  |  |  |                 if (self.right instanceof AST_Constant | 
					
						
							|  |  |  |  |                     && self.left instanceof AST_Binary | 
					
						
							|  |  |  |  |                     && self.left.operator == self.operator) { | 
					
						
							|  |  |  |  |                     if (self.left.left instanceof AST_Constant) { | 
					
						
							|  |  |  |  |                         self = make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                             operator: self.operator, | 
					
						
							|  |  |  |  |                             left: make_node(AST_Binary, self.left, { | 
					
						
							|  |  |  |  |                                 operator: self.operator, | 
					
						
							|  |  |  |  |                                 left: self.left.left, | 
					
						
							|  |  |  |  |                                 right: self.right, | 
					
						
							|  |  |  |  |                                 start: self.left.left.start, | 
					
						
							|  |  |  |  |                                 end: self.right.end | 
					
						
							|  |  |  |  |                             }), | 
					
						
							|  |  |  |  |                             right: self.left.right | 
					
						
							|  |  |  |  |                         }); | 
					
						
							|  |  |  |  |                     } else if (self.left.right instanceof AST_Constant) { | 
					
						
							|  |  |  |  |                         self = make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                             operator: self.operator, | 
					
						
							|  |  |  |  |                             left: make_node(AST_Binary, self.left, { | 
					
						
							|  |  |  |  |                                 operator: self.operator, | 
					
						
							|  |  |  |  |                                 left: self.left.right, | 
					
						
							|  |  |  |  |                                 right: self.right, | 
					
						
							|  |  |  |  |                                 start: self.left.right.start, | 
					
						
							|  |  |  |  |                                 end: self.right.end | 
					
						
							|  |  |  |  |                             }), | 
					
						
							|  |  |  |  |                             right: self.left.left | 
					
						
							|  |  |  |  |                         }); | 
					
						
							|  |  |  |  |                     } | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |                 // (a | 1) | (2 | d) => (3 | a) | b
 | 
					
						
							|  |  |  |  |                 if (self.left instanceof AST_Binary | 
					
						
							|  |  |  |  |                     && self.left.operator == self.operator | 
					
						
							|  |  |  |  |                     && self.left.right instanceof AST_Constant | 
					
						
							|  |  |  |  |                     && self.right instanceof AST_Binary | 
					
						
							|  |  |  |  |                     && self.right.operator == self.operator | 
					
						
							|  |  |  |  |                     && self.right.left instanceof AST_Constant) { | 
					
						
							|  |  |  |  |                     self = make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                         operator: self.operator, | 
					
						
							|  |  |  |  |                         left: make_node(AST_Binary, self.left, { | 
					
						
							|  |  |  |  |                             operator: self.operator, | 
					
						
							|  |  |  |  |                             left: make_node(AST_Binary, self.left.left, { | 
					
						
							|  |  |  |  |                                 operator: self.operator, | 
					
						
							|  |  |  |  |                                 left: self.left.right, | 
					
						
							|  |  |  |  |                                 right: self.right.left, | 
					
						
							|  |  |  |  |                                 start: self.left.right.start, | 
					
						
							|  |  |  |  |                                 end: self.right.left.end | 
					
						
							|  |  |  |  |                             }), | 
					
						
							|  |  |  |  |                             right: self.left.left | 
					
						
							|  |  |  |  |                         }), | 
					
						
							|  |  |  |  |                         right: self.right.right | 
					
						
							|  |  |  |  |                     }); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     // x && (y && z)  ==>  x && y && z
 | 
					
						
							|  |  |  |  |     // x || (y || z)  ==>  x || y || z
 | 
					
						
							|  |  |  |  |     // x + ("y" + z)  ==>  x + "y" + z
 | 
					
						
							|  |  |  |  |     // "x" + (y + "z")==>  "x" + y + "z"
 | 
					
						
							|  |  |  |  |     if (self.right instanceof AST_Binary | 
					
						
							|  |  |  |  |         && self.right.operator == self.operator | 
					
						
							|  |  |  |  |         && (lazy_op.has(self.operator) | 
					
						
							|  |  |  |  |             || (self.operator == "+" | 
					
						
							|  |  |  |  |                 && (self.right.left.is_string(compressor) | 
					
						
							|  |  |  |  |                     || (self.left.is_string(compressor) | 
					
						
							|  |  |  |  |                         && self.right.right.is_string(compressor))))) | 
					
						
							|  |  |  |  |     ) { | 
					
						
							|  |  |  |  |         self.left = make_node(AST_Binary, self.left, { | 
					
						
							|  |  |  |  |             operator : self.operator, | 
					
						
							|  |  |  |  |             left     : self.left.transform(compressor), | 
					
						
							|  |  |  |  |             right    : self.right.left.transform(compressor) | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |         self.right = self.right.right.transform(compressor); | 
					
						
							|  |  |  |  |         return self.transform(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     var ev = self.evaluate(compressor); | 
					
						
							|  |  |  |  |     if (ev !== self) { | 
					
						
							|  |  |  |  |         ev = make_node_from_constant(ev, self).optimize(compressor); | 
					
						
							|  |  |  |  |         return best_of(compressor, ev, self); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_SymbolExport, function(self) { | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_SymbolRef, function(self, compressor) { | 
					
						
							|  |  |  |  |     if ( | 
					
						
							|  |  |  |  |         !compressor.option("ie8") | 
					
						
							|  |  |  |  |         && is_undeclared_ref(self) | 
					
						
							|  |  |  |  |         && !compressor.find_parent(AST_With) | 
					
						
							|  |  |  |  |     ) { | 
					
						
							|  |  |  |  |         switch (self.name) { | 
					
						
							|  |  |  |  |           case "undefined": | 
					
						
							|  |  |  |  |             return make_node(AST_Undefined, self).optimize(compressor); | 
					
						
							|  |  |  |  |           case "NaN": | 
					
						
							|  |  |  |  |             return make_node(AST_NaN, self).optimize(compressor); | 
					
						
							|  |  |  |  |           case "Infinity": | 
					
						
							|  |  |  |  |             return make_node(AST_Infinity, self).optimize(compressor); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     const parent = compressor.parent(); | 
					
						
							|  |  |  |  |     if (compressor.option("reduce_vars") && is_lhs(self, parent) !== self) { | 
					
						
							|  |  |  |  |         return inline_into_symbolref(self, compressor); | 
					
						
							|  |  |  |  |     } else { | 
					
						
							|  |  |  |  |         return self; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function is_atomic(lhs, self) { | 
					
						
							|  |  |  |  |     return lhs instanceof AST_SymbolRef || lhs.TYPE === self.TYPE; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Undefined, function(self, compressor) { | 
					
						
							|  |  |  |  |     if (compressor.option("unsafe_undefined")) { | 
					
						
							|  |  |  |  |         var undef = find_variable(compressor, "undefined"); | 
					
						
							|  |  |  |  |         if (undef) { | 
					
						
							|  |  |  |  |             var ref = make_node(AST_SymbolRef, self, { | 
					
						
							|  |  |  |  |                 name   : "undefined", | 
					
						
							|  |  |  |  |                 scope  : undef.scope, | 
					
						
							|  |  |  |  |                 thedef : undef | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |             set_flag(ref, UNDEFINED); | 
					
						
							|  |  |  |  |             return ref; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     var lhs = is_lhs(compressor.self(), compressor.parent()); | 
					
						
							|  |  |  |  |     if (lhs && is_atomic(lhs, self)) return self; | 
					
						
							|  |  |  |  |     return make_node(AST_UnaryPrefix, self, { | 
					
						
							|  |  |  |  |         operator: "void", | 
					
						
							|  |  |  |  |         expression: make_node(AST_Number, self, { | 
					
						
							|  |  |  |  |             value: 0 | 
					
						
							|  |  |  |  |         }) | 
					
						
							|  |  |  |  |     }); | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Infinity, function(self, compressor) { | 
					
						
							|  |  |  |  |     var lhs = is_lhs(compressor.self(), compressor.parent()); | 
					
						
							|  |  |  |  |     if (lhs && is_atomic(lhs, self)) return self; | 
					
						
							|  |  |  |  |     if ( | 
					
						
							|  |  |  |  |         compressor.option("keep_infinity") | 
					
						
							|  |  |  |  |         && !(lhs && !is_atomic(lhs, self)) | 
					
						
							|  |  |  |  |         && !find_variable(compressor, "Infinity") | 
					
						
							|  |  |  |  |     ) { | 
					
						
							|  |  |  |  |         return self; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |         operator: "/", | 
					
						
							|  |  |  |  |         left: make_node(AST_Number, self, { | 
					
						
							|  |  |  |  |             value: 1 | 
					
						
							|  |  |  |  |         }), | 
					
						
							|  |  |  |  |         right: make_node(AST_Number, self, { | 
					
						
							|  |  |  |  |             value: 0 | 
					
						
							|  |  |  |  |         }) | 
					
						
							|  |  |  |  |     }); | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_NaN, function(self, compressor) { | 
					
						
							|  |  |  |  |     var lhs = is_lhs(compressor.self(), compressor.parent()); | 
					
						
							|  |  |  |  |     if (lhs && !is_atomic(lhs, self) | 
					
						
							|  |  |  |  |         || find_variable(compressor, "NaN")) { | 
					
						
							|  |  |  |  |         return make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |             operator: "/", | 
					
						
							|  |  |  |  |             left: make_node(AST_Number, self, { | 
					
						
							|  |  |  |  |                 value: 0 | 
					
						
							|  |  |  |  |             }), | 
					
						
							|  |  |  |  |             right: make_node(AST_Number, self, { | 
					
						
							|  |  |  |  |                 value: 0 | 
					
						
							|  |  |  |  |             }) | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | const ASSIGN_OPS = makePredicate("+ - / * % >> << >>> | ^ &"); | 
					
						
							|  |  |  |  | const ASSIGN_OPS_COMMUTATIVE = makePredicate("* | ^ &"); | 
					
						
							|  |  |  |  | def_optimize(AST_Assign, function(self, compressor) { | 
					
						
							|  |  |  |  |     if (self.logical) { | 
					
						
							|  |  |  |  |         return self.lift_sequences(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     var def; | 
					
						
							|  |  |  |  |     // x = x ---> x
 | 
					
						
							|  |  |  |  |     if ( | 
					
						
							|  |  |  |  |         self.operator === "=" | 
					
						
							|  |  |  |  |         && self.left instanceof AST_SymbolRef | 
					
						
							|  |  |  |  |         && self.left.name !== "arguments" | 
					
						
							|  |  |  |  |         && !(def = self.left.definition()).undeclared | 
					
						
							|  |  |  |  |         && self.right.equivalent_to(self.left) | 
					
						
							|  |  |  |  |     ) { | 
					
						
							|  |  |  |  |         return self.right; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (compressor.option("dead_code") | 
					
						
							|  |  |  |  |         && self.left instanceof AST_SymbolRef | 
					
						
							|  |  |  |  |         && (def = self.left.definition()).scope === compressor.find_parent(AST_Lambda)) { | 
					
						
							|  |  |  |  |         var level = 0, node, parent = self; | 
					
						
							|  |  |  |  |         do { | 
					
						
							|  |  |  |  |             node = parent; | 
					
						
							|  |  |  |  |             parent = compressor.parent(level++); | 
					
						
							|  |  |  |  |             if (parent instanceof AST_Exit) { | 
					
						
							|  |  |  |  |                 if (in_try(level, parent)) break; | 
					
						
							|  |  |  |  |                 if (is_reachable(def.scope, [ def ])) break; | 
					
						
							|  |  |  |  |                 if (self.operator == "=") return self.right; | 
					
						
							|  |  |  |  |                 def.fixed = false; | 
					
						
							|  |  |  |  |                 return make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                     operator: self.operator.slice(0, -1), | 
					
						
							|  |  |  |  |                     left: self.left, | 
					
						
							|  |  |  |  |                     right: self.right | 
					
						
							|  |  |  |  |                 }).optimize(compressor); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } while (parent instanceof AST_Binary && parent.right === node | 
					
						
							|  |  |  |  |             || parent instanceof AST_Sequence && parent.tail_node() === node); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     self = self.lift_sequences(compressor); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) { | 
					
						
							|  |  |  |  |         // x = expr1 OP expr2
 | 
					
						
							|  |  |  |  |         if (self.right.left instanceof AST_SymbolRef | 
					
						
							|  |  |  |  |             && self.right.left.name == self.left.name | 
					
						
							|  |  |  |  |             && ASSIGN_OPS.has(self.right.operator)) { | 
					
						
							|  |  |  |  |             // x = x - 2  --->  x -= 2
 | 
					
						
							|  |  |  |  |             self.operator = self.right.operator + "="; | 
					
						
							|  |  |  |  |             self.right = self.right.right; | 
					
						
							|  |  |  |  |         } else if (self.right.right instanceof AST_SymbolRef | 
					
						
							|  |  |  |  |             && self.right.right.name == self.left.name | 
					
						
							|  |  |  |  |             && ASSIGN_OPS_COMMUTATIVE.has(self.right.operator) | 
					
						
							|  |  |  |  |             && !self.right.left.has_side_effects(compressor)) { | 
					
						
							|  |  |  |  |             // x = 2 & x  --->  x &= 2
 | 
					
						
							|  |  |  |  |             self.operator = self.right.operator + "="; | 
					
						
							|  |  |  |  |             self.right = self.right.left; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     function in_try(level, node) { | 
					
						
							|  |  |  |  |         var right = self.right; | 
					
						
							|  |  |  |  |         self.right = make_node(AST_Null, right); | 
					
						
							|  |  |  |  |         var may_throw = node.may_throw(compressor); | 
					
						
							|  |  |  |  |         self.right = right; | 
					
						
							|  |  |  |  |         var scope = self.left.definition().scope; | 
					
						
							|  |  |  |  |         var parent; | 
					
						
							|  |  |  |  |         while ((parent = compressor.parent(level++)) !== scope) { | 
					
						
							|  |  |  |  |             if (parent instanceof AST_Try) { | 
					
						
							|  |  |  |  |                 if (parent.bfinally) return true; | 
					
						
							|  |  |  |  |                 if (may_throw && parent.bcatch) return true; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_DefaultAssign, function(self, compressor) { | 
					
						
							|  |  |  |  |     if (!compressor.option("evaluate")) { | 
					
						
							|  |  |  |  |         return self; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     var evaluateRight = self.right.evaluate(compressor); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // `[x = undefined] = foo` ---> `[x] = foo`
 | 
					
						
							|  |  |  |  |     if (evaluateRight === undefined) { | 
					
						
							|  |  |  |  |         self = self.left; | 
					
						
							|  |  |  |  |     } else if (evaluateRight !== self.right) { | 
					
						
							|  |  |  |  |         evaluateRight = make_node_from_constant(evaluateRight, self.right); | 
					
						
							|  |  |  |  |         self.right = best_of_expression(evaluateRight, self.right); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function is_nullish_check(check, check_subject, compressor) { | 
					
						
							|  |  |  |  |     if (check_subject.may_throw(compressor)) return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     let nullish_side; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // foo == null
 | 
					
						
							|  |  |  |  |     if ( | 
					
						
							|  |  |  |  |         check instanceof AST_Binary | 
					
						
							|  |  |  |  |         && check.operator === "==" | 
					
						
							|  |  |  |  |         // which side is nullish?
 | 
					
						
							|  |  |  |  |         && ( | 
					
						
							|  |  |  |  |             (nullish_side = is_nullish(check.left, compressor) && check.left) | 
					
						
							|  |  |  |  |             || (nullish_side = is_nullish(check.right, compressor) && check.right) | 
					
						
							|  |  |  |  |         ) | 
					
						
							|  |  |  |  |         // is the other side the same as the check_subject
 | 
					
						
							|  |  |  |  |         && ( | 
					
						
							|  |  |  |  |             nullish_side === check.left | 
					
						
							|  |  |  |  |                 ? check.right | 
					
						
							|  |  |  |  |                 : check.left | 
					
						
							|  |  |  |  |         ).equivalent_to(check_subject) | 
					
						
							|  |  |  |  |     ) { | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // foo === null || foo === undefined
 | 
					
						
							|  |  |  |  |     if (check instanceof AST_Binary && check.operator === "||") { | 
					
						
							|  |  |  |  |         let null_cmp; | 
					
						
							|  |  |  |  |         let undefined_cmp; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         const find_comparison = cmp => { | 
					
						
							|  |  |  |  |             if (!( | 
					
						
							|  |  |  |  |                 cmp instanceof AST_Binary | 
					
						
							|  |  |  |  |                 && (cmp.operator === "===" || cmp.operator === "==") | 
					
						
							|  |  |  |  |             )) { | 
					
						
							|  |  |  |  |                 return false; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             let found = 0; | 
					
						
							|  |  |  |  |             let defined_side; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             if (cmp.left instanceof AST_Null) { | 
					
						
							|  |  |  |  |                 found++; | 
					
						
							|  |  |  |  |                 null_cmp = cmp; | 
					
						
							|  |  |  |  |                 defined_side = cmp.right; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             if (cmp.right instanceof AST_Null) { | 
					
						
							|  |  |  |  |                 found++; | 
					
						
							|  |  |  |  |                 null_cmp = cmp; | 
					
						
							|  |  |  |  |                 defined_side = cmp.left; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             if (is_undefined(cmp.left, compressor)) { | 
					
						
							|  |  |  |  |                 found++; | 
					
						
							|  |  |  |  |                 undefined_cmp = cmp; | 
					
						
							|  |  |  |  |                 defined_side = cmp.right; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             if (is_undefined(cmp.right, compressor)) { | 
					
						
							|  |  |  |  |                 found++; | 
					
						
							|  |  |  |  |                 undefined_cmp = cmp; | 
					
						
							|  |  |  |  |                 defined_side = cmp.left; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             if (found !== 1) { | 
					
						
							|  |  |  |  |                 return false; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             if (!defined_side.equivalent_to(check_subject)) { | 
					
						
							|  |  |  |  |                 return false; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             return true; | 
					
						
							|  |  |  |  |         }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (!find_comparison(check.left)) return false; | 
					
						
							|  |  |  |  |         if (!find_comparison(check.right)) return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (null_cmp && undefined_cmp && null_cmp !== undefined_cmp) { | 
					
						
							|  |  |  |  |             return true; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     return false; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Conditional, function(self, compressor) { | 
					
						
							|  |  |  |  |     if (!compressor.option("conditionals")) return self; | 
					
						
							|  |  |  |  |     // This looks like lift_sequences(), should probably be under "sequences"
 | 
					
						
							|  |  |  |  |     if (self.condition instanceof AST_Sequence) { | 
					
						
							|  |  |  |  |         var expressions = self.condition.expressions.slice(); | 
					
						
							|  |  |  |  |         self.condition = expressions.pop(); | 
					
						
							|  |  |  |  |         expressions.push(self); | 
					
						
							|  |  |  |  |         return make_sequence(self, expressions); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     var cond = self.condition.evaluate(compressor); | 
					
						
							|  |  |  |  |     if (cond !== self.condition) { | 
					
						
							|  |  |  |  |         if (cond) { | 
					
						
							|  |  |  |  |             return maintain_this_binding(compressor.parent(), compressor.self(), self.consequent); | 
					
						
							|  |  |  |  |         } else { | 
					
						
							|  |  |  |  |             return maintain_this_binding(compressor.parent(), compressor.self(), self.alternative); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     var negated = cond.negate(compressor, first_in_statement(compressor)); | 
					
						
							|  |  |  |  |     if (best_of(compressor, cond, negated) === negated) { | 
					
						
							|  |  |  |  |         self = make_node(AST_Conditional, self, { | 
					
						
							|  |  |  |  |             condition: negated, | 
					
						
							|  |  |  |  |             consequent: self.alternative, | 
					
						
							|  |  |  |  |             alternative: self.consequent | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     var condition = self.condition; | 
					
						
							|  |  |  |  |     var consequent = self.consequent; | 
					
						
							|  |  |  |  |     var alternative = self.alternative; | 
					
						
							|  |  |  |  |     // x?x:y --> x||y
 | 
					
						
							|  |  |  |  |     if (condition instanceof AST_SymbolRef | 
					
						
							|  |  |  |  |         && consequent instanceof AST_SymbolRef | 
					
						
							|  |  |  |  |         && condition.definition() === consequent.definition()) { | 
					
						
							|  |  |  |  |         return make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |             operator: "||", | 
					
						
							|  |  |  |  |             left: condition, | 
					
						
							|  |  |  |  |             right: alternative | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     // if (foo) exp = something; else exp = something_else;
 | 
					
						
							|  |  |  |  |     //                   |
 | 
					
						
							|  |  |  |  |     //                   v
 | 
					
						
							|  |  |  |  |     // exp = foo ? something : something_else;
 | 
					
						
							|  |  |  |  |     if ( | 
					
						
							|  |  |  |  |         consequent instanceof AST_Assign | 
					
						
							|  |  |  |  |         && alternative instanceof AST_Assign | 
					
						
							|  |  |  |  |         && consequent.operator === alternative.operator | 
					
						
							|  |  |  |  |         && consequent.logical === alternative.logical | 
					
						
							|  |  |  |  |         && consequent.left.equivalent_to(alternative.left) | 
					
						
							|  |  |  |  |         && (!self.condition.has_side_effects(compressor) | 
					
						
							|  |  |  |  |             || consequent.operator == "=" | 
					
						
							|  |  |  |  |                 && !consequent.left.has_side_effects(compressor)) | 
					
						
							|  |  |  |  |     ) { | 
					
						
							|  |  |  |  |         return make_node(AST_Assign, self, { | 
					
						
							|  |  |  |  |             operator: consequent.operator, | 
					
						
							|  |  |  |  |             left: consequent.left, | 
					
						
							|  |  |  |  |             logical: consequent.logical, | 
					
						
							|  |  |  |  |             right: make_node(AST_Conditional, self, { | 
					
						
							|  |  |  |  |                 condition: self.condition, | 
					
						
							|  |  |  |  |                 consequent: consequent.right, | 
					
						
							|  |  |  |  |                 alternative: alternative.right | 
					
						
							|  |  |  |  |             }) | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     // x ? y(a) : y(b) --> y(x ? a : b)
 | 
					
						
							|  |  |  |  |     var arg_index; | 
					
						
							|  |  |  |  |     if (consequent instanceof AST_Call | 
					
						
							|  |  |  |  |         && alternative.TYPE === consequent.TYPE | 
					
						
							|  |  |  |  |         && consequent.args.length > 0 | 
					
						
							|  |  |  |  |         && consequent.args.length == alternative.args.length | 
					
						
							|  |  |  |  |         && consequent.expression.equivalent_to(alternative.expression) | 
					
						
							|  |  |  |  |         && !self.condition.has_side_effects(compressor) | 
					
						
							|  |  |  |  |         && !consequent.expression.has_side_effects(compressor) | 
					
						
							|  |  |  |  |         && typeof (arg_index = single_arg_diff()) == "number") { | 
					
						
							|  |  |  |  |         var node = consequent.clone(); | 
					
						
							|  |  |  |  |         node.args[arg_index] = make_node(AST_Conditional, self, { | 
					
						
							|  |  |  |  |             condition: self.condition, | 
					
						
							|  |  |  |  |             consequent: consequent.args[arg_index], | 
					
						
							|  |  |  |  |             alternative: alternative.args[arg_index] | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |         return node; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     // a ? b : c ? b : d --> (a || c) ? b : d
 | 
					
						
							|  |  |  |  |     if (alternative instanceof AST_Conditional | 
					
						
							|  |  |  |  |         && consequent.equivalent_to(alternative.consequent)) { | 
					
						
							|  |  |  |  |         return make_node(AST_Conditional, self, { | 
					
						
							|  |  |  |  |             condition: make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                 operator: "||", | 
					
						
							|  |  |  |  |                 left: condition, | 
					
						
							|  |  |  |  |                 right: alternative.condition | 
					
						
							|  |  |  |  |             }), | 
					
						
							|  |  |  |  |             consequent: consequent, | 
					
						
							|  |  |  |  |             alternative: alternative.alternative | 
					
						
							|  |  |  |  |         }).optimize(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // a == null ? b : a -> a ?? b
 | 
					
						
							|  |  |  |  |     if ( | 
					
						
							|  |  |  |  |         compressor.option("ecma") >= 2020 && | 
					
						
							|  |  |  |  |         is_nullish_check(condition, alternative, compressor) | 
					
						
							|  |  |  |  |     ) { | 
					
						
							|  |  |  |  |         return make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |             operator: "??", | 
					
						
							|  |  |  |  |             left: alternative, | 
					
						
							|  |  |  |  |             right: consequent | 
					
						
							|  |  |  |  |         }).optimize(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // a ? b : (c, b) --> (a || c), b
 | 
					
						
							|  |  |  |  |     if (alternative instanceof AST_Sequence | 
					
						
							|  |  |  |  |         && consequent.equivalent_to(alternative.expressions[alternative.expressions.length - 1])) { | 
					
						
							|  |  |  |  |         return make_sequence(self, [ | 
					
						
							|  |  |  |  |             make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                 operator: "||", | 
					
						
							|  |  |  |  |                 left: condition, | 
					
						
							|  |  |  |  |                 right: make_sequence(self, alternative.expressions.slice(0, -1)) | 
					
						
							|  |  |  |  |             }), | 
					
						
							|  |  |  |  |             consequent | 
					
						
							|  |  |  |  |         ]).optimize(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     // a ? b : (c && b) --> (a || c) && b
 | 
					
						
							|  |  |  |  |     if (alternative instanceof AST_Binary | 
					
						
							|  |  |  |  |         && alternative.operator == "&&" | 
					
						
							|  |  |  |  |         && consequent.equivalent_to(alternative.right)) { | 
					
						
							|  |  |  |  |         return make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |             operator: "&&", | 
					
						
							|  |  |  |  |             left: make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                 operator: "||", | 
					
						
							|  |  |  |  |                 left: condition, | 
					
						
							|  |  |  |  |                 right: alternative.left | 
					
						
							|  |  |  |  |             }), | 
					
						
							|  |  |  |  |             right: consequent | 
					
						
							|  |  |  |  |         }).optimize(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     // x?y?z:a:a --> x&&y?z:a
 | 
					
						
							|  |  |  |  |     if (consequent instanceof AST_Conditional | 
					
						
							|  |  |  |  |         && consequent.alternative.equivalent_to(alternative)) { | 
					
						
							|  |  |  |  |         return make_node(AST_Conditional, self, { | 
					
						
							|  |  |  |  |             condition: make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                 left: self.condition, | 
					
						
							|  |  |  |  |                 operator: "&&", | 
					
						
							|  |  |  |  |                 right: consequent.condition | 
					
						
							|  |  |  |  |             }), | 
					
						
							|  |  |  |  |             consequent: consequent.consequent, | 
					
						
							|  |  |  |  |             alternative: alternative | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     // x ? y : y --> x, y
 | 
					
						
							|  |  |  |  |     if (consequent.equivalent_to(alternative)) { | 
					
						
							|  |  |  |  |         return make_sequence(self, [ | 
					
						
							|  |  |  |  |             self.condition, | 
					
						
							|  |  |  |  |             consequent | 
					
						
							|  |  |  |  |         ]).optimize(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     // x ? y || z : z --> x && y || z
 | 
					
						
							|  |  |  |  |     if (consequent instanceof AST_Binary | 
					
						
							|  |  |  |  |         && consequent.operator == "||" | 
					
						
							|  |  |  |  |         && consequent.right.equivalent_to(alternative)) { | 
					
						
							|  |  |  |  |         return make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |             operator: "||", | 
					
						
							|  |  |  |  |             left: make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                 operator: "&&", | 
					
						
							|  |  |  |  |                 left: self.condition, | 
					
						
							|  |  |  |  |                 right: consequent.left | 
					
						
							|  |  |  |  |             }), | 
					
						
							|  |  |  |  |             right: alternative | 
					
						
							|  |  |  |  |         }).optimize(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     const in_bool = compressor.in_boolean_context(); | 
					
						
							|  |  |  |  |     if (is_true(self.consequent)) { | 
					
						
							|  |  |  |  |         if (is_false(self.alternative)) { | 
					
						
							|  |  |  |  |             // c ? true : false ---> !!c
 | 
					
						
							|  |  |  |  |             return booleanize(self.condition); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         // c ? true : x ---> !!c || x
 | 
					
						
							|  |  |  |  |         return make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |             operator: "||", | 
					
						
							|  |  |  |  |             left: booleanize(self.condition), | 
					
						
							|  |  |  |  |             right: self.alternative | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (is_false(self.consequent)) { | 
					
						
							|  |  |  |  |         if (is_true(self.alternative)) { | 
					
						
							|  |  |  |  |             // c ? false : true ---> !c
 | 
					
						
							|  |  |  |  |             return booleanize(self.condition.negate(compressor)); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         // c ? false : x ---> !c && x
 | 
					
						
							|  |  |  |  |         return make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |             operator: "&&", | 
					
						
							|  |  |  |  |             left: booleanize(self.condition.negate(compressor)), | 
					
						
							|  |  |  |  |             right: self.alternative | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (is_true(self.alternative)) { | 
					
						
							|  |  |  |  |         // c ? x : true ---> !c || x
 | 
					
						
							|  |  |  |  |         return make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |             operator: "||", | 
					
						
							|  |  |  |  |             left: booleanize(self.condition.negate(compressor)), | 
					
						
							|  |  |  |  |             right: self.consequent | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (is_false(self.alternative)) { | 
					
						
							|  |  |  |  |         // c ? x : false ---> !!c && x
 | 
					
						
							|  |  |  |  |         return make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |             operator: "&&", | 
					
						
							|  |  |  |  |             left: booleanize(self.condition), | 
					
						
							|  |  |  |  |             right: self.consequent | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     function booleanize(node) { | 
					
						
							|  |  |  |  |         if (node.is_boolean()) return node; | 
					
						
							|  |  |  |  |         // !!expression
 | 
					
						
							|  |  |  |  |         return make_node(AST_UnaryPrefix, node, { | 
					
						
							|  |  |  |  |             operator: "!", | 
					
						
							|  |  |  |  |             expression: node.negate(compressor) | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // AST_True or !0
 | 
					
						
							|  |  |  |  |     function is_true(node) { | 
					
						
							|  |  |  |  |         return node instanceof AST_True | 
					
						
							|  |  |  |  |             || in_bool | 
					
						
							|  |  |  |  |                 && node instanceof AST_Constant | 
					
						
							|  |  |  |  |                 && node.getValue() | 
					
						
							|  |  |  |  |             || (node instanceof AST_UnaryPrefix | 
					
						
							|  |  |  |  |                 && node.operator == "!" | 
					
						
							|  |  |  |  |                 && node.expression instanceof AST_Constant | 
					
						
							|  |  |  |  |                 && !node.expression.getValue()); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     // AST_False or !1
 | 
					
						
							|  |  |  |  |     function is_false(node) { | 
					
						
							|  |  |  |  |         return node instanceof AST_False | 
					
						
							|  |  |  |  |             || in_bool | 
					
						
							|  |  |  |  |                 && node instanceof AST_Constant | 
					
						
							|  |  |  |  |                 && !node.getValue() | 
					
						
							|  |  |  |  |             || (node instanceof AST_UnaryPrefix | 
					
						
							|  |  |  |  |                 && node.operator == "!" | 
					
						
							|  |  |  |  |                 && node.expression instanceof AST_Constant | 
					
						
							|  |  |  |  |                 && node.expression.getValue()); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     function single_arg_diff() { | 
					
						
							|  |  |  |  |         var a = consequent.args; | 
					
						
							|  |  |  |  |         var b = alternative.args; | 
					
						
							|  |  |  |  |         for (var i = 0, len = a.length; i < len; i++) { | 
					
						
							|  |  |  |  |             if (a[i] instanceof AST_Expansion) return; | 
					
						
							|  |  |  |  |             if (!a[i].equivalent_to(b[i])) { | 
					
						
							|  |  |  |  |                 if (b[i] instanceof AST_Expansion) return; | 
					
						
							|  |  |  |  |                 for (var j = i + 1; j < len; j++) { | 
					
						
							|  |  |  |  |                     if (a[j] instanceof AST_Expansion) return; | 
					
						
							|  |  |  |  |                     if (!a[j].equivalent_to(b[j])) return; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |                 return i; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Boolean, function(self, compressor) { | 
					
						
							|  |  |  |  |     if (compressor.in_boolean_context()) return make_node(AST_Number, self, { | 
					
						
							|  |  |  |  |         value: +self.value | 
					
						
							|  |  |  |  |     }); | 
					
						
							|  |  |  |  |     var p = compressor.parent(); | 
					
						
							|  |  |  |  |     if (compressor.option("booleans_as_integers")) { | 
					
						
							|  |  |  |  |         if (p instanceof AST_Binary && (p.operator == "===" || p.operator == "!==")) { | 
					
						
							|  |  |  |  |             p.operator = p.operator.replace(/=$/, ""); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         return make_node(AST_Number, self, { | 
					
						
							|  |  |  |  |             value: +self.value | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (compressor.option("booleans")) { | 
					
						
							|  |  |  |  |         if (p instanceof AST_Binary && (p.operator == "==" | 
					
						
							|  |  |  |  |                                         || p.operator == "!=")) { | 
					
						
							|  |  |  |  |             return make_node(AST_Number, self, { | 
					
						
							|  |  |  |  |                 value: +self.value | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         return make_node(AST_UnaryPrefix, self, { | 
					
						
							|  |  |  |  |             operator: "!", | 
					
						
							|  |  |  |  |             expression: make_node(AST_Number, self, { | 
					
						
							|  |  |  |  |                 value: 1 - self.value | 
					
						
							|  |  |  |  |             }) | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function safe_to_flatten(value, compressor) { | 
					
						
							|  |  |  |  |     if (value instanceof AST_SymbolRef) { | 
					
						
							|  |  |  |  |         value = value.fixed_value(); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (!value) return false; | 
					
						
							|  |  |  |  |     if (!(value instanceof AST_Lambda || value instanceof AST_Class)) return true; | 
					
						
							|  |  |  |  |     if (!(value instanceof AST_Lambda && value.contains_this())) return true; | 
					
						
							|  |  |  |  |     return compressor.parent() instanceof AST_New; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | AST_PropAccess.DEFMETHOD("flatten_object", function(key, compressor) { | 
					
						
							|  |  |  |  |     if (!compressor.option("properties")) return; | 
					
						
							|  |  |  |  |     if (key === "__proto__") return; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     var arrows = compressor.option("unsafe_arrows") && compressor.option("ecma") >= 2015; | 
					
						
							|  |  |  |  |     var expr = this.expression; | 
					
						
							|  |  |  |  |     if (expr instanceof AST_Object) { | 
					
						
							|  |  |  |  |         var props = expr.properties; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         for (var i = props.length; --i >= 0;) { | 
					
						
							|  |  |  |  |             var prop = props[i]; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             if ("" + (prop instanceof AST_ConciseMethod ? prop.key.name : prop.key) == key) { | 
					
						
							|  |  |  |  |                 const all_props_flattenable = props.every((p) => | 
					
						
							|  |  |  |  |                     (p instanceof AST_ObjectKeyVal | 
					
						
							|  |  |  |  |                         || arrows && p instanceof AST_ConciseMethod && !p.is_generator | 
					
						
							|  |  |  |  |                     ) | 
					
						
							|  |  |  |  |                     && !p.computed_key() | 
					
						
							|  |  |  |  |                 ); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 if (!all_props_flattenable) return; | 
					
						
							|  |  |  |  |                 if (!safe_to_flatten(prop.value, compressor)) return; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 return make_node(AST_Sub, this, { | 
					
						
							|  |  |  |  |                     expression: make_node(AST_Array, expr, { | 
					
						
							|  |  |  |  |                         elements: props.map(function(prop) { | 
					
						
							|  |  |  |  |                             var v = prop.value; | 
					
						
							|  |  |  |  |                             if (v instanceof AST_Accessor) { | 
					
						
							|  |  |  |  |                                 v = make_node(AST_Function, v, v); | 
					
						
							|  |  |  |  |                             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                             var k = prop.key; | 
					
						
							|  |  |  |  |                             if (k instanceof AST_Node && !(k instanceof AST_SymbolMethod)) { | 
					
						
							|  |  |  |  |                                 return make_sequence(prop, [ k, v ]); | 
					
						
							|  |  |  |  |                             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                             return v; | 
					
						
							|  |  |  |  |                         }) | 
					
						
							|  |  |  |  |                     }), | 
					
						
							|  |  |  |  |                     property: make_node(AST_Number, this, { | 
					
						
							|  |  |  |  |                         value: i | 
					
						
							|  |  |  |  |                     }) | 
					
						
							|  |  |  |  |                 }); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Sub, function(self, compressor) { | 
					
						
							|  |  |  |  |     var expr = self.expression; | 
					
						
							|  |  |  |  |     var prop = self.property; | 
					
						
							|  |  |  |  |     if (compressor.option("properties")) { | 
					
						
							|  |  |  |  |         var key = prop.evaluate(compressor); | 
					
						
							|  |  |  |  |         if (key !== prop) { | 
					
						
							|  |  |  |  |             if (typeof key == "string") { | 
					
						
							|  |  |  |  |                 if (key == "undefined") { | 
					
						
							|  |  |  |  |                     key = undefined; | 
					
						
							|  |  |  |  |                 } else { | 
					
						
							|  |  |  |  |                     var value = parseFloat(key); | 
					
						
							|  |  |  |  |                     if (value.toString() == key) { | 
					
						
							|  |  |  |  |                         key = value; | 
					
						
							|  |  |  |  |                     } | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             prop = self.property = best_of_expression(prop, make_node_from_constant(key, prop).transform(compressor)); | 
					
						
							|  |  |  |  |             var property = "" + key; | 
					
						
							|  |  |  |  |             if (is_basic_identifier_string(property) | 
					
						
							|  |  |  |  |                 && property.length <= prop.size() + 1) { | 
					
						
							|  |  |  |  |                 return make_node(AST_Dot, self, { | 
					
						
							|  |  |  |  |                     expression: expr, | 
					
						
							|  |  |  |  |                     optional: self.optional, | 
					
						
							|  |  |  |  |                     property: property, | 
					
						
							|  |  |  |  |                     quote: prop.quote, | 
					
						
							|  |  |  |  |                 }).optimize(compressor); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     var fn; | 
					
						
							|  |  |  |  |     OPT_ARGUMENTS: if (compressor.option("arguments") | 
					
						
							|  |  |  |  |         && expr instanceof AST_SymbolRef | 
					
						
							|  |  |  |  |         && expr.name == "arguments" | 
					
						
							|  |  |  |  |         && expr.definition().orig.length == 1 | 
					
						
							|  |  |  |  |         && (fn = expr.scope) instanceof AST_Lambda | 
					
						
							|  |  |  |  |         && fn.uses_arguments | 
					
						
							|  |  |  |  |         && !(fn instanceof AST_Arrow) | 
					
						
							|  |  |  |  |         && prop instanceof AST_Number) { | 
					
						
							|  |  |  |  |         var index = prop.getValue(); | 
					
						
							|  |  |  |  |         var params = new Set(); | 
					
						
							|  |  |  |  |         var argnames = fn.argnames; | 
					
						
							|  |  |  |  |         for (var n = 0; n < argnames.length; n++) { | 
					
						
							|  |  |  |  |             if (!(argnames[n] instanceof AST_SymbolFunarg)) { | 
					
						
							|  |  |  |  |                 break OPT_ARGUMENTS; // destructuring parameter - bail
 | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             var param = argnames[n].name; | 
					
						
							|  |  |  |  |             if (params.has(param)) { | 
					
						
							|  |  |  |  |                 break OPT_ARGUMENTS; // duplicate parameter - bail
 | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             params.add(param); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         var argname = fn.argnames[index]; | 
					
						
							|  |  |  |  |         if (argname && compressor.has_directive("use strict")) { | 
					
						
							|  |  |  |  |             var def = argname.definition(); | 
					
						
							|  |  |  |  |             if (!compressor.option("reduce_vars") || def.assignments || def.orig.length > 1) { | 
					
						
							|  |  |  |  |                 argname = null; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } else if (!argname && !compressor.option("keep_fargs") && index < fn.argnames.length + 5) { | 
					
						
							|  |  |  |  |             while (index >= fn.argnames.length) { | 
					
						
							|  |  |  |  |                 argname = fn.create_symbol(AST_SymbolFunarg, { | 
					
						
							|  |  |  |  |                     source: fn, | 
					
						
							|  |  |  |  |                     scope: fn, | 
					
						
							|  |  |  |  |                     tentative_name: "argument_" + fn.argnames.length, | 
					
						
							|  |  |  |  |                 }); | 
					
						
							|  |  |  |  |                 fn.argnames.push(argname); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         if (argname) { | 
					
						
							|  |  |  |  |             var sym = make_node(AST_SymbolRef, self, argname); | 
					
						
							|  |  |  |  |             sym.reference({}); | 
					
						
							|  |  |  |  |             clear_flag(argname, UNUSED); | 
					
						
							|  |  |  |  |             return sym; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (is_lhs(self, compressor.parent())) return self; | 
					
						
							|  |  |  |  |     if (key !== prop) { | 
					
						
							|  |  |  |  |         var sub = self.flatten_object(property, compressor); | 
					
						
							|  |  |  |  |         if (sub) { | 
					
						
							|  |  |  |  |             expr = self.expression = sub.expression; | 
					
						
							|  |  |  |  |             prop = self.property = sub.property; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (compressor.option("properties") && compressor.option("side_effects") | 
					
						
							|  |  |  |  |         && prop instanceof AST_Number && expr instanceof AST_Array) { | 
					
						
							|  |  |  |  |         var index = prop.getValue(); | 
					
						
							|  |  |  |  |         var elements = expr.elements; | 
					
						
							|  |  |  |  |         var retValue = elements[index]; | 
					
						
							|  |  |  |  |         FLATTEN: if (safe_to_flatten(retValue, compressor)) { | 
					
						
							|  |  |  |  |             var flatten = true; | 
					
						
							|  |  |  |  |             var values = []; | 
					
						
							|  |  |  |  |             for (var i = elements.length; --i > index;) { | 
					
						
							|  |  |  |  |                 var value = elements[i].drop_side_effect_free(compressor); | 
					
						
							|  |  |  |  |                 if (value) { | 
					
						
							|  |  |  |  |                     values.unshift(value); | 
					
						
							|  |  |  |  |                     if (flatten && value.has_side_effects(compressor)) flatten = false; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             if (retValue instanceof AST_Expansion) break FLATTEN; | 
					
						
							|  |  |  |  |             retValue = retValue instanceof AST_Hole ? make_node(AST_Undefined, retValue) : retValue; | 
					
						
							|  |  |  |  |             if (!flatten) values.unshift(retValue); | 
					
						
							|  |  |  |  |             while (--i >= 0) { | 
					
						
							|  |  |  |  |                 var value = elements[i]; | 
					
						
							|  |  |  |  |                 if (value instanceof AST_Expansion) break FLATTEN; | 
					
						
							|  |  |  |  |                 value = value.drop_side_effect_free(compressor); | 
					
						
							|  |  |  |  |                 if (value) values.unshift(value); | 
					
						
							|  |  |  |  |                 else index--; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             if (flatten) { | 
					
						
							|  |  |  |  |                 values.push(retValue); | 
					
						
							|  |  |  |  |                 return make_sequence(self, values).optimize(compressor); | 
					
						
							|  |  |  |  |             } else return make_node(AST_Sub, self, { | 
					
						
							|  |  |  |  |                 expression: make_node(AST_Array, expr, { | 
					
						
							|  |  |  |  |                     elements: values | 
					
						
							|  |  |  |  |                 }), | 
					
						
							|  |  |  |  |                 property: make_node(AST_Number, prop, { | 
					
						
							|  |  |  |  |                     value: index | 
					
						
							|  |  |  |  |                 }) | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     var ev = self.evaluate(compressor); | 
					
						
							|  |  |  |  |     if (ev !== self) { | 
					
						
							|  |  |  |  |         ev = make_node_from_constant(ev, self).optimize(compressor); | 
					
						
							|  |  |  |  |         return best_of(compressor, ev, self); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Chain, function (self, compressor) { | 
					
						
							|  |  |  |  |     if (is_nullish(self.expression, compressor)) { | 
					
						
							|  |  |  |  |         let parent = compressor.parent(); | 
					
						
							|  |  |  |  |         // It's valid to delete a nullish optional chain, but if we optimized
 | 
					
						
							|  |  |  |  |         // this to `delete undefined` then it would appear to be a syntax error
 | 
					
						
							|  |  |  |  |         // when we try to optimize the delete. Thankfully, `delete 0` is fine.
 | 
					
						
							|  |  |  |  |         if (parent instanceof AST_UnaryPrefix && parent.operator === "delete") { | 
					
						
							|  |  |  |  |             return make_node_from_constant(0, self); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         return make_node(AST_Undefined, self); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | AST_Lambda.DEFMETHOD("contains_this", function() { | 
					
						
							|  |  |  |  |     return walk(this, node => { | 
					
						
							|  |  |  |  |         if (node instanceof AST_This) return walk_abort; | 
					
						
							|  |  |  |  |         if ( | 
					
						
							|  |  |  |  |             node !== this | 
					
						
							|  |  |  |  |             && node instanceof AST_Scope | 
					
						
							|  |  |  |  |             && !(node instanceof AST_Arrow) | 
					
						
							|  |  |  |  |         ) { | 
					
						
							|  |  |  |  |             return true; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     }); | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Dot, function(self, compressor) { | 
					
						
							|  |  |  |  |     const parent = compressor.parent(); | 
					
						
							|  |  |  |  |     if (is_lhs(self, parent)) return self; | 
					
						
							|  |  |  |  |     if (compressor.option("unsafe_proto") | 
					
						
							|  |  |  |  |         && self.expression instanceof AST_Dot | 
					
						
							|  |  |  |  |         && self.expression.property == "prototype") { | 
					
						
							|  |  |  |  |         var exp = self.expression.expression; | 
					
						
							|  |  |  |  |         if (is_undeclared_ref(exp)) switch (exp.name) { | 
					
						
							|  |  |  |  |           case "Array": | 
					
						
							|  |  |  |  |             self.expression = make_node(AST_Array, self.expression, { | 
					
						
							|  |  |  |  |                 elements: [] | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |           case "Function": | 
					
						
							|  |  |  |  |             self.expression = make_node(AST_Function, self.expression, { | 
					
						
							|  |  |  |  |                 argnames: [], | 
					
						
							|  |  |  |  |                 body: [] | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |           case "Number": | 
					
						
							|  |  |  |  |             self.expression = make_node(AST_Number, self.expression, { | 
					
						
							|  |  |  |  |                 value: 0 | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |           case "Object": | 
					
						
							|  |  |  |  |             self.expression = make_node(AST_Object, self.expression, { | 
					
						
							|  |  |  |  |                 properties: [] | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |           case "RegExp": | 
					
						
							|  |  |  |  |             self.expression = make_node(AST_RegExp, self.expression, { | 
					
						
							|  |  |  |  |                 value: { source: "t", flags: "" } | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |           case "String": | 
					
						
							|  |  |  |  |             self.expression = make_node(AST_String, self.expression, { | 
					
						
							|  |  |  |  |                 value: "" | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (!(parent instanceof AST_Call) || !has_annotation(parent, _NOINLINE)) { | 
					
						
							|  |  |  |  |         const sub = self.flatten_object(self.property, compressor); | 
					
						
							|  |  |  |  |         if (sub) return sub.optimize(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (self.expression instanceof AST_PropAccess | 
					
						
							|  |  |  |  |         && parent instanceof AST_PropAccess) { | 
					
						
							|  |  |  |  |         return self; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     let ev = self.evaluate(compressor); | 
					
						
							|  |  |  |  |     if (ev !== self) { | 
					
						
							|  |  |  |  |         ev = make_node_from_constant(ev, self).optimize(compressor); | 
					
						
							|  |  |  |  |         return best_of(compressor, ev, self); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function literals_in_boolean_context(self, compressor) { | 
					
						
							|  |  |  |  |     if (compressor.in_boolean_context()) { | 
					
						
							|  |  |  |  |         return best_of(compressor, self, make_sequence(self, [ | 
					
						
							|  |  |  |  |             self, | 
					
						
							|  |  |  |  |             make_node(AST_True, self) | 
					
						
							|  |  |  |  |         ]).optimize(compressor)); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function inline_array_like_spread(elements) { | 
					
						
							|  |  |  |  |     for (var i = 0; i < elements.length; i++) { | 
					
						
							|  |  |  |  |         var el = elements[i]; | 
					
						
							|  |  |  |  |         if (el instanceof AST_Expansion) { | 
					
						
							|  |  |  |  |             var expr = el.expression; | 
					
						
							|  |  |  |  |             if ( | 
					
						
							|  |  |  |  |                 expr instanceof AST_Array | 
					
						
							|  |  |  |  |                 && !expr.elements.some(elm => elm instanceof AST_Hole) | 
					
						
							|  |  |  |  |             ) { | 
					
						
							|  |  |  |  |                 elements.splice(i, 1, ...expr.elements); | 
					
						
							|  |  |  |  |                 // Step back one, as the element at i is now new.
 | 
					
						
							|  |  |  |  |                 i--; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             // In array-like spread, spreading a non-iterable value is TypeError.
 | 
					
						
							|  |  |  |  |             // We therefore can’t optimize anything else, unlike with object spread.
 | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Array, function(self, compressor) { | 
					
						
							|  |  |  |  |     var optimized = literals_in_boolean_context(self, compressor); | 
					
						
							|  |  |  |  |     if (optimized !== self) { | 
					
						
							|  |  |  |  |         return optimized; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     inline_array_like_spread(self.elements); | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function inline_object_prop_spread(props, compressor) { | 
					
						
							|  |  |  |  |     for (var i = 0; i < props.length; i++) { | 
					
						
							|  |  |  |  |         var prop = props[i]; | 
					
						
							|  |  |  |  |         if (prop instanceof AST_Expansion) { | 
					
						
							|  |  |  |  |             const expr = prop.expression; | 
					
						
							|  |  |  |  |             if ( | 
					
						
							|  |  |  |  |                 expr instanceof AST_Object | 
					
						
							|  |  |  |  |                 && expr.properties.every(prop => prop instanceof AST_ObjectKeyVal) | 
					
						
							|  |  |  |  |             ) { | 
					
						
							|  |  |  |  |                 props.splice(i, 1, ...expr.properties); | 
					
						
							|  |  |  |  |                 // Step back one, as the property at i is now new.
 | 
					
						
							|  |  |  |  |                 i--; | 
					
						
							|  |  |  |  |             } else if (expr instanceof AST_Constant | 
					
						
							|  |  |  |  |                 && !(expr instanceof AST_String)) { | 
					
						
							|  |  |  |  |                 // Unlike array-like spread, in object spread, spreading a
 | 
					
						
							|  |  |  |  |                 // non-iterable value silently does nothing; it is thus safe
 | 
					
						
							|  |  |  |  |                 // to remove. AST_String is the only iterable AST_Constant.
 | 
					
						
							|  |  |  |  |                 props.splice(i, 1); | 
					
						
							|  |  |  |  |                 i--; | 
					
						
							|  |  |  |  |             } else if (is_nullish(expr, compressor)) { | 
					
						
							|  |  |  |  |                 // Likewise, null and undefined can be silently removed.
 | 
					
						
							|  |  |  |  |                 props.splice(i, 1); | 
					
						
							|  |  |  |  |                 i--; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Object, function(self, compressor) { | 
					
						
							|  |  |  |  |     var optimized = literals_in_boolean_context(self, compressor); | 
					
						
							|  |  |  |  |     if (optimized !== self) { | 
					
						
							|  |  |  |  |         return optimized; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     inline_object_prop_spread(self.properties, compressor); | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_RegExp, literals_in_boolean_context); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Return, function(self, compressor) { | 
					
						
							|  |  |  |  |     if (self.value && is_undefined(self.value, compressor)) { | 
					
						
							|  |  |  |  |         self.value = null; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Arrow, opt_AST_Lambda); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Function, function(self, compressor) { | 
					
						
							|  |  |  |  |     self = opt_AST_Lambda(self, compressor); | 
					
						
							|  |  |  |  |     if (compressor.option("unsafe_arrows") | 
					
						
							|  |  |  |  |         && compressor.option("ecma") >= 2015 | 
					
						
							|  |  |  |  |         && !self.name | 
					
						
							|  |  |  |  |         && !self.is_generator | 
					
						
							|  |  |  |  |         && !self.uses_arguments | 
					
						
							|  |  |  |  |         && !self.pinned()) { | 
					
						
							|  |  |  |  |         const uses_this = walk(self, node => { | 
					
						
							|  |  |  |  |             if (node instanceof AST_This) return walk_abort; | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |         if (!uses_this) return make_node(AST_Arrow, self, self).optimize(compressor); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Class, function(self) { | 
					
						
							|  |  |  |  |     // HACK to avoid compress failure.
 | 
					
						
							|  |  |  |  |     // AST_Class is not really an AST_Scope/AST_Block as it lacks a body.
 | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_ClassStaticBlock, function(self, compressor) { | 
					
						
							|  |  |  |  |     tighten_body(self.body, compressor); | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Yield, function(self, compressor) { | 
					
						
							|  |  |  |  |     if (self.expression && !self.is_star && is_undefined(self.expression, compressor)) { | 
					
						
							|  |  |  |  |         self.expression = null; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_TemplateString, function(self, compressor) { | 
					
						
							|  |  |  |  |     if ( | 
					
						
							|  |  |  |  |         !compressor.option("evaluate") | 
					
						
							|  |  |  |  |         || compressor.parent() instanceof AST_PrefixedTemplateString | 
					
						
							|  |  |  |  |     ) { | 
					
						
							|  |  |  |  |         return self; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     var segments = []; | 
					
						
							|  |  |  |  |     for (var i = 0; i < self.segments.length; i++) { | 
					
						
							|  |  |  |  |         var segment = self.segments[i]; | 
					
						
							|  |  |  |  |         if (segment instanceof AST_Node) { | 
					
						
							|  |  |  |  |             var result = segment.evaluate(compressor); | 
					
						
							|  |  |  |  |             // Evaluate to constant value
 | 
					
						
							|  |  |  |  |             // Constant value shorter than ${segment}
 | 
					
						
							|  |  |  |  |             if (result !== segment && (result + "").length <= segment.size() + "${}".length) { | 
					
						
							|  |  |  |  |                 // There should always be a previous and next segment if segment is a node
 | 
					
						
							|  |  |  |  |                 segments[segments.length - 1].value = segments[segments.length - 1].value + result + self.segments[++i].value; | 
					
						
							|  |  |  |  |                 continue; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             // `before ${`innerBefore ${any} innerAfter`} after` => `before innerBefore ${any} innerAfter after`
 | 
					
						
							|  |  |  |  |             // TODO:
 | 
					
						
							|  |  |  |  |             // `before ${'test' + foo} after` => `before innerBefore ${any} innerAfter after`
 | 
					
						
							|  |  |  |  |             // `before ${foo + 'test} after` => `before innerBefore ${any} innerAfter after`
 | 
					
						
							|  |  |  |  |             if (segment instanceof AST_TemplateString) { | 
					
						
							|  |  |  |  |                 var inners = segment.segments; | 
					
						
							|  |  |  |  |                 segments[segments.length - 1].value += inners[0].value; | 
					
						
							|  |  |  |  |                 for (var j = 1; j < inners.length; j++) { | 
					
						
							|  |  |  |  |                     segment = inners[j]; | 
					
						
							|  |  |  |  |                     segments.push(segment); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |                 continue; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         segments.push(segment); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     self.segments = segments; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // `foo` => "foo"
 | 
					
						
							|  |  |  |  |     if (segments.length == 1) { | 
					
						
							|  |  |  |  |         return make_node(AST_String, self, segments[0]); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if ( | 
					
						
							|  |  |  |  |         segments.length === 3 | 
					
						
							|  |  |  |  |         && segments[1] instanceof AST_Node | 
					
						
							|  |  |  |  |         && ( | 
					
						
							|  |  |  |  |             segments[1].is_string(compressor) | 
					
						
							|  |  |  |  |             || segments[1].is_number(compressor) | 
					
						
							|  |  |  |  |             || is_nullish(segments[1], compressor) | 
					
						
							|  |  |  |  |             || compressor.option("unsafe") | 
					
						
							|  |  |  |  |         ) | 
					
						
							|  |  |  |  |     ) { | 
					
						
							|  |  |  |  |         // `foo${bar}` => "foo" + bar
 | 
					
						
							|  |  |  |  |         if (segments[2].value === "") { | 
					
						
							|  |  |  |  |             return make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                 operator: "+", | 
					
						
							|  |  |  |  |                 left: make_node(AST_String, self, { | 
					
						
							|  |  |  |  |                     value: segments[0].value, | 
					
						
							|  |  |  |  |                 }), | 
					
						
							|  |  |  |  |                 right: segments[1], | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         // `${bar}baz` => bar + "baz"
 | 
					
						
							|  |  |  |  |         if (segments[0].value === "") { | 
					
						
							|  |  |  |  |             return make_node(AST_Binary, self, { | 
					
						
							|  |  |  |  |                 operator: "+", | 
					
						
							|  |  |  |  |                 left: segments[1], | 
					
						
							|  |  |  |  |                 right: make_node(AST_String, self, { | 
					
						
							|  |  |  |  |                     value: segments[2].value, | 
					
						
							|  |  |  |  |                 }), | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_PrefixedTemplateString, function(self) { | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // ["p"]:1 ---> p:1
 | 
					
						
							|  |  |  |  | // [42]:1 ---> 42:1
 | 
					
						
							|  |  |  |  | function lift_key(self, compressor) { | 
					
						
							|  |  |  |  |     if (!compressor.option("computed_props")) return self; | 
					
						
							|  |  |  |  |     // save a comparison in the typical case
 | 
					
						
							|  |  |  |  |     if (!(self.key instanceof AST_Constant)) return self; | 
					
						
							|  |  |  |  |     // allow certain acceptable props as not all AST_Constants are true constants
 | 
					
						
							|  |  |  |  |     if (self.key instanceof AST_String || self.key instanceof AST_Number) { | 
					
						
							|  |  |  |  |         if (self.key.value === "__proto__") return self; | 
					
						
							|  |  |  |  |         if (self.key.value == "constructor" | 
					
						
							|  |  |  |  |             && compressor.parent() instanceof AST_Class) return self; | 
					
						
							|  |  |  |  |         if (self instanceof AST_ObjectKeyVal) { | 
					
						
							|  |  |  |  |             self.quote = self.key.quote; | 
					
						
							|  |  |  |  |             self.key = self.key.value; | 
					
						
							|  |  |  |  |         } else if (self instanceof AST_ClassProperty) { | 
					
						
							|  |  |  |  |             self.quote = self.key.quote; | 
					
						
							|  |  |  |  |             self.key = make_node(AST_SymbolClassProperty, self.key, { | 
					
						
							|  |  |  |  |                 name: self.key.value | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |         } else { | 
					
						
							|  |  |  |  |             self.quote = self.key.quote; | 
					
						
							|  |  |  |  |             self.key = make_node(AST_SymbolMethod, self.key, { | 
					
						
							|  |  |  |  |                 name: self.key.value | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_ObjectProperty, lift_key); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_ConciseMethod, function(self, compressor) { | 
					
						
							|  |  |  |  |     lift_key(self, compressor); | 
					
						
							|  |  |  |  |     // p(){return x;} ---> p:()=>x
 | 
					
						
							|  |  |  |  |     if (compressor.option("arrows") | 
					
						
							|  |  |  |  |         && compressor.parent() instanceof AST_Object | 
					
						
							|  |  |  |  |         && !self.is_generator | 
					
						
							|  |  |  |  |         && !self.value.uses_arguments | 
					
						
							|  |  |  |  |         && !self.value.pinned() | 
					
						
							|  |  |  |  |         && self.value.body.length == 1 | 
					
						
							|  |  |  |  |         && self.value.body[0] instanceof AST_Return | 
					
						
							|  |  |  |  |         && self.value.body[0].value | 
					
						
							|  |  |  |  |         && !self.value.contains_this()) { | 
					
						
							|  |  |  |  |         var arrow = make_node(AST_Arrow, self.value, self.value); | 
					
						
							|  |  |  |  |         arrow.async = self.async; | 
					
						
							|  |  |  |  |         arrow.is_generator = self.is_generator; | 
					
						
							|  |  |  |  |         return make_node(AST_ObjectKeyVal, self, { | 
					
						
							|  |  |  |  |             key: self.key instanceof AST_SymbolMethod ? self.key.name : self.key, | 
					
						
							|  |  |  |  |             value: arrow, | 
					
						
							|  |  |  |  |             quote: self.quote, | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_ObjectKeyVal, function(self, compressor) { | 
					
						
							|  |  |  |  |     lift_key(self, compressor); | 
					
						
							|  |  |  |  |     // p:function(){} ---> p(){}
 | 
					
						
							|  |  |  |  |     // p:function*(){} ---> *p(){}
 | 
					
						
							|  |  |  |  |     // p:async function(){} ---> async p(){}
 | 
					
						
							|  |  |  |  |     // p:()=>{} ---> p(){}
 | 
					
						
							|  |  |  |  |     // p:async()=>{} ---> async p(){}
 | 
					
						
							|  |  |  |  |     var unsafe_methods = compressor.option("unsafe_methods"); | 
					
						
							|  |  |  |  |     if (unsafe_methods | 
					
						
							|  |  |  |  |         && compressor.option("ecma") >= 2015 | 
					
						
							|  |  |  |  |         && (!(unsafe_methods instanceof RegExp) || unsafe_methods.test(self.key + ""))) { | 
					
						
							|  |  |  |  |         var key = self.key; | 
					
						
							|  |  |  |  |         var value = self.value; | 
					
						
							|  |  |  |  |         var is_arrow_with_block = value instanceof AST_Arrow | 
					
						
							|  |  |  |  |             && Array.isArray(value.body) | 
					
						
							|  |  |  |  |             && !value.contains_this(); | 
					
						
							|  |  |  |  |         if ((is_arrow_with_block || value instanceof AST_Function) && !value.name) { | 
					
						
							|  |  |  |  |             return make_node(AST_ConciseMethod, self, { | 
					
						
							|  |  |  |  |                 async: value.async, | 
					
						
							|  |  |  |  |                 is_generator: value.is_generator, | 
					
						
							|  |  |  |  |                 key: key instanceof AST_Node ? key : make_node(AST_SymbolMethod, self, { | 
					
						
							|  |  |  |  |                     name: key, | 
					
						
							|  |  |  |  |                 }), | 
					
						
							|  |  |  |  |                 value: make_node(AST_Accessor, value, value), | 
					
						
							|  |  |  |  |                 quote: self.quote, | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def_optimize(AST_Destructuring, function(self, compressor) { | 
					
						
							|  |  |  |  |     if (compressor.option("pure_getters") == true | 
					
						
							|  |  |  |  |         && compressor.option("unused") | 
					
						
							|  |  |  |  |         && !self.is_array | 
					
						
							|  |  |  |  |         && Array.isArray(self.names) | 
					
						
							|  |  |  |  |         && !is_destructuring_export_decl(compressor) | 
					
						
							|  |  |  |  |         && !(self.names[self.names.length - 1] instanceof AST_Expansion)) { | 
					
						
							|  |  |  |  |         var keep = []; | 
					
						
							|  |  |  |  |         for (var i = 0; i < self.names.length; i++) { | 
					
						
							|  |  |  |  |             var elem = self.names[i]; | 
					
						
							|  |  |  |  |             if (!(elem instanceof AST_ObjectKeyVal | 
					
						
							|  |  |  |  |                 && typeof elem.key == "string" | 
					
						
							|  |  |  |  |                 && elem.value instanceof AST_SymbolDeclaration | 
					
						
							|  |  |  |  |                 && !should_retain(compressor, elem.value.definition()))) { | 
					
						
							|  |  |  |  |                 keep.push(elem); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         if (keep.length != self.names.length) { | 
					
						
							|  |  |  |  |             self.names = keep; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return self; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     function is_destructuring_export_decl(compressor) { | 
					
						
							|  |  |  |  |         var ancestors = [/^VarDef$/, /^(Const|Let|Var)$/, /^Export$/]; | 
					
						
							|  |  |  |  |         for (var a = 0, p = 0, len = ancestors.length; a < len; p++) { | 
					
						
							|  |  |  |  |             var parent = compressor.parent(p); | 
					
						
							|  |  |  |  |             if (!parent) return false; | 
					
						
							|  |  |  |  |             if (a === 0 && parent.TYPE == "Destructuring") continue; | 
					
						
							|  |  |  |  |             if (!ancestors[a].test(parent.TYPE)) { | 
					
						
							|  |  |  |  |                 return false; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             a++; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     function should_retain(compressor, def) { | 
					
						
							|  |  |  |  |         if (def.references.length) return true; | 
					
						
							|  |  |  |  |         if (!def.global) return false; | 
					
						
							|  |  |  |  |         if (compressor.toplevel.vars) { | 
					
						
							|  |  |  |  |              if (compressor.top_retain) { | 
					
						
							|  |  |  |  |                  return compressor.top_retain(def); | 
					
						
							|  |  |  |  |              } | 
					
						
							|  |  |  |  |              return false; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | export { | 
					
						
							|  |  |  |  |     Compressor, | 
					
						
							|  |  |  |  | }; |