You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					968 lines
				
				36 KiB
			
		
		
			
		
	
	
					968 lines
				
				36 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								/***********************************************************************
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  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_Array,
							 | 
						||
| 
								 | 
							
								  AST_Arrow,
							 | 
						||
| 
								 | 
							
								  AST_Assign,
							 | 
						||
| 
								 | 
							
								  AST_Binary,
							 | 
						||
| 
								 | 
							
								  AST_Block,
							 | 
						||
| 
								 | 
							
								  AST_BlockStatement,
							 | 
						||
| 
								 | 
							
								  AST_Call,
							 | 
						||
| 
								 | 
							
								  AST_Case,
							 | 
						||
| 
								 | 
							
								  AST_Chain,
							 | 
						||
| 
								 | 
							
								  AST_Class,
							 | 
						||
| 
								 | 
							
								  AST_DefClass,
							 | 
						||
| 
								 | 
							
								  AST_ClassStaticBlock,
							 | 
						||
| 
								 | 
							
								  AST_ClassProperty,
							 | 
						||
| 
								 | 
							
								  AST_ConciseMethod,
							 | 
						||
| 
								 | 
							
								  AST_Conditional,
							 | 
						||
| 
								 | 
							
								  AST_Constant,
							 | 
						||
| 
								 | 
							
								  AST_Definitions,
							 | 
						||
| 
								 | 
							
								  AST_Dot,
							 | 
						||
| 
								 | 
							
								  AST_EmptyStatement,
							 | 
						||
| 
								 | 
							
								  AST_Expansion,
							 | 
						||
| 
								 | 
							
								  AST_False,
							 | 
						||
| 
								 | 
							
								  AST_Function,
							 | 
						||
| 
								 | 
							
								  AST_If,
							 | 
						||
| 
								 | 
							
								  AST_Import,
							 | 
						||
| 
								 | 
							
								  AST_Jump,
							 | 
						||
| 
								 | 
							
								  AST_LabeledStatement,
							 | 
						||
| 
								 | 
							
								  AST_Lambda,
							 | 
						||
| 
								 | 
							
								  AST_New,
							 | 
						||
| 
								 | 
							
								  AST_Node,
							 | 
						||
| 
								 | 
							
								  AST_Null,
							 | 
						||
| 
								 | 
							
								  AST_Number,
							 | 
						||
| 
								 | 
							
								  AST_Object,
							 | 
						||
| 
								 | 
							
								  AST_ObjectGetter,
							 | 
						||
| 
								 | 
							
								  AST_ObjectKeyVal,
							 | 
						||
| 
								 | 
							
								  AST_ObjectProperty,
							 | 
						||
| 
								 | 
							
								  AST_ObjectSetter,
							 | 
						||
| 
								 | 
							
								  AST_PropAccess,
							 | 
						||
| 
								 | 
							
								  AST_RegExp,
							 | 
						||
| 
								 | 
							
								  AST_Return,
							 | 
						||
| 
								 | 
							
								  AST_Sequence,
							 | 
						||
| 
								 | 
							
								  AST_SimpleStatement,
							 | 
						||
| 
								 | 
							
								  AST_Statement,
							 | 
						||
| 
								 | 
							
								  AST_String,
							 | 
						||
| 
								 | 
							
								  AST_Sub,
							 | 
						||
| 
								 | 
							
								  AST_Switch,
							 | 
						||
| 
								 | 
							
								  AST_SwitchBranch,
							 | 
						||
| 
								 | 
							
								  AST_SymbolClassProperty,
							 | 
						||
| 
								 | 
							
								  AST_SymbolDeclaration,
							 | 
						||
| 
								 | 
							
								  AST_SymbolRef,
							 | 
						||
| 
								 | 
							
								  AST_TemplateSegment,
							 | 
						||
| 
								 | 
							
								  AST_TemplateString,
							 | 
						||
| 
								 | 
							
								  AST_This,
							 | 
						||
| 
								 | 
							
								  AST_Toplevel,
							 | 
						||
| 
								 | 
							
								  AST_True,
							 | 
						||
| 
								 | 
							
								  AST_Try,
							 | 
						||
| 
								 | 
							
								  AST_Unary,
							 | 
						||
| 
								 | 
							
								  AST_UnaryPostfix,
							 | 
						||
| 
								 | 
							
								  AST_UnaryPrefix,
							 | 
						||
| 
								 | 
							
								  AST_Undefined,
							 | 
						||
| 
								 | 
							
								  AST_VarDef,
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  TreeTransformer,
							 | 
						||
| 
								 | 
							
								  walk,
							 | 
						||
| 
								 | 
							
								  walk_abort,
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  _PURE
							 | 
						||
| 
								 | 
							
								} from "../ast.js";
							 | 
						||
| 
								 | 
							
								import {
							 | 
						||
| 
								 | 
							
								    makePredicate,
							 | 
						||
| 
								 | 
							
								    return_true,
							 | 
						||
| 
								 | 
							
								    return_false,
							 | 
						||
| 
								 | 
							
								    return_null,
							 | 
						||
| 
								 | 
							
								    return_this,
							 | 
						||
| 
								 | 
							
								    make_node,
							 | 
						||
| 
								 | 
							
								    member,
							 | 
						||
| 
								 | 
							
								    noop,
							 | 
						||
| 
								 | 
							
								    has_annotation,
							 | 
						||
| 
								 | 
							
								    HOP
							 | 
						||
| 
								 | 
							
								} from "../utils/index.js";
							 | 
						||
| 
								 | 
							
								import { make_node_from_constant, make_sequence, best_of_expression, read_property } from "./common.js";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { INLINED, UNDEFINED, has_flag } from "./compressor-flags.js";
							 | 
						||
| 
								 | 
							
								import { pure_prop_access_globals, is_pure_native_fn, is_pure_native_method } from "./native-objects.js";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Functions and methods to infer certain facts about expressions
							 | 
						||
| 
								 | 
							
								// It's not always possible to be 100% sure about something just by static analysis,
							 | 
						||
| 
								 | 
							
								// so `true` means yes, and `false` means maybe
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export const is_undeclared_ref = (node) =>
							 | 
						||
| 
								 | 
							
								    node instanceof AST_SymbolRef && node.definition().undeclared;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export const lazy_op = makePredicate("&& || ??");
							 | 
						||
| 
								 | 
							
								export const unary_side_effects = makePredicate("delete ++ --");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// methods to determine whether an expression has a boolean result type
							 | 
						||
| 
								 | 
							
								(function(def_is_boolean) {
							 | 
						||
| 
								 | 
							
								    const unary_bool = makePredicate("! delete");
							 | 
						||
| 
								 | 
							
								    const binary_bool = makePredicate("in instanceof == != === !== < <= >= >");
							 | 
						||
| 
								 | 
							
								    def_is_boolean(AST_Node, return_false);
							 | 
						||
| 
								 | 
							
								    def_is_boolean(AST_UnaryPrefix, function() {
							 | 
						||
| 
								 | 
							
								        return unary_bool.has(this.operator);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_is_boolean(AST_Binary, function() {
							 | 
						||
| 
								 | 
							
								        return binary_bool.has(this.operator)
							 | 
						||
| 
								 | 
							
								            || lazy_op.has(this.operator)
							 | 
						||
| 
								 | 
							
								                && this.left.is_boolean()
							 | 
						||
| 
								 | 
							
								                && this.right.is_boolean();
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_is_boolean(AST_Conditional, function() {
							 | 
						||
| 
								 | 
							
								        return this.consequent.is_boolean() && this.alternative.is_boolean();
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_is_boolean(AST_Assign, function() {
							 | 
						||
| 
								 | 
							
								        return this.operator == "=" && this.right.is_boolean();
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_is_boolean(AST_Sequence, function() {
							 | 
						||
| 
								 | 
							
								        return this.tail_node().is_boolean();
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_is_boolean(AST_True, return_true);
							 | 
						||
| 
								 | 
							
								    def_is_boolean(AST_False, return_true);
							 | 
						||
| 
								 | 
							
								})(function(node, func) {
							 | 
						||
| 
								 | 
							
								    node.DEFMETHOD("is_boolean", func);
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// methods to determine if an expression has a numeric result type
							 | 
						||
| 
								 | 
							
								(function(def_is_number) {
							 | 
						||
| 
								 | 
							
								    def_is_number(AST_Node, return_false);
							 | 
						||
| 
								 | 
							
								    def_is_number(AST_Number, return_true);
							 | 
						||
| 
								 | 
							
								    const unary = makePredicate("+ - ~ ++ --");
							 | 
						||
| 
								 | 
							
								    def_is_number(AST_Unary, function() {
							 | 
						||
| 
								 | 
							
								        return unary.has(this.operator);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    const numeric_ops = makePredicate("- * / % & | ^ << >> >>>");
							 | 
						||
| 
								 | 
							
								    def_is_number(AST_Binary, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return numeric_ops.has(this.operator) || this.operator == "+"
							 | 
						||
| 
								 | 
							
								            && this.left.is_number(compressor)
							 | 
						||
| 
								 | 
							
								            && this.right.is_number(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_is_number(AST_Assign, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return numeric_ops.has(this.operator.slice(0, -1))
							 | 
						||
| 
								 | 
							
								            || this.operator == "=" && this.right.is_number(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_is_number(AST_Sequence, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.tail_node().is_number(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_is_number(AST_Conditional, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.consequent.is_number(compressor) && this.alternative.is_number(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								})(function(node, func) {
							 | 
						||
| 
								 | 
							
								    node.DEFMETHOD("is_number", func);
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// methods to determine if an expression has a string result type
							 | 
						||
| 
								 | 
							
								(function(def_is_string) {
							 | 
						||
| 
								 | 
							
								    def_is_string(AST_Node, return_false);
							 | 
						||
| 
								 | 
							
								    def_is_string(AST_String, return_true);
							 | 
						||
| 
								 | 
							
								    def_is_string(AST_TemplateString, return_true);
							 | 
						||
| 
								 | 
							
								    def_is_string(AST_UnaryPrefix, function() {
							 | 
						||
| 
								 | 
							
								        return this.operator == "typeof";
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_is_string(AST_Binary, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.operator == "+" &&
							 | 
						||
| 
								 | 
							
								            (this.left.is_string(compressor) || this.right.is_string(compressor));
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_is_string(AST_Assign, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_is_string(AST_Sequence, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.tail_node().is_string(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_is_string(AST_Conditional, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								})(function(node, func) {
							 | 
						||
| 
								 | 
							
								    node.DEFMETHOD("is_string", func);
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export function is_undefined(node, compressor) {
							 | 
						||
| 
								 | 
							
								    return (
							 | 
						||
| 
								 | 
							
								        has_flag(node, UNDEFINED)
							 | 
						||
| 
								 | 
							
								        || node instanceof AST_Undefined
							 | 
						||
| 
								 | 
							
								        || node instanceof AST_UnaryPrefix
							 | 
						||
| 
								 | 
							
								            && node.operator == "void"
							 | 
						||
| 
								 | 
							
								            && !node.expression.has_side_effects(compressor)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Is the node explicitly null or undefined.
							 | 
						||
| 
								 | 
							
								function is_null_or_undefined(node, compressor) {
							 | 
						||
| 
								 | 
							
								    let fixed;
							 | 
						||
| 
								 | 
							
								    return (
							 | 
						||
| 
								 | 
							
								        node instanceof AST_Null
							 | 
						||
| 
								 | 
							
								        || is_undefined(node, compressor)
							 | 
						||
| 
								 | 
							
								        || (
							 | 
						||
| 
								 | 
							
								            node instanceof AST_SymbolRef
							 | 
						||
| 
								 | 
							
								            && (fixed = node.definition().fixed) instanceof AST_Node
							 | 
						||
| 
								 | 
							
								            && is_nullish(fixed, compressor)
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Find out if this expression is optionally chained from a base-point that we
							 | 
						||
| 
								 | 
							
								// can statically analyze as null or undefined.
							 | 
						||
| 
								 | 
							
								export function is_nullish_shortcircuited(node, compressor) {
							 | 
						||
| 
								 | 
							
								    if (node instanceof AST_PropAccess || node instanceof AST_Call) {
							 | 
						||
| 
								 | 
							
								        return (
							 | 
						||
| 
								 | 
							
								            (node.optional && is_null_or_undefined(node.expression, compressor))
							 | 
						||
| 
								 | 
							
								            || is_nullish_shortcircuited(node.expression, compressor)
							 | 
						||
| 
								 | 
							
								        );
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (node instanceof AST_Chain) return is_nullish_shortcircuited(node.expression, compressor);
							 | 
						||
| 
								 | 
							
								    return false;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Find out if something is == null, or can short circuit into nullish.
							 | 
						||
| 
								 | 
							
								// Used to optimize ?. and ??
							 | 
						||
| 
								 | 
							
								export function is_nullish(node, compressor) {
							 | 
						||
| 
								 | 
							
								    if (is_null_or_undefined(node, compressor)) return true;
							 | 
						||
| 
								 | 
							
								    return is_nullish_shortcircuited(node, compressor);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Determine if expression might cause side effects
							 | 
						||
| 
								 | 
							
								// If there's a possibility that a node may change something when it's executed, this returns true
							 | 
						||
| 
								 | 
							
								(function(def_has_side_effects) {
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_Node, return_true);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_EmptyStatement, return_false);
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_Constant, return_false);
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_This, return_false);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function any(list, compressor) {
							 | 
						||
| 
								 | 
							
								        for (var i = list.length; --i >= 0;)
							 | 
						||
| 
								 | 
							
								            if (list[i].has_side_effects(compressor))
							 | 
						||
| 
								 | 
							
								                return true;
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_Block, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return any(this.body, compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_Call, function(compressor) {
							 | 
						||
| 
								 | 
							
								        if (
							 | 
						||
| 
								 | 
							
								            !this.is_callee_pure(compressor)
							 | 
						||
| 
								 | 
							
								            && (!this.expression.is_call_pure(compressor)
							 | 
						||
| 
								 | 
							
								                || this.expression.has_side_effects(compressor))
							 | 
						||
| 
								 | 
							
								        ) {
							 | 
						||
| 
								 | 
							
								            return true;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return any(this.args, compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_Switch, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.expression.has_side_effects(compressor)
							 | 
						||
| 
								 | 
							
								            || any(this.body, compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_Case, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.expression.has_side_effects(compressor)
							 | 
						||
| 
								 | 
							
								            || any(this.body, compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_Try, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return any(this.body, compressor)
							 | 
						||
| 
								 | 
							
								            || this.bcatch && this.bcatch.has_side_effects(compressor)
							 | 
						||
| 
								 | 
							
								            || this.bfinally && this.bfinally.has_side_effects(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_If, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.condition.has_side_effects(compressor)
							 | 
						||
| 
								 | 
							
								            || this.body && this.body.has_side_effects(compressor)
							 | 
						||
| 
								 | 
							
								            || this.alternative && this.alternative.has_side_effects(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_LabeledStatement, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.body.has_side_effects(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_SimpleStatement, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.body.has_side_effects(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_Lambda, return_false);
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_Class, function (compressor) {
							 | 
						||
| 
								 | 
							
								        if (this.extends && this.extends.has_side_effects(compressor)) {
							 | 
						||
| 
								 | 
							
								            return true;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return any(this.properties, compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_ClassStaticBlock, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return any(this.body, compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_Binary, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.left.has_side_effects(compressor)
							 | 
						||
| 
								 | 
							
								            || this.right.has_side_effects(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_Assign, return_true);
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_Conditional, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.condition.has_side_effects(compressor)
							 | 
						||
| 
								 | 
							
								            || this.consequent.has_side_effects(compressor)
							 | 
						||
| 
								 | 
							
								            || this.alternative.has_side_effects(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_Unary, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return unary_side_effects.has(this.operator)
							 | 
						||
| 
								 | 
							
								            || this.expression.has_side_effects(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_SymbolRef, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return !this.is_declared(compressor) && !pure_prop_access_globals.has(this.name);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_SymbolClassProperty, return_false);
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_SymbolDeclaration, return_false);
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_Object, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return any(this.properties, compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_ObjectProperty, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return (
							 | 
						||
| 
								 | 
							
								            this.computed_key() && this.key.has_side_effects(compressor)
							 | 
						||
| 
								 | 
							
								            || this.value && this.value.has_side_effects(compressor)
							 | 
						||
| 
								 | 
							
								        );
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_ClassProperty, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return (
							 | 
						||
| 
								 | 
							
								            this.computed_key() && this.key.has_side_effects(compressor)
							 | 
						||
| 
								 | 
							
								            || this.static && this.value && this.value.has_side_effects(compressor)
							 | 
						||
| 
								 | 
							
								        );
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_ConciseMethod, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.computed_key() && this.key.has_side_effects(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_ObjectGetter, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.computed_key() && this.key.has_side_effects(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_ObjectSetter, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.computed_key() && this.key.has_side_effects(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_Array, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return any(this.elements, compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_Dot, function(compressor) {
							 | 
						||
| 
								 | 
							
								        if (is_nullish(this, compressor)) return false;
							 | 
						||
| 
								 | 
							
								        return !this.optional && this.expression.may_throw_on_access(compressor)
							 | 
						||
| 
								 | 
							
								            || this.expression.has_side_effects(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_Sub, function(compressor) {
							 | 
						||
| 
								 | 
							
								        if (is_nullish(this, compressor)) return false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return !this.optional && this.expression.may_throw_on_access(compressor)
							 | 
						||
| 
								 | 
							
								            || this.expression.has_side_effects(compressor)
							 | 
						||
| 
								 | 
							
								            || this.property.has_side_effects(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_Chain, function (compressor) {
							 | 
						||
| 
								 | 
							
								        return this.expression.has_side_effects(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_Sequence, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return any(this.expressions, compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_Definitions, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return any(this.definitions, compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_VarDef, function() {
							 | 
						||
| 
								 | 
							
								        return this.value;
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_TemplateSegment, return_false);
							 | 
						||
| 
								 | 
							
								    def_has_side_effects(AST_TemplateString, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return any(this.segments, compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								})(function(node, func) {
							 | 
						||
| 
								 | 
							
								    node.DEFMETHOD("has_side_effects", func);
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// determine if expression may throw
							 | 
						||
| 
								 | 
							
								(function(def_may_throw) {
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_Node, return_true);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_Constant, return_false);
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_EmptyStatement, return_false);
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_Lambda, return_false);
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_SymbolDeclaration, return_false);
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_This, return_false);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function any(list, compressor) {
							 | 
						||
| 
								 | 
							
								        for (var i = list.length; --i >= 0;)
							 | 
						||
| 
								 | 
							
								            if (list[i].may_throw(compressor))
							 | 
						||
| 
								 | 
							
								                return true;
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_Class, function(compressor) {
							 | 
						||
| 
								 | 
							
								        if (this.extends && this.extends.may_throw(compressor)) return true;
							 | 
						||
| 
								 | 
							
								        return any(this.properties, compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_ClassStaticBlock, function (compressor) {
							 | 
						||
| 
								 | 
							
								        return any(this.body, compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_Array, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return any(this.elements, compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_Assign, function(compressor) {
							 | 
						||
| 
								 | 
							
								        if (this.right.may_throw(compressor)) return true;
							 | 
						||
| 
								 | 
							
								        if (!compressor.has_directive("use strict")
							 | 
						||
| 
								 | 
							
								            && this.operator == "="
							 | 
						||
| 
								 | 
							
								            && this.left instanceof AST_SymbolRef) {
							 | 
						||
| 
								 | 
							
								            return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return this.left.may_throw(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_Binary, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.left.may_throw(compressor)
							 | 
						||
| 
								 | 
							
								            || this.right.may_throw(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_Block, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return any(this.body, compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_Call, function(compressor) {
							 | 
						||
| 
								 | 
							
								        if (is_nullish(this, compressor)) return false;
							 | 
						||
| 
								 | 
							
								        if (any(this.args, compressor)) return true;
							 | 
						||
| 
								 | 
							
								        if (this.is_callee_pure(compressor)) return false;
							 | 
						||
| 
								 | 
							
								        if (this.expression.may_throw(compressor)) return true;
							 | 
						||
| 
								 | 
							
								        return !(this.expression instanceof AST_Lambda)
							 | 
						||
| 
								 | 
							
								            || any(this.expression.body, compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_Case, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.expression.may_throw(compressor)
							 | 
						||
| 
								 | 
							
								            || any(this.body, compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_Conditional, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.condition.may_throw(compressor)
							 | 
						||
| 
								 | 
							
								            || this.consequent.may_throw(compressor)
							 | 
						||
| 
								 | 
							
								            || this.alternative.may_throw(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_Definitions, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return any(this.definitions, compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_If, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.condition.may_throw(compressor)
							 | 
						||
| 
								 | 
							
								            || this.body && this.body.may_throw(compressor)
							 | 
						||
| 
								 | 
							
								            || this.alternative && this.alternative.may_throw(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_LabeledStatement, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.body.may_throw(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_Object, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return any(this.properties, compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_ObjectProperty, function(compressor) {
							 | 
						||
| 
								 | 
							
								        // TODO key may throw too
							 | 
						||
| 
								 | 
							
								        return this.value ? this.value.may_throw(compressor) : false;
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_ClassProperty, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return (
							 | 
						||
| 
								 | 
							
								            this.computed_key() && this.key.may_throw(compressor)
							 | 
						||
| 
								 | 
							
								            || this.static && this.value && this.value.may_throw(compressor)
							 | 
						||
| 
								 | 
							
								        );
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_ConciseMethod, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.computed_key() && this.key.may_throw(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_ObjectGetter, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.computed_key() && this.key.may_throw(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_ObjectSetter, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.computed_key() && this.key.may_throw(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_Return, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.value && this.value.may_throw(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_Sequence, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return any(this.expressions, compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_SimpleStatement, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.body.may_throw(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_Dot, function(compressor) {
							 | 
						||
| 
								 | 
							
								        if (is_nullish(this, compressor)) return false;
							 | 
						||
| 
								 | 
							
								        return !this.optional && this.expression.may_throw_on_access(compressor)
							 | 
						||
| 
								 | 
							
								            || this.expression.may_throw(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_Sub, function(compressor) {
							 | 
						||
| 
								 | 
							
								        if (is_nullish(this, compressor)) return false;
							 | 
						||
| 
								 | 
							
								        return !this.optional && this.expression.may_throw_on_access(compressor)
							 | 
						||
| 
								 | 
							
								            || this.expression.may_throw(compressor)
							 | 
						||
| 
								 | 
							
								            || this.property.may_throw(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_Chain, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.expression.may_throw(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_Switch, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.expression.may_throw(compressor)
							 | 
						||
| 
								 | 
							
								            || any(this.body, compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_SymbolRef, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return !this.is_declared(compressor) && !pure_prop_access_globals.has(this.name);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_SymbolClassProperty, return_false);
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_Try, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.bcatch ? this.bcatch.may_throw(compressor) : any(this.body, compressor)
							 | 
						||
| 
								 | 
							
								            || this.bfinally && this.bfinally.may_throw(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_Unary, function(compressor) {
							 | 
						||
| 
								 | 
							
								        if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef)
							 | 
						||
| 
								 | 
							
								            return false;
							 | 
						||
| 
								 | 
							
								        return this.expression.may_throw(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw(AST_VarDef, function(compressor) {
							 | 
						||
| 
								 | 
							
								        if (!this.value) return false;
							 | 
						||
| 
								 | 
							
								        return this.value.may_throw(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								})(function(node, func) {
							 | 
						||
| 
								 | 
							
								    node.DEFMETHOD("may_throw", func);
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// determine if expression is constant
							 | 
						||
| 
								 | 
							
								(function(def_is_constant_expression) {
							 | 
						||
| 
								 | 
							
								    function all_refs_local(scope) {
							 | 
						||
| 
								 | 
							
								        let result = true;
							 | 
						||
| 
								 | 
							
								        walk(this, node => {
							 | 
						||
| 
								 | 
							
								            if (node instanceof AST_SymbolRef) {
							 | 
						||
| 
								 | 
							
								                if (has_flag(this, INLINED)) {
							 | 
						||
| 
								 | 
							
								                    result = false;
							 | 
						||
| 
								 | 
							
								                    return walk_abort;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                var def = node.definition();
							 | 
						||
| 
								 | 
							
								                if (
							 | 
						||
| 
								 | 
							
								                    member(def, this.enclosed)
							 | 
						||
| 
								 | 
							
								                    && !this.variables.has(def.name)
							 | 
						||
| 
								 | 
							
								                ) {
							 | 
						||
| 
								 | 
							
								                    if (scope) {
							 | 
						||
| 
								 | 
							
								                        var scope_def = scope.find_variable(node);
							 | 
						||
| 
								 | 
							
								                        if (def.undeclared ? !scope_def : scope_def === def) {
							 | 
						||
| 
								 | 
							
								                            result = "f";
							 | 
						||
| 
								 | 
							
								                            return true;
							 | 
						||
| 
								 | 
							
								                        }
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                    result = false;
							 | 
						||
| 
								 | 
							
								                    return walk_abort;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                return true;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if (node instanceof AST_This && this instanceof AST_Arrow) {
							 | 
						||
| 
								 | 
							
								                result = false;
							 | 
						||
| 
								 | 
							
								                return walk_abort;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								        return result;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def_is_constant_expression(AST_Node, return_false);
							 | 
						||
| 
								 | 
							
								    def_is_constant_expression(AST_Constant, return_true);
							 | 
						||
| 
								 | 
							
								    def_is_constant_expression(AST_Class, function(scope) {
							 | 
						||
| 
								 | 
							
								        if (this.extends && !this.extends.is_constant_expression(scope)) {
							 | 
						||
| 
								 | 
							
								            return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        for (const prop of this.properties) {
							 | 
						||
| 
								 | 
							
								            if (prop.computed_key() && !prop.key.is_constant_expression(scope)) {
							 | 
						||
| 
								 | 
							
								                return false;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if (prop.static && prop.value && !prop.value.is_constant_expression(scope)) {
							 | 
						||
| 
								 | 
							
								                return false;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if (prop instanceof AST_ClassStaticBlock) {
							 | 
						||
| 
								 | 
							
								                return false;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return all_refs_local.call(this, scope);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_is_constant_expression(AST_Lambda, all_refs_local);
							 | 
						||
| 
								 | 
							
								    def_is_constant_expression(AST_Unary, function() {
							 | 
						||
| 
								 | 
							
								        return this.expression.is_constant_expression();
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_is_constant_expression(AST_Binary, function() {
							 | 
						||
| 
								 | 
							
								        return this.left.is_constant_expression()
							 | 
						||
| 
								 | 
							
								            && this.right.is_constant_expression();
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_is_constant_expression(AST_Array, function() {
							 | 
						||
| 
								 | 
							
								        return this.elements.every((l) => l.is_constant_expression());
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_is_constant_expression(AST_Object, function() {
							 | 
						||
| 
								 | 
							
								        return this.properties.every((l) => l.is_constant_expression());
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_is_constant_expression(AST_ObjectProperty, function() {
							 | 
						||
| 
								 | 
							
								        return !!(!(this.key instanceof AST_Node) && this.value && this.value.is_constant_expression());
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								})(function(node, func) {
							 | 
						||
| 
								 | 
							
								    node.DEFMETHOD("is_constant_expression", func);
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// may_throw_on_access()
							 | 
						||
| 
								 | 
							
								// returns true if this node may be null, undefined or contain `AST_Accessor`
							 | 
						||
| 
								 | 
							
								(function(def_may_throw_on_access) {
							 | 
						||
| 
								 | 
							
								    AST_Node.DEFMETHOD("may_throw_on_access", function(compressor) {
							 | 
						||
| 
								 | 
							
								        return !compressor.option("pure_getters")
							 | 
						||
| 
								 | 
							
								            || this._dot_throw(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function is_strict(compressor) {
							 | 
						||
| 
								 | 
							
								        return /strict/.test(compressor.option("pure_getters"));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def_may_throw_on_access(AST_Node, is_strict);
							 | 
						||
| 
								 | 
							
								    def_may_throw_on_access(AST_Null, return_true);
							 | 
						||
| 
								 | 
							
								    def_may_throw_on_access(AST_Undefined, return_true);
							 | 
						||
| 
								 | 
							
								    def_may_throw_on_access(AST_Constant, return_false);
							 | 
						||
| 
								 | 
							
								    def_may_throw_on_access(AST_Array, return_false);
							 | 
						||
| 
								 | 
							
								    def_may_throw_on_access(AST_Object, function(compressor) {
							 | 
						||
| 
								 | 
							
								        if (!is_strict(compressor)) return false;
							 | 
						||
| 
								 | 
							
								        for (var i = this.properties.length; --i >=0;)
							 | 
						||
| 
								 | 
							
								            if (this.properties[i]._dot_throw(compressor)) return true;
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    // Do not be as strict with classes as we are with objects.
							 | 
						||
| 
								 | 
							
								    // Hopefully the community is not going to abuse static getters and setters.
							 | 
						||
| 
								 | 
							
								    // https://github.com/terser/terser/issues/724#issuecomment-643655656
							 | 
						||
| 
								 | 
							
								    def_may_throw_on_access(AST_Class, return_false);
							 | 
						||
| 
								 | 
							
								    def_may_throw_on_access(AST_ObjectProperty, return_false);
							 | 
						||
| 
								 | 
							
								    def_may_throw_on_access(AST_ObjectGetter, return_true);
							 | 
						||
| 
								 | 
							
								    def_may_throw_on_access(AST_Expansion, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.expression._dot_throw(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw_on_access(AST_Function, return_false);
							 | 
						||
| 
								 | 
							
								    def_may_throw_on_access(AST_Arrow, return_false);
							 | 
						||
| 
								 | 
							
								    def_may_throw_on_access(AST_UnaryPostfix, return_false);
							 | 
						||
| 
								 | 
							
								    def_may_throw_on_access(AST_UnaryPrefix, function() {
							 | 
						||
| 
								 | 
							
								        return this.operator == "void";
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw_on_access(AST_Binary, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return (this.operator == "&&" || this.operator == "||" || this.operator == "??")
							 | 
						||
| 
								 | 
							
								            && (this.left._dot_throw(compressor) || this.right._dot_throw(compressor));
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw_on_access(AST_Assign, function(compressor) {
							 | 
						||
| 
								 | 
							
								        if (this.logical) return true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return this.operator == "="
							 | 
						||
| 
								 | 
							
								            && this.right._dot_throw(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw_on_access(AST_Conditional, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.consequent._dot_throw(compressor)
							 | 
						||
| 
								 | 
							
								            || this.alternative._dot_throw(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw_on_access(AST_Dot, function(compressor) {
							 | 
						||
| 
								 | 
							
								        if (!is_strict(compressor)) return false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (this.property == "prototype") {
							 | 
						||
| 
								 | 
							
								            return !(
							 | 
						||
| 
								 | 
							
								                this.expression instanceof AST_Function
							 | 
						||
| 
								 | 
							
								                || this.expression instanceof AST_Class
							 | 
						||
| 
								 | 
							
								            );
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw_on_access(AST_Chain, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.expression._dot_throw(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw_on_access(AST_Sequence, function(compressor) {
							 | 
						||
| 
								 | 
							
								        return this.tail_node()._dot_throw(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_may_throw_on_access(AST_SymbolRef, function(compressor) {
							 | 
						||
| 
								 | 
							
								        if (this.name === "arguments" && this.scope instanceof AST_Lambda) return false;
							 | 
						||
| 
								 | 
							
								        if (has_flag(this, UNDEFINED)) return true;
							 | 
						||
| 
								 | 
							
								        if (!is_strict(compressor)) return false;
							 | 
						||
| 
								 | 
							
								        if (is_undeclared_ref(this) && this.is_declared(compressor)) return false;
							 | 
						||
| 
								 | 
							
								        if (this.is_immutable()) return false;
							 | 
						||
| 
								 | 
							
								        var fixed = this.fixed_value();
							 | 
						||
| 
								 | 
							
								        return !fixed || fixed._dot_throw(compressor);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								})(function(node, func) {
							 | 
						||
| 
								 | 
							
								    node.DEFMETHOD("_dot_throw", func);
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export function is_lhs(node, parent) {
							 | 
						||
| 
								 | 
							
								    if (parent instanceof AST_Unary && unary_side_effects.has(parent.operator)) return parent.expression;
							 | 
						||
| 
								 | 
							
								    if (parent instanceof AST_Assign && parent.left === node) return node;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								(function(def_find_defs) {
							 | 
						||
| 
								 | 
							
								    function to_node(value, orig) {
							 | 
						||
| 
								 | 
							
								        if (value instanceof AST_Node) {
							 | 
						||
| 
								 | 
							
								            if (!(value instanceof AST_Constant)) {
							 | 
						||
| 
								 | 
							
								                // Value may be a function, an array including functions and even a complex assign / block expression,
							 | 
						||
| 
								 | 
							
								                // so it should never be shared in different places.
							 | 
						||
| 
								 | 
							
								                // Otherwise wrong information may be used in the compression phase
							 | 
						||
| 
								 | 
							
								                value = value.clone(true);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            return make_node(value.CTOR, orig, value);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (Array.isArray(value)) return make_node(AST_Array, orig, {
							 | 
						||
| 
								 | 
							
								            elements: value.map(function(value) {
							 | 
						||
| 
								 | 
							
								                return to_node(value, orig);
							 | 
						||
| 
								 | 
							
								            })
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								        if (value && typeof value == "object") {
							 | 
						||
| 
								 | 
							
								            var props = [];
							 | 
						||
| 
								 | 
							
								            for (var key in value) if (HOP(value, key)) {
							 | 
						||
| 
								 | 
							
								                props.push(make_node(AST_ObjectKeyVal, orig, {
							 | 
						||
| 
								 | 
							
								                    key: key,
							 | 
						||
| 
								 | 
							
								                    value: to_node(value[key], orig)
							 | 
						||
| 
								 | 
							
								                }));
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            return make_node(AST_Object, orig, {
							 | 
						||
| 
								 | 
							
								                properties: props
							 | 
						||
| 
								 | 
							
								            });
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return make_node_from_constant(value, orig);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    AST_Toplevel.DEFMETHOD("resolve_defines", function(compressor) {
							 | 
						||
| 
								 | 
							
								        if (!compressor.option("global_defs")) return this;
							 | 
						||
| 
								 | 
							
								        this.figure_out_scope({ ie8: compressor.option("ie8") });
							 | 
						||
| 
								 | 
							
								        return this.transform(new TreeTransformer(function(node) {
							 | 
						||
| 
								 | 
							
								            var def = node._find_defs(compressor, "");
							 | 
						||
| 
								 | 
							
								            if (!def) return;
							 | 
						||
| 
								 | 
							
								            var level = 0, child = node, parent;
							 | 
						||
| 
								 | 
							
								            while (parent = this.parent(level++)) {
							 | 
						||
| 
								 | 
							
								                if (!(parent instanceof AST_PropAccess)) break;
							 | 
						||
| 
								 | 
							
								                if (parent.expression !== child) break;
							 | 
						||
| 
								 | 
							
								                child = parent;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if (is_lhs(child, parent)) {
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            return def;
							 | 
						||
| 
								 | 
							
								        }));
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_find_defs(AST_Node, noop);
							 | 
						||
| 
								 | 
							
								    def_find_defs(AST_Chain, function(compressor, suffix) {
							 | 
						||
| 
								 | 
							
								        return this.expression._find_defs(compressor, suffix);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_find_defs(AST_Dot, function(compressor, suffix) {
							 | 
						||
| 
								 | 
							
								        return this.expression._find_defs(compressor, "." + this.property + suffix);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_find_defs(AST_SymbolDeclaration, function() {
							 | 
						||
| 
								 | 
							
								        if (!this.global()) return;
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_find_defs(AST_SymbolRef, function(compressor, suffix) {
							 | 
						||
| 
								 | 
							
								        if (!this.global()) return;
							 | 
						||
| 
								 | 
							
								        var defines = compressor.option("global_defs");
							 | 
						||
| 
								 | 
							
								        var name = this.name + suffix;
							 | 
						||
| 
								 | 
							
								        if (HOP(defines, name)) return to_node(defines[name], this);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								})(function(node, func) {
							 | 
						||
| 
								 | 
							
								    node.DEFMETHOD("_find_defs", func);
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// method to negate an expression
							 | 
						||
| 
								 | 
							
								(function(def_negate) {
							 | 
						||
| 
								 | 
							
								    function basic_negation(exp) {
							 | 
						||
| 
								 | 
							
								        return make_node(AST_UnaryPrefix, exp, {
							 | 
						||
| 
								 | 
							
								            operator: "!",
							 | 
						||
| 
								 | 
							
								            expression: exp
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    function best(orig, alt, first_in_statement) {
							 | 
						||
| 
								 | 
							
								        var negated = basic_negation(orig);
							 | 
						||
| 
								 | 
							
								        if (first_in_statement) {
							 | 
						||
| 
								 | 
							
								            var stat = make_node(AST_SimpleStatement, alt, {
							 | 
						||
| 
								 | 
							
								                body: alt
							 | 
						||
| 
								 | 
							
								            });
							 | 
						||
| 
								 | 
							
								            return best_of_expression(negated, stat) === stat ? alt : negated;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return best_of_expression(negated, alt);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    def_negate(AST_Node, function() {
							 | 
						||
| 
								 | 
							
								        return basic_negation(this);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_negate(AST_Statement, function() {
							 | 
						||
| 
								 | 
							
								        throw new Error("Cannot negate a statement");
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_negate(AST_Function, function() {
							 | 
						||
| 
								 | 
							
								        return basic_negation(this);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_negate(AST_Arrow, function() {
							 | 
						||
| 
								 | 
							
								        return basic_negation(this);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_negate(AST_UnaryPrefix, function() {
							 | 
						||
| 
								 | 
							
								        if (this.operator == "!")
							 | 
						||
| 
								 | 
							
								            return this.expression;
							 | 
						||
| 
								 | 
							
								        return basic_negation(this);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_negate(AST_Sequence, function(compressor) {
							 | 
						||
| 
								 | 
							
								        var expressions = this.expressions.slice();
							 | 
						||
| 
								 | 
							
								        expressions.push(expressions.pop().negate(compressor));
							 | 
						||
| 
								 | 
							
								        return make_sequence(this, expressions);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_negate(AST_Conditional, function(compressor, first_in_statement) {
							 | 
						||
| 
								 | 
							
								        var self = this.clone();
							 | 
						||
| 
								 | 
							
								        self.consequent = self.consequent.negate(compressor);
							 | 
						||
| 
								 | 
							
								        self.alternative = self.alternative.negate(compressor);
							 | 
						||
| 
								 | 
							
								        return best(this, self, first_in_statement);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_negate(AST_Binary, function(compressor, first_in_statement) {
							 | 
						||
| 
								 | 
							
								        var self = this.clone(), op = this.operator;
							 | 
						||
| 
								 | 
							
								        if (compressor.option("unsafe_comps")) {
							 | 
						||
| 
								 | 
							
								            switch (op) {
							 | 
						||
| 
								 | 
							
								              case "<=" : self.operator = ">"  ; return self;
							 | 
						||
| 
								 | 
							
								              case "<"  : self.operator = ">=" ; return self;
							 | 
						||
| 
								 | 
							
								              case ">=" : self.operator = "<"  ; return self;
							 | 
						||
| 
								 | 
							
								              case ">"  : self.operator = "<=" ; return self;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        switch (op) {
							 | 
						||
| 
								 | 
							
								          case "==" : self.operator = "!="; return self;
							 | 
						||
| 
								 | 
							
								          case "!=" : self.operator = "=="; return self;
							 | 
						||
| 
								 | 
							
								          case "===": self.operator = "!=="; return self;
							 | 
						||
| 
								 | 
							
								          case "!==": self.operator = "==="; return self;
							 | 
						||
| 
								 | 
							
								          case "&&":
							 | 
						||
| 
								 | 
							
								            self.operator = "||";
							 | 
						||
| 
								 | 
							
								            self.left = self.left.negate(compressor, first_in_statement);
							 | 
						||
| 
								 | 
							
								            self.right = self.right.negate(compressor);
							 | 
						||
| 
								 | 
							
								            return best(this, self, first_in_statement);
							 | 
						||
| 
								 | 
							
								          case "||":
							 | 
						||
| 
								 | 
							
								            self.operator = "&&";
							 | 
						||
| 
								 | 
							
								            self.left = self.left.negate(compressor, first_in_statement);
							 | 
						||
| 
								 | 
							
								            self.right = self.right.negate(compressor);
							 | 
						||
| 
								 | 
							
								            return best(this, self, first_in_statement);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return basic_negation(this);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								})(function(node, func) {
							 | 
						||
| 
								 | 
							
								    node.DEFMETHOD("negate", function(compressor, first_in_statement) {
							 | 
						||
| 
								 | 
							
								        return func.call(this, compressor, first_in_statement);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Is the callee of this function pure?
							 | 
						||
| 
								 | 
							
								var global_pure_fns = makePredicate("Boolean decodeURI decodeURIComponent Date encodeURI encodeURIComponent Error escape EvalError isFinite isNaN Number Object parseFloat parseInt RangeError ReferenceError String SyntaxError TypeError unescape URIError");
							 | 
						||
| 
								 | 
							
								AST_Call.DEFMETHOD("is_callee_pure", function(compressor) {
							 | 
						||
| 
								 | 
							
								    if (compressor.option("unsafe")) {
							 | 
						||
| 
								 | 
							
								        var expr = this.expression;
							 | 
						||
| 
								 | 
							
								        var first_arg = (this.args && this.args[0] && this.args[0].evaluate(compressor));
							 | 
						||
| 
								 | 
							
								        if (
							 | 
						||
| 
								 | 
							
								            expr.expression && expr.expression.name === "hasOwnProperty" &&
							 | 
						||
| 
								 | 
							
								            (first_arg == null || first_arg.thedef && first_arg.thedef.undeclared)
							 | 
						||
| 
								 | 
							
								        ) {
							 | 
						||
| 
								 | 
							
								            return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (is_undeclared_ref(expr) && global_pure_fns.has(expr.name)) return true;
							 | 
						||
| 
								 | 
							
								        if (
							 | 
						||
| 
								 | 
							
								            expr instanceof AST_Dot
							 | 
						||
| 
								 | 
							
								            && is_undeclared_ref(expr.expression)
							 | 
						||
| 
								 | 
							
								            && is_pure_native_fn(expr.expression.name, expr.property)
							 | 
						||
| 
								 | 
							
								        ) {
							 | 
						||
| 
								 | 
							
								            return true;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return !!has_annotation(this, _PURE) || !compressor.pure_funcs(this);
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// If I call this, is it a pure function?
							 | 
						||
| 
								 | 
							
								AST_Node.DEFMETHOD("is_call_pure", return_false);
							 | 
						||
| 
								 | 
							
								AST_Dot.DEFMETHOD("is_call_pure", function(compressor) {
							 | 
						||
| 
								 | 
							
								    if (!compressor.option("unsafe")) return;
							 | 
						||
| 
								 | 
							
								    const expr = this.expression;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    let native_obj;
							 | 
						||
| 
								 | 
							
								    if (expr instanceof AST_Array) {
							 | 
						||
| 
								 | 
							
								        native_obj = "Array";
							 | 
						||
| 
								 | 
							
								    } else if (expr.is_boolean()) {
							 | 
						||
| 
								 | 
							
								        native_obj = "Boolean";
							 | 
						||
| 
								 | 
							
								    } else if (expr.is_number(compressor)) {
							 | 
						||
| 
								 | 
							
								        native_obj = "Number";
							 | 
						||
| 
								 | 
							
								    } else if (expr instanceof AST_RegExp) {
							 | 
						||
| 
								 | 
							
								        native_obj = "RegExp";
							 | 
						||
| 
								 | 
							
								    } else if (expr.is_string(compressor)) {
							 | 
						||
| 
								 | 
							
								        native_obj = "String";
							 | 
						||
| 
								 | 
							
								    } else if (!this.may_throw_on_access(compressor)) {
							 | 
						||
| 
								 | 
							
								        native_obj = "Object";
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return native_obj != null && is_pure_native_method(native_obj, this.property);
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// tell me if a statement aborts
							 | 
						||
| 
								 | 
							
								export const aborts = (thing) => thing && thing.aborts();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								(function(def_aborts) {
							 | 
						||
| 
								 | 
							
								    def_aborts(AST_Statement, return_null);
							 | 
						||
| 
								 | 
							
								    def_aborts(AST_Jump, return_this);
							 | 
						||
| 
								 | 
							
								    function block_aborts() {
							 | 
						||
| 
								 | 
							
								        for (var i = 0; i < this.body.length; i++) {
							 | 
						||
| 
								 | 
							
								            if (aborts(this.body[i])) {
							 | 
						||
| 
								 | 
							
								                return this.body[i];
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return null;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    def_aborts(AST_Import, return_null);
							 | 
						||
| 
								 | 
							
								    def_aborts(AST_BlockStatement, block_aborts);
							 | 
						||
| 
								 | 
							
								    def_aborts(AST_SwitchBranch, block_aborts);
							 | 
						||
| 
								 | 
							
								    def_aborts(AST_DefClass, function () {
							 | 
						||
| 
								 | 
							
								        for (const prop of this.properties) {
							 | 
						||
| 
								 | 
							
								            if (prop instanceof AST_ClassStaticBlock) {
							 | 
						||
| 
								 | 
							
								                if (prop.aborts()) return prop;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return null;
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    def_aborts(AST_ClassStaticBlock, block_aborts);
							 | 
						||
| 
								 | 
							
								    def_aborts(AST_If, function() {
							 | 
						||
| 
								 | 
							
								        return this.alternative && aborts(this.body) && aborts(this.alternative) && this;
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								})(function(node, func) {
							 | 
						||
| 
								 | 
							
								    node.DEFMETHOD("aborts", func);
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export function is_modified(compressor, tw, node, value, level, immutable) {
							 | 
						||
| 
								 | 
							
								    var parent = tw.parent(level);
							 | 
						||
| 
								 | 
							
								    var lhs = is_lhs(node, parent);
							 | 
						||
| 
								 | 
							
								    if (lhs) return lhs;
							 | 
						||
| 
								 | 
							
								    if (!immutable
							 | 
						||
| 
								 | 
							
								        && parent instanceof AST_Call
							 | 
						||
| 
								 | 
							
								        && parent.expression === node
							 | 
						||
| 
								 | 
							
								        && !(value instanceof AST_Arrow)
							 | 
						||
| 
								 | 
							
								        && !(value instanceof AST_Class)
							 | 
						||
| 
								 | 
							
								        && !parent.is_callee_pure(compressor)
							 | 
						||
| 
								 | 
							
								        && (!(value instanceof AST_Function)
							 | 
						||
| 
								 | 
							
								            || !(parent instanceof AST_New) && value.contains_this())) {
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (parent instanceof AST_Array) {
							 | 
						||
| 
								 | 
							
								        return is_modified(compressor, tw, parent, parent, level + 1);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (parent instanceof AST_ObjectKeyVal && node === parent.value) {
							 | 
						||
| 
								 | 
							
								        var obj = tw.parent(level + 1);
							 | 
						||
| 
								 | 
							
								        return is_modified(compressor, tw, obj, obj, level + 2);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (parent instanceof AST_PropAccess && parent.expression === node) {
							 | 
						||
| 
								 | 
							
								        var prop = read_property(value, parent.property);
							 | 
						||
| 
								 | 
							
								        return !immutable && is_modified(compressor, tw, parent, prop, level + 1);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 |