vendor/uglifyjs/lib/process.js in uglifier-0.4.0 vs vendor/uglifyjs/lib/process.js in uglifier-0.5.0
- old
+ new
@@ -8,18 +8,17 @@
This file implements some AST processors. They work on data built
by parse-js.
Exported functions:
- - ast_mangle(ast, include_toplevel) -- mangles the
- variable/function names in the AST. Returns an AST. Pass true
- as second argument to mangle toplevel names too.
+ - ast_mangle(ast, options) -- mangles the variable/function names
+ in the AST. Returns an AST.
- ast_squeeze(ast) -- employs various optimizations to make the
final generated code even smaller. Returns an AST.
- - gen_code(ast, beautify) -- generates JS code from the AST. Pass
+ - gen_code(ast, options) -- generates JS code from the AST. Pass
true (or an object, see the code for some options) as second
argument to get "pretty" (indented) code.
-------------------------------- (C) ---------------------------------
@@ -254,12 +253,12 @@
this.names = {}; // names defined in this scope
this.mangled = {}; // mangled names (orig.name => mangled)
this.rev_mangled = {}; // reverse lookup (mangled => orig.name)
this.cname = -1; // current mangled name
this.refs = {}; // names referenced from this scope
- this.uses_with = false; // will become TRUE if eval() is detected in this or any subscopes
- this.uses_eval = false; // will become TRUE if with() is detected in this or any subscopes
+ this.uses_with = false; // will become TRUE if with() is detected in this or any subscopes
+ this.uses_eval = false; // will become TRUE if eval() is detected in this or any subscopes
this.parent = parent; // parent scope
this.children = []; // sub-scopes
if (parent) {
this.level = parent.level + 1;
parent.children.push(this);
@@ -934,13 +933,14 @@
return w.with_walkers({
"sub": function(expr, subscript) {
if (subscript[0] == "string") {
var name = subscript[1];
- if (is_identifier(name)) {
+ if (is_identifier(name))
return [ "dot", walk(expr), name ];
- }
+ else if (/^[1-9][0-9]*$/.test(name) || name === "0")
+ return [ "sub", walk(expr), [ "num", parseInt(name, 10) ] ];
}
},
"if": make_if,
"toplevel": function(body) {
return [ "toplevel", with_scope(this.scope, function(){
@@ -1027,55 +1027,78 @@
/* -----[ re-generate code from the AST ]----- */
var DOT_CALL_NO_PARENS = jsp.array_to_hash([
"name",
"array",
+ "object",
"string",
"dot",
"sub",
"call",
"regexp"
]);
-function make_string(str) {
+function make_string(str, ascii_only) {
var dq = 0, sq = 0;
- str = str.replace(/[\\\b\f\n\r\t\x22\x27]/g, function(s){
+ str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029]/g, function(s){
switch (s) {
case "\\": return "\\\\";
case "\b": return "\\b";
case "\f": return "\\f";
case "\n": return "\\n";
case "\r": return "\\r";
case "\t": return "\\t";
+ case "\u2028": return "\\u2028";
+ case "\u2029": return "\\u2029";
case '"': ++dq; return '"';
case "'": ++sq; return "'";
}
return s;
});
- if (dq > sq) {
- return "'" + str.replace(/\x27/g, "\\'") + "'";
- } else {
- return '"' + str.replace(/\x22/g, '\\"') + '"';
- }
+ if (ascii_only) str = to_ascii(str);
+ if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'";
+ else return '"' + str.replace(/\x22/g, '\\"') + '"';
};
-function gen_code(ast, beautify) {
- if (beautify) beautify = defaults(beautify, {
+function to_ascii(str) {
+ return str.replace(/[\u0080-\uffff]/g, function(ch) {
+ var code = ch.charCodeAt(0).toString(16);
+ while (code.length < 4) code = "0" + code;
+ return "\\u" + code;
+ });
+};
+
+function gen_code(ast, options) {
+ options = defaults(options, {
indent_start : 0,
indent_level : 4,
quote_keys : false,
- space_colon : false
+ space_colon : false,
+ beautify : false,
+ ascii_only : false
});
+ var beautify = !!options.beautify;
var indentation = 0,
newline = beautify ? "\n" : "",
space = beautify ? " " : "";
+ function encode_string(str) {
+ return make_string(str, options.ascii_only);
+ };
+
+ function make_name(name) {
+ name = name.toString();
+ if (options.ascii_only)
+ name = to_ascii(name);
+ return name;
+ };
+
function indent(line) {
if (line == null)
line = "";
if (beautify)
- line = repeat_string(" ", beautify.indent_start + indentation * beautify.indent_level) + line;
+ line = repeat_string(" ", options.indent_start + indentation * options.indent_level) + line;
return line;
};
function with_indent(cont, incr) {
if (incr == null) incr = 1;
@@ -1125,11 +1148,11 @@
}
return best_of([ a[0], best_of(a.slice(1)) ]);
};
function needs_parens(expr) {
- if (expr[0] == "function") {
+ if (expr[0] == "function" || expr[0] == "object") {
// dot/call on a literal function requires the
// function literal itself to be parenthesized
// only if it's the first "thing" in a
// statement. This means that the parent is
// "stat", but it could also be a "seq" and
@@ -1137,13 +1160,12 @@
// parent is "stat", and so on. Messy stuff,
// but it worths the trouble.
var a = slice($stack), self = a.pop(), p = a.pop();
while (p) {
if (p[0] == "stat") return true;
- if ((p[0] == "seq" && p[1] === self) ||
- (p[0] == "call" && p[1] === self) ||
- (p[0] == "binary" && p[2] === self)) {
+ if (((p[0] == "seq" || p[0] == "call" || p[0] == "dot" || p[0] == "sub" || p[0] == "conditional") && p[1] === self) ||
+ ((p[0] == "binary" || p[0] == "assign" || p[0] == "unary-postfix") && p[2] === self)) {
self = p;
p = a.pop();
} else {
return false;
}
@@ -1166,11 +1188,11 @@
}
return best_of(a);
};
var generators = {
- "string": make_string,
+ "string": encode_string,
"num": make_num,
"name": make_name,
"toplevel": function(statements) {
return make_block_statements(statements)
.join(newline + newline);
@@ -1234,13 +1256,14 @@
else op = "=";
return add_spaces([ make(lvalue), op, parenthesize(rvalue, "seq") ]);
},
"dot": function(expr) {
var out = make(expr), i = 1;
- if (expr[0] == "num")
- out += ".";
- else if (needs_parens(expr))
+ if (expr[0] == "num") {
+ if (!/\./.test(expr[1]))
+ out += ".";
+ } else if (needs_parens(expr))
out = "(" + out + ")";
while (i < arguments.length)
out += "." + make_name(arguments[i++]);
return out;
},
@@ -1331,19 +1354,19 @@
// getter/setter. The name is in p[0], the arg.list in p[1][2], the
// body in p[1][3] and type ("get" / "set") in p[2].
return indent(make_function(p[0], p[1][2], p[1][3], p[2]));
}
var key = p[0], val = make(p[1]);
- if (beautify && beautify.quote_keys) {
- key = make_string(key);
+ if (options.quote_keys) {
+ key = encode_string(key);
} else if ((typeof key == "number" || !beautify && +key + "" == key)
&& parseFloat(key) >= 0) {
key = make_num(+key);
} else if (!is_identifier(key)) {
- key = make_string(key);
+ key = encode_string(key);
}
- return indent(add_spaces(beautify && beautify.space_colon
+ return indent(add_spaces(beautify && options.space_colon
? [ key, ":", val ]
: [ key + ":", val ]));
}).join("," + newline);
}) + newline + indent("}");
},
@@ -1412,14 +1435,10 @@
}
out += "(" + add_commas(MAP(args, make_name)) + ")";
return add_spaces([ out, make_block(body) ]);
};
- function make_name(name) {
- return name.toString();
- };
-
function make_block_statements(statements) {
for (var a = [], last = statements.length - 1, i = 0; i <= last; ++i) {
var stat = statements[i];
var code = make(stat);
if (code != ";") {
@@ -1465,11 +1484,11 @@
};
function make_1vardef(def) {
var name = def[0], val = def[1];
if (val != null)
- name = add_spaces([ name, "=", make(val) ]);
+ name = add_spaces([ make_name(name), "=", make(val) ]);
return name;
};
var $stack = [];
@@ -1586,9 +1605,12 @@
exports.ast_walker = ast_walker;
exports.ast_mangle = ast_mangle;
exports.ast_squeeze = ast_squeeze;
exports.gen_code = gen_code;
exports.ast_add_scope = ast_add_scope;
-exports.ast_squeeze_more = require("./squeeze-more").ast_squeeze_more;
exports.set_logger = function(logger) { warn = logger };
exports.make_string = make_string;
exports.split_lines = split_lines;
+exports.MAP = MAP;
+
+// keep this last!
+exports.ast_squeeze_more = require("./squeeze-more").ast_squeeze_more;