react / wstein / node_modules / jest-cli / node_modules / istanbul / node_modules / handlebars / node_modules / uglify-js / lib / output.js
80713 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 OutputStream(options) {4647options = defaults(options, {48indent_start : 0,49indent_level : 4,50quote_keys : false,51space_colon : true,52ascii_only : false,53inline_script : false,54width : 80,55max_line_len : 32000,56ie_proof : true,57beautify : false,58source_map : null,59bracketize : false,60semicolons : true,61comments : false,62preserve_line : false,63negate_iife : !(options && options.beautify),64}, true);6566var indentation = 0;67var current_col = 0;68var current_line = 1;69var current_pos = 0;70var OUTPUT = "";7172function to_ascii(str, identifier) {73return str.replace(/[\u0080-\uffff]/g, function(ch) {74var code = ch.charCodeAt(0).toString(16);75if (code.length <= 2 && !identifier) {76while (code.length < 2) code = "0" + code;77return "\\x" + code;78} else {79while (code.length < 4) code = "0" + code;80return "\\u" + code;81}82});83};8485function make_string(str) {86var dq = 0, sq = 0;87str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0]/g, function(s){88switch (s) {89case "\\": return "\\\\";90case "\b": return "\\b";91case "\f": return "\\f";92case "\n": return "\\n";93case "\r": return "\\r";94case "\u2028": return "\\u2028";95case "\u2029": return "\\u2029";96case '"': ++dq; return '"';97case "'": ++sq; return "'";98case "\0": return "\\0";99}100return s;101});102if (options.ascii_only) str = to_ascii(str);103if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'";104else return '"' + str.replace(/\x22/g, '\\"') + '"';105};106107function encode_string(str) {108var ret = make_string(str);109if (options.inline_script)110ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1");111return ret;112};113114function make_name(name) {115name = name.toString();116if (options.ascii_only)117name = to_ascii(name, true);118return name;119};120121function make_indent(back) {122return repeat_string(" ", options.indent_start + indentation - back * options.indent_level);123};124125/* -----[ beautification/minification ]----- */126127var might_need_space = false;128var might_need_semicolon = false;129var last = null;130131function last_char() {132return last.charAt(last.length - 1);133};134135function maybe_newline() {136if (options.max_line_len && current_col > options.max_line_len)137print("\n");138};139140var requireSemicolonChars = makePredicate("( [ + * / - , .");141142function print(str) {143str = String(str);144var ch = str.charAt(0);145if (might_need_semicolon) {146if ((!ch || ";}".indexOf(ch) < 0) && !/[;]$/.test(last)) {147if (options.semicolons || requireSemicolonChars(ch)) {148OUTPUT += ";";149current_col++;150current_pos++;151} else {152OUTPUT += "\n";153current_pos++;154current_line++;155current_col = 0;156}157if (!options.beautify)158might_need_space = false;159}160might_need_semicolon = false;161maybe_newline();162}163164if (!options.beautify && options.preserve_line && stack[stack.length - 1]) {165var target_line = stack[stack.length - 1].start.line;166while (current_line < target_line) {167OUTPUT += "\n";168current_pos++;169current_line++;170current_col = 0;171might_need_space = false;172}173}174175if (might_need_space) {176var prev = last_char();177if ((is_identifier_char(prev)178&& (is_identifier_char(ch) || ch == "\\"))179|| (/^[\+\-\/]$/.test(ch) && ch == prev))180{181OUTPUT += " ";182current_col++;183current_pos++;184}185might_need_space = false;186}187var a = str.split(/\r?\n/), n = a.length - 1;188current_line += n;189if (n == 0) {190current_col += a[n].length;191} else {192current_col = a[n].length;193}194current_pos += str.length;195last = str;196OUTPUT += str;197};198199var space = options.beautify ? function() {200print(" ");201} : function() {202might_need_space = true;203};204205var indent = options.beautify ? function(half) {206if (options.beautify) {207print(make_indent(half ? 0.5 : 0));208}209} : noop;210211var with_indent = options.beautify ? function(col, cont) {212if (col === true) col = next_indent();213var save_indentation = indentation;214indentation = col;215var ret = cont();216indentation = save_indentation;217return ret;218} : function(col, cont) { return cont() };219220var newline = options.beautify ? function() {221print("\n");222} : noop;223224var semicolon = options.beautify ? function() {225print(";");226} : function() {227might_need_semicolon = true;228};229230function force_semicolon() {231might_need_semicolon = false;232print(";");233};234235function next_indent() {236return indentation + options.indent_level;237};238239function with_block(cont) {240var ret;241print("{");242newline();243with_indent(next_indent(), function(){244ret = cont();245});246indent();247print("}");248return ret;249};250251function with_parens(cont) {252print("(");253//XXX: still nice to have that for argument lists254//var ret = with_indent(current_col, cont);255var ret = cont();256print(")");257return ret;258};259260function with_square(cont) {261print("[");262//var ret = with_indent(current_col, cont);263var ret = cont();264print("]");265return ret;266};267268function comma() {269print(",");270space();271};272273function colon() {274print(":");275if (options.space_colon) space();276};277278var add_mapping = options.source_map ? function(token, name) {279try {280if (token) options.source_map.add(281token.file || "?",282current_line, current_col,283token.line, token.col,284(!name && token.type == "name") ? token.value : name285);286} catch(ex) {287AST_Node.warn("Couldn't figure out mapping for {file}:{line},{col} → {cline},{ccol} [{name}]", {288file: token.file,289line: token.line,290col: token.col,291cline: current_line,292ccol: current_col,293name: name || ""294})295}296} : noop;297298function get() {299return OUTPUT;300};301302var stack = [];303return {304get : get,305toString : get,306indent : indent,307indentation : function() { return indentation },308current_width : function() { return current_col - indentation },309should_break : function() { return options.width && this.current_width() >= options.width },310newline : newline,311print : print,312space : space,313comma : comma,314colon : colon,315last : function() { return last },316semicolon : semicolon,317force_semicolon : force_semicolon,318to_ascii : to_ascii,319print_name : function(name) { print(make_name(name)) },320print_string : function(str) { print(encode_string(str)) },321next_indent : next_indent,322with_indent : with_indent,323with_block : with_block,324with_parens : with_parens,325with_square : with_square,326add_mapping : add_mapping,327option : function(opt) { return options[opt] },328line : function() { return current_line },329col : function() { return current_col },330pos : function() { return current_pos },331push_node : function(node) { stack.push(node) },332pop_node : function() { return stack.pop() },333stack : function() { return stack },334parent : function(n) {335return stack[stack.length - 2 - (n || 0)];336}337};338339};340341/* -----[ code generators ]----- */342343(function(){344345/* -----[ utils ]----- */346347function DEFPRINT(nodetype, generator) {348nodetype.DEFMETHOD("_codegen", generator);349};350351AST_Node.DEFMETHOD("print", function(stream, force_parens){352var self = this, generator = self._codegen;353stream.push_node(self);354var needs_parens = self.needs_parens(stream);355var fc = self instanceof AST_Function && stream.option("negate_iife");356if (force_parens || (needs_parens && !fc)) {357stream.with_parens(function(){358self.add_comments(stream);359self.add_source_map(stream);360generator(self, stream);361});362} else {363self.add_comments(stream);364if (needs_parens && fc) stream.print("!");365self.add_source_map(stream);366generator(self, stream);367}368stream.pop_node();369});370371AST_Node.DEFMETHOD("print_to_string", function(options){372var s = OutputStream(options);373this.print(s);374return s.get();375});376377/* -----[ comments ]----- */378379AST_Node.DEFMETHOD("add_comments", function(output){380var c = output.option("comments"), self = this;381if (c) {382var start = self.start;383if (start && !start._comments_dumped) {384start._comments_dumped = true;385var comments = start.comments_before;386387// XXX: ugly fix for https://github.com/mishoo/UglifyJS2/issues/112388// if this node is `return` or `throw`, we cannot allow comments before389// the returned or thrown value.390if (self instanceof AST_Exit &&391self.value && self.value.start.comments_before.length > 0) {392comments = (comments || []).concat(self.value.start.comments_before);393self.value.start.comments_before = [];394}395396if (c.test) {397comments = comments.filter(function(comment){398return c.test(comment.value);399});400} else if (typeof c == "function") {401comments = comments.filter(function(comment){402return c(self, comment);403});404}405comments.forEach(function(c){406if (c.type == "comment1") {407output.print("//" + c.value + "\n");408output.indent();409}410else if (c.type == "comment2") {411output.print("/*" + c.value + "*/");412if (start.nlb) {413output.print("\n");414output.indent();415} else {416output.space();417}418}419});420}421}422});423424/* -----[ PARENTHESES ]----- */425426function PARENS(nodetype, func) {427nodetype.DEFMETHOD("needs_parens", func);428};429430PARENS(AST_Node, function(){431return false;432});433434// a function expression needs parens around it when it's provably435// the first token to appear in a statement.436PARENS(AST_Function, function(output){437return first_in_statement(output);438});439440// same goes for an object literal, because otherwise it would be441// interpreted as a block of code.442PARENS(AST_Object, function(output){443return first_in_statement(output);444});445446PARENS(AST_Unary, function(output){447var p = output.parent();448return p instanceof AST_PropAccess && p.expression === this;449});450451PARENS(AST_Seq, function(output){452var p = output.parent();453return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)454|| p instanceof AST_Unary // !(foo, bar, baz)455|| p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8456|| p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4457|| p instanceof AST_Dot // (1, {foo:2}).foo ==> 2458|| p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]459|| p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2460|| p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30)461* ==> 20 (side effect, set a := 10 and b := 20) */462;463});464465PARENS(AST_Binary, function(output){466var p = output.parent();467// (foo && bar)()468if (p instanceof AST_Call && p.expression === this)469return true;470// typeof (foo && bar)471if (p instanceof AST_Unary)472return true;473// (foo && bar)["prop"], (foo && bar).prop474if (p instanceof AST_PropAccess && p.expression === this)475return true;476// this deals with precedence: 3 * (2 + 1)477if (p instanceof AST_Binary) {478var po = p.operator, pp = PRECEDENCE[po];479var so = this.operator, sp = PRECEDENCE[so];480if (pp > sp481|| (pp == sp482&& this === p.right483&& !(so == po &&484(so == "*" ||485so == "&&" ||486so == "||")))) {487return true;488}489}490});491492PARENS(AST_PropAccess, function(output){493var p = output.parent();494if (p instanceof AST_New && p.expression === this) {495// i.e. new (foo.bar().baz)496//497// if there's one call into this subtree, then we need498// parens around it too, otherwise the call will be499// interpreted as passing the arguments to the upper New500// expression.501try {502this.walk(new TreeWalker(function(node){503if (node instanceof AST_Call) throw p;504}));505} catch(ex) {506if (ex !== p) throw ex;507return true;508}509}510});511512PARENS(AST_Call, function(output){513var p = output.parent();514return p instanceof AST_New && p.expression === this;515});516517PARENS(AST_New, function(output){518var p = output.parent();519if (no_constructor_parens(this, output)520&& (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]()521|| p instanceof AST_Call && p.expression === this)) // (new foo)(bar)522return true;523});524525PARENS(AST_Number, function(output){526var p = output.parent();527if (this.getValue() < 0 && p instanceof AST_PropAccess && p.expression === this)528return true;529});530531PARENS(AST_NaN, function(output){532var p = output.parent();533if (p instanceof AST_PropAccess && p.expression === this)534return true;535});536537function assign_and_conditional_paren_rules(output) {538var p = output.parent();539// !(a = false) → true540if (p instanceof AST_Unary)541return true;542// 1 + (a = 2) + 3 → 6, side effect setting a = 2543if (p instanceof AST_Binary && !(p instanceof AST_Assign))544return true;545// (a = func)() —or— new (a = Object)()546if (p instanceof AST_Call && p.expression === this)547return true;548// (a = foo) ? bar : baz549if (p instanceof AST_Conditional && p.condition === this)550return true;551// (a = foo)["prop"] —or— (a = foo).prop552if (p instanceof AST_PropAccess && p.expression === this)553return true;554};555556PARENS(AST_Assign, assign_and_conditional_paren_rules);557PARENS(AST_Conditional, assign_and_conditional_paren_rules);558559/* -----[ PRINTERS ]----- */560561DEFPRINT(AST_Directive, function(self, output){562output.print_string(self.value);563output.semicolon();564});565DEFPRINT(AST_Debugger, function(self, output){566output.print("debugger");567output.semicolon();568});569570/* -----[ statements ]----- */571572function display_body(body, is_toplevel, output) {573var last = body.length - 1;574body.forEach(function(stmt, i){575if (!(stmt instanceof AST_EmptyStatement)) {576output.indent();577stmt.print(output);578if (!(i == last && is_toplevel)) {579output.newline();580if (is_toplevel) output.newline();581}582}583});584};585586AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output){587force_statement(this.body, output);588});589590DEFPRINT(AST_Statement, function(self, output){591self.body.print(output);592output.semicolon();593});594DEFPRINT(AST_Toplevel, function(self, output){595display_body(self.body, true, output);596output.print("");597});598DEFPRINT(AST_LabeledStatement, function(self, output){599self.label.print(output);600output.colon();601self.body.print(output);602});603DEFPRINT(AST_SimpleStatement, function(self, output){604self.body.print(output);605output.semicolon();606});607function print_bracketed(body, output) {608if (body.length > 0) output.with_block(function(){609display_body(body, false, output);610});611else output.print("{}");612};613DEFPRINT(AST_BlockStatement, function(self, output){614print_bracketed(self.body, output);615});616DEFPRINT(AST_EmptyStatement, function(self, output){617output.semicolon();618});619DEFPRINT(AST_Do, function(self, output){620output.print("do");621output.space();622self._do_print_body(output);623output.space();624output.print("while");625output.space();626output.with_parens(function(){627self.condition.print(output);628});629output.semicolon();630});631DEFPRINT(AST_While, function(self, output){632output.print("while");633output.space();634output.with_parens(function(){635self.condition.print(output);636});637output.space();638self._do_print_body(output);639});640DEFPRINT(AST_For, function(self, output){641output.print("for");642output.space();643output.with_parens(function(){644if (self.init) {645if (self.init instanceof AST_Definitions) {646self.init.print(output);647} else {648parenthesize_for_noin(self.init, output, true);649}650output.print(";");651output.space();652} else {653output.print(";");654}655if (self.condition) {656self.condition.print(output);657output.print(";");658output.space();659} else {660output.print(";");661}662if (self.step) {663self.step.print(output);664}665});666output.space();667self._do_print_body(output);668});669DEFPRINT(AST_ForIn, function(self, output){670output.print("for");671output.space();672output.with_parens(function(){673self.init.print(output);674output.space();675output.print("in");676output.space();677self.object.print(output);678});679output.space();680self._do_print_body(output);681});682DEFPRINT(AST_With, function(self, output){683output.print("with");684output.space();685output.with_parens(function(){686self.expression.print(output);687});688output.space();689self._do_print_body(output);690});691692/* -----[ functions ]----- */693AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword){694var self = this;695if (!nokeyword) {696output.print("function");697}698if (self.name) {699output.space();700self.name.print(output);701}702output.with_parens(function(){703self.argnames.forEach(function(arg, i){704if (i) output.comma();705arg.print(output);706});707});708output.space();709print_bracketed(self.body, output);710});711DEFPRINT(AST_Lambda, function(self, output){712self._do_print(output);713});714715/* -----[ exits ]----- */716AST_Exit.DEFMETHOD("_do_print", function(output, kind){717output.print(kind);718if (this.value) {719output.space();720this.value.print(output);721}722output.semicolon();723});724DEFPRINT(AST_Return, function(self, output){725self._do_print(output, "return");726});727DEFPRINT(AST_Throw, function(self, output){728self._do_print(output, "throw");729});730731/* -----[ loop control ]----- */732AST_LoopControl.DEFMETHOD("_do_print", function(output, kind){733output.print(kind);734if (this.label) {735output.space();736this.label.print(output);737}738output.semicolon();739});740DEFPRINT(AST_Break, function(self, output){741self._do_print(output, "break");742});743DEFPRINT(AST_Continue, function(self, output){744self._do_print(output, "continue");745});746747/* -----[ if ]----- */748function make_then(self, output) {749if (output.option("bracketize")) {750make_block(self.body, output);751return;752}753// The squeezer replaces "block"-s that contain only a single754// statement with the statement itself; technically, the AST755// is correct, but this can create problems when we output an756// IF having an ELSE clause where the THEN clause ends in an757// IF *without* an ELSE block (then the outer ELSE would refer758// to the inner IF). This function checks for this case and759// adds the block brackets if needed.760if (!self.body)761return output.force_semicolon();762if (self.body instanceof AST_Do763&& output.option("ie_proof")) {764// https://github.com/mishoo/UglifyJS/issues/#issue/57 IE765// croaks with "syntax error" on code like this: if (foo)766// do ... while(cond); else ... we need block brackets767// around do/while768make_block(self.body, output);769return;770}771var b = self.body;772while (true) {773if (b instanceof AST_If) {774if (!b.alternative) {775make_block(self.body, output);776return;777}778b = b.alternative;779}780else if (b instanceof AST_StatementWithBody) {781b = b.body;782}783else break;784}785force_statement(self.body, output);786};787DEFPRINT(AST_If, function(self, output){788output.print("if");789output.space();790output.with_parens(function(){791self.condition.print(output);792});793output.space();794if (self.alternative) {795make_then(self, output);796output.space();797output.print("else");798output.space();799force_statement(self.alternative, output);800} else {801self._do_print_body(output);802}803});804805/* -----[ switch ]----- */806DEFPRINT(AST_Switch, function(self, output){807output.print("switch");808output.space();809output.with_parens(function(){810self.expression.print(output);811});812output.space();813if (self.body.length > 0) output.with_block(function(){814self.body.forEach(function(stmt, i){815if (i) output.newline();816output.indent(true);817stmt.print(output);818});819});820else output.print("{}");821});822AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output){823if (this.body.length > 0) {824output.newline();825this.body.forEach(function(stmt){826output.indent();827stmt.print(output);828output.newline();829});830}831});832DEFPRINT(AST_Default, function(self, output){833output.print("default:");834self._do_print_body(output);835});836DEFPRINT(AST_Case, function(self, output){837output.print("case");838output.space();839self.expression.print(output);840output.print(":");841self._do_print_body(output);842});843844/* -----[ exceptions ]----- */845DEFPRINT(AST_Try, function(self, output){846output.print("try");847output.space();848print_bracketed(self.body, output);849if (self.bcatch) {850output.space();851self.bcatch.print(output);852}853if (self.bfinally) {854output.space();855self.bfinally.print(output);856}857});858DEFPRINT(AST_Catch, function(self, output){859output.print("catch");860output.space();861output.with_parens(function(){862self.argname.print(output);863});864output.space();865print_bracketed(self.body, output);866});867DEFPRINT(AST_Finally, function(self, output){868output.print("finally");869output.space();870print_bracketed(self.body, output);871});872873/* -----[ var/const ]----- */874AST_Definitions.DEFMETHOD("_do_print", function(output, kind){875output.print(kind);876output.space();877this.definitions.forEach(function(def, i){878if (i) output.comma();879def.print(output);880});881var p = output.parent();882var in_for = p instanceof AST_For || p instanceof AST_ForIn;883var avoid_semicolon = in_for && p.init === this;884if (!avoid_semicolon)885output.semicolon();886});887DEFPRINT(AST_Var, function(self, output){888self._do_print(output, "var");889});890DEFPRINT(AST_Const, function(self, output){891self._do_print(output, "const");892});893894function parenthesize_for_noin(node, output, noin) {895if (!noin) node.print(output);896else try {897// need to take some precautions here:898// https://github.com/mishoo/UglifyJS2/issues/60899node.walk(new TreeWalker(function(node){900if (node instanceof AST_Binary && node.operator == "in")901throw output;902}));903node.print(output);904} catch(ex) {905if (ex !== output) throw ex;906node.print(output, true);907}908};909910DEFPRINT(AST_VarDef, function(self, output){911self.name.print(output);912if (self.value) {913output.space();914output.print("=");915output.space();916var p = output.parent(1);917var noin = p instanceof AST_For || p instanceof AST_ForIn;918parenthesize_for_noin(self.value, output, noin);919}920});921922/* -----[ other expressions ]----- */923DEFPRINT(AST_Call, function(self, output){924self.expression.print(output);925if (self instanceof AST_New && no_constructor_parens(self, output))926return;927output.with_parens(function(){928self.args.forEach(function(expr, i){929if (i) output.comma();930expr.print(output);931});932});933});934DEFPRINT(AST_New, function(self, output){935output.print("new");936output.space();937AST_Call.prototype._codegen(self, output);938});939940AST_Seq.DEFMETHOD("_do_print", function(output){941this.car.print(output);942if (this.cdr) {943output.comma();944if (output.should_break()) {945output.newline();946output.indent();947}948this.cdr.print(output);949}950});951DEFPRINT(AST_Seq, function(self, output){952self._do_print(output);953// var p = output.parent();954// if (p instanceof AST_Statement) {955// output.with_indent(output.next_indent(), function(){956// self._do_print(output);957// });958// } else {959// self._do_print(output);960// }961});962DEFPRINT(AST_Dot, function(self, output){963var expr = self.expression;964expr.print(output);965if (expr instanceof AST_Number && expr.getValue() >= 0) {966if (!/[xa-f.]/i.test(output.last())) {967output.print(".");968}969}970output.print(".");971// the name after dot would be mapped about here.972output.add_mapping(self.end);973output.print_name(self.property);974});975DEFPRINT(AST_Sub, function(self, output){976self.expression.print(output);977output.print("[");978self.property.print(output);979output.print("]");980});981DEFPRINT(AST_UnaryPrefix, function(self, output){982var op = self.operator;983output.print(op);984if (/^[a-z]/i.test(op))985output.space();986self.expression.print(output);987});988DEFPRINT(AST_UnaryPostfix, function(self, output){989self.expression.print(output);990output.print(self.operator);991});992DEFPRINT(AST_Binary, function(self, output){993self.left.print(output);994output.space();995output.print(self.operator);996output.space();997self.right.print(output);998});999DEFPRINT(AST_Conditional, function(self, output){1000self.condition.print(output);1001output.space();1002output.print("?");1003output.space();1004self.consequent.print(output);1005output.space();1006output.colon();1007self.alternative.print(output);1008});10091010/* -----[ literals ]----- */1011DEFPRINT(AST_Array, function(self, output){1012output.with_square(function(){1013var a = self.elements, len = a.length;1014if (len > 0) output.space();1015a.forEach(function(exp, i){1016if (i) output.comma();1017exp.print(output);1018});1019if (len > 0) output.space();1020});1021});1022DEFPRINT(AST_Object, function(self, output){1023if (self.properties.length > 0) output.with_block(function(){1024self.properties.forEach(function(prop, i){1025if (i) {1026output.print(",");1027output.newline();1028}1029output.indent();1030prop.print(output);1031});1032output.newline();1033});1034else output.print("{}");1035});1036DEFPRINT(AST_ObjectKeyVal, function(self, output){1037var key = self.key;1038if (output.option("quote_keys")) {1039output.print_string(key + "");1040} else if ((typeof key == "number"1041|| !output.option("beautify")1042&& +key + "" == key)1043&& parseFloat(key) >= 0) {1044output.print(make_num(key));1045} else if (!is_identifier(key)) {1046output.print_string(key);1047} else {1048output.print_name(key);1049}1050output.colon();1051self.value.print(output);1052});1053DEFPRINT(AST_ObjectSetter, function(self, output){1054output.print("set");1055self.value._do_print(output, true);1056});1057DEFPRINT(AST_ObjectGetter, function(self, output){1058output.print("get");1059self.value._do_print(output, true);1060});1061DEFPRINT(AST_Symbol, function(self, output){1062var def = self.definition();1063output.print_name(def ? def.mangled_name || def.name : self.name);1064});1065DEFPRINT(AST_Undefined, function(self, output){1066output.print("void 0");1067});1068DEFPRINT(AST_Hole, noop);1069DEFPRINT(AST_Infinity, function(self, output){1070output.print("1/0");1071});1072DEFPRINT(AST_NaN, function(self, output){1073output.print("0/0");1074});1075DEFPRINT(AST_This, function(self, output){1076output.print("this");1077});1078DEFPRINT(AST_Constant, function(self, output){1079output.print(self.getValue());1080});1081DEFPRINT(AST_String, function(self, output){1082output.print_string(self.getValue());1083});1084DEFPRINT(AST_Number, function(self, output){1085output.print(make_num(self.getValue()));1086});1087DEFPRINT(AST_RegExp, function(self, output){1088var str = self.getValue().toString();1089if (output.option("ascii_only"))1090str = output.to_ascii(str);1091output.print(str);1092var p = output.parent();1093if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self)1094output.print(" ");1095});10961097function force_statement(stat, output) {1098if (output.option("bracketize")) {1099if (!stat || stat instanceof AST_EmptyStatement)1100output.print("{}");1101else if (stat instanceof AST_BlockStatement)1102stat.print(output);1103else output.with_block(function(){1104output.indent();1105stat.print(output);1106output.newline();1107});1108} else {1109if (!stat || stat instanceof AST_EmptyStatement)1110output.force_semicolon();1111else1112stat.print(output);1113}1114};11151116// return true if the node at the top of the stack (that means the1117// innermost node in the current output) is lexically the first in1118// a statement.1119function first_in_statement(output) {1120var a = output.stack(), i = a.length, node = a[--i], p = a[--i];1121while (i > 0) {1122if (p instanceof AST_Statement && p.body === node)1123return true;1124if ((p instanceof AST_Seq && p.car === node ) ||1125(p instanceof AST_Call && p.expression === node && !(p instanceof AST_New) ) ||1126(p instanceof AST_Dot && p.expression === node ) ||1127(p instanceof AST_Sub && p.expression === node ) ||1128(p instanceof AST_Conditional && p.condition === node ) ||1129(p instanceof AST_Binary && p.left === node ) ||1130(p instanceof AST_UnaryPostfix && p.expression === node ))1131{1132node = p;1133p = a[--i];1134} else {1135return false;1136}1137}1138};11391140// self should be AST_New. decide if we want to show parens or not.1141function no_constructor_parens(self, output) {1142return self.args.length == 0 && !output.option("beautify");1143};11441145function best_of(a) {1146var best = a[0], len = best.length;1147for (var i = 1; i < a.length; ++i) {1148if (a[i].length < len) {1149best = a[i];1150len = best.length;1151}1152}1153return best;1154};11551156function make_num(num) {1157var str = num.toString(10), a = [ str.replace(/^0\./, ".").replace('e+', 'e') ], m;1158if (Math.floor(num) === num) {1159if (num >= 0) {1160a.push("0x" + num.toString(16).toLowerCase(), // probably pointless1161"0" + num.toString(8)); // same.1162} else {1163a.push("-0x" + (-num).toString(16).toLowerCase(), // probably pointless1164"-0" + (-num).toString(8)); // same.1165}1166if ((m = /^(.*?)(0+)$/.exec(num))) {1167a.push(m[1] + "e" + m[2].length);1168}1169} else if ((m = /^0?\.(0+)(.*)$/.exec(num))) {1170a.push(m[2] + "e-" + (m[1].length + m[2].length),1171str.substr(str.indexOf(".")));1172}1173return best_of(a);1174};11751176function make_block(stmt, output) {1177if (stmt instanceof AST_BlockStatement) {1178stmt.print(output);1179return;1180}1181output.with_block(function(){1182output.indent();1183stmt.print(output);1184output.newline();1185});1186};11871188/* -----[ source map generators ]----- */11891190function DEFMAP(nodetype, generator) {1191nodetype.DEFMETHOD("add_source_map", function(stream){1192generator(this, stream);1193});1194};11951196// We could easily add info for ALL nodes, but it seems to me that1197// would be quite wasteful, hence this noop in the base class.1198DEFMAP(AST_Node, noop);11991200function basic_sourcemap_gen(self, output) {1201output.add_mapping(self.start);1202};12031204// XXX: I'm not exactly sure if we need it for all of these nodes,1205// or if we should add even more.12061207DEFMAP(AST_Directive, basic_sourcemap_gen);1208DEFMAP(AST_Debugger, basic_sourcemap_gen);1209DEFMAP(AST_Symbol, basic_sourcemap_gen);1210DEFMAP(AST_Jump, basic_sourcemap_gen);1211DEFMAP(AST_StatementWithBody, basic_sourcemap_gen);1212DEFMAP(AST_LabeledStatement, noop); // since the label symbol will mark it1213DEFMAP(AST_Lambda, basic_sourcemap_gen);1214DEFMAP(AST_Switch, basic_sourcemap_gen);1215DEFMAP(AST_SwitchBranch, basic_sourcemap_gen);1216DEFMAP(AST_BlockStatement, basic_sourcemap_gen);1217DEFMAP(AST_Toplevel, noop);1218DEFMAP(AST_New, basic_sourcemap_gen);1219DEFMAP(AST_Try, basic_sourcemap_gen);1220DEFMAP(AST_Catch, basic_sourcemap_gen);1221DEFMAP(AST_Finally, basic_sourcemap_gen);1222DEFMAP(AST_Definitions, basic_sourcemap_gen);1223DEFMAP(AST_Constant, basic_sourcemap_gen);1224DEFMAP(AST_ObjectProperty, function(self, output){1225output.add_mapping(self.start, self.key);1226});12271228})();122912301231