react / react-0.13.3 / examples / basic-commonjs / node_modules / browserify / node_modules / umd / node_modules / uglify-js / lib / compress.js
80743 views/***********************************************************************12A JavaScript tokenizer / parser / beautifier / compressor.3https://github.com/mishoo/UglifyJS245-------------------------------- (C) ---------------------------------67Author: Mihai Bazon8<[email protected]>9http://mihai.bazon.net/blog1011Distributed under the BSD license:1213Copyright 2012 (c) Mihai Bazon <[email protected]>1415Redistribution and use in source and binary forms, with or without16modification, are permitted provided that the following conditions17are met:1819* Redistributions of source code must retain the above20copyright notice, this list of conditions and the following21disclaimer.2223* Redistributions in binary form must reproduce the above24copyright notice, this list of conditions and the following25disclaimer in the documentation and/or other materials26provided with the distribution.2728THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY29EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE30IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR31PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE32LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,33OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,34PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR35PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY36THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR37TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF38THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF39SUCH DAMAGE.4041***********************************************************************/4243"use strict";4445function Compressor(options, false_by_default) {46if (!(this instanceof Compressor))47return new Compressor(options, false_by_default);48TreeTransformer.call(this, this.before, this.after);49this.options = defaults(options, {50sequences : !false_by_default,51properties : !false_by_default,52dead_code : !false_by_default,53drop_debugger : !false_by_default,54unsafe : false,55unsafe_comps : false,56conditionals : !false_by_default,57comparisons : !false_by_default,58evaluate : !false_by_default,59booleans : !false_by_default,60loops : !false_by_default,61unused : !false_by_default,62hoist_funs : !false_by_default,63keep_fargs : false,64keep_fnames : false,65hoist_vars : false,66if_return : !false_by_default,67join_vars : !false_by_default,68cascade : !false_by_default,69side_effects : !false_by_default,70pure_getters : false,71pure_funcs : null,72negate_iife : !false_by_default,73screw_ie8 : false,74drop_console : false,75angular : false,7677warnings : true,78global_defs : {}79}, true);80};8182Compressor.prototype = new TreeTransformer;83merge(Compressor.prototype, {84option: function(key) { return this.options[key] },85warn: function() {86if (this.options.warnings)87AST_Node.warn.apply(AST_Node, arguments);88},89before: function(node, descend, in_list) {90if (node._squeezed) return node;91var was_scope = false;92if (node instanceof AST_Scope) {93node = node.hoist_declarations(this);94was_scope = true;95}96descend(node, this);97node = node.optimize(this);98if (was_scope && node instanceof AST_Scope) {99node.drop_unused(this);100descend(node, this);101}102node._squeezed = true;103return node;104}105});106107(function(){108109function OPT(node, optimizer) {110node.DEFMETHOD("optimize", function(compressor){111var self = this;112if (self._optimized) return self;113var opt = optimizer(self, compressor);114opt._optimized = true;115if (opt === self) return opt;116return opt.transform(compressor);117});118};119120OPT(AST_Node, function(self, compressor){121return self;122});123124AST_Node.DEFMETHOD("equivalent_to", function(node){125// XXX: this is a rather expensive way to test two node's equivalence:126return this.print_to_string() == node.print_to_string();127});128129function make_node(ctor, orig, props) {130if (!props) props = {};131if (orig) {132if (!props.start) props.start = orig.start;133if (!props.end) props.end = orig.end;134}135return new ctor(props);136};137138function make_node_from_constant(compressor, val, orig) {139// XXX: WIP.140// if (val instanceof AST_Node) return val.transform(new TreeTransformer(null, function(node){141// if (node instanceof AST_SymbolRef) {142// var scope = compressor.find_parent(AST_Scope);143// var def = scope.find_variable(node);144// node.thedef = def;145// return node;146// }147// })).transform(compressor);148149if (val instanceof AST_Node) return val.transform(compressor);150switch (typeof val) {151case "string":152return make_node(AST_String, orig, {153value: val154}).optimize(compressor);155case "number":156return make_node(isNaN(val) ? AST_NaN : AST_Number, orig, {157value: val158}).optimize(compressor);159case "boolean":160return make_node(val ? AST_True : AST_False, orig).optimize(compressor);161case "undefined":162return make_node(AST_Undefined, orig).optimize(compressor);163default:164if (val === null) {165return make_node(AST_Null, orig, { value: null }).optimize(compressor);166}167if (val instanceof RegExp) {168return make_node(AST_RegExp, orig, { value: val }).optimize(compressor);169}170throw new Error(string_template("Can't handle constant of type: {type}", {171type: typeof val172}));173}174};175176function as_statement_array(thing) {177if (thing === null) return [];178if (thing instanceof AST_BlockStatement) return thing.body;179if (thing instanceof AST_EmptyStatement) return [];180if (thing instanceof AST_Statement) return [ thing ];181throw new Error("Can't convert thing to statement array");182};183184function is_empty(thing) {185if (thing === null) return true;186if (thing instanceof AST_EmptyStatement) return true;187if (thing instanceof AST_BlockStatement) return thing.body.length == 0;188return false;189};190191function loop_body(x) {192if (x instanceof AST_Switch) return x;193if (x instanceof AST_For || x instanceof AST_ForIn || x instanceof AST_DWLoop) {194return (x.body instanceof AST_BlockStatement ? x.body : x);195}196return x;197};198199function tighten_body(statements, compressor) {200var CHANGED;201do {202CHANGED = false;203if (compressor.option("angular")) {204statements = process_for_angular(statements);205}206statements = eliminate_spurious_blocks(statements);207if (compressor.option("dead_code")) {208statements = eliminate_dead_code(statements, compressor);209}210if (compressor.option("if_return")) {211statements = handle_if_return(statements, compressor);212}213if (compressor.option("sequences")) {214statements = sequencesize(statements, compressor);215}216if (compressor.option("join_vars")) {217statements = join_consecutive_vars(statements, compressor);218}219} while (CHANGED);220221if (compressor.option("negate_iife")) {222negate_iifes(statements, compressor);223}224225return statements;226227function process_for_angular(statements) {228function has_inject(comment) {229return /@ngInject/.test(comment.value);230}231function make_arguments_names_list(func) {232return func.argnames.map(function(sym){233return make_node(AST_String, sym, { value: sym.name });234});235}236function make_array(orig, elements) {237return make_node(AST_Array, orig, { elements: elements });238}239function make_injector(func, name) {240return make_node(AST_SimpleStatement, func, {241body: make_node(AST_Assign, func, {242operator: "=",243left: make_node(AST_Dot, name, {244expression: make_node(AST_SymbolRef, name, name),245property: "$inject"246}),247right: make_array(func, make_arguments_names_list(func))248})249});250}251function check_expression(body) {252if (body && body.args) {253// if this is a function call check all of arguments passed254body.args.forEach(function(argument, index, array) {255var comments = argument.start.comments_before;256// if the argument is function preceded by @ngInject257if (argument instanceof AST_Lambda && comments.length && has_inject(comments[0])) {258// replace the function with an array of names of its parameters and function at the end259array[index] = make_array(argument, make_arguments_names_list(argument).concat(argument));260}261});262// if this is chained call check previous one recursively263if (body.expression && body.expression.expression) {264check_expression(body.expression.expression);265}266}267}268return statements.reduce(function(a, stat){269a.push(stat);270271if (stat.body && stat.body.args) {272check_expression(stat.body);273} else {274var token = stat.start;275var comments = token.comments_before;276if (comments && comments.length > 0) {277var last = comments.pop();278if (has_inject(last)) {279// case 1: defun280if (stat instanceof AST_Defun) {281a.push(make_injector(stat, stat.name));282}283else if (stat instanceof AST_Definitions) {284stat.definitions.forEach(function(def) {285if (def.value && def.value instanceof AST_Lambda) {286a.push(make_injector(def.value, def.name));287}288});289}290else {291compressor.warn("Unknown statement marked with @ngInject [{file}:{line},{col}]", token);292}293}294}295}296297return a;298}, []);299}300301function eliminate_spurious_blocks(statements) {302var seen_dirs = [];303return statements.reduce(function(a, stat){304if (stat instanceof AST_BlockStatement) {305CHANGED = true;306a.push.apply(a, eliminate_spurious_blocks(stat.body));307} else if (stat instanceof AST_EmptyStatement) {308CHANGED = true;309} else if (stat instanceof AST_Directive) {310if (seen_dirs.indexOf(stat.value) < 0) {311a.push(stat);312seen_dirs.push(stat.value);313} else {314CHANGED = true;315}316} else {317a.push(stat);318}319return a;320}, []);321};322323function handle_if_return(statements, compressor) {324var self = compressor.self();325var in_lambda = self instanceof AST_Lambda;326var ret = [];327loop: for (var i = statements.length; --i >= 0;) {328var stat = statements[i];329switch (true) {330case (in_lambda && stat instanceof AST_Return && !stat.value && ret.length == 0):331CHANGED = true;332// note, ret.length is probably always zero333// because we drop unreachable code before this334// step. nevertheless, it's good to check.335continue loop;336case stat instanceof AST_If:337if (stat.body instanceof AST_Return) {338//---339// pretty silly case, but:340// if (foo()) return; return; ==> foo(); return;341if (((in_lambda && ret.length == 0)342|| (ret[0] instanceof AST_Return && !ret[0].value))343&& !stat.body.value && !stat.alternative) {344CHANGED = true;345var cond = make_node(AST_SimpleStatement, stat.condition, {346body: stat.condition347});348ret.unshift(cond);349continue loop;350}351//---352// if (foo()) return x; return y; ==> return foo() ? x : y;353if (ret[0] instanceof AST_Return && stat.body.value && ret[0].value && !stat.alternative) {354CHANGED = true;355stat = stat.clone();356stat.alternative = ret[0];357ret[0] = stat.transform(compressor);358continue loop;359}360//---361// if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined;362if ((ret.length == 0 || ret[0] instanceof AST_Return) && stat.body.value && !stat.alternative && in_lambda) {363CHANGED = true;364stat = stat.clone();365stat.alternative = ret[0] || make_node(AST_Return, stat, {366value: make_node(AST_Undefined, stat)367});368ret[0] = stat.transform(compressor);369continue loop;370}371//---372// if (foo()) return; [ else x... ]; y... ==> if (!foo()) { x...; y... }373if (!stat.body.value && in_lambda) {374CHANGED = true;375stat = stat.clone();376stat.condition = stat.condition.negate(compressor);377stat.body = make_node(AST_BlockStatement, stat, {378body: as_statement_array(stat.alternative).concat(ret)379});380stat.alternative = null;381ret = [ stat.transform(compressor) ];382continue loop;383}384//---385if (ret.length == 1 && in_lambda && ret[0] instanceof AST_SimpleStatement386&& (!stat.alternative || stat.alternative instanceof AST_SimpleStatement)) {387CHANGED = true;388ret.push(make_node(AST_Return, ret[0], {389value: make_node(AST_Undefined, ret[0])390}).transform(compressor));391ret = as_statement_array(stat.alternative).concat(ret);392ret.unshift(stat);393continue loop;394}395}396397var ab = aborts(stat.body);398var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab.label) : null;399if (ab && ((ab instanceof AST_Return && !ab.value && in_lambda)400|| (ab instanceof AST_Continue && self === loop_body(lct))401|| (ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct))) {402if (ab.label) {403remove(ab.label.thedef.references, ab);404}405CHANGED = true;406var body = as_statement_array(stat.body).slice(0, -1);407stat = stat.clone();408stat.condition = stat.condition.negate(compressor);409stat.body = make_node(AST_BlockStatement, stat, {410body: as_statement_array(stat.alternative).concat(ret)411});412stat.alternative = make_node(AST_BlockStatement, stat, {413body: body414});415ret = [ stat.transform(compressor) ];416continue loop;417}418419var ab = aborts(stat.alternative);420var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab.label) : null;421if (ab && ((ab instanceof AST_Return && !ab.value && in_lambda)422|| (ab instanceof AST_Continue && self === loop_body(lct))423|| (ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct))) {424if (ab.label) {425remove(ab.label.thedef.references, ab);426}427CHANGED = true;428stat = stat.clone();429stat.body = make_node(AST_BlockStatement, stat.body, {430body: as_statement_array(stat.body).concat(ret)431});432stat.alternative = make_node(AST_BlockStatement, stat.alternative, {433body: as_statement_array(stat.alternative).slice(0, -1)434});435ret = [ stat.transform(compressor) ];436continue loop;437}438439ret.unshift(stat);440break;441default:442ret.unshift(stat);443break;444}445}446return ret;447};448449function eliminate_dead_code(statements, compressor) {450var has_quit = false;451var orig = statements.length;452var self = compressor.self();453statements = statements.reduce(function(a, stat){454if (has_quit) {455extract_declarations_from_unreachable_code(compressor, stat, a);456} else {457if (stat instanceof AST_LoopControl) {458var lct = compressor.loopcontrol_target(stat.label);459if ((stat instanceof AST_Break460&& lct instanceof AST_BlockStatement461&& loop_body(lct) === self) || (stat instanceof AST_Continue462&& loop_body(lct) === self)) {463if (stat.label) {464remove(stat.label.thedef.references, stat);465}466} else {467a.push(stat);468}469} else {470a.push(stat);471}472if (aborts(stat)) has_quit = true;473}474return a;475}, []);476CHANGED = statements.length != orig;477return statements;478};479480function sequencesize(statements, compressor) {481if (statements.length < 2) return statements;482var seq = [], ret = [];483function push_seq() {484seq = AST_Seq.from_array(seq);485if (seq) ret.push(make_node(AST_SimpleStatement, seq, {486body: seq487}));488seq = [];489};490statements.forEach(function(stat){491if (stat instanceof AST_SimpleStatement && seq.length < 2000) seq.push(stat.body);492else push_seq(), ret.push(stat);493});494push_seq();495ret = sequencesize_2(ret, compressor);496CHANGED = ret.length != statements.length;497return ret;498};499500function sequencesize_2(statements, compressor) {501function cons_seq(right) {502ret.pop();503var left = prev.body;504if (left instanceof AST_Seq) {505left.add(right);506} else {507left = AST_Seq.cons(left, right);508}509return left.transform(compressor);510};511var ret = [], prev = null;512statements.forEach(function(stat){513if (prev) {514if (stat instanceof AST_For) {515var opera = {};516try {517prev.body.walk(new TreeWalker(function(node){518if (node instanceof AST_Binary && node.operator == "in")519throw opera;520}));521if (stat.init && !(stat.init instanceof AST_Definitions)) {522stat.init = cons_seq(stat.init);523}524else if (!stat.init) {525stat.init = prev.body;526ret.pop();527}528} catch(ex) {529if (ex !== opera) throw ex;530}531}532else if (stat instanceof AST_If) {533stat.condition = cons_seq(stat.condition);534}535else if (stat instanceof AST_With) {536stat.expression = cons_seq(stat.expression);537}538else if (stat instanceof AST_Exit && stat.value) {539stat.value = cons_seq(stat.value);540}541else if (stat instanceof AST_Exit) {542stat.value = cons_seq(make_node(AST_Undefined, stat));543}544else if (stat instanceof AST_Switch) {545stat.expression = cons_seq(stat.expression);546}547}548ret.push(stat);549prev = stat instanceof AST_SimpleStatement ? stat : null;550});551return ret;552};553554function join_consecutive_vars(statements, compressor) {555var prev = null;556return statements.reduce(function(a, stat){557if (stat instanceof AST_Definitions && prev && prev.TYPE == stat.TYPE) {558prev.definitions = prev.definitions.concat(stat.definitions);559CHANGED = true;560}561else if (stat instanceof AST_For562&& prev instanceof AST_Definitions563&& (!stat.init || stat.init.TYPE == prev.TYPE)) {564CHANGED = true;565a.pop();566if (stat.init) {567stat.init.definitions = prev.definitions.concat(stat.init.definitions);568} else {569stat.init = prev;570}571a.push(stat);572prev = stat;573}574else {575prev = stat;576a.push(stat);577}578return a;579}, []);580};581582function negate_iifes(statements, compressor) {583statements.forEach(function(stat){584if (stat instanceof AST_SimpleStatement) {585stat.body = (function transform(thing) {586return thing.transform(new TreeTransformer(function(node){587if (node instanceof AST_Call && node.expression instanceof AST_Function) {588return make_node(AST_UnaryPrefix, node, {589operator: "!",590expression: node591});592}593else if (node instanceof AST_Call) {594node.expression = transform(node.expression);595}596else if (node instanceof AST_Seq) {597node.car = transform(node.car);598}599else if (node instanceof AST_Conditional) {600var expr = transform(node.condition);601if (expr !== node.condition) {602// it has been negated, reverse603node.condition = expr;604var tmp = node.consequent;605node.consequent = node.alternative;606node.alternative = tmp;607}608}609return node;610}));611})(stat.body);612}613});614};615616};617618function extract_declarations_from_unreachable_code(compressor, stat, target) {619compressor.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start);620stat.walk(new TreeWalker(function(node){621if (node instanceof AST_Definitions) {622compressor.warn("Declarations in unreachable code! [{file}:{line},{col}]", node.start);623node.remove_initializers();624target.push(node);625return true;626}627if (node instanceof AST_Defun) {628target.push(node);629return true;630}631if (node instanceof AST_Scope) {632return true;633}634}));635};636637/* -----[ boolean/negation helpers ]----- */638639// methods to determine whether an expression has a boolean result type640(function (def){641var unary_bool = [ "!", "delete" ];642var binary_bool = [ "in", "instanceof", "==", "!=", "===", "!==", "<", "<=", ">=", ">" ];643def(AST_Node, function(){ return false });644def(AST_UnaryPrefix, function(){645return member(this.operator, unary_bool);646});647def(AST_Binary, function(){648return member(this.operator, binary_bool) ||649( (this.operator == "&&" || this.operator == "||") &&650this.left.is_boolean() && this.right.is_boolean() );651});652def(AST_Conditional, function(){653return this.consequent.is_boolean() && this.alternative.is_boolean();654});655def(AST_Assign, function(){656return this.operator == "=" && this.right.is_boolean();657});658def(AST_Seq, function(){659return this.cdr.is_boolean();660});661def(AST_True, function(){ return true });662def(AST_False, function(){ return true });663})(function(node, func){664node.DEFMETHOD("is_boolean", func);665});666667// methods to determine if an expression has a string result type668(function (def){669def(AST_Node, function(){ return false });670def(AST_String, function(){ return true });671def(AST_UnaryPrefix, function(){672return this.operator == "typeof";673});674def(AST_Binary, function(compressor){675return this.operator == "+" &&676(this.left.is_string(compressor) || this.right.is_string(compressor));677});678def(AST_Assign, function(compressor){679return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor);680});681def(AST_Seq, function(compressor){682return this.cdr.is_string(compressor);683});684def(AST_Conditional, function(compressor){685return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);686});687def(AST_Call, function(compressor){688return compressor.option("unsafe")689&& this.expression instanceof AST_SymbolRef690&& this.expression.name == "String"691&& this.expression.undeclared();692});693})(function(node, func){694node.DEFMETHOD("is_string", func);695});696697function best_of(ast1, ast2) {698return ast1.print_to_string().length >699ast2.print_to_string().length700? ast2 : ast1;701};702703// methods to evaluate a constant expression704(function (def){705// The evaluate method returns an array with one or two706// elements. If the node has been successfully reduced to a707// constant, then the second element tells us the value;708// otherwise the second element is missing. The first element709// of the array is always an AST_Node descendant; if710// evaluation was successful it's a node that represents the711// constant; otherwise it's the original or a replacement node.712AST_Node.DEFMETHOD("evaluate", function(compressor){713if (!compressor.option("evaluate")) return [ this ];714try {715var val = this._eval(compressor);716return [ best_of(make_node_from_constant(compressor, val, this), this), val ];717} catch(ex) {718if (ex !== def) throw ex;719return [ this ];720}721});722def(AST_Statement, function(){723throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));724});725def(AST_Function, function(){726// XXX: AST_Function inherits from AST_Scope, which itself727// inherits from AST_Statement; however, an AST_Function728// isn't really a statement. This could byte in other729// places too. :-( Wish JS had multiple inheritance.730throw def;731});732function ev(node, compressor) {733if (!compressor) throw new Error("Compressor must be passed");734735return node._eval(compressor);736};737def(AST_Node, function(){738throw def; // not constant739});740def(AST_Constant, function(){741return this.getValue();742});743def(AST_UnaryPrefix, function(compressor){744var e = this.expression;745switch (this.operator) {746case "!": return !ev(e, compressor);747case "typeof":748// Function would be evaluated to an array and so typeof would749// incorrectly return 'object'. Hence making is a special case.750if (e instanceof AST_Function) return typeof function(){};751752e = ev(e, compressor);753754// typeof <RegExp> returns "object" or "function" on different platforms755// so cannot evaluate reliably756if (e instanceof RegExp) throw def;757758return typeof e;759case "void": return void ev(e, compressor);760case "~": return ~ev(e, compressor);761case "-":762e = ev(e, compressor);763if (e === 0) throw def;764return -e;765case "+": return +ev(e, compressor);766}767throw def;768});769def(AST_Binary, function(c){770var left = this.left, right = this.right;771switch (this.operator) {772case "&&" : return ev(left, c) && ev(right, c);773case "||" : return ev(left, c) || ev(right, c);774case "|" : return ev(left, c) | ev(right, c);775case "&" : return ev(left, c) & ev(right, c);776case "^" : return ev(left, c) ^ ev(right, c);777case "+" : return ev(left, c) + ev(right, c);778case "*" : return ev(left, c) * ev(right, c);779case "/" : return ev(left, c) / ev(right, c);780case "%" : return ev(left, c) % ev(right, c);781case "-" : return ev(left, c) - ev(right, c);782case "<<" : return ev(left, c) << ev(right, c);783case ">>" : return ev(left, c) >> ev(right, c);784case ">>>" : return ev(left, c) >>> ev(right, c);785case "==" : return ev(left, c) == ev(right, c);786case "===" : return ev(left, c) === ev(right, c);787case "!=" : return ev(left, c) != ev(right, c);788case "!==" : return ev(left, c) !== ev(right, c);789case "<" : return ev(left, c) < ev(right, c);790case "<=" : return ev(left, c) <= ev(right, c);791case ">" : return ev(left, c) > ev(right, c);792case ">=" : return ev(left, c) >= ev(right, c);793case "in" : return ev(left, c) in ev(right, c);794case "instanceof" : return ev(left, c) instanceof ev(right, c);795}796throw def;797});798def(AST_Conditional, function(compressor){799return ev(this.condition, compressor)800? ev(this.consequent, compressor)801: ev(this.alternative, compressor);802});803def(AST_SymbolRef, function(compressor){804var d = this.definition();805if (d && d.constant && d.init) return ev(d.init, compressor);806throw def;807});808def(AST_Dot, function(compressor){809if (compressor.option("unsafe") && this.property == "length") {810var str = ev(this.expression, compressor);811if (typeof str == "string")812return str.length;813}814throw def;815});816})(function(node, func){817node.DEFMETHOD("_eval", func);818});819820// method to negate an expression821(function(def){822function basic_negation(exp) {823return make_node(AST_UnaryPrefix, exp, {824operator: "!",825expression: exp826});827};828def(AST_Node, function(){829return basic_negation(this);830});831def(AST_Statement, function(){832throw new Error("Cannot negate a statement");833});834def(AST_Function, function(){835return basic_negation(this);836});837def(AST_UnaryPrefix, function(){838if (this.operator == "!")839return this.expression;840return basic_negation(this);841});842def(AST_Seq, function(compressor){843var self = this.clone();844self.cdr = self.cdr.negate(compressor);845return self;846});847def(AST_Conditional, function(compressor){848var self = this.clone();849self.consequent = self.consequent.negate(compressor);850self.alternative = self.alternative.negate(compressor);851return best_of(basic_negation(this), self);852});853def(AST_Binary, function(compressor){854var self = this.clone(), op = this.operator;855if (compressor.option("unsafe_comps")) {856switch (op) {857case "<=" : self.operator = ">" ; return self;858case "<" : self.operator = ">=" ; return self;859case ">=" : self.operator = "<" ; return self;860case ">" : self.operator = "<=" ; return self;861}862}863switch (op) {864case "==" : self.operator = "!="; return self;865case "!=" : self.operator = "=="; return self;866case "===": self.operator = "!=="; return self;867case "!==": self.operator = "==="; return self;868case "&&":869self.operator = "||";870self.left = self.left.negate(compressor);871self.right = self.right.negate(compressor);872return best_of(basic_negation(this), self);873case "||":874self.operator = "&&";875self.left = self.left.negate(compressor);876self.right = self.right.negate(compressor);877return best_of(basic_negation(this), self);878}879return basic_negation(this);880});881})(function(node, func){882node.DEFMETHOD("negate", function(compressor){883return func.call(this, compressor);884});885});886887// determine if expression has side effects888(function(def){889def(AST_Node, function(compressor){ return true });890891def(AST_EmptyStatement, function(compressor){ return false });892def(AST_Constant, function(compressor){ return false });893def(AST_This, function(compressor){ return false });894895def(AST_Call, function(compressor){896var pure = compressor.option("pure_funcs");897if (!pure) return true;898return pure.indexOf(this.expression.print_to_string()) < 0;899});900901def(AST_Block, function(compressor){902for (var i = this.body.length; --i >= 0;) {903if (this.body[i].has_side_effects(compressor))904return true;905}906return false;907});908909def(AST_SimpleStatement, function(compressor){910return this.body.has_side_effects(compressor);911});912def(AST_Defun, function(compressor){ return true });913def(AST_Function, function(compressor){ return false });914def(AST_Binary, function(compressor){915return this.left.has_side_effects(compressor)916|| this.right.has_side_effects(compressor);917});918def(AST_Assign, function(compressor){ return true });919def(AST_Conditional, function(compressor){920return this.condition.has_side_effects(compressor)921|| this.consequent.has_side_effects(compressor)922|| this.alternative.has_side_effects(compressor);923});924def(AST_Unary, function(compressor){925return this.operator == "delete"926|| this.operator == "++"927|| this.operator == "--"928|| this.expression.has_side_effects(compressor);929});930def(AST_SymbolRef, function(compressor){931return this.global() && this.undeclared();932});933def(AST_Object, function(compressor){934for (var i = this.properties.length; --i >= 0;)935if (this.properties[i].has_side_effects(compressor))936return true;937return false;938});939def(AST_ObjectProperty, function(compressor){940return this.value.has_side_effects(compressor);941});942def(AST_Array, function(compressor){943for (var i = this.elements.length; --i >= 0;)944if (this.elements[i].has_side_effects(compressor))945return true;946return false;947});948def(AST_Dot, function(compressor){949if (!compressor.option("pure_getters")) return true;950return this.expression.has_side_effects(compressor);951});952def(AST_Sub, function(compressor){953if (!compressor.option("pure_getters")) return true;954return this.expression.has_side_effects(compressor)955|| this.property.has_side_effects(compressor);956});957def(AST_PropAccess, function(compressor){958return !compressor.option("pure_getters");959});960def(AST_Seq, function(compressor){961return this.car.has_side_effects(compressor)962|| this.cdr.has_side_effects(compressor);963});964})(function(node, func){965node.DEFMETHOD("has_side_effects", func);966});967968// tell me if a statement aborts969function aborts(thing) {970return thing && thing.aborts();971};972(function(def){973def(AST_Statement, function(){ return null });974def(AST_Jump, function(){ return this });975function block_aborts(){976var n = this.body.length;977return n > 0 && aborts(this.body[n - 1]);978};979def(AST_BlockStatement, block_aborts);980def(AST_SwitchBranch, block_aborts);981def(AST_If, function(){982return this.alternative && aborts(this.body) && aborts(this.alternative) && this;983});984})(function(node, func){985node.DEFMETHOD("aborts", func);986});987988/* -----[ optimizers ]----- */989990OPT(AST_Directive, function(self, compressor){991if (self.scope.has_directive(self.value) !== self.scope) {992return make_node(AST_EmptyStatement, self);993}994return self;995});996997OPT(AST_Debugger, function(self, compressor){998if (compressor.option("drop_debugger"))999return make_node(AST_EmptyStatement, self);1000return self;1001});10021003OPT(AST_LabeledStatement, function(self, compressor){1004if (self.body instanceof AST_Break1005&& compressor.loopcontrol_target(self.body.label) === self.body) {1006return make_node(AST_EmptyStatement, self);1007}1008return self.label.references.length == 0 ? self.body : self;1009});10101011OPT(AST_Block, function(self, compressor){1012self.body = tighten_body(self.body, compressor);1013return self;1014});10151016OPT(AST_BlockStatement, function(self, compressor){1017self.body = tighten_body(self.body, compressor);1018switch (self.body.length) {1019case 1: return self.body[0];1020case 0: return make_node(AST_EmptyStatement, self);1021}1022return self;1023});10241025AST_Scope.DEFMETHOD("drop_unused", function(compressor){1026var self = this;1027if (compressor.option("unused")1028&& !(self instanceof AST_Toplevel)1029&& !self.uses_eval1030) {1031var in_use = [];1032var initializations = new Dictionary();1033// pass 1: find out which symbols are directly used in1034// this scope (not in nested scopes).1035var scope = this;1036var tw = new TreeWalker(function(node, descend){1037if (node !== self) {1038if (node instanceof AST_Defun) {1039initializations.add(node.name.name, node);1040return true; // don't go in nested scopes1041}1042if (node instanceof AST_Definitions && scope === self) {1043node.definitions.forEach(function(def){1044if (def.value) {1045initializations.add(def.name.name, def.value);1046if (def.value.has_side_effects(compressor)) {1047def.value.walk(tw);1048}1049}1050});1051return true;1052}1053if (node instanceof AST_SymbolRef) {1054push_uniq(in_use, node.definition());1055return true;1056}1057if (node instanceof AST_Scope) {1058var save_scope = scope;1059scope = node;1060descend();1061scope = save_scope;1062return true;1063}1064}1065});1066self.walk(tw);1067// pass 2: for every used symbol we need to walk its1068// initialization code to figure out if it uses other1069// symbols (that may not be in_use).1070for (var i = 0; i < in_use.length; ++i) {1071in_use[i].orig.forEach(function(decl){1072// undeclared globals will be instanceof AST_SymbolRef1073var init = initializations.get(decl.name);1074if (init) init.forEach(function(init){1075var tw = new TreeWalker(function(node){1076if (node instanceof AST_SymbolRef) {1077push_uniq(in_use, node.definition());1078}1079});1080init.walk(tw);1081});1082});1083}1084// pass 3: we should drop declarations not in_use1085var tt = new TreeTransformer(1086function before(node, descend, in_list) {1087if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {1088if (compressor.option("unsafe") && !compressor.option("keep_fargs")) {1089for (var a = node.argnames, i = a.length; --i >= 0;) {1090var sym = a[i];1091if (sym.unreferenced()) {1092a.pop();1093compressor.warn("Dropping unused function argument {name} [{file}:{line},{col}]", {1094name : sym.name,1095file : sym.start.file,1096line : sym.start.line,1097col : sym.start.col1098});1099}1100else break;1101}1102}1103}1104if (node instanceof AST_Defun && node !== self) {1105if (!member(node.name.definition(), in_use)) {1106compressor.warn("Dropping unused function {name} [{file}:{line},{col}]", {1107name : node.name.name,1108file : node.name.start.file,1109line : node.name.start.line,1110col : node.name.start.col1111});1112return make_node(AST_EmptyStatement, node);1113}1114return node;1115}1116if (node instanceof AST_Definitions && !(tt.parent() instanceof AST_ForIn)) {1117var def = node.definitions.filter(function(def){1118if (member(def.name.definition(), in_use)) return true;1119var w = {1120name : def.name.name,1121file : def.name.start.file,1122line : def.name.start.line,1123col : def.name.start.col1124};1125if (def.value && def.value.has_side_effects(compressor)) {1126def._unused_side_effects = true;1127compressor.warn("Side effects in initialization of unused variable {name} [{file}:{line},{col}]", w);1128return true;1129}1130compressor.warn("Dropping unused variable {name} [{file}:{line},{col}]", w);1131return false;1132});1133// place uninitialized names at the start1134def = mergeSort(def, function(a, b){1135if (!a.value && b.value) return -1;1136if (!b.value && a.value) return 1;1137return 0;1138});1139// for unused names whose initialization has1140// side effects, we can cascade the init. code1141// into the next one, or next statement.1142var side_effects = [];1143for (var i = 0; i < def.length;) {1144var x = def[i];1145if (x._unused_side_effects) {1146side_effects.push(x.value);1147def.splice(i, 1);1148} else {1149if (side_effects.length > 0) {1150side_effects.push(x.value);1151x.value = AST_Seq.from_array(side_effects);1152side_effects = [];1153}1154++i;1155}1156}1157if (side_effects.length > 0) {1158side_effects = make_node(AST_BlockStatement, node, {1159body: [ make_node(AST_SimpleStatement, node, {1160body: AST_Seq.from_array(side_effects)1161}) ]1162});1163} else {1164side_effects = null;1165}1166if (def.length == 0 && !side_effects) {1167return make_node(AST_EmptyStatement, node);1168}1169if (def.length == 0) {1170return in_list ? MAP.splice(side_effects.body) : side_effects;1171}1172node.definitions = def;1173if (side_effects) {1174side_effects.body.unshift(node);1175return in_list ? MAP.splice(side_effects.body) : side_effects;1176}1177return node;1178}1179if (node instanceof AST_For) {1180descend(node, this);11811182if (node.init instanceof AST_BlockStatement) {1183// certain combination of unused name + side effect leads to:1184// https://github.com/mishoo/UglifyJS2/issues/441185// that's an invalid AST.1186// We fix it at this stage by moving the `var` outside the `for`.11871188var body = node.init.body.slice(0, -1);1189node.init = node.init.body.slice(-1)[0].body;1190body.push(node);11911192return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, {1193body: body1194});1195}1196}1197if (node instanceof AST_Scope && node !== self)1198return node;1199}1200);1201self.transform(tt);1202}1203});12041205AST_Scope.DEFMETHOD("hoist_declarations", function(compressor){1206var hoist_funs = compressor.option("hoist_funs");1207var hoist_vars = compressor.option("hoist_vars");1208var self = this;1209if (hoist_funs || hoist_vars) {1210var dirs = [];1211var hoisted = [];1212var vars = new Dictionary(), vars_found = 0, var_decl = 0;1213// let's count var_decl first, we seem to waste a lot of1214// space if we hoist `var` when there's only one.1215self.walk(new TreeWalker(function(node){1216if (node instanceof AST_Scope && node !== self)1217return true;1218if (node instanceof AST_Var) {1219++var_decl;1220return true;1221}1222}));1223hoist_vars = hoist_vars && var_decl > 1;1224var tt = new TreeTransformer(1225function before(node) {1226if (node !== self) {1227if (node instanceof AST_Directive) {1228dirs.push(node);1229return make_node(AST_EmptyStatement, node);1230}1231if (node instanceof AST_Defun && hoist_funs) {1232hoisted.push(node);1233return make_node(AST_EmptyStatement, node);1234}1235if (node instanceof AST_Var && hoist_vars) {1236node.definitions.forEach(function(def){1237vars.set(def.name.name, def);1238++vars_found;1239});1240var seq = node.to_assignments();1241var p = tt.parent();1242if (p instanceof AST_ForIn && p.init === node) {1243if (seq == null) return node.definitions[0].name;1244return seq;1245}1246if (p instanceof AST_For && p.init === node) {1247return seq;1248}1249if (!seq) return make_node(AST_EmptyStatement, node);1250return make_node(AST_SimpleStatement, node, {1251body: seq1252});1253}1254if (node instanceof AST_Scope)1255return node; // to avoid descending in nested scopes1256}1257}1258);1259self = self.transform(tt);1260if (vars_found > 0) {1261// collect only vars which don't show up in self's arguments list1262var defs = [];1263vars.each(function(def, name){1264if (self instanceof AST_Lambda1265&& find_if(function(x){ return x.name == def.name.name },1266self.argnames)) {1267vars.del(name);1268} else {1269def = def.clone();1270def.value = null;1271defs.push(def);1272vars.set(name, def);1273}1274});1275if (defs.length > 0) {1276// try to merge in assignments1277for (var i = 0; i < self.body.length;) {1278if (self.body[i] instanceof AST_SimpleStatement) {1279var expr = self.body[i].body, sym, assign;1280if (expr instanceof AST_Assign1281&& expr.operator == "="1282&& (sym = expr.left) instanceof AST_Symbol1283&& vars.has(sym.name))1284{1285var def = vars.get(sym.name);1286if (def.value) break;1287def.value = expr.right;1288remove(defs, def);1289defs.push(def);1290self.body.splice(i, 1);1291continue;1292}1293if (expr instanceof AST_Seq1294&& (assign = expr.car) instanceof AST_Assign1295&& assign.operator == "="1296&& (sym = assign.left) instanceof AST_Symbol1297&& vars.has(sym.name))1298{1299var def = vars.get(sym.name);1300if (def.value) break;1301def.value = assign.right;1302remove(defs, def);1303defs.push(def);1304self.body[i].body = expr.cdr;1305continue;1306}1307}1308if (self.body[i] instanceof AST_EmptyStatement) {1309self.body.splice(i, 1);1310continue;1311}1312if (self.body[i] instanceof AST_BlockStatement) {1313var tmp = [ i, 1 ].concat(self.body[i].body);1314self.body.splice.apply(self.body, tmp);1315continue;1316}1317break;1318}1319defs = make_node(AST_Var, self, {1320definitions: defs1321});1322hoisted.push(defs);1323};1324}1325self.body = dirs.concat(hoisted, self.body);1326}1327return self;1328});13291330OPT(AST_SimpleStatement, function(self, compressor){1331if (compressor.option("side_effects")) {1332if (!self.body.has_side_effects(compressor)) {1333compressor.warn("Dropping side-effect-free statement [{file}:{line},{col}]", self.start);1334return make_node(AST_EmptyStatement, self);1335}1336}1337return self;1338});13391340OPT(AST_DWLoop, function(self, compressor){1341var cond = self.condition.evaluate(compressor);1342self.condition = cond[0];1343if (!compressor.option("loops")) return self;1344if (cond.length > 1) {1345if (cond[1]) {1346return make_node(AST_For, self, {1347body: self.body1348});1349} else if (self instanceof AST_While) {1350if (compressor.option("dead_code")) {1351var a = [];1352extract_declarations_from_unreachable_code(compressor, self.body, a);1353return make_node(AST_BlockStatement, self, { body: a });1354}1355}1356}1357return self;1358});13591360function if_break_in_loop(self, compressor) {1361function drop_it(rest) {1362rest = as_statement_array(rest);1363if (self.body instanceof AST_BlockStatement) {1364self.body = self.body.clone();1365self.body.body = rest.concat(self.body.body.slice(1));1366self.body = self.body.transform(compressor);1367} else {1368self.body = make_node(AST_BlockStatement, self.body, {1369body: rest1370}).transform(compressor);1371}1372if_break_in_loop(self, compressor);1373}1374var first = self.body instanceof AST_BlockStatement ? self.body.body[0] : self.body;1375if (first instanceof AST_If) {1376if (first.body instanceof AST_Break1377&& compressor.loopcontrol_target(first.body.label) === self) {1378if (self.condition) {1379self.condition = make_node(AST_Binary, self.condition, {1380left: self.condition,1381operator: "&&",1382right: first.condition.negate(compressor),1383});1384} else {1385self.condition = first.condition.negate(compressor);1386}1387drop_it(first.alternative);1388}1389else if (first.alternative instanceof AST_Break1390&& compressor.loopcontrol_target(first.alternative.label) === self) {1391if (self.condition) {1392self.condition = make_node(AST_Binary, self.condition, {1393left: self.condition,1394operator: "&&",1395right: first.condition,1396});1397} else {1398self.condition = first.condition;1399}1400drop_it(first.body);1401}1402}1403};14041405OPT(AST_While, function(self, compressor) {1406if (!compressor.option("loops")) return self;1407self = AST_DWLoop.prototype.optimize.call(self, compressor);1408if (self instanceof AST_While) {1409if_break_in_loop(self, compressor);1410self = make_node(AST_For, self, self).transform(compressor);1411}1412return self;1413});14141415OPT(AST_For, function(self, compressor){1416var cond = self.condition;1417if (cond) {1418cond = cond.evaluate(compressor);1419self.condition = cond[0];1420}1421if (!compressor.option("loops")) return self;1422if (cond) {1423if (cond.length > 1 && !cond[1]) {1424if (compressor.option("dead_code")) {1425var a = [];1426if (self.init instanceof AST_Statement) {1427a.push(self.init);1428}1429else if (self.init) {1430a.push(make_node(AST_SimpleStatement, self.init, {1431body: self.init1432}));1433}1434extract_declarations_from_unreachable_code(compressor, self.body, a);1435return make_node(AST_BlockStatement, self, { body: a });1436}1437}1438}1439if_break_in_loop(self, compressor);1440return self;1441});14421443OPT(AST_If, function(self, compressor){1444if (!compressor.option("conditionals")) return self;1445// if condition can be statically determined, warn and drop1446// one of the blocks. note, statically determined implies1447// “has no side effects”; also it doesn't work for cases like1448// `x && true`, though it probably should.1449var cond = self.condition.evaluate(compressor);1450self.condition = cond[0];1451if (cond.length > 1) {1452if (cond[1]) {1453compressor.warn("Condition always true [{file}:{line},{col}]", self.condition.start);1454if (compressor.option("dead_code")) {1455var a = [];1456if (self.alternative) {1457extract_declarations_from_unreachable_code(compressor, self.alternative, a);1458}1459a.push(self.body);1460return make_node(AST_BlockStatement, self, { body: a }).transform(compressor);1461}1462} else {1463compressor.warn("Condition always false [{file}:{line},{col}]", self.condition.start);1464if (compressor.option("dead_code")) {1465var a = [];1466extract_declarations_from_unreachable_code(compressor, self.body, a);1467if (self.alternative) a.push(self.alternative);1468return make_node(AST_BlockStatement, self, { body: a }).transform(compressor);1469}1470}1471}1472if (is_empty(self.alternative)) self.alternative = null;1473var negated = self.condition.negate(compressor);1474var negated_is_best = best_of(self.condition, negated) === negated;1475if (self.alternative && negated_is_best) {1476negated_is_best = false; // because we already do the switch here.1477self.condition = negated;1478var tmp = self.body;1479self.body = self.alternative || make_node(AST_EmptyStatement);1480self.alternative = tmp;1481}1482if (is_empty(self.body) && is_empty(self.alternative)) {1483return make_node(AST_SimpleStatement, self.condition, {1484body: self.condition1485}).transform(compressor);1486}1487if (self.body instanceof AST_SimpleStatement1488&& self.alternative instanceof AST_SimpleStatement) {1489return make_node(AST_SimpleStatement, self, {1490body: make_node(AST_Conditional, self, {1491condition : self.condition,1492consequent : self.body.body,1493alternative : self.alternative.body1494})1495}).transform(compressor);1496}1497if (is_empty(self.alternative) && self.body instanceof AST_SimpleStatement) {1498if (negated_is_best) return make_node(AST_SimpleStatement, self, {1499body: make_node(AST_Binary, self, {1500operator : "||",1501left : negated,1502right : self.body.body1503})1504}).transform(compressor);1505return make_node(AST_SimpleStatement, self, {1506body: make_node(AST_Binary, self, {1507operator : "&&",1508left : self.condition,1509right : self.body.body1510})1511}).transform(compressor);1512}1513if (self.body instanceof AST_EmptyStatement1514&& self.alternative1515&& self.alternative instanceof AST_SimpleStatement) {1516return make_node(AST_SimpleStatement, self, {1517body: make_node(AST_Binary, self, {1518operator : "||",1519left : self.condition,1520right : self.alternative.body1521})1522}).transform(compressor);1523}1524if (self.body instanceof AST_Exit1525&& self.alternative instanceof AST_Exit1526&& self.body.TYPE == self.alternative.TYPE) {1527return make_node(self.body.CTOR, self, {1528value: make_node(AST_Conditional, self, {1529condition : self.condition,1530consequent : self.body.value || make_node(AST_Undefined, self.body).optimize(compressor),1531alternative : self.alternative.value || make_node(AST_Undefined, self.alternative).optimize(compressor)1532})1533}).transform(compressor);1534}1535if (self.body instanceof AST_If1536&& !self.body.alternative1537&& !self.alternative) {1538self.condition = make_node(AST_Binary, self.condition, {1539operator: "&&",1540left: self.condition,1541right: self.body.condition1542}).transform(compressor);1543self.body = self.body.body;1544}1545if (aborts(self.body)) {1546if (self.alternative) {1547var alt = self.alternative;1548self.alternative = null;1549return make_node(AST_BlockStatement, self, {1550body: [ self, alt ]1551}).transform(compressor);1552}1553}1554if (aborts(self.alternative)) {1555var body = self.body;1556self.body = self.alternative;1557self.condition = negated_is_best ? negated : self.condition.negate(compressor);1558self.alternative = null;1559return make_node(AST_BlockStatement, self, {1560body: [ self, body ]1561}).transform(compressor);1562}1563return self;1564});15651566OPT(AST_Switch, function(self, compressor){1567if (self.body.length == 0 && compressor.option("conditionals")) {1568return make_node(AST_SimpleStatement, self, {1569body: self.expression1570}).transform(compressor);1571}1572for(;;) {1573var last_branch = self.body[self.body.length - 1];1574if (last_branch) {1575var stat = last_branch.body[last_branch.body.length - 1]; // last statement1576if (stat instanceof AST_Break && loop_body(compressor.loopcontrol_target(stat.label)) === self)1577last_branch.body.pop();1578if (last_branch instanceof AST_Default && last_branch.body.length == 0) {1579self.body.pop();1580continue;1581}1582}1583break;1584}1585var exp = self.expression.evaluate(compressor);1586out: if (exp.length == 2) try {1587// constant expression1588self.expression = exp[0];1589if (!compressor.option("dead_code")) break out;1590var value = exp[1];1591var in_if = false;1592var in_block = false;1593var started = false;1594var stopped = false;1595var ruined = false;1596var tt = new TreeTransformer(function(node, descend, in_list){1597if (node instanceof AST_Lambda || node instanceof AST_SimpleStatement) {1598// no need to descend these node types1599return node;1600}1601else if (node instanceof AST_Switch && node === self) {1602node = node.clone();1603descend(node, this);1604return ruined ? node : make_node(AST_BlockStatement, node, {1605body: node.body.reduce(function(a, branch){1606return a.concat(branch.body);1607}, [])1608}).transform(compressor);1609}1610else if (node instanceof AST_If || node instanceof AST_Try) {1611var save = in_if;1612in_if = !in_block;1613descend(node, this);1614in_if = save;1615return node;1616}1617else if (node instanceof AST_StatementWithBody || node instanceof AST_Switch) {1618var save = in_block;1619in_block = true;1620descend(node, this);1621in_block = save;1622return node;1623}1624else if (node instanceof AST_Break && this.loopcontrol_target(node.label) === self) {1625if (in_if) {1626ruined = true;1627return node;1628}1629if (in_block) return node;1630stopped = true;1631return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);1632}1633else if (node instanceof AST_SwitchBranch && this.parent() === self) {1634if (stopped) return MAP.skip;1635if (node instanceof AST_Case) {1636var exp = node.expression.evaluate(compressor);1637if (exp.length < 2) {1638// got a case with non-constant expression, baling out1639throw self;1640}1641if (exp[1] === value || started) {1642started = true;1643if (aborts(node)) stopped = true;1644descend(node, this);1645return node;1646}1647return MAP.skip;1648}1649descend(node, this);1650return node;1651}1652});1653tt.stack = compressor.stack.slice(); // so that's able to see parent nodes1654self = self.transform(tt);1655} catch(ex) {1656if (ex !== self) throw ex;1657}1658return self;1659});16601661OPT(AST_Case, function(self, compressor){1662self.body = tighten_body(self.body, compressor);1663return self;1664});16651666OPT(AST_Try, function(self, compressor){1667self.body = tighten_body(self.body, compressor);1668return self;1669});16701671AST_Definitions.DEFMETHOD("remove_initializers", function(){1672this.definitions.forEach(function(def){ def.value = null });1673});16741675AST_Definitions.DEFMETHOD("to_assignments", function(){1676var assignments = this.definitions.reduce(function(a, def){1677if (def.value) {1678var name = make_node(AST_SymbolRef, def.name, def.name);1679a.push(make_node(AST_Assign, def, {1680operator : "=",1681left : name,1682right : def.value1683}));1684}1685return a;1686}, []);1687if (assignments.length == 0) return null;1688return AST_Seq.from_array(assignments);1689});16901691OPT(AST_Definitions, function(self, compressor){1692if (self.definitions.length == 0)1693return make_node(AST_EmptyStatement, self);1694return self;1695});16961697OPT(AST_Function, function(self, compressor){1698self = AST_Lambda.prototype.optimize.call(self, compressor);1699if (compressor.option("unused") && !compressor.option("keep_fnames")) {1700if (self.name && self.name.unreferenced()) {1701self.name = null;1702}1703}1704return self;1705});17061707OPT(AST_Call, function(self, compressor){1708if (compressor.option("unsafe")) {1709var exp = self.expression;1710if (exp instanceof AST_SymbolRef && exp.undeclared()) {1711switch (exp.name) {1712case "Array":1713if (self.args.length != 1) {1714return make_node(AST_Array, self, {1715elements: self.args1716}).transform(compressor);1717}1718break;1719case "Object":1720if (self.args.length == 0) {1721return make_node(AST_Object, self, {1722properties: []1723});1724}1725break;1726case "String":1727if (self.args.length == 0) return make_node(AST_String, self, {1728value: ""1729});1730if (self.args.length <= 1) return make_node(AST_Binary, self, {1731left: self.args[0],1732operator: "+",1733right: make_node(AST_String, self, { value: "" })1734}).transform(compressor);1735break;1736case "Number":1737if (self.args.length == 0) return make_node(AST_Number, self, {1738value: 01739});1740if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {1741expression: self.args[0],1742operator: "+"1743}).transform(compressor);1744case "Boolean":1745if (self.args.length == 0) return make_node(AST_False, self);1746if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {1747expression: make_node(AST_UnaryPrefix, null, {1748expression: self.args[0],1749operator: "!"1750}),1751operator: "!"1752}).transform(compressor);1753break;1754case "Function":1755// new Function() => function(){}1756if (self.args.length == 0) return make_node(AST_Function, self, {1757argnames: [],1758body: []1759});1760if (all(self.args, function(x){ return x instanceof AST_String })) {1761// quite a corner-case, but we can handle it:1762// https://github.com/mishoo/UglifyJS2/issues/2031763// if the code argument is a constant, then we can minify it.1764try {1765var code = "(function(" + self.args.slice(0, -1).map(function(arg){1766return arg.value;1767}).join(",") + "){" + self.args[self.args.length - 1].value + "})()";1768var ast = parse(code);1769ast.figure_out_scope({ screw_ie8: compressor.option("screw_ie8") });1770var comp = new Compressor(compressor.options);1771ast = ast.transform(comp);1772ast.figure_out_scope({ screw_ie8: compressor.option("screw_ie8") });1773ast.mangle_names();1774var fun;1775try {1776ast.walk(new TreeWalker(function(node){1777if (node instanceof AST_Lambda) {1778fun = node;1779throw ast;1780}1781}));1782} catch(ex) {1783if (ex !== ast) throw ex;1784};1785if (!fun) return self;1786var args = fun.argnames.map(function(arg, i){1787return make_node(AST_String, self.args[i], {1788value: arg.print_to_string()1789});1790});1791var code = OutputStream();1792AST_BlockStatement.prototype._codegen.call(fun, fun, code);1793code = code.toString().replace(/^\{|\}$/g, "");1794args.push(make_node(AST_String, self.args[self.args.length - 1], {1795value: code1796}));1797self.args = args;1798return self;1799} catch(ex) {1800if (ex instanceof JS_Parse_Error) {1801compressor.warn("Error parsing code passed to new Function [{file}:{line},{col}]", self.args[self.args.length - 1].start);1802compressor.warn(ex.toString());1803} else {1804console.log(ex);1805throw ex;1806}1807}1808}1809break;1810}1811}1812else if (exp instanceof AST_Dot && exp.property == "toString" && self.args.length == 0) {1813return make_node(AST_Binary, self, {1814left: make_node(AST_String, self, { value: "" }),1815operator: "+",1816right: exp.expression1817}).transform(compressor);1818}1819else if (exp instanceof AST_Dot && exp.expression instanceof AST_Array && exp.property == "join") EXIT: {1820var separator = self.args.length == 0 ? "," : self.args[0].evaluate(compressor)[1];1821if (separator == null) break EXIT; // not a constant1822var elements = exp.expression.elements.reduce(function(a, el){1823el = el.evaluate(compressor);1824if (a.length == 0 || el.length == 1) {1825a.push(el);1826} else {1827var last = a[a.length - 1];1828if (last.length == 2) {1829// it's a constant1830var val = "" + last[1] + separator + el[1];1831a[a.length - 1] = [ make_node_from_constant(compressor, val, last[0]), val ];1832} else {1833a.push(el);1834}1835}1836return a;1837}, []);1838if (elements.length == 0) return make_node(AST_String, self, { value: "" });1839if (elements.length == 1) return elements[0][0];1840if (separator == "") {1841var first;1842if (elements[0][0] instanceof AST_String1843|| elements[1][0] instanceof AST_String) {1844first = elements.shift()[0];1845} else {1846first = make_node(AST_String, self, { value: "" });1847}1848return elements.reduce(function(prev, el){1849return make_node(AST_Binary, el[0], {1850operator : "+",1851left : prev,1852right : el[0],1853});1854}, first).transform(compressor);1855}1856// need this awkward cloning to not affect original element1857// best_of will decide which one to get through.1858var node = self.clone();1859node.expression = node.expression.clone();1860node.expression.expression = node.expression.expression.clone();1861node.expression.expression.elements = elements.map(function(el){1862return el[0];1863});1864return best_of(self, node);1865}1866}1867if (compressor.option("side_effects")) {1868if (self.expression instanceof AST_Function1869&& self.args.length == 01870&& !AST_Block.prototype.has_side_effects.call(self.expression, compressor)) {1871return make_node(AST_Undefined, self).transform(compressor);1872}1873}1874if (compressor.option("drop_console")) {1875if (self.expression instanceof AST_PropAccess) {1876var name = self.expression.expression;1877while (name.expression) {1878name = name.expression;1879}1880if (name instanceof AST_SymbolRef1881&& name.name == "console"1882&& name.undeclared()) {1883return make_node(AST_Undefined, self).transform(compressor);1884}1885}1886}1887return self.evaluate(compressor)[0];1888});18891890OPT(AST_New, function(self, compressor){1891if (compressor.option("unsafe")) {1892var exp = self.expression;1893if (exp instanceof AST_SymbolRef && exp.undeclared()) {1894switch (exp.name) {1895case "Object":1896case "RegExp":1897case "Function":1898case "Error":1899case "Array":1900return make_node(AST_Call, self, self).transform(compressor);1901}1902}1903}1904return self;1905});19061907OPT(AST_Seq, function(self, compressor){1908if (!compressor.option("side_effects"))1909return self;1910if (!self.car.has_side_effects(compressor)) {1911// we shouldn't compress (1,eval)(something) to1912// eval(something) because that changes the meaning of1913// eval (becomes lexical instead of global).1914var p;1915if (!(self.cdr instanceof AST_SymbolRef1916&& self.cdr.name == "eval"1917&& self.cdr.undeclared()1918&& (p = compressor.parent()) instanceof AST_Call1919&& p.expression === self)) {1920return self.cdr;1921}1922}1923if (compressor.option("cascade")) {1924if (self.car instanceof AST_Assign1925&& !self.car.left.has_side_effects(compressor)) {1926if (self.car.left.equivalent_to(self.cdr)) {1927return self.car;1928}1929if (self.cdr instanceof AST_Call1930&& self.cdr.expression.equivalent_to(self.car.left)) {1931self.cdr.expression = self.car;1932return self.cdr;1933}1934}1935if (!self.car.has_side_effects(compressor)1936&& !self.cdr.has_side_effects(compressor)1937&& self.car.equivalent_to(self.cdr)) {1938return self.car;1939}1940}1941if (self.cdr instanceof AST_UnaryPrefix1942&& self.cdr.operator == "void"1943&& !self.cdr.expression.has_side_effects(compressor)) {1944self.cdr.expression = self.car;1945return self.cdr;1946}1947if (self.cdr instanceof AST_Undefined) {1948return make_node(AST_UnaryPrefix, self, {1949operator : "void",1950expression : self.car1951});1952}1953return self;1954});19551956AST_Unary.DEFMETHOD("lift_sequences", function(compressor){1957if (compressor.option("sequences")) {1958if (this.expression instanceof AST_Seq) {1959var seq = this.expression;1960var x = seq.to_array();1961this.expression = x.pop();1962x.push(this);1963seq = AST_Seq.from_array(x).transform(compressor);1964return seq;1965}1966}1967return this;1968});19691970OPT(AST_UnaryPostfix, function(self, compressor){1971return self.lift_sequences(compressor);1972});19731974OPT(AST_UnaryPrefix, function(self, compressor){1975self = self.lift_sequences(compressor);1976var e = self.expression;1977if (compressor.option("booleans") && compressor.in_boolean_context()) {1978switch (self.operator) {1979case "!":1980if (e instanceof AST_UnaryPrefix && e.operator == "!") {1981// !!foo ==> foo, if we're in boolean context1982return e.expression;1983}1984break;1985case "typeof":1986// typeof always returns a non-empty string, thus it's1987// always true in booleans1988compressor.warn("Boolean expression always true [{file}:{line},{col}]", self.start);1989return make_node(AST_True, self);1990}1991if (e instanceof AST_Binary && self.operator == "!") {1992self = best_of(self, e.negate(compressor));1993}1994}1995return self.evaluate(compressor)[0];1996});19971998function has_side_effects_or_prop_access(node, compressor) {1999var save_pure_getters = compressor.option("pure_getters");2000compressor.options.pure_getters = false;2001var ret = node.has_side_effects(compressor);2002compressor.options.pure_getters = save_pure_getters;2003return ret;2004}20052006AST_Binary.DEFMETHOD("lift_sequences", function(compressor){2007if (compressor.option("sequences")) {2008if (this.left instanceof AST_Seq) {2009var seq = this.left;2010var x = seq.to_array();2011this.left = x.pop();2012x.push(this);2013seq = AST_Seq.from_array(x).transform(compressor);2014return seq;2015}2016if (this.right instanceof AST_Seq2017&& this instanceof AST_Assign2018&& !has_side_effects_or_prop_access(this.left, compressor)) {2019var seq = this.right;2020var x = seq.to_array();2021this.right = x.pop();2022x.push(this);2023seq = AST_Seq.from_array(x).transform(compressor);2024return seq;2025}2026}2027return this;2028});20292030var commutativeOperators = makePredicate("== === != !== * & | ^");20312032OPT(AST_Binary, function(self, compressor){2033var reverse = compressor.has_directive("use asm") ? noop2034: function(op, force) {2035if (force || !(self.left.has_side_effects(compressor) || self.right.has_side_effects(compressor))) {2036if (op) self.operator = op;2037var tmp = self.left;2038self.left = self.right;2039self.right = tmp;2040}2041};2042if (commutativeOperators(self.operator)) {2043if (self.right instanceof AST_Constant2044&& !(self.left instanceof AST_Constant)) {2045// if right is a constant, whatever side effects the2046// left side might have could not influence the2047// result. hence, force switch.20482049if (!(self.left instanceof AST_Binary2050&& PRECEDENCE[self.left.operator] >= PRECEDENCE[self.operator])) {2051reverse(null, true);2052}2053}2054if (/^[!=]==?$/.test(self.operator)) {2055if (self.left instanceof AST_SymbolRef && self.right instanceof AST_Conditional) {2056if (self.right.consequent instanceof AST_SymbolRef2057&& self.right.consequent.definition() === self.left.definition()) {2058if (/^==/.test(self.operator)) return self.right.condition;2059if (/^!=/.test(self.operator)) return self.right.condition.negate(compressor);2060}2061if (self.right.alternative instanceof AST_SymbolRef2062&& self.right.alternative.definition() === self.left.definition()) {2063if (/^==/.test(self.operator)) return self.right.condition.negate(compressor);2064if (/^!=/.test(self.operator)) return self.right.condition;2065}2066}2067if (self.right instanceof AST_SymbolRef && self.left instanceof AST_Conditional) {2068if (self.left.consequent instanceof AST_SymbolRef2069&& self.left.consequent.definition() === self.right.definition()) {2070if (/^==/.test(self.operator)) return self.left.condition;2071if (/^!=/.test(self.operator)) return self.left.condition.negate(compressor);2072}2073if (self.left.alternative instanceof AST_SymbolRef2074&& self.left.alternative.definition() === self.right.definition()) {2075if (/^==/.test(self.operator)) return self.left.condition.negate(compressor);2076if (/^!=/.test(self.operator)) return self.left.condition;2077}2078}2079}2080}2081self = self.lift_sequences(compressor);2082if (compressor.option("comparisons")) switch (self.operator) {2083case "===":2084case "!==":2085if ((self.left.is_string(compressor) && self.right.is_string(compressor)) ||2086(self.left.is_boolean() && self.right.is_boolean())) {2087self.operator = self.operator.substr(0, 2);2088}2089// XXX: intentionally falling down to the next case2090case "==":2091case "!=":2092if (self.left instanceof AST_String2093&& self.left.value == "undefined"2094&& self.right instanceof AST_UnaryPrefix2095&& self.right.operator == "typeof"2096&& compressor.option("unsafe")) {2097if (!(self.right.expression instanceof AST_SymbolRef)2098|| !self.right.expression.undeclared()) {2099self.right = self.right.expression;2100self.left = make_node(AST_Undefined, self.left).optimize(compressor);2101if (self.operator.length == 2) self.operator += "=";2102}2103}2104break;2105}2106if (compressor.option("booleans") && compressor.in_boolean_context()) switch (self.operator) {2107case "&&":2108var ll = self.left.evaluate(compressor);2109var rr = self.right.evaluate(compressor);2110if ((ll.length > 1 && !ll[1]) || (rr.length > 1 && !rr[1])) {2111compressor.warn("Boolean && always false [{file}:{line},{col}]", self.start);2112if (self.left.has_side_effects(compressor)) {2113return make_node(AST_Seq, self, {2114car: self.left,2115cdr: make_node(AST_False)2116}).optimize(compressor);2117}2118return make_node(AST_False, self);2119}2120if (ll.length > 1 && ll[1]) {2121return rr[0];2122}2123if (rr.length > 1 && rr[1]) {2124return ll[0];2125}2126break;2127case "||":2128var ll = self.left.evaluate(compressor);2129var rr = self.right.evaluate(compressor);2130if ((ll.length > 1 && ll[1]) || (rr.length > 1 && rr[1])) {2131compressor.warn("Boolean || always true [{file}:{line},{col}]", self.start);2132if (self.left.has_side_effects(compressor)) {2133return make_node(AST_Seq, self, {2134car: self.left,2135cdr: make_node(AST_True)2136}).optimize(compressor);2137}2138return make_node(AST_True, self);2139}2140if (ll.length > 1 && !ll[1]) {2141return rr[0];2142}2143if (rr.length > 1 && !rr[1]) {2144return ll[0];2145}2146break;2147case "+":2148var ll = self.left.evaluate(compressor);2149var rr = self.right.evaluate(compressor);2150if ((ll.length > 1 && ll[0] instanceof AST_String && ll[1]) ||2151(rr.length > 1 && rr[0] instanceof AST_String && rr[1])) {2152compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);2153return make_node(AST_True, self);2154}2155break;2156}2157if (compressor.option("comparisons")) {2158if (!(compressor.parent() instanceof AST_Binary)2159|| compressor.parent() instanceof AST_Assign) {2160var negated = make_node(AST_UnaryPrefix, self, {2161operator: "!",2162expression: self.negate(compressor)2163});2164self = best_of(self, negated);2165}2166switch (self.operator) {2167case "<": reverse(">"); break;2168case "<=": reverse(">="); break;2169}2170}2171if (self.operator == "+" && self.right instanceof AST_String2172&& self.right.getValue() === "" && self.left instanceof AST_Binary2173&& self.left.operator == "+" && self.left.is_string(compressor)) {2174return self.left;2175}2176if (compressor.option("evaluate")) {2177if (self.operator == "+") {2178if (self.left instanceof AST_Constant2179&& self.right instanceof AST_Binary2180&& self.right.operator == "+"2181&& self.right.left instanceof AST_Constant2182&& self.right.is_string(compressor)) {2183self = make_node(AST_Binary, self, {2184operator: "+",2185left: make_node(AST_String, null, {2186value: "" + self.left.getValue() + self.right.left.getValue(),2187start: self.left.start,2188end: self.right.left.end2189}),2190right: self.right.right2191});2192}2193if (self.right instanceof AST_Constant2194&& self.left instanceof AST_Binary2195&& self.left.operator == "+"2196&& self.left.right instanceof AST_Constant2197&& self.left.is_string(compressor)) {2198self = make_node(AST_Binary, self, {2199operator: "+",2200left: self.left.left,2201right: make_node(AST_String, null, {2202value: "" + self.left.right.getValue() + self.right.getValue(),2203start: self.left.right.start,2204end: self.right.end2205})2206});2207}2208if (self.left instanceof AST_Binary2209&& self.left.operator == "+"2210&& self.left.is_string(compressor)2211&& self.left.right instanceof AST_Constant2212&& self.right instanceof AST_Binary2213&& self.right.operator == "+"2214&& self.right.left instanceof AST_Constant2215&& self.right.is_string(compressor)) {2216self = make_node(AST_Binary, self, {2217operator: "+",2218left: make_node(AST_Binary, self.left, {2219operator: "+",2220left: self.left.left,2221right: make_node(AST_String, null, {2222value: "" + self.left.right.getValue() + self.right.left.getValue(),2223start: self.left.right.start,2224end: self.right.left.end2225})2226}),2227right: self.right.right2228});2229}2230}2231}2232// x * (y * z) ==> x * y * z2233if (self.right instanceof AST_Binary2234&& self.right.operator == self.operator2235&& (self.operator == "*" || self.operator == "&&" || self.operator == "||"))2236{2237self.left = make_node(AST_Binary, self.left, {2238operator : self.operator,2239left : self.left,2240right : self.right.left2241});2242self.right = self.right.right;2243return self.transform(compressor);2244}2245return self.evaluate(compressor)[0];2246});22472248OPT(AST_SymbolRef, function(self, compressor){2249if (self.undeclared()) {2250var defines = compressor.option("global_defs");2251if (defines && defines.hasOwnProperty(self.name)) {2252return make_node_from_constant(compressor, defines[self.name], self);2253}2254switch (self.name) {2255case "undefined":2256return make_node(AST_Undefined, self);2257case "NaN":2258return make_node(AST_NaN, self).transform(compressor);2259case "Infinity":2260return make_node(AST_Infinity, self).transform(compressor);2261}2262}2263return self;2264});22652266OPT(AST_Infinity, function (self, compressor) {2267return make_node(AST_Binary, self, {2268operator : '/',2269left : make_node(AST_Number, self, {value: 1}),2270right : make_node(AST_Number, self, {value: 0})2271});2272});22732274OPT(AST_Undefined, function(self, compressor){2275if (compressor.option("unsafe")) {2276var scope = compressor.find_parent(AST_Scope);2277var undef = scope.find_variable("undefined");2278if (undef) {2279var ref = make_node(AST_SymbolRef, self, {2280name : "undefined",2281scope : scope,2282thedef : undef2283});2284ref.reference();2285return ref;2286}2287}2288return self;2289});22902291var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];2292OPT(AST_Assign, function(self, compressor){2293self = self.lift_sequences(compressor);2294if (self.operator == "="2295&& self.left instanceof AST_SymbolRef2296&& self.right instanceof AST_Binary2297&& self.right.left instanceof AST_SymbolRef2298&& self.right.left.name == self.left.name2299&& member(self.right.operator, ASSIGN_OPS)) {2300self.operator = self.right.operator + "=";2301self.right = self.right.right;2302}2303return self;2304});23052306OPT(AST_Conditional, function(self, compressor){2307if (!compressor.option("conditionals")) return self;2308if (self.condition instanceof AST_Seq) {2309var car = self.condition.car;2310self.condition = self.condition.cdr;2311return AST_Seq.cons(car, self);2312}2313var cond = self.condition.evaluate(compressor);2314if (cond.length > 1) {2315if (cond[1]) {2316compressor.warn("Condition always true [{file}:{line},{col}]", self.start);2317return self.consequent;2318} else {2319compressor.warn("Condition always false [{file}:{line},{col}]", self.start);2320return self.alternative;2321}2322}2323var negated = cond[0].negate(compressor);2324if (best_of(cond[0], negated) === negated) {2325self = make_node(AST_Conditional, self, {2326condition: negated,2327consequent: self.alternative,2328alternative: self.consequent2329});2330}2331var consequent = self.consequent;2332var alternative = self.alternative;2333if (consequent instanceof AST_Assign2334&& alternative instanceof AST_Assign2335&& consequent.operator == alternative.operator2336&& consequent.left.equivalent_to(alternative.left)2337&& !consequent.left.has_side_effects(compressor)2338) {2339/*2340* Stuff like this:2341* if (foo) exp = something; else exp = something_else;2342* ==>2343* exp = foo ? something : something_else;2344*/2345return make_node(AST_Assign, self, {2346operator: consequent.operator,2347left: consequent.left,2348right: make_node(AST_Conditional, self, {2349condition: self.condition,2350consequent: consequent.right,2351alternative: alternative.right2352})2353});2354}2355if (consequent instanceof AST_Call2356&& alternative.TYPE === consequent.TYPE2357&& consequent.args.length == alternative.args.length2358&& !consequent.expression.has_side_effects(compressor)2359&& consequent.expression.equivalent_to(alternative.expression)) {2360if (consequent.args.length == 0) {2361return make_node(AST_Seq, self, {2362car: self.condition,2363cdr: consequent2364});2365}2366if (consequent.args.length == 1) {2367consequent.args[0] = make_node(AST_Conditional, self, {2368condition: self.condition,2369consequent: consequent.args[0],2370alternative: alternative.args[0]2371});2372return consequent;2373}2374}2375// x?y?z:a:a --> x&&y?z:a2376if (consequent instanceof AST_Conditional2377&& consequent.alternative.equivalent_to(alternative)) {2378return make_node(AST_Conditional, self, {2379condition: make_node(AST_Binary, self, {2380left: self.condition,2381operator: "&&",2382right: consequent.condition2383}),2384consequent: consequent.consequent,2385alternative: alternative2386});2387}2388// x=y?1:1 --> x=12389if (consequent instanceof AST_Constant2390&& alternative instanceof AST_Constant2391&& consequent.equivalent_to(alternative)) {2392if (self.condition.has_side_effects(compressor)) {2393return AST_Seq.from_array([self.condition, make_node_from_constant(compressor, consequent.value, self)]);2394} else {2395return make_node_from_constant(compressor, consequent.value, self);23962397}2398}2399// x=y?true:false --> x=!!y2400if (consequent instanceof AST_True2401&& alternative instanceof AST_False) {2402self.condition = self.condition.negate(compressor);2403return make_node(AST_UnaryPrefix, self.condition, {2404operator: "!",2405expression: self.condition2406});2407}2408// x=y?false:true --> x=!y2409if (consequent instanceof AST_False2410&& alternative instanceof AST_True) {2411return self.condition.negate(compressor)2412}2413return self;2414});24152416OPT(AST_Boolean, function(self, compressor){2417if (compressor.option("booleans")) {2418var p = compressor.parent();2419if (p instanceof AST_Binary && (p.operator == "=="2420|| p.operator == "!=")) {2421compressor.warn("Non-strict equality against boolean: {operator} {value} [{file}:{line},{col}]", {2422operator : p.operator,2423value : self.value,2424file : p.start.file,2425line : p.start.line,2426col : p.start.col,2427});2428return make_node(AST_Number, self, {2429value: +self.value2430});2431}2432return make_node(AST_UnaryPrefix, self, {2433operator: "!",2434expression: make_node(AST_Number, self, {2435value: 1 - self.value2436})2437});2438}2439return self;2440});24412442OPT(AST_Sub, function(self, compressor){2443var prop = self.property;2444if (prop instanceof AST_String && compressor.option("properties")) {2445prop = prop.getValue();2446if (RESERVED_WORDS(prop) ? compressor.option("screw_ie8") : is_identifier_string(prop)) {2447return make_node(AST_Dot, self, {2448expression : self.expression,2449property : prop2450}).optimize(compressor);2451}2452var v = parseFloat(prop);2453if (!isNaN(v) && v.toString() == prop) {2454self.property = make_node(AST_Number, self.property, {2455value: v2456});2457}2458}2459return self;2460});24612462OPT(AST_Dot, function(self, compressor){2463var prop = self.property;2464if (RESERVED_WORDS(prop) && !compressor.option("screw_ie8")) {2465return make_node(AST_Sub, self, {2466expression : self.expression,2467property : make_node(AST_String, self, {2468value: prop2469})2470}).optimize(compressor);2471}2472return self.evaluate(compressor)[0];2473});24742475function literals_in_boolean_context(self, compressor) {2476if (compressor.option("booleans") && compressor.in_boolean_context() && !self.has_side_effects(compressor)) {2477return make_node(AST_True, self);2478}2479return self;2480};2481OPT(AST_Array, literals_in_boolean_context);2482OPT(AST_Object, literals_in_boolean_context);2483OPT(AST_RegExp, literals_in_boolean_context);24842485})();248624872488