lib/uglify.js in uglifier-1.1.0 vs lib/uglify.js in uglifier-1.2.0

- old
+ new

@@ -302,13 +302,13 @@ } }; function JS_Parse_Error(message, line, col, pos) { this.message = message; - this.line = line; - this.col = col; - this.pos = pos; + this.line = line + 1; + this.col = col + 1; + this.pos = pos + 1; this.stack = new Error().stack; }; JS_Parse_Error.prototype.toString = function() { return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack; @@ -374,16 +374,17 @@ function token(type, value, is_comment) { S.regex_allowed = ((type == "operator" && !HOP(UNARY_POSTFIX, value)) || (type == "keyword" && HOP(KEYWORDS_BEFORE_EXPRESSION, value)) || (type == "punc" && HOP(PUNC_BEFORE_EXPRESSION, value))); var ret = { - type : type, - value : value, - line : S.tokline, - col : S.tokcol, - pos : S.tokpos, - nlb : S.newline_before + type : type, + value : value, + line : S.tokline, + col : S.tokcol, + pos : S.tokpos, + endpos : S.pos, + nlb : S.newline_before }; if (!is_comment) { ret.comments_before = S.comments_before; S.comments_before = []; } @@ -516,12 +517,11 @@ function read_multiline_comment() { next(); return with_eof_error("Unterminated multiline comment", function(){ var i = find("*/", true), - text = S.text.substring(S.pos, i), - tok = token("comment2", text, true); + text = S.text.substring(S.pos, i); S.pos = i + 2; S.line += text.split("\n").length - 1; S.newline_before = text.indexOf("\n") >= 0; // https://github.com/mishoo/UglifyJS/issues/#issue/100 @@ -529,11 +529,11 @@ warn("WARNING: at line " + S.line); warn("*** Found \"conditional comment\": " + text); warn("*** UglifyJS DISCARDS ALL COMMENTS. This means your code might no longer work properly in Internet Explorer."); } - return tok; + return token("comment2", text, true); }); }; function read_name() { var backslash = false, name = "", ch; @@ -980,11 +980,11 @@ var obj = expression(); expect(")"); return as("for-in", init, lhs, obj, in_loop(statement)); }; - var function_ = maybe_embed_tokens(function(in_statement) { + var function_ = function(in_statement) { var name = is("name") ? prog1(S.token.value, next) : null; if (in_statement && !name) unexpected(); expect("("); return as(in_statement ? "defun" : "function", @@ -1008,11 +1008,11 @@ var a = block_(); --S.in_function; S.in_loop = loop; return a; })()); - }); + }; function if_() { var cond = parenthesised(), body = statement(), belse; if (is("keyword", "else")) { next(); @@ -1356,11 +1356,11 @@ return str.split(""); }; function member(name, array) { for (var i = array.length; --i >= 0;) - if (array[i] === name) + if (array[i] == name) return true; return false; }; function HOP(obj, prop) { @@ -1770,10 +1770,11 @@ var w = ast_walker(), walk = w.walk; var having_eval = []; function with_new_scope(cont) { current_scope = new Scope(current_scope); + current_scope.labels = new Scope(); var ret = current_scope.body = cont(); ret.scope = current_scope; current_scope = current_scope.parent; return ret; }; @@ -1802,18 +1803,23 @@ if (d[1]) reference(d[0]); }); }; }; + function _breacont(label) { + if (label) + current_scope.labels.refs[label] = true; + }; + return with_new_scope(function(){ // process AST var ret = w.with_walkers({ "function": _lambda, "defun": _lambda, - "label": function(name, stat) { define(name, "label") }, - "break": function(label) { if (label) reference(label) }, - "continue": function(label) { if (label) reference(label) }, + "label": function(name, stat) { current_scope.labels.define(name) }, + "break": _breacont, + "continue": _breacont, "with": function(expr, block) { for (var s = current_scope; s; s = s.parent) s.uses_with = true; }, "var": _vardefs("var"), @@ -1895,19 +1901,22 @@ return null; } }; function _lambda(name, args, body) { - var is_defun = this[0] == "defun", extra; - if (name) { - if (is_defun) name = get_mangled(name); - else { - extra = {}; - if (!(scope.uses_eval || scope.uses_with)) - name = extra[name] = scope.next_mangled(); - else - extra[name] = name; + if (!options.no_functions) { + var is_defun = this[0] == "defun", extra; + if (name) { + if (is_defun) name = get_mangled(name); + else if (body.scope.references(name)) { + extra = {}; + if (!(scope.uses_eval || scope.uses_with)) + name = extra[name] = scope.next_mangled(); + else + extra[name] = name; + } + else name = null; } } body = with_scope(body.scope, function(){ args = MAP(args, function(name){ return get_mangled(name) }); return MAP(body, walk); @@ -1934,10 +1943,14 @@ return [ this[0], MAP(defs, function(d){ return [ get_mangled(d[0]), walk(d[1]) ]; }) ]; }; + function _breacont(label) { + if (label) return [ this[0], scope.labels.get_mangled(label) ]; + }; + return w.with_walkers({ "function": _lambda, "defun": function() { // move function declarations to the top when // they are not in some block. @@ -1948,13 +1961,20 @@ case "defun": return MAP.at_top(ast); } return ast; }, - "label": function(label, stat) { return [ this[0], get_mangled(label), walk(stat) ] }, - "break": function(label) { if (label) return [ this[0], get_mangled(label) ] }, - "continue": function(label) { if (label) return [ this[0], get_mangled(label) ] }, + "label": function(label, stat) { + if (scope.labels.refs[label]) return [ + this[0], + scope.labels.get_mangled(label, true), + walk(stat) + ]; + return walk(stat); + }, + "break": _breacont, + "continue": _breacont, "var": _vardefs, "const": _vardefs, "name": function(name) { return get_define(name) || [ this[0], get_mangled(name) ]; }, @@ -2364,11 +2384,11 @@ dead_code : true, no_warnings : false, keep_comps : true }); - var w = ast_walker(), walk = w.walk, scope; + var w = ast_walker(), walk = w.walk; function negate(c) { var not_c = [ "unary-prefix", "!", c ]; switch (c[0]) { case "unary-prefix": @@ -2416,19 +2436,10 @@ warn_unreachable(val ? e : t); return (val ? t : e); }, make_real_conditional); }; - function with_scope(s, cont) { - var _scope = scope; - scope = s; - var ret = cont(); - ret.scope = s; - scope = _scope; - return ret; - }; - function rmblock(block) { if (block != null && block[0] == "block" && block[1]) { if (block[1].length == 1) block = block[1][0]; else if (block[1].length == 0) @@ -2436,18 +2447,11 @@ } return block; }; function _lambda(name, args, body) { - var is_defun = this[0] == "defun"; - body = with_scope(body.scope, function(){ - var ret = tighten(body, "lambda"); - if (!is_defun && name && !scope.references(name)) - name = null; - return ret; - }); - return [ this[0], name, args, body ]; + return [ this[0], name, args, tighten(body, "lambda") ]; }; // this function does a few things: // 1. discard useless blocks // 2. join consecutive var declarations @@ -2657,13 +2661,11 @@ return [ "sub", walk(expr), [ "num", parseInt(name, 10) ] ]; } }, "if": make_if, "toplevel": function(body) { - return [ "toplevel", with_scope(this.scope, function(){ - return tighten(body); - }) ]; + return [ "toplevel", tighten(body) ]; }, "switch": function(expr, body) { var last = body.length - 1; return [ "switch", walk(expr), MAP(body, function(branch, i){ var block = tighten(branch[1]); @@ -2734,11 +2736,10 @@ return [ this[0], op, lvalue, rvalue ]; } }, function() { for (var i = 0; i < 2; ++i) { ast = prepare_ifs(ast); - ast = ast_add_scope(ast); ast = walk(ast); } return ast; }); }; @@ -2806,11 +2807,11 @@ space = beautify ? " " : ""; function encode_string(str) { var ret = make_string(str, options.ascii_only); if (options.inline_script) - ret = ret.replace(/<\x2fscript([>/\t\n\f\r ])/gi, "<\\/script$1"); + ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1"); return ret; }; function make_name(name) { name = name.toString(); @@ -3414,24 +3415,42 @@ return [ this[0], with_scope(this.scope, curry(MAP, body, walk)) ]; }, "function": _lambda, "defun": _lambda, "new": function(ctor, args) { - if (ctor[0] == "name" && ctor[1] == "Array" && !scope.has("Array")) { - if (args.length != 1) { - return [ "array", args ]; - } else { - return walk([ "call", [ "name", "Array" ], args ]); + if (ctor[0] == "name") { + if (ctor[1] == "Array" && !scope.has("Array")) { + if (args.length != 1) { + return [ "array", args ]; + } else { + return walk([ "call", [ "name", "Array" ], args ]); + } + } else if (ctor[1] == "Object" && !scope.has("Object")) { + if (!args.length) { + return [ "object", [] ]; + } else { + return walk([ "call", [ "name", "Object" ], args ]); + } + } else if ((ctor[1] == "RegExp" || ctor[1] == "Function" || ctor[1] == "Error") && !scope.has(ctor[1])) { + return walk([ "call", [ "name", ctor[1] ], args]); } } }, "call": function(expr, args) { if (expr[0] == "dot" && expr[2] == "toString" && args.length == 0) { // foo.toString() ==> foo+"" return [ "binary", "+", expr[1], [ "string", "" ]]; } - if (expr[0] == "name" && expr[1] == "Array" && args.length != 1 && !scope.has("Array")) { - return [ "array", args ]; + if (expr[0] == "name") { + if (expr[1] == "Array" && args.length != 1 && !scope.has("Array")) { + return [ "array", args ]; + } + if (expr[1] == "Object" && !args.length && !scope.has("Object")) { + return [ "object", [] ]; + } + if (expr[1] == "String" && !scope.has("String")) { + return [ "binary", "+", args[0], [ "string", "" ]]; + } } } }, function() { return walk(pro.ast_add_scope(ast)); });