aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/ast.js137
-rw-r--r--lib/compress.js597
-rw-r--r--lib/mozilla-ast.js35
-rw-r--r--lib/output.js230
-rw-r--r--lib/parse.js209
-rw-r--r--lib/propmangle.js8
-rw-r--r--lib/scope.js24
-rw-r--r--lib/sourcemap.js73
-rw-r--r--lib/transform.js132
-rw-r--r--lib/utils.js14
10 files changed, 694 insertions, 765 deletions
diff --git a/lib/ast.js b/lib/ast.js
index 1a77a59d..c37ba598 100644
--- a/lib/ast.js
+++ b/lib/ast.js
@@ -44,21 +44,21 @@
"use strict";
function DEFNODE(type, props, methods, base) {
- if (arguments.length < 4) base = AST_Node;
- if (!props) props = [];
- else props = props.split(/\s+/);
+ if (typeof base === "undefined") base = AST_Node;
+ props = props ? props.split(/\s+/) : [];
var self_props = props;
- if (base && base.PROPS)
- props = props.concat(base.PROPS);
- var code = "return function AST_" + type + "(props){ if (props) { ";
- for (var i = props.length; --i >= 0;) {
- code += "this." + props[i] + " = props." + props[i] + ";";
- }
+ if (base && base.PROPS) props = props.concat(base.PROPS);
+ var code = [
+ "return function AST_", type, "(props){",
+ "if(props){",
+ ];
+ props.forEach(function(prop) {
+ code.push("this.", prop, "=props.", prop, ";");
+ });
var proto = base && new base;
- if (proto && proto.initialize || (methods && methods.initialize))
- code += "this.initialize();";
- code += "}}";
- var ctor = new Function(code)();
+ if (proto && proto.initialize || methods && methods.initialize) code.push("this.initialize();");
+ code.push("}}");
+ var ctor = new Function(code.join(""))();
if (proto) {
ctor.prototype = proto;
ctor.BASE = base;
@@ -71,11 +71,11 @@ function DEFNODE(type, props, methods, base) {
if (type) {
ctor.prototype.TYPE = ctor.TYPE = type;
}
- if (methods) for (i in methods) if (HOP(methods, i)) {
- if (/^\$/.test(i)) {
- ctor[i.substr(1)] = methods[i];
+ if (methods) for (var name in methods) if (HOP(methods, name)) {
+ if (/^\$/.test(name)) {
+ ctor[name.substr(1)] = methods[name];
} else {
- ctor.prototype[i] = methods[i];
+ ctor.prototype[name] = methods[name];
}
}
ctor.DEFMETHOD = function(name, method) {
@@ -85,7 +85,7 @@ function DEFNODE(type, props, methods, base) {
exports["AST_" + type] = ctor;
}
return ctor;
-};
+}
var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos nlb comments_before comments_after file raw", {
}, null);
@@ -148,7 +148,7 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
body: "[AST_Node] an expression node (should not be instanceof AST_Statement)"
},
_walk: function(visitor) {
- return visitor._visit(this, function(){
+ return visitor._visit(this, function() {
this.body._walk(visitor);
});
}
@@ -158,11 +158,10 @@ function walk_body(node, visitor) {
var body = node.body;
if (body instanceof AST_Statement) {
body._walk(visitor);
- }
- else for (var i = 0, len = body.length; i < len; i++) {
- body[i]._walk(visitor);
- }
-};
+ } else body.forEach(function(node) {
+ node._walk(visitor);
+ });
+}
var AST_Block = DEFNODE("Block", "body", {
$documentation: "A body of statements (usually braced)",
@@ -170,7 +169,7 @@ var AST_Block = DEFNODE("Block", "body", {
body: "[AST_Statement*] an array of statements"
},
_walk: function(visitor) {
- return visitor._visit(this, function(){
+ return visitor._visit(this, function() {
walk_body(this, visitor);
});
}
@@ -197,7 +196,7 @@ var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
label: "[AST_Label] a label definition"
},
_walk: function(visitor) {
- return visitor._visit(this, function(){
+ return visitor._visit(this, function() {
this.label._walk(visitor);
this.body._walk(visitor);
});
@@ -233,7 +232,7 @@ var AST_DWLoop = DEFNODE("DWLoop", "condition", {
var AST_Do = DEFNODE("Do", null, {
$documentation: "A `do` statement",
_walk: function(visitor) {
- return visitor._visit(this, function(){
+ return visitor._visit(this, function() {
this.body._walk(visitor);
this.condition._walk(visitor);
});
@@ -243,7 +242,7 @@ var AST_Do = DEFNODE("Do", null, {
var AST_While = DEFNODE("While", null, {
$documentation: "A `while` statement",
_walk: function(visitor) {
- return visitor._visit(this, function(){
+ return visitor._visit(this, function() {
this.condition._walk(visitor);
this.body._walk(visitor);
});
@@ -258,7 +257,7 @@ var AST_For = DEFNODE("For", "init condition step", {
step: "[AST_Node?] the `for` update clause, or null if empty"
},
_walk: function(visitor) {
- return visitor._visit(this, function(){
+ return visitor._visit(this, function() {
if (this.init) this.init._walk(visitor);
if (this.condition) this.condition._walk(visitor);
if (this.step) this.step._walk(visitor);
@@ -274,7 +273,7 @@ var AST_ForIn = DEFNODE("ForIn", "init object", {
object: "[AST_Node] the object that we're looping through"
},
_walk: function(visitor) {
- return visitor._visit(this, function(){
+ return visitor._visit(this, function() {
this.init._walk(visitor);
this.object._walk(visitor);
this.body._walk(visitor);
@@ -288,7 +287,7 @@ var AST_With = DEFNODE("With", "expression", {
expression: "[AST_Node] the `with` expression"
},
_walk: function(visitor) {
- return visitor._visit(this, function(){
+ return visitor._visit(this, function() {
this.expression._walk(visitor);
this.body._walk(visitor);
});
@@ -329,7 +328,7 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
var body = this.body;
var wrapped_tl = "(function(exports){'$ORIG';})(typeof " + name + "=='undefined'?(" + name + "={}):" + name + ");";
wrapped_tl = parse(wrapped_tl);
- wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){
+ wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node) {
if (node instanceof AST_Directive && node.value == "$ORIG") {
return MAP.splice(body);
}
@@ -363,12 +362,11 @@ var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments", {
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array"
},
_walk: function(visitor) {
- return visitor._visit(this, function(){
+ return visitor._visit(this, function() {
if (this.name) this.name._walk(visitor);
- var argnames = this.argnames;
- for (var i = 0, len = argnames.length; i < len; i++) {
- argnames[i]._walk(visitor);
- }
+ this.argnames.forEach(function(argname) {
+ argname._walk(visitor);
+ });
walk_body(this, visitor);
});
}
@@ -398,7 +396,7 @@ var AST_Exit = DEFNODE("Exit", "value", {
value: "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return"
},
_walk: function(visitor) {
- return visitor._visit(this, this.value && function(){
+ return visitor._visit(this, this.value && function() {
this.value._walk(visitor);
});
}
@@ -418,7 +416,7 @@ var AST_LoopControl = DEFNODE("LoopControl", "label", {
label: "[AST_LabelRef?] the label, or null if none",
},
_walk: function(visitor) {
- return visitor._visit(this, this.label && function(){
+ return visitor._visit(this, this.label && function() {
this.label._walk(visitor);
});
}
@@ -441,7 +439,7 @@ var AST_If = DEFNODE("If", "condition alternative", {
alternative: "[AST_Statement?] the `else` part, or null if not present"
},
_walk: function(visitor) {
- return visitor._visit(this, function(){
+ return visitor._visit(this, function() {
this.condition._walk(visitor);
this.body._walk(visitor);
if (this.alternative) this.alternative._walk(visitor);
@@ -457,7 +455,7 @@ var AST_Switch = DEFNODE("Switch", "expression", {
expression: "[AST_Node] the `switch` “discriminant”"
},
_walk: function(visitor) {
- return visitor._visit(this, function(){
+ return visitor._visit(this, function() {
this.expression._walk(visitor);
walk_body(this, visitor);
});
@@ -478,7 +476,7 @@ var AST_Case = DEFNODE("Case", "expression", {
expression: "[AST_Node] the `case` expression"
},
_walk: function(visitor) {
- return visitor._visit(this, function(){
+ return visitor._visit(this, function() {
this.expression._walk(visitor);
walk_body(this, visitor);
});
@@ -494,7 +492,7 @@ var AST_Try = DEFNODE("Try", "bcatch bfinally", {
bfinally: "[AST_Finally?] the finally block, or null if not present"
},
_walk: function(visitor) {
- return visitor._visit(this, function(){
+ return visitor._visit(this, function() {
walk_body(this, visitor);
if (this.bcatch) this.bcatch._walk(visitor);
if (this.bfinally) this.bfinally._walk(visitor);
@@ -508,7 +506,7 @@ var AST_Catch = DEFNODE("Catch", "argname", {
argname: "[AST_SymbolCatch] symbol for the exception"
},
_walk: function(visitor) {
- return visitor._visit(this, function(){
+ return visitor._visit(this, function() {
this.argname._walk(visitor);
walk_body(this, visitor);
});
@@ -527,11 +525,10 @@ var AST_Definitions = DEFNODE("Definitions", "definitions", {
definitions: "[AST_VarDef*] array of variable definitions"
},
_walk: function(visitor) {
- return visitor._visit(this, function(){
- var definitions = this.definitions;
- for (var i = 0, len = definitions.length; i < len; i++) {
- definitions[i]._walk(visitor);
- }
+ return visitor._visit(this, function() {
+ this.definitions.forEach(function(defn) {
+ defn._walk(visitor);
+ });
});
}
}, AST_Statement);
@@ -547,7 +544,7 @@ var AST_VarDef = DEFNODE("VarDef", "name value", {
value: "[AST_Node?] initializer, or null of there's no initializer"
},
_walk: function(visitor) {
- return visitor._visit(this, function(){
+ return visitor._visit(this, function() {
this.name._walk(visitor);
if (this.value) this.value._walk(visitor);
});
@@ -582,7 +579,7 @@ var AST_Sequence = DEFNODE("Sequence", "expressions", {
expressions: "[AST_Node*] array of expressions (at least two)"
},
_walk: function(visitor) {
- return visitor._visit(this, function(){
+ return visitor._visit(this, function() {
this.expressions.forEach(function(node) {
node._walk(visitor);
});
@@ -601,7 +598,7 @@ var AST_PropAccess = DEFNODE("PropAccess", "expression property", {
var AST_Dot = DEFNODE("Dot", null, {
$documentation: "A dotted property access expression",
_walk: function(visitor) {
- return visitor._visit(this, function(){
+ return visitor._visit(this, function() {
this.expression._walk(visitor);
});
}
@@ -610,7 +607,7 @@ var AST_Dot = DEFNODE("Dot", null, {
var AST_Sub = DEFNODE("Sub", null, {
$documentation: "Index-style property access, i.e. `a[\"foo\"]`",
_walk: function(visitor) {
- return visitor._visit(this, function(){
+ return visitor._visit(this, function() {
this.expression._walk(visitor);
this.property._walk(visitor);
});
@@ -624,7 +621,7 @@ var AST_Unary = DEFNODE("Unary", "operator expression", {
expression: "[AST_Node] expression that this unary operator applies to"
},
_walk: function(visitor) {
- return visitor._visit(this, function(){
+ return visitor._visit(this, function() {
this.expression._walk(visitor);
});
}
@@ -646,7 +643,7 @@ var AST_Binary = DEFNODE("Binary", "operator left right", {
right: "[AST_Node] right-hand side expression"
},
_walk: function(visitor) {
- return visitor._visit(this, function(){
+ return visitor._visit(this, function() {
this.left._walk(visitor);
this.right._walk(visitor);
});
@@ -661,7 +658,7 @@ var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative",
alternative: "[AST_Node]"
},
_walk: function(visitor) {
- return visitor._visit(this, function(){
+ return visitor._visit(this, function() {
this.condition._walk(visitor);
this.consequent._walk(visitor);
this.alternative._walk(visitor);
@@ -681,11 +678,10 @@ var AST_Array = DEFNODE("Array", "elements", {
elements: "[AST_Node*] array of elements"
},
_walk: function(visitor) {
- return visitor._visit(this, function(){
- var elements = this.elements;
- for (var i = 0, len = elements.length; i < len; i++) {
- elements[i]._walk(visitor);
- }
+ return visitor._visit(this, function() {
+ this.elements.forEach(function(element) {
+ element._walk(visitor);
+ });
});
}
});
@@ -696,11 +692,10 @@ var AST_Object = DEFNODE("Object", "properties", {
properties: "[AST_ObjectProperty*] array of properties"
},
_walk: function(visitor) {
- return visitor._visit(this, function(){
- var properties = this.properties;
- for (var i = 0, len = properties.length; i < len; i++) {
- properties[i]._walk(visitor);
- }
+ return visitor._visit(this, function() {
+ this.properties.forEach(function(prop) {
+ prop._walk(visitor);
+ });
});
}
});
@@ -712,7 +707,7 @@ var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
value: "[AST_Node] property value. For getters and setters this is an AST_Accessor."
},
_walk: function(visitor) {
- return visitor._visit(this, function(){
+ return visitor._visit(this, function() {
this.value._walk(visitor);
});
}
@@ -839,12 +834,12 @@ var AST_NaN = DEFNODE("NaN", null, {
var AST_Undefined = DEFNODE("Undefined", null, {
$documentation: "The `undefined` value",
- value: (function(){}())
+ value: function(){}()
}, AST_Atom);
var AST_Hole = DEFNODE("Hole", null, {
$documentation: "A hole in an array",
- value: (function(){}())
+ value: function(){}()
}, AST_Atom);
var AST_Infinity = DEFNODE("Infinity", null, {
@@ -872,11 +867,11 @@ function TreeWalker(callback) {
this.visit = callback;
this.stack = [];
this.directives = Object.create(null);
-};
+}
TreeWalker.prototype = {
_visit: function(node, descend) {
this.push(node);
- var ret = this.visit(node, descend ? function(){
+ var ret = this.visit(node, descend ? function() {
descend.call(node);
} : noop);
if (!ret && descend) {
diff --git a/lib/compress.js b/lib/compress.js
index 1832f7a8..ad01e48c 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -136,7 +136,7 @@ function Compressor(options, false_by_default) {
var sequences = this.options["sequences"];
this.sequences_limit = sequences == 1 ? 800 : sequences | 0;
this.warnings_produced = {};
-};
+}
Compressor.prototype = new TreeTransformer;
merge(Compressor.prototype, {
@@ -201,11 +201,10 @@ merge(Compressor.prototype, {
},
before: function(node, descend, in_list) {
if (node._squeezed) return node;
- var was_scope = false;
- if (node instanceof AST_Scope) {
- node = node.hoist_properties(this);
- node = node.hoist_declarations(this);
- was_scope = true;
+ var is_scope = node instanceof AST_Scope;
+ if (is_scope) {
+ node.hoist_properties(this);
+ node.hoist_declarations(this);
}
// Before https://github.com/mishoo/UglifyJS2/pull/1602 AST_Node.optimize()
// would call AST_Node.transform() if a different instance of AST_Node is
@@ -220,7 +219,7 @@ merge(Compressor.prototype, {
// output and performance.
descend(node, this);
var opt = node.optimize(this);
- if (was_scope && opt instanceof AST_Scope) {
+ if (is_scope) {
opt.drop_unused(this);
descend(opt, this);
}
@@ -229,24 +228,12 @@ merge(Compressor.prototype, {
}
});
-(function(){
-
- function OPT(node, optimizer) {
- node.DEFMETHOD("optimize", function(compressor){
- var self = this;
- if (self._optimized) return self;
- if (compressor.has_directive("use asm")) return self;
- var opt = optimizer(self, compressor);
- opt._optimized = true;
- return opt;
- });
- };
-
- OPT(AST_Node, function(self, compressor){
+(function(OPT) {
+ OPT(AST_Node, function(self, compressor) {
return self;
});
- AST_Node.DEFMETHOD("equivalent_to", function(node){
+ AST_Node.DEFMETHOD("equivalent_to", function(node) {
return this.TYPE == node.TYPE && this.print_to_string() == node.print_to_string();
});
@@ -821,7 +808,7 @@ merge(Compressor.prototype, {
tw.in_loop = saved_loop;
return true;
});
- })(function(node, func){
+ })(function(node, func) {
node.DEFMETHOD("reduce_vars", func);
});
@@ -894,7 +881,7 @@ merge(Compressor.prototype, {
if (!props.end) props.end = orig.end;
}
return new ctor(props);
- };
+ }
function make_sequence(orig, expressions) {
if (expressions.length == 1) return expressions[0];
@@ -971,21 +958,21 @@ merge(Compressor.prototype, {
if (thing instanceof AST_EmptyStatement) return [];
if (thing instanceof AST_Statement) return [ thing ];
throw new Error("Can't convert thing to statement array");
- };
+ }
function is_empty(thing) {
if (thing === null) return true;
if (thing instanceof AST_EmptyStatement) return true;
if (thing instanceof AST_BlockStatement) return thing.body.length == 0;
return false;
- };
+ }
function loop_body(x) {
if (x instanceof AST_IterationStatement) {
return x.body instanceof AST_BlockStatement ? x.body : x;
}
return x;
- };
+ }
function root_expr(prop) {
while (prop instanceof AST_PropAccess) prop = prop.expression;
@@ -1406,7 +1393,10 @@ merge(Compressor.prototype, {
}
} else if (expr instanceof AST_VarDef) {
if (expr.value) {
- candidates.push(hit_stack.slice());
+ var def = expr.name.definition();
+ if (def.references.length > def.replaced) {
+ candidates.push(hit_stack.slice());
+ }
extract_candidates(expr.value);
}
}
@@ -1476,7 +1466,6 @@ merge(Compressor.prototype, {
var def = expr.name.definition();
if (!member(expr.name, def.orig)) return;
var referenced = def.references.length - def.replaced;
- if (!referenced) return;
var declared = def.orig.length - def.eliminated;
if (declared > 1 && !(expr.name instanceof AST_SymbolFunarg)
|| (referenced > 1 ? mangleable_var(expr) : !compressor.exposed(def))) {
@@ -1947,7 +1936,7 @@ merge(Compressor.prototype, {
CHANGED = true;
var left = prev.body;
return make_sequence(left, [ left, right ]).transform(compressor);
- };
+ }
var n = 0, prev;
for (var i = 0; i < statements.length; i++) {
var stat = statements[i];
@@ -2149,7 +2138,7 @@ merge(Compressor.prototype, {
if (!(stat instanceof AST_Defun)) {
compressor.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start);
}
- stat.walk(new TreeWalker(function(node){
+ stat.walk(new TreeWalker(function(node) {
if (node instanceof AST_Definitions) {
compressor.warn("Declarations in unreachable code! [{file}:{line},{col}]", node.start);
node.remove_initializers();
@@ -2164,7 +2153,7 @@ merge(Compressor.prototype, {
return true;
}
}));
- };
+ }
function get_value(key) {
if (key instanceof AST_Constant) {
@@ -2272,83 +2261,83 @@ merge(Compressor.prototype, {
/* -----[ boolean/negation helpers ]----- */
// methods to determine whether an expression has a boolean result type
- (function(def){
+ (function(def) {
var unary_bool = makePredicate("! delete");
var binary_bool = makePredicate("in instanceof == != === !== < <= >= >");
def(AST_Node, return_false);
- def(AST_UnaryPrefix, function(){
+ def(AST_UnaryPrefix, function() {
return unary_bool[this.operator];
});
- def(AST_Binary, function(){
+ def(AST_Binary, function() {
return binary_bool[this.operator]
|| lazy_op[this.operator]
&& this.left.is_boolean()
&& this.right.is_boolean();
});
- def(AST_Conditional, function(){
+ def(AST_Conditional, function() {
return this.consequent.is_boolean() && this.alternative.is_boolean();
});
- def(AST_Assign, function(){
+ def(AST_Assign, function() {
return this.operator == "=" && this.right.is_boolean();
});
- def(AST_Sequence, function(){
+ def(AST_Sequence, function() {
return this.tail_node().is_boolean();
});
def(AST_True, return_true);
def(AST_False, return_true);
- })(function(node, func){
+ })(function(node, func) {
node.DEFMETHOD("is_boolean", func);
});
// methods to determine if an expression has a numeric result type
- (function(def){
+ (function(def) {
def(AST_Node, return_false);
def(AST_Number, return_true);
var unary = makePredicate("+ - ~ ++ --");
- def(AST_Unary, function(){
+ def(AST_Unary, function() {
return unary[this.operator];
});
var binary = makePredicate("- * / % & | ^ << >> >>>");
- def(AST_Binary, function(compressor){
+ def(AST_Binary, function(compressor) {
return binary[this.operator] || this.operator == "+"
&& this.left.is_number(compressor)
&& this.right.is_number(compressor);
});
- def(AST_Assign, function(compressor){
+ def(AST_Assign, function(compressor) {
return binary[this.operator.slice(0, -1)]
|| this.operator == "=" && this.right.is_number(compressor);
});
- def(AST_Sequence, function(compressor){
+ def(AST_Sequence, function(compressor) {
return this.tail_node().is_number(compressor);
});
- def(AST_Conditional, function(compressor){
+ def(AST_Conditional, function(compressor) {
return this.consequent.is_number(compressor) && this.alternative.is_number(compressor);
});
- })(function(node, func){
+ })(function(node, func) {
node.DEFMETHOD("is_number", func);
});
// methods to determine if an expression has a string result type
- (function(def){
+ (function(def) {
def(AST_Node, return_false);
def(AST_String, return_true);
- def(AST_UnaryPrefix, function(){
+ def(AST_UnaryPrefix, function() {
return this.operator == "typeof";
});
- def(AST_Binary, function(compressor){
+ def(AST_Binary, function(compressor) {
return this.operator == "+" &&
(this.left.is_string(compressor) || this.right.is_string(compressor));
});
- def(AST_Assign, function(compressor){
+ def(AST_Assign, function(compressor) {
return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor);
});
- def(AST_Sequence, function(compressor){
+ def(AST_Sequence, function(compressor) {
return this.tail_node().is_string(compressor);
});
- def(AST_Conditional, function(compressor){
+ def(AST_Conditional, function(compressor) {
return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);
});
- })(function(node, func){
+ })(function(node, func) {
node.DEFMETHOD("is_string", func);
});
@@ -2360,7 +2349,7 @@ merge(Compressor.prototype, {
if (parent instanceof AST_Assign && parent.left === node) return node;
}
- (function(def){
+ (function(def) {
AST_Node.DEFMETHOD("resolve_defines", function(compressor) {
if (!compressor.option("global_defs")) return;
var def = this._find_defs(compressor, "");
@@ -2399,10 +2388,10 @@ merge(Compressor.prototype, {
return make_node_from_constant(value, orig);
}
def(AST_Node, noop);
- def(AST_Dot, function(compressor, suffix){
+ def(AST_Dot, function(compressor, suffix) {
return this.expression._find_defs(compressor, "." + this.property + suffix);
});
- def(AST_SymbolRef, function(compressor, suffix){
+ def(AST_SymbolRef, function(compressor, suffix) {
if (!this.global()) return;
var name;
var defines = compressor.option("global_defs");
@@ -2418,7 +2407,7 @@ merge(Compressor.prototype, {
return node;
}
});
- })(function(node, func){
+ })(function(node, func) {
node.DEFMETHOD("_find_defs", func);
});
@@ -2533,13 +2522,13 @@ merge(Compressor.prototype, {
convert_to_predicate(static_fns);
// methods to evaluate a constant expression
- (function(def){
+ (function(def) {
// If the node has been successfully reduced to a constant,
// then its value is returned; otherwise the element itself
// is returned.
// They can be distinguished as constant value is never a
// descendant of AST_Node.
- AST_Node.DEFMETHOD("evaluate", function(compressor){
+ AST_Node.DEFMETHOD("evaluate", function(compressor) {
if (!compressor.option("evaluate")) return this;
var cached = [];
var val = this._eval(compressor, cached, 1);
@@ -2551,7 +2540,7 @@ merge(Compressor.prototype, {
return val;
});
var unaryPrefix = makePredicate("! ~ - + void");
- AST_Node.DEFMETHOD("is_constant", function(){
+ AST_Node.DEFMETHOD("is_constant", function() {
// Accomodate when compress option evaluate=false
// as well as the common constant expressions !0 and -1
if (this instanceof AST_Constant) {
@@ -2562,12 +2551,12 @@ merge(Compressor.prototype, {
&& unaryPrefix[this.operator];
}
});
- def(AST_Statement, function(){
+ def(AST_Statement, function() {
throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
});
def(AST_Lambda, return_this);
def(AST_Node, return_this);
- def(AST_Constant, function(){
+ def(AST_Constant, function() {
return this.getValue();
});
def(AST_Function, function(compressor) {
@@ -2811,12 +2800,12 @@ merge(Compressor.prototype, {
return this;
});
def(AST_New, return_this);
- })(function(node, func){
+ })(function(node, func) {
node.DEFMETHOD("_eval", func);
});
// method to negate an expression
- (function(def){
+ (function(def) {
function basic_negation(exp) {
return make_node(AST_UnaryPrefix, exp, {
operator: "!",
@@ -2833,32 +2822,32 @@ merge(Compressor.prototype, {
}
return best_of_expression(negated, alt);
}
- def(AST_Node, function(){
+ def(AST_Node, function() {
return basic_negation(this);
});
- def(AST_Statement, function(){
+ def(AST_Statement, function() {
throw new Error("Cannot negate a statement");
});
- def(AST_Function, function(){
+ def(AST_Function, function() {
return basic_negation(this);
});
- def(AST_UnaryPrefix, function(){
+ def(AST_UnaryPrefix, function() {
if (this.operator == "!")
return this.expression;
return basic_negation(this);
});
- def(AST_Sequence, function(compressor){
+ def(AST_Sequence, function(compressor) {
var expressions = this.expressions.slice();
expressions.push(expressions.pop().negate(compressor));
return make_sequence(this, expressions);
});
- def(AST_Conditional, function(compressor, first_in_statement){
+ def(AST_Conditional, function(compressor, first_in_statement) {
var self = this.clone();
self.consequent = self.consequent.negate(compressor);
self.alternative = self.alternative.negate(compressor);
return best(this, self, first_in_statement);
});
- def(AST_Binary, function(compressor, first_in_statement){
+ def(AST_Binary, function(compressor, first_in_statement) {
var self = this.clone(), op = this.operator;
if (compressor.option("unsafe_comps")) {
switch (op) {
@@ -2886,8 +2875,8 @@ merge(Compressor.prototype, {
}
return basic_negation(this);
});
- })(function(node, func){
- node.DEFMETHOD("negate", function(compressor, first_in_statement){
+ })(function(node, func) {
+ node.DEFMETHOD("negate", function(compressor, first_in_statement) {
return func.call(this, compressor, first_in_statement);
});
});
@@ -2926,7 +2915,7 @@ merge(Compressor.prototype, {
});
// determine if expression has side effects
- (function(def){
+ (function(def) {
def(AST_Node, return_true);
def(AST_EmptyStatement, return_false);
@@ -2940,10 +2929,10 @@ merge(Compressor.prototype, {
return false;
}
- def(AST_Block, function(compressor){
+ def(AST_Block, function(compressor) {
return any(this.body, compressor);
});
- def(AST_Call, function(compressor){
+ def(AST_Call, function(compressor) {
if (!this.is_expr_pure(compressor)
&& (!this.expression.is_call_pure(compressor)
|| this.expression.has_side_effects(compressor))) {
@@ -2951,82 +2940,82 @@ merge(Compressor.prototype, {
}
return any(this.args, compressor);
});
- def(AST_Switch, function(compressor){
+ def(AST_Switch, function(compressor) {
return this.expression.has_side_effects(compressor)
|| any(this.body, compressor);
});
- def(AST_Case, function(compressor){
+ def(AST_Case, function(compressor) {
return this.expression.has_side_effects(compressor)
|| any(this.body, compressor);
});
- def(AST_Try, function(compressor){
+ def(AST_Try, function(compressor) {
return any(this.body, compressor)
|| this.bcatch && this.bcatch.has_side_effects(compressor)
|| this.bfinally && this.bfinally.has_side_effects(compressor);
});
- def(AST_If, function(compressor){
+ def(AST_If, function(compressor) {
return this.condition.has_side_effects(compressor)
|| this.body && this.body.has_side_effects(compressor)
|| this.alternative && this.alternative.has_side_effects(compressor);
});
- def(AST_LabeledStatement, function(compressor){
+ def(AST_LabeledStatement, function(compressor) {
return this.body.has_side_effects(compressor);
});
- def(AST_SimpleStatement, function(compressor){
+ def(AST_SimpleStatement, function(compressor) {
return this.body.has_side_effects(compressor);
});
def(AST_Lambda, return_false);
- def(AST_Binary, function(compressor){
+ def(AST_Binary, function(compressor) {
return this.left.has_side_effects(compressor)
|| this.right.has_side_effects(compressor);
});
def(AST_Assign, return_true);
- def(AST_Conditional, function(compressor){
+ def(AST_Conditional, function(compressor) {
return this.condition.has_side_effects(compressor)
|| this.consequent.has_side_effects(compressor)
|| this.alternative.has_side_effects(compressor);
});
- def(AST_Unary, function(compressor){
+ def(AST_Unary, function(compressor) {
return unary_side_effects[this.operator]
|| this.expression.has_side_effects(compressor);
});
- def(AST_SymbolRef, function(compressor){
+ def(AST_SymbolRef, function(compressor) {
return !this.is_declared(compressor);
});
def(AST_SymbolDeclaration, return_false);
- def(AST_Object, function(compressor){
+ def(AST_Object, function(compressor) {
return any(this.properties, compressor);
});
- def(AST_ObjectProperty, function(compressor){
+ def(AST_ObjectProperty, function(compressor) {
return this.value.has_side_effects(compressor);
});
- def(AST_Array, function(compressor){
+ def(AST_Array, function(compressor) {
return any(this.elements, compressor);
});
- def(AST_Dot, function(compressor){
+ def(AST_Dot, function(compressor) {
return this.expression.may_throw_on_access(compressor)
|| this.expression.has_side_effects(compressor);
});
- def(AST_Sub, function(compressor){
+ def(AST_Sub, function(compressor) {
return this.expression.may_throw_on_access(compressor)
|| this.expression.has_side_effects(compressor)
|| this.property.has_side_effects(compressor);
});
- def(AST_Sequence, function(compressor){
+ def(AST_Sequence, function(compressor) {
return any(this.expressions, compressor);
});
- def(AST_Definitions, function(compressor){
+ def(AST_Definitions, function(compressor) {
return any(this.definitions, compressor);
});
- def(AST_VarDef, function(compressor){
+ def(AST_VarDef, function(compressor) {
return this.value;
});
- })(function(node, func){
+ })(function(node, func) {
node.DEFMETHOD("has_side_effects", func);
});
// determine if expression may throw
- (function(def){
+ (function(def) {
def(AST_Node, return_true);
def(AST_Constant, return_false);
@@ -3042,10 +3031,10 @@ merge(Compressor.prototype, {
return false;
}
- def(AST_Array, function(compressor){
+ def(AST_Array, function(compressor) {
return any(this.elements, compressor);
});
- def(AST_Assign, function(compressor){
+ def(AST_Assign, function(compressor) {
if (this.right.may_throw(compressor)) return true;
if (!compressor.has_directive("use strict")
&& this.operator == "="
@@ -3054,90 +3043,90 @@ merge(Compressor.prototype, {
}
return this.left.may_throw(compressor);
});
- def(AST_Binary, function(compressor){
+ def(AST_Binary, function(compressor) {
return this.left.may_throw(compressor)
|| this.right.may_throw(compressor);
});
- def(AST_Block, function(compressor){
+ def(AST_Block, function(compressor) {
return any(this.body, compressor);
});
- def(AST_Call, function(compressor){
+ def(AST_Call, function(compressor) {
if (any(this.args, compressor)) return true;
if (this.is_expr_pure(compressor)) return false;
if (this.expression.may_throw(compressor)) return true;
return !(this.expression instanceof AST_Lambda)
|| any(this.expression.body, compressor);
});
- def(AST_Case, function(compressor){
+ def(AST_Case, function(compressor) {
return this.expression.may_throw(compressor)
|| any(this.body, compressor);
});
- def(AST_Conditional, function(compressor){
+ def(AST_Conditional, function(compressor) {
return this.condition.may_throw(compressor)
|| this.consequent.may_throw(compressor)
|| this.alternative.may_throw(compressor);
});
- def(AST_Definitions, function(compressor){
+ def(AST_Definitions, function(compressor) {
return any(this.definitions, compressor);
});
- def(AST_Dot, function(compressor){
+ def(AST_Dot, function(compressor) {
return this.expression.may_throw_on_access(compressor)
|| this.expression.may_throw(compressor);
});
- def(AST_If, function(compressor){
+ def(AST_If, function(compressor) {
return this.condition.may_throw(compressor)
|| this.body && this.body.may_throw(compressor)
|| this.alternative && this.alternative.may_throw(compressor);
});
- def(AST_LabeledStatement, function(compressor){
+ def(AST_LabeledStatement, function(compressor) {
return this.body.may_throw(compressor);
});
- def(AST_Object, function(compressor){
+ def(AST_Object, function(compressor) {
return any(this.properties, compressor);
});
- def(AST_ObjectProperty, function(compressor){
+ def(AST_ObjectProperty, function(compressor) {
return this.value.may_throw(compressor);
});
- def(AST_Return, function(compressor){
+ def(AST_Return, function(compressor) {
return this.value && this.value.may_throw(compressor);
});
- def(AST_Sequence, function(compressor){
+ def(AST_Sequence, function(compressor) {
return any(this.expressions, compressor);
});
- def(AST_SimpleStatement, function(compressor){
+ def(AST_SimpleStatement, function(compressor) {
return this.body.may_throw(compressor);
});
- def(AST_Sub, function(compressor){
+ def(AST_Sub, function(compressor) {
return this.expression.may_throw_on_access(compressor)
|| this.expression.may_throw(compressor)
|| this.property.may_throw(compressor);
});
- def(AST_Switch, function(compressor){
+ def(AST_Switch, function(compressor) {
return this.expression.may_throw(compressor)
|| any(this.body, compressor);
});
- def(AST_SymbolRef, function(compressor){
+ def(AST_SymbolRef, function(compressor) {
return !this.is_declared(compressor);
});
- def(AST_Try, function(compressor){
+ def(AST_Try, function(compressor) {
return this.bcatch ? this.bcatch.may_throw(compressor) : any(this.body, compressor)
|| this.bfinally && this.bfinally.may_throw(compressor);
});
- def(AST_Unary, function(compressor){
+ def(AST_Unary, function(compressor) {
if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef)
return false;
return this.expression.may_throw(compressor);
});
- def(AST_VarDef, function(compressor){
+ def(AST_VarDef, function(compressor) {
if (!this.value) return false;
return this.value.may_throw(compressor);
});
- })(function(node, func){
+ })(function(node, func) {
node.DEFMETHOD("may_throw", func);
});
// determine if expression is constant
- (function(def){
+ (function(def) {
function all(list) {
for (var i = list.length; --i >= 0;)
if (!list[i].is_constant_expression())
@@ -3146,7 +3135,7 @@ merge(Compressor.prototype, {
}
def(AST_Node, return_false);
def(AST_Constant, return_true);
- def(AST_Lambda, function(scope){
+ def(AST_Lambda, function(scope) {
var self = this;
var result = true;
self.walk(new TreeWalker(function(node) {
@@ -3173,61 +3162,61 @@ merge(Compressor.prototype, {
}));
return result;
});
- def(AST_Unary, function(){
+ def(AST_Unary, function() {
return this.expression.is_constant_expression();
});
- def(AST_Binary, function(){
+ def(AST_Binary, function() {
return this.left.is_constant_expression() && this.right.is_constant_expression();
});
- def(AST_Array, function(){
+ def(AST_Array, function() {
return all(this.elements);
});
- def(AST_Object, function(){
+ def(AST_Object, function() {
return all(this.properties);
});
- def(AST_ObjectProperty, function(){
+ def(AST_ObjectProperty, function() {
return this.value.is_constant_expression();
});
- })(function(node, func){
+ })(function(node, func) {
node.DEFMETHOD("is_constant_expression", func);
});
// tell me if a statement aborts
function aborts(thing) {
return thing && thing.aborts();
- };
- (function(def){
+ }
+ (function(def) {
def(AST_Statement, return_null);
def(AST_Jump, return_this);
- function block_aborts(){
+ function block_aborts() {
var n = this.body.length;
return n > 0 && aborts(this.body[n - 1]);
- };
+ }
def(AST_BlockStatement, block_aborts);
def(AST_SwitchBranch, block_aborts);
- def(AST_If, function(){
+ def(AST_If, function() {
return this.alternative && aborts(this.body) && aborts(this.alternative) && this;
});
- })(function(node, func){
+ })(function(node, func) {
node.DEFMETHOD("aborts", func);
});
/* -----[ optimizers ]----- */
- OPT(AST_Directive, function(self, compressor){
+ OPT(AST_Directive, function(self, compressor) {
if (compressor.has_directive(self.value) !== self) {
return make_node(AST_EmptyStatement, self);
}
return self;
});
- OPT(AST_Debugger, function(self, compressor){
+ OPT(AST_Debugger, function(self, compressor) {
if (compressor.option("drop_debugger"))
return make_node(AST_EmptyStatement, self);
return self;
});
- OPT(AST_LabeledStatement, function(self, compressor){
+ OPT(AST_LabeledStatement, function(self, compressor) {
if (self.body instanceof AST_Break
&& compressor.loopcontrol_target(self.body) === self.body) {
return make_node(AST_EmptyStatement, self);
@@ -3235,12 +3224,12 @@ merge(Compressor.prototype, {
return self.label.references.length == 0 ? self.body : self;
});
- OPT(AST_Block, function(self, compressor){
+ OPT(AST_Block, function(self, compressor) {
tighten_body(self.body, compressor);
return self;
});
- OPT(AST_BlockStatement, function(self, compressor){
+ OPT(AST_BlockStatement, function(self, compressor) {
tighten_body(self.body, compressor);
switch (self.body.length) {
case 1: return self.body[0];
@@ -3249,7 +3238,7 @@ merge(Compressor.prototype, {
return self;
});
- OPT(AST_Lambda, function(self, compressor){
+ OPT(AST_Lambda, function(self, compressor) {
tighten_body(self.body, compressor);
if (compressor.option("side_effects")
&& self.body.length == 1
@@ -3259,7 +3248,7 @@ merge(Compressor.prototype, {
return self;
});
- AST_Scope.DEFMETHOD("drop_unused", function(compressor){
+ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
if (!compressor.option("unused")) return;
if (compressor.has_directive("use asm")) return;
var self = this;
@@ -3299,7 +3288,7 @@ merge(Compressor.prototype, {
// pass 1: find out which symbols are directly used in
// this scope (not in nested scopes).
var scope = this;
- var tw = new TreeWalker(function(node, descend){
+ var tw = new TreeWalker(function(node, descend) {
if (node === self) return;
if (node instanceof AST_Defun) {
var node_def = node.name.definition();
@@ -3316,7 +3305,7 @@ merge(Compressor.prototype, {
var_defs_by_id.add(node.definition().id, node);
}
if (node instanceof AST_Definitions && scope === self) {
- node.definitions.forEach(function(def){
+ node.definitions.forEach(function(def) {
var node_def = def.name.definition();
if (def.name instanceof AST_SymbolVar) {
var_defs_by_id.add(node_def.id, def);
@@ -3607,135 +3596,128 @@ merge(Compressor.prototype, {
}
});
- AST_Scope.DEFMETHOD("hoist_declarations", function(compressor){
- var self = this;
- if (compressor.has_directive("use asm")) return self;
+ AST_Scope.DEFMETHOD("hoist_declarations", function(compressor) {
+ if (compressor.has_directive("use asm")) return;
var hoist_funs = compressor.option("hoist_funs");
var hoist_vars = compressor.option("hoist_vars");
- if (hoist_funs || hoist_vars) {
- var dirs = [];
- var hoisted = [];
- var vars = new Dictionary(), vars_found = 0, var_decl = 0;
+ var self = this;
+ if (hoist_vars) {
// let's count var_decl first, we seem to waste a lot of
// space if we hoist `var` when there's only one.
- self.walk(new TreeWalker(function(node){
- if (node instanceof AST_Scope && node !== self)
- return true;
+ var var_decl = 0;
+ self.walk(new TreeWalker(function(node) {
+ if (var_decl > 1) return true;
+ if (node instanceof AST_Scope && node !== self) return true;
if (node instanceof AST_Var) {
- ++var_decl;
+ var_decl++;
return true;
}
}));
- hoist_vars = hoist_vars && var_decl > 1;
- var tt = new TreeTransformer(
- function before(node) {
- if (node !== self) {
- if (node instanceof AST_Directive) {
- dirs.push(node);
- return make_node(AST_EmptyStatement, node);
- }
- if (hoist_funs && node instanceof AST_Defun
- && (tt.parent() === self || !compressor.has_directive("use strict"))) {
- hoisted.push(node);
- return make_node(AST_EmptyStatement, node);
- }
- if (hoist_vars && node instanceof AST_Var) {
- node.definitions.forEach(function(def){
- vars.set(def.name.name, def);
- ++vars_found;
- });
- var seq = node.to_assignments(compressor);
- var p = tt.parent();
- if (p instanceof AST_ForIn && p.init === node) {
- if (seq == null) {
- var def = node.definitions[0].name;
- return make_node(AST_SymbolRef, def, def);
- }
- return seq;
- }
- if (p instanceof AST_For && p.init === node) {
- return seq;
- }
- if (!seq) return make_node(AST_EmptyStatement, node);
- return make_node(AST_SimpleStatement, node, {
- body: seq
- });
- }
- if (node instanceof AST_Scope)
- return node; // to avoid descending in nested scopes
- }
- }
- );
- self = self.transform(tt);
- if (vars_found > 0) {
- // collect only vars which don't show up in self's arguments list
- var defs = [];
- vars.each(function(def, name){
- if (self instanceof AST_Lambda
- && !all(self.argnames, function(argname) {
- return argname.name != name;
- })) {
- vars.del(name);
- } else {
- def = def.clone();
- def.value = null;
- defs.push(def);
- vars.set(name, def);
- }
+ if (var_decl <= 1) hoist_vars = false;
+ }
+ if (!hoist_funs && !hoist_vars) return;
+ var dirs = [];
+ var hoisted = [];
+ var vars = new Dictionary(), vars_found = 0;
+ var tt = new TreeTransformer(function(node) {
+ if (node === self) return;
+ if (node instanceof AST_Directive) {
+ dirs.push(node);
+ return make_node(AST_EmptyStatement, node);
+ }
+ if (hoist_funs && node instanceof AST_Defun
+ && (tt.parent() === self || !compressor.has_directive("use strict"))) {
+ hoisted.push(node);
+ return make_node(AST_EmptyStatement, node);
+ }
+ if (hoist_vars && node instanceof AST_Var) {
+ node.definitions.forEach(function(def) {
+ vars.set(def.name.name, def);
+ ++vars_found;
});
- if (defs.length > 0) {
- // try to merge in assignments
- for (var i = 0; i < self.body.length;) {
- if (self.body[i] instanceof AST_SimpleStatement) {
- var expr = self.body[i].body, sym, assign;
- if (expr instanceof AST_Assign
- && expr.operator == "="
- && (sym = expr.left) instanceof AST_Symbol
- && vars.has(sym.name))
- {
- var def = vars.get(sym.name);
- if (def.value) break;
- def.value = expr.right;
- remove(defs, def);
- defs.push(def);
- self.body.splice(i, 1);
- continue;
- }
- if (expr instanceof AST_Sequence
- && (assign = expr.expressions[0]) instanceof AST_Assign
- && assign.operator == "="
- && (sym = assign.left) instanceof AST_Symbol
- && vars.has(sym.name))
- {
- var def = vars.get(sym.name);
- if (def.value) break;
- def.value = assign.right;
- remove(defs, def);
- defs.push(def);
- self.body[i].body = make_sequence(expr, expr.expressions.slice(1));
- continue;
- }
- }
- if (self.body[i] instanceof AST_EmptyStatement) {
+ var seq = node.to_assignments(compressor);
+ var p = tt.parent();
+ if (p instanceof AST_ForIn && p.init === node) {
+ if (seq) return seq;
+ var def = node.definitions[0].name;
+ return make_node(AST_SymbolRef, def, def);
+ }
+ if (p instanceof AST_For && p.init === node) return seq;
+ if (!seq) return make_node(AST_EmptyStatement, node);
+ return make_node(AST_SimpleStatement, node, {
+ body: seq
+ });
+ }
+ if (node instanceof AST_Scope) return node;
+ });
+ self.transform(tt);
+ if (vars_found > 0) {
+ // collect only vars which don't show up in self's arguments list
+ var defs = [];
+ vars.each(function(def, name) {
+ if (self instanceof AST_Lambda
+ && !all(self.argnames, function(argname) {
+ return argname.name != name;
+ })) {
+ vars.del(name);
+ } else {
+ def = def.clone();
+ def.value = null;
+ defs.push(def);
+ vars.set(name, def);
+ }
+ });
+ if (defs.length > 0) {
+ // try to merge in assignments
+ for (var i = 0; i < self.body.length;) {
+ if (self.body[i] instanceof AST_SimpleStatement) {
+ var expr = self.body[i].body, sym, assign;
+ if (expr instanceof AST_Assign
+ && expr.operator == "="
+ && (sym = expr.left) instanceof AST_Symbol
+ && vars.has(sym.name))
+ {
+ var def = vars.get(sym.name);
+ if (def.value) break;
+ def.value = expr.right;
+ remove(defs, def);
+ defs.push(def);
self.body.splice(i, 1);
continue;
}
- if (self.body[i] instanceof AST_BlockStatement) {
- var tmp = [ i, 1 ].concat(self.body[i].body);
- self.body.splice.apply(self.body, tmp);
+ if (expr instanceof AST_Sequence
+ && (assign = expr.expressions[0]) instanceof AST_Assign
+ && assign.operator == "="
+ && (sym = assign.left) instanceof AST_Symbol
+ && vars.has(sym.name))
+ {
+ var def = vars.get(sym.name);
+ if (def.value) break;
+ def.value = assign.right;
+ remove(defs, def);
+ defs.push(def);
+ self.body[i].body = make_sequence(expr, expr.expressions.slice(1));
continue;
}
- break;
}
- defs = make_node(AST_Var, self, {
- definitions: defs
- });
- hoisted.push(defs);
- };
+ if (self.body[i] instanceof AST_EmptyStatement) {
+ self.body.splice(i, 1);
+ continue;
+ }
+ if (self.body[i] instanceof AST_BlockStatement) {
+ var tmp = [ i, 1 ].concat(self.body[i].body);
+ self.body.splice.apply(self.body, tmp);
+ continue;
+ }
+ break;
+ }
+ defs = make_node(AST_Var, self, {
+ definitions: defs
+ });
+ hoisted.push(defs);
}
- self.body = dirs.concat(hoisted, self.body);
}
- return self;
+ self.body = dirs.concat(hoisted, self.body);
});
AST_Scope.DEFMETHOD("var_names", function() {
@@ -3761,12 +3743,12 @@ merge(Compressor.prototype, {
return name;
});
- AST_Scope.DEFMETHOD("hoist_properties", function(compressor){
+ AST_Scope.DEFMETHOD("hoist_properties", function(compressor) {
+ if (!compressor.option("hoist_props") || compressor.has_directive("use asm")) return;
var self = this;
- if (!compressor.option("hoist_props") || compressor.has_directive("use asm")) return self;
var top_retain = self instanceof AST_Toplevel && compressor.top_retain || return_false;
var defs_by_id = Object.create(null);
- return self.transform(new TreeTransformer(function(node, descend) {
+ self.transform(new TreeTransformer(function(node, descend) {
if (node instanceof AST_Assign
&& node.operator == "="
&& node.write_only
@@ -3832,6 +3814,7 @@ merge(Compressor.prototype, {
if (def.assignments != count) return;
if (def.direct_access) return;
if (def.escaped == 1) return;
+ if (def.references.length == count) return;
if (def.single_use) return;
if (top_retain(def)) return;
if (sym.fixed_value() !== right) return;
@@ -3853,7 +3836,7 @@ merge(Compressor.prototype, {
// drop_side_effect_free()
// remove side-effect-free parts which only affects return value
- (function(def){
+ (function(def) {
// Drop side-effect-free elements from an array of expressions.
// Returns an array of expressions with side-effects or null
// if all elements were dropped. Note: original array may be
@@ -3876,7 +3859,7 @@ merge(Compressor.prototype, {
def(AST_Node, return_this);
def(AST_Constant, return_null);
def(AST_This, return_null);
- def(AST_Call, function(compressor, first_in_statement){
+ def(AST_Call, function(compressor, first_in_statement) {
if (!this.is_expr_pure(compressor)) {
if (this.expression.is_call_pure(compressor)) {
var exprs = this.args.slice();
@@ -3908,7 +3891,7 @@ merge(Compressor.prototype, {
});
def(AST_Accessor, return_null);
def(AST_Function, return_null);
- def(AST_Binary, function(compressor, first_in_statement){
+ def(AST_Binary, function(compressor, first_in_statement) {
var right = this.right.drop_side_effect_free(compressor);
if (!right) return this.left.drop_side_effect_free(compressor, first_in_statement);
if (lazy_op[this.operator]) {
@@ -3922,7 +3905,7 @@ merge(Compressor.prototype, {
return make_sequence(this, [ left, right ]);
}
});
- def(AST_Assign, function(compressor){
+ def(AST_Assign, function(compressor) {
var left = this.left;
if (left.has_side_effects(compressor)
|| compressor.has_directive("use strict")
@@ -3936,7 +3919,7 @@ merge(Compressor.prototype, {
}
return this;
});
- def(AST_Conditional, function(compressor){
+ def(AST_Conditional, function(compressor) {
var consequent = this.consequent.drop_side_effect_free(compressor);
var alternative = this.alternative.drop_side_effect_free(compressor);
if (consequent === this.consequent && alternative === this.alternative) return this;
@@ -3955,7 +3938,7 @@ merge(Compressor.prototype, {
node.alternative = alternative;
return node;
});
- def(AST_Unary, function(compressor, first_in_statement){
+ def(AST_Unary, function(compressor, first_in_statement) {
if (unary_side_effects[this.operator]) {
this.write_only = !this.expression.has_side_effects(compressor);
return this;
@@ -3971,22 +3954,22 @@ merge(Compressor.prototype, {
def(AST_SymbolRef, function(compressor) {
return this.is_declared(compressor) ? null : this;
});
- def(AST_Object, function(compressor, first_in_statement){
+ def(AST_Object, function(compressor, first_in_statement) {
var values = trim(this.properties, compressor, first_in_statement);
return values && make_sequence(this, values);
});
- def(AST_ObjectProperty, function(compressor, first_in_statement){
+ def(AST_ObjectProperty, function(compressor, first_in_statement) {
return this.value.drop_side_effect_free(compressor, first_in_statement);
});
- def(AST_Array, function(compressor, first_in_statement){
+ def(AST_Array, function(compressor, first_in_statement) {
var values = trim(this.elements, compressor, first_in_statement);
return values && make_sequence(this, values);
});
- def(AST_Dot, function(compressor, first_in_statement){
+ def(AST_Dot, function(compressor, first_in_statement) {
if (this.expression.may_throw_on_access(compressor)) return this;
return this.expression.drop_side_effect_free(compressor, first_in_statement);
});
- def(AST_Sub, function(compressor, first_in_statement){
+ def(AST_Sub, function(compressor, first_in_statement) {
if (this.expression.may_throw_on_access(compressor)) return this;
var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
if (!expression) return this.property.drop_side_effect_free(compressor, first_in_statement);
@@ -3994,7 +3977,7 @@ merge(Compressor.prototype, {
if (!property) return expression;
return make_sequence(this, [ expression, property ]);
});
- def(AST_Sequence, function(compressor){
+ def(AST_Sequence, function(compressor) {
var last = this.tail_node();
var expr = last.drop_side_effect_free(compressor);
if (expr === last) return this;
@@ -4002,11 +3985,11 @@ merge(Compressor.prototype, {
if (expr) expressions.push(expr);
return make_sequence(this, expressions);
});
- })(function(node, func){
+ })(function(node, func) {
node.DEFMETHOD("drop_side_effect_free", func);
});
- OPT(AST_SimpleStatement, function(self, compressor){
+ OPT(AST_SimpleStatement, function(self, compressor) {
if (compressor.option("side_effects")) {
var body = self.body;
var node = body.drop_side_effect_free(compressor, true);
@@ -4021,7 +4004,7 @@ merge(Compressor.prototype, {
return self;
});
- OPT(AST_While, function(self, compressor){
+ OPT(AST_While, function(self, compressor) {
return compressor.option("loops") ? make_node(AST_For, self, self).optimize(compressor) : self;
});
@@ -4039,7 +4022,7 @@ merge(Compressor.prototype, {
return found;
}
- OPT(AST_Do, function(self, compressor){
+ OPT(AST_Do, function(self, compressor) {
if (!compressor.option("loops")) return self;
var cond = self.condition.is_truthy() || self.condition.tail_node().evaluate(compressor);
if (!(cond instanceof AST_Node)) {
@@ -4142,7 +4125,7 @@ merge(Compressor.prototype, {
}
}
- OPT(AST_For, function(self, compressor){
+ OPT(AST_For, function(self, compressor) {
if (!compressor.option("loops")) return self;
if (compressor.option("side_effects") && self.init) {
self.init = self.init.drop_side_effect_free(compressor);
@@ -4191,7 +4174,7 @@ merge(Compressor.prototype, {
return if_break_in_loop(self, compressor);
});
- OPT(AST_If, function(self, compressor){
+ OPT(AST_If, function(self, compressor) {
if (is_empty(self.alternative)) self.alternative = null;
if (!compressor.option("conditionals")) return self;
@@ -4337,7 +4320,7 @@ merge(Compressor.prototype, {
return self;
});
- OPT(AST_Switch, function(self, compressor){
+ OPT(AST_Switch, function(self, compressor) {
if (!compressor.option("switches")) return self;
var branch;
var value = self.expression.evaluate(compressor);
@@ -4443,7 +4426,7 @@ merge(Compressor.prototype, {
}
});
- OPT(AST_Try, function(self, compressor){
+ OPT(AST_Try, function(self, compressor) {
tighten_body(self.body, compressor);
if (self.bcatch && self.bfinally && all(self.bfinally.body, is_empty)) self.bfinally = null;
if (compressor.option("dead_code") && all(self.body, is_empty)) {
@@ -4468,13 +4451,15 @@ merge(Compressor.prototype, {
return self;
});
- AST_Definitions.DEFMETHOD("remove_initializers", function(){
- this.definitions.forEach(function(def){ def.value = null });
+ AST_Definitions.DEFMETHOD("remove_initializers", function() {
+ this.definitions.forEach(function(def) {
+ def.value = null;
+ });
});
- AST_Definitions.DEFMETHOD("to_assignments", function(compressor){
+ AST_Definitions.DEFMETHOD("to_assignments", function(compressor) {
var reduce_vars = compressor.option("reduce_vars");
- var assignments = this.definitions.reduce(function(a, def){
+ var assignments = this.definitions.reduce(function(a, def) {
if (def.value) {
var name = make_node(AST_SymbolRef, def.name, def.name);
a.push(make_node(AST_Assign, def, {
@@ -4493,7 +4478,7 @@ merge(Compressor.prototype, {
return make_sequence(this, assignments);
});
- OPT(AST_Definitions, function(self, compressor){
+ OPT(AST_Definitions, function(self, compressor) {
if (self.definitions.length == 0)
return make_node(AST_EmptyStatement, self);
return self;
@@ -4669,7 +4654,7 @@ merge(Compressor.prototype, {
} else {
first = make_node(AST_String, self, { value: "" });
}
- return elements.reduce(function(prev, el){
+ return elements.reduce(function(prev, el) {
return make_node(AST_Binary, el, {
operator : "+",
left : prev,
@@ -5048,7 +5033,7 @@ merge(Compressor.prototype, {
return self;
});
- OPT(AST_Sequence, function(self, compressor){
+ OPT(AST_Sequence, function(self, compressor) {
if (!compressor.option("side_effects")) return self;
var expressions = [];
filter_for_side_effects();
@@ -5086,7 +5071,7 @@ merge(Compressor.prototype, {
}
});
- AST_Unary.DEFMETHOD("lift_sequences", function(compressor){
+ AST_Unary.DEFMETHOD("lift_sequences", function(compressor) {
if (compressor.option("sequences") && this.expression instanceof AST_Sequence) {
var x = this.expression.expressions.slice();
var e = this.clone();
@@ -5097,11 +5082,11 @@ merge(Compressor.prototype, {
return this;
});
- OPT(AST_UnaryPostfix, function(self, compressor){
+ OPT(AST_UnaryPostfix, function(self, compressor) {
return self.lift_sequences(compressor);
});
- OPT(AST_UnaryPrefix, function(self, compressor){
+ OPT(AST_UnaryPrefix, function(self, compressor) {
var e = self.expression;
if (self.operator == "delete"
&& !(e instanceof AST_SymbolRef
@@ -5177,7 +5162,7 @@ merge(Compressor.prototype, {
return self;
});
- AST_Binary.DEFMETHOD("lift_sequences", function(compressor){
+ AST_Binary.DEFMETHOD("lift_sequences", function(compressor) {
if (compressor.option("sequences")) {
if (this.left instanceof AST_Sequence) {
var x = this.left.expressions.slice();
@@ -5218,7 +5203,7 @@ merge(Compressor.prototype, {
|| node instanceof AST_Object;
}
- OPT(AST_Binary, function(self, compressor){
+ OPT(AST_Binary, function(self, compressor) {
function reversible() {
return self.left.is_constant()
|| self.right.is_constant()
@@ -5666,7 +5651,7 @@ merge(Compressor.prototype, {
return node;
}
- OPT(AST_SymbolRef, function(self, compressor){
+ OPT(AST_SymbolRef, function(self, compressor) {
var def = self.resolve_defines(compressor);
if (def) {
return def.optimize(compressor);
@@ -5799,7 +5784,7 @@ merge(Compressor.prototype, {
return lhs instanceof AST_SymbolRef || lhs.TYPE === self.TYPE;
}
- OPT(AST_Undefined, function(self, compressor){
+ OPT(AST_Undefined, function(self, compressor) {
if (compressor.option("unsafe_undefined")) {
var undef = find_variable(compressor, "undefined");
if (undef) {
@@ -5822,7 +5807,7 @@ merge(Compressor.prototype, {
});
});
- OPT(AST_Infinity, function(self, compressor){
+ OPT(AST_Infinity, function(self, compressor) {
var lhs = is_lhs(compressor.self(), compressor.parent());
if (lhs && is_atomic(lhs, self)) return self;
if (compressor.option("keep_infinity")
@@ -5840,7 +5825,7 @@ merge(Compressor.prototype, {
});
});
- OPT(AST_NaN, function(self, compressor){
+ OPT(AST_NaN, function(self, compressor) {
var lhs = is_lhs(compressor.self(), compressor.parent());
if (lhs && !is_atomic(lhs, self)
|| find_variable(compressor, "NaN")) {
@@ -5880,7 +5865,7 @@ merge(Compressor.prototype, {
var ASSIGN_OPS = makePredicate("+ - / * % >> << >>> | ^ &");
var ASSIGN_OPS_COMMUTATIVE = makePredicate("* | ^ &");
- OPT(AST_Assign, function(self, compressor){
+ OPT(AST_Assign, function(self, compressor) {
var def;
if (compressor.option("dead_code")
&& self.left instanceof AST_SymbolRef
@@ -5940,7 +5925,7 @@ merge(Compressor.prototype, {
}
});
- OPT(AST_Conditional, function(self, compressor){
+ OPT(AST_Conditional, function(self, compressor) {
if (!compressor.option("conditionals")) return self;
// This looks like lift_sequences(), should probably be under "sequences"
if (self.condition instanceof AST_Sequence) {
@@ -6160,7 +6145,7 @@ merge(Compressor.prototype, {
}
});
- OPT(AST_Boolean, function(self, compressor){
+ OPT(AST_Boolean, function(self, compressor) {
if (!compressor.option("booleans")) return self;
if (compressor.in_boolean_context()) return make_node(AST_Number, self, {
value: +self.value
@@ -6186,7 +6171,7 @@ merge(Compressor.prototype, {
});
});
- OPT(AST_Sub, function(self, compressor){
+ OPT(AST_Sub, function(self, compressor) {
var expr = self.expression;
var prop = self.property;
if (compressor.option("properties")) {
@@ -6330,7 +6315,7 @@ merge(Compressor.prototype, {
}
});
- OPT(AST_Dot, function(self, compressor){
+ OPT(AST_Dot, function(self, compressor) {
if (self.property == "arguments" || self.property == "caller") {
compressor.warn("Function.protoype.{prop} not supported [{file}:{line},{col}]", {
prop: self.property,
@@ -6392,19 +6377,27 @@ merge(Compressor.prototype, {
return self;
});
- OPT(AST_Return, function(self, compressor){
+ OPT(AST_Return, function(self, compressor) {
if (self.value && is_undefined(self.value, compressor)) {
self.value = null;
}
return self;
});
- OPT(AST_VarDef, function(self, compressor){
+ OPT(AST_VarDef, function(self, compressor) {
var defines = compressor.option("global_defs");
if (defines && HOP(defines, self.name.name)) {
compressor.warn('global_defs ' + self.name.name + ' redefined [{file}:{line},{col}]', self.start);
}
return self;
});
-
-})();
+})(function(node, optimizer) {
+ node.DEFMETHOD("optimize", function(compressor) {
+ var self = this;
+ if (self._optimized) return self;
+ if (compressor.has_directive("use asm")) return self;
+ var opt = optimizer(self, compressor);
+ opt._optimized = true;
+ return opt;
+ });
+});
diff --git a/lib/mozilla-ast.js b/lib/mozilla-ast.js
index 8e66c916..dace808a 100644
--- a/lib/mozilla-ast.js
+++ b/lib/mozilla-ast.js
@@ -43,11 +43,9 @@
"use strict";
-(function(){
-
- var normalize_directives = function(body) {
+(function() {
+ function normalize_directives(body) {
var in_directive = true;
-
for (var i = 0; i < body.length; i++) {
if (in_directive && body[i] instanceof AST_Statement && body[i].body instanceof AST_String) {
body[i] = new AST_Directive({
@@ -59,9 +57,8 @@
in_directive = false;
}
}
-
return body;
- };
+ }
var MOZ_TO_ME = {
Program: function(M) {
@@ -129,7 +126,7 @@
return new AST_Array({
start : my_start_token(M),
end : my_end_token(M),
- elements : M.elements.map(function(elem){
+ elements : M.elements.map(function(elem) {
return elem === null ? new AST_Hole() : from_moz(elem);
})
});
@@ -138,7 +135,7 @@
return new AST_Object({
start : my_start_token(M),
end : my_end_token(M),
- properties : M.properties.map(function(prop){
+ properties : M.properties.map(function(prop) {
prop.type = "Property";
return from_moz(prop)
})
@@ -480,7 +477,7 @@
endpos : range ? range[0] : moznode.start,
raw : raw_token(moznode),
});
- };
+ }
function my_end_token(moznode) {
var loc = moznode.loc, end = loc && loc.end;
@@ -495,7 +492,7 @@
endpos : range ? range[1] : moznode.end,
raw : raw_token(moznode),
});
- };
+ }
function map(moztype, mytype, propmap) {
var moz_to_me = "function From_Moz_" + moztype + "(M){\n";
@@ -507,7 +504,7 @@
me_to_moz += "return {\n" +
"type: " + JSON.stringify(moztype);
- if (propmap) propmap.split(/\s*,\s*/).forEach(function(prop){
+ if (propmap) propmap.split(/\s*,\s*/).forEach(function(prop) {
var m = /([a-z0-9$_]+)(=|@|>|%)([a-z0-9$_]+)/i.exec(prop);
if (!m) throw new Error("Can't understand property map: " + prop);
var moz = m[1], how = m[2], my = m[3];
@@ -550,7 +547,7 @@
);
MOZ_TO_ME[moztype] = moz_to_me;
def_to_moz(mytype, me_to_moz);
- };
+ }
var FROM_MOZ_STACK = null;
@@ -559,9 +556,9 @@
var ret = node != null ? MOZ_TO_ME[node.type](node) : null;
FROM_MOZ_STACK.pop();
return ret;
- };
+ }
- AST_Node.from_mozilla_ast = function(node){
+ AST_Node.from_mozilla_ast = function(node) {
var save_stack = FROM_MOZ_STACK;
FROM_MOZ_STACK = [];
var ast = from_moz(node);
@@ -600,24 +597,24 @@
}
}
return moznode;
- };
+ }
function def_to_moz(mytype, handler) {
mytype.DEFMETHOD("to_mozilla_ast", function() {
return set_moz_loc(this, handler(this));
});
- };
+ }
function to_moz(node) {
return node != null ? node.to_mozilla_ast() : null;
- };
+ }
function to_moz_block(node) {
return {
type: "BlockStatement",
body: node.body.map(to_moz)
};
- };
+ }
function to_moz_scope(type, node) {
var body = node.body.map(to_moz);
@@ -628,5 +625,5 @@
type: type,
body: body
};
- };
+ }
})();
diff --git a/lib/output.js b/lib/output.js
index 6d7b0723..1dbc1f6e 100644
--- a/lib/output.js
+++ b/lib/output.js
@@ -137,7 +137,7 @@ function OutputStream(options) {
function make_string(str, quote) {
var dq = 0, sq = 0;
str = str.replace(/[\\\b\f\n\r\v\t\x22\x27\u2028\u2029\0\ufeff]/g,
- function(s, i){
+ function(s, i) {
switch (s) {
case '"': ++dq; return '"';
case "'": ++sq; return "'";
@@ -408,7 +408,7 @@ function OutputStream(options) {
var ret;
print("{");
newline();
- with_indent(next_indent(), function(){
+ with_indent(next_indent(), function() {
ret = cont();
});
indent();
@@ -631,7 +631,7 @@ function OutputStream(options) {
/* -----[ code generators ]----- */
-(function(){
+(function() {
/* -----[ utils ]----- */
@@ -643,7 +643,7 @@ function OutputStream(options) {
var active_scope = null;
var use_asm = null;
- AST_Node.DEFMETHOD("print", function(stream, force_parens){
+ AST_Node.DEFMETHOD("print", function(stream, force_parens) {
var self = this, generator = self._codegen;
if (self instanceof AST_Scope) {
active_scope = self;
@@ -670,7 +670,7 @@ function OutputStream(options) {
});
AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
- AST_Node.DEFMETHOD("print_to_string", function(options){
+ AST_Node.DEFMETHOD("print_to_string", function(options) {
var s = OutputStream(options);
this.print(s);
return s.get();
@@ -680,7 +680,7 @@ function OutputStream(options) {
function PARENS(nodetype, func) {
if (Array.isArray(nodetype)) {
- nodetype.forEach(function(nodetype){
+ nodetype.forEach(function(nodetype) {
PARENS(nodetype, func);
});
} else {
@@ -692,7 +692,7 @@ function OutputStream(options) {
// a function expression needs parens around it when it's provably
// the first token to appear in a statement.
- PARENS(AST_Function, function(output){
+ PARENS(AST_Function, function(output) {
if (!output.has_parens() && first_in_statement(output)) {
return true;
}
@@ -714,17 +714,17 @@ function OutputStream(options) {
// same goes for an object literal, because otherwise it would be
// interpreted as a block of code.
- PARENS(AST_Object, function(output){
+ PARENS(AST_Object, function(output) {
return !output.has_parens() && first_in_statement(output);
});
- PARENS(AST_Unary, function(output){
+ PARENS(AST_Unary, function(output) {
var p = output.parent();
return p instanceof AST_PropAccess && p.expression === this
|| p instanceof AST_Call && p.expression === this;
});
- PARENS(AST_Sequence, function(output){
+ PARENS(AST_Sequence, function(output) {
var p = output.parent();
return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
|| p instanceof AST_Unary // !(foo, bar, baz)
@@ -738,7 +738,7 @@ function OutputStream(options) {
;
});
- PARENS(AST_Binary, function(output){
+ PARENS(AST_Binary, function(output) {
var p = output.parent();
// (foo && bar)()
if (p instanceof AST_Call && p.expression === this)
@@ -761,7 +761,7 @@ function OutputStream(options) {
}
});
- PARENS(AST_PropAccess, function(output){
+ PARENS(AST_PropAccess, function(output) {
var p = output.parent();
if (p instanceof AST_New && p.expression === this) {
// i.e. new (foo.bar().baz)
@@ -782,7 +782,7 @@ function OutputStream(options) {
}
});
- PARENS(AST_Call, function(output){
+ PARENS(AST_Call, function(output) {
var p = output.parent(), p1;
if (p instanceof AST_New && p.expression === this)
return true;
@@ -796,7 +796,7 @@ function OutputStream(options) {
&& p1.left === p;
});
- PARENS(AST_New, function(output){
+ PARENS(AST_New, function(output) {
var p = output.parent();
if (!need_constructor_parens(this, output)
&& (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]()
@@ -804,7 +804,7 @@ function OutputStream(options) {
return true;
});
- PARENS(AST_Number, function(output){
+ PARENS(AST_Number, function(output) {
var p = output.parent();
if (p instanceof AST_PropAccess && p.expression === this) {
var value = this.getValue();
@@ -814,7 +814,7 @@ function OutputStream(options) {
}
});
- PARENS([ AST_Assign, AST_Conditional ], function(output){
+ PARENS([ AST_Assign, AST_Conditional ], function(output) {
var p = output.parent();
// !(a = false) → true
if (p instanceof AST_Unary)
@@ -835,11 +835,11 @@ function OutputStream(options) {
/* -----[ PRINTERS ]----- */
- DEFPRINT(AST_Directive, function(self, output){
+ DEFPRINT(AST_Directive, function(self, output) {
output.print_string(self.value, self.quote);
output.semicolon();
});
- DEFPRINT(AST_Debugger, function(self, output){
+ DEFPRINT(AST_Debugger, function(self, output) {
output.print("debugger");
output.semicolon();
});
@@ -849,7 +849,7 @@ function OutputStream(options) {
function display_body(body, is_toplevel, output, allow_directives) {
var last = body.length - 1;
in_directive = allow_directives;
- body.forEach(function(stmt, i){
+ body.forEach(function(stmt, i) {
if (in_directive === true && !(stmt instanceof AST_Directive ||
stmt instanceof AST_EmptyStatement ||
(stmt instanceof AST_SimpleStatement && stmt.body instanceof AST_String)
@@ -874,24 +874,24 @@ function OutputStream(options) {
in_directive = false;
}
- AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output){
+ AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output) {
force_statement(this.body, output);
});
- DEFPRINT(AST_Statement, function(self, output){
+ DEFPRINT(AST_Statement, function(self, output) {
self.body.print(output);
output.semicolon();
});
- DEFPRINT(AST_Toplevel, function(self, output){
+ DEFPRINT(AST_Toplevel, function(self, output) {
display_body(self.body, true, output, true);
output.print("");
});
- DEFPRINT(AST_LabeledStatement, function(self, output){
+ DEFPRINT(AST_LabeledStatement, function(self, output) {
self.label.print(output);
output.colon();
self.body.print(output);
});
- DEFPRINT(AST_SimpleStatement, function(self, output){
+ DEFPRINT(AST_SimpleStatement, function(self, output) {
self.body.print(output);
output.semicolon();
});
@@ -909,37 +909,37 @@ function OutputStream(options) {
});
} else print_braced_empty(self, output);
}
- DEFPRINT(AST_BlockStatement, function(self, output){
+ DEFPRINT(AST_BlockStatement, function(self, output) {
print_braced(self, output);
});
- DEFPRINT(AST_EmptyStatement, function(self, output){
+ DEFPRINT(AST_EmptyStatement, function(self, output) {
output.semicolon();
});
- DEFPRINT(AST_Do, function(self, output){
+ DEFPRINT(AST_Do, function(self, output) {
output.print("do");
output.space();
make_block(self.body, output);
output.space();
output.print("while");
output.space();
- output.with_parens(function(){
+ output.with_parens(function() {
self.condition.print(output);
});
output.semicolon();
});
- DEFPRINT(AST_While, function(self, output){
+ DEFPRINT(AST_While, function(self, output) {
output.print("while");
output.space();
- output.with_parens(function(){
+ output.with_parens(function() {
self.condition.print(output);
});
output.space();
self._do_print_body(output);
});
- DEFPRINT(AST_For, function(self, output){
+ DEFPRINT(AST_For, function(self, output) {
output.print("for");
output.space();
- output.with_parens(function(){
+ output.with_parens(function() {
if (self.init) {
if (self.init instanceof AST_Definitions) {
self.init.print(output);
@@ -965,10 +965,10 @@ function OutputStream(options) {
output.space();
self._do_print_body(output);
});
- DEFPRINT(AST_ForIn, function(self, output){
+ DEFPRINT(AST_ForIn, function(self, output) {
output.print("for");
output.space();
- output.with_parens(function(){
+ output.with_parens(function() {
self.init.print(output);
output.space();
output.print("in");
@@ -978,10 +978,10 @@ function OutputStream(options) {
output.space();
self._do_print_body(output);
});
- DEFPRINT(AST_With, function(self, output){
+ DEFPRINT(AST_With, function(self, output) {
output.print("with");
output.space();
- output.with_parens(function(){
+ output.with_parens(function() {
self.expression.print(output);
});
output.space();
@@ -989,7 +989,7 @@ function OutputStream(options) {
});
/* -----[ functions ]----- */
- AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword){
+ AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword) {
var self = this;
if (!nokeyword) {
output.print("function");
@@ -998,8 +998,8 @@ function OutputStream(options) {
output.space();
self.name.print(output);
}
- output.with_parens(function(){
- self.argnames.forEach(function(arg, i){
+ output.with_parens(function() {
+ self.argnames.forEach(function(arg, i) {
if (i) output.comma();
arg.print(output);
});
@@ -1007,40 +1007,31 @@ function OutputStream(options) {
output.space();
print_braced(self, output, true);
});
- DEFPRINT(AST_Lambda, function(self, output){
+ DEFPRINT(AST_Lambda, function(self, output) {
self._do_print(output);
});
- /* -----[ exits ]----- */
- AST_Exit.DEFMETHOD("_do_print", function(output, kind){
+ /* -----[ jumps ]----- */
+ function print_jump(output, kind, target) {
output.print(kind);
- if (this.value) {
+ if (target) {
output.space();
- this.value.print(output);
+ target.print(output);
}
output.semicolon();
- });
- DEFPRINT(AST_Return, function(self, output){
- self._do_print(output, "return");
- });
- DEFPRINT(AST_Throw, function(self, output){
- self._do_print(output, "throw");
- });
+ }
- /* -----[ loop control ]----- */
- AST_LoopControl.DEFMETHOD("_do_print", function(output, kind){
- output.print(kind);
- if (this.label) {
- output.space();
- this.label.print(output);
- }
- output.semicolon();
+ DEFPRINT(AST_Return, function(self, output) {
+ print_jump(output, "return", self.value);
+ });
+ DEFPRINT(AST_Throw, function(self, output) {
+ print_jump(output, "throw", self.value);
});
- DEFPRINT(AST_Break, function(self, output){
- self._do_print(output, "break");
+ DEFPRINT(AST_Break, function(self, output) {
+ print_jump(output, "break", self.label);
});
- DEFPRINT(AST_Continue, function(self, output){
- self._do_print(output, "continue");
+ DEFPRINT(AST_Continue, function(self, output) {
+ print_jump(output, "continue", self.label);
});
/* -----[ if ]----- */
@@ -1072,10 +1063,10 @@ function OutputStream(options) {
}
force_statement(self.body, output);
}
- DEFPRINT(AST_If, function(self, output){
+ DEFPRINT(AST_If, function(self, output) {
output.print("if");
output.space();
- output.with_parens(function(){
+ output.with_parens(function() {
self.condition.print(output);
});
output.space();
@@ -1094,17 +1085,17 @@ function OutputStream(options) {
});
/* -----[ switch ]----- */
- DEFPRINT(AST_Switch, function(self, output){
+ DEFPRINT(AST_Switch, function(self, output) {
output.print("switch");
output.space();
- output.with_parens(function(){
+ output.with_parens(function() {
self.expression.print(output);
});
output.space();
var last = self.body.length - 1;
if (last < 0) print_braced_empty(self, output);
- else output.with_block(function(){
- self.body.forEach(function(branch, i){
+ else output.with_block(function() {
+ self.body.forEach(function(branch, i) {
output.indent(true);
branch.print(output);
if (i < last && branch.body.length > 0)
@@ -1112,19 +1103,19 @@ function OutputStream(options) {
});
});
});
- AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output){
+ AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output) {
output.newline();
- this.body.forEach(function(stmt){
+ this.body.forEach(function(stmt) {
output.indent();
stmt.print(output);
output.newline();
});
});
- DEFPRINT(AST_Default, function(self, output){
+ DEFPRINT(AST_Default, function(self, output) {
output.print("default:");
self._do_print_body(output);
});
- DEFPRINT(AST_Case, function(self, output){
+ DEFPRINT(AST_Case, function(self, output) {
output.print("case");
output.space();
self.expression.print(output);
@@ -1133,7 +1124,7 @@ function OutputStream(options) {
});
/* -----[ exceptions ]----- */
- DEFPRINT(AST_Try, function(self, output){
+ DEFPRINT(AST_Try, function(self, output) {
output.print("try");
output.space();
print_braced(self, output);
@@ -1146,37 +1137,30 @@ function OutputStream(options) {
self.bfinally.print(output);
}
});
- DEFPRINT(AST_Catch, function(self, output){
+ DEFPRINT(AST_Catch, function(self, output) {
output.print("catch");
output.space();
- output.with_parens(function(){
+ output.with_parens(function() {
self.argname.print(output);
});
output.space();
print_braced(self, output);
});
- DEFPRINT(AST_Finally, function(self, output){
+ DEFPRINT(AST_Finally, function(self, output) {
output.print("finally");
output.space();
print_braced(self, output);
});
- /* -----[ var/const ]----- */
- AST_Definitions.DEFMETHOD("_do_print", function(output, kind){
- output.print(kind);
+ DEFPRINT(AST_Var, function(self, output) {
+ output.print("var");
output.space();
- this.definitions.forEach(function(def, i){
+ self.definitions.forEach(function(def, i) {
if (i) output.comma();
def.print(output);
});
var p = output.parent();
- var in_for = p instanceof AST_For || p instanceof AST_ForIn;
- var avoid_semicolon = in_for && p.init === this;
- if (!avoid_semicolon)
- output.semicolon();
- });
- DEFPRINT(AST_Var, function(self, output){
- self._do_print(output, "var");
+ if (p.init !== self || !(p instanceof AST_For || p instanceof AST_ForIn)) output.semicolon();
});
function parenthesize_for_noin(node, output, noin) {
@@ -1193,7 +1177,7 @@ function OutputStream(options) {
node.print(output, parens);
}
- DEFPRINT(AST_VarDef, function(self, output){
+ DEFPRINT(AST_VarDef, function(self, output) {
self.name.print(output);
if (self.value) {
output.space();
@@ -1206,28 +1190,27 @@ function OutputStream(options) {
});
/* -----[ other expressions ]----- */
- DEFPRINT(AST_Call, function(self, output){
+ DEFPRINT(AST_Call, function(self, output) {
self.expression.print(output);
if (self instanceof AST_New && !need_constructor_parens(self, output))
return;
if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) {
output.add_mapping(self.start);
}
- output.with_parens(function(){
- self.args.forEach(function(expr, i){
+ output.with_parens(function() {
+ self.args.forEach(function(expr, i) {
if (i) output.comma();
expr.print(output);
});
});
});
- DEFPRINT(AST_New, function(self, output){
+ DEFPRINT(AST_New, function(self, output) {
output.print("new");
output.space();
AST_Call.prototype._codegen(self, output);
});
-
- AST_Sequence.DEFMETHOD("_do_print", function(output){
- this.expressions.forEach(function(node, index) {
+ DEFPRINT(AST_Sequence, function(self, output) {
+ self.expressions.forEach(function(node, index) {
if (index > 0) {
output.comma();
if (output.should_break()) {
@@ -1238,18 +1221,7 @@ function OutputStream(options) {
node.print(output);
});
});
- DEFPRINT(AST_Sequence, function(self, output){
- self._do_print(output);
- // var p = output.parent();
- // if (p instanceof AST_Statement) {
- // output.with_indent(output.next_indent(), function(){
- // self._do_print(output);
- // });
- // } else {
- // self._do_print(output);
- // }
- });
- DEFPRINT(AST_Dot, function(self, output){
+ DEFPRINT(AST_Dot, function(self, output) {
var expr = self.expression;
expr.print(output);
var prop = self.property;
@@ -1270,13 +1242,13 @@ function OutputStream(options) {
output.print_name(prop);
}
});
- DEFPRINT(AST_Sub, function(self, output){
+ DEFPRINT(AST_Sub, function(self, output) {
self.expression.print(output);
output.print("[");
self.property.print(output);
output.print("]");
});
- DEFPRINT(AST_UnaryPrefix, function(self, output){
+ DEFPRINT(AST_UnaryPrefix, function(self, output) {
var op = self.operator;
output.print(op);
if (/^[a-z]/i.test(op)
@@ -1287,11 +1259,11 @@ function OutputStream(options) {
}
self.expression.print(output);
});
- DEFPRINT(AST_UnaryPostfix, function(self, output){
+ DEFPRINT(AST_UnaryPostfix, function(self, output) {
self.expression.print(output);
output.print(self.operator);
});
- DEFPRINT(AST_Binary, function(self, output){
+ DEFPRINT(AST_Binary, function(self, output) {
var op = self.operator;
self.left.print(output);
if (op[0] == ">" /* ">>" ">>>" ">" ">=" */
@@ -1317,7 +1289,7 @@ function OutputStream(options) {
}
self.right.print(output);
});
- DEFPRINT(AST_Conditional, function(self, output){
+ DEFPRINT(AST_Conditional, function(self, output) {
self.condition.print(output);
output.space();
output.print("?");
@@ -1329,11 +1301,11 @@ function OutputStream(options) {
});
/* -----[ literals ]----- */
- DEFPRINT(AST_Array, function(self, output){
- output.with_square(function(){
+ DEFPRINT(AST_Array, function(self, output) {
+ output.with_square(function() {
var a = self.elements, len = a.length;
if (len > 0) output.space();
- a.forEach(function(exp, i){
+ a.forEach(function(exp, i) {
if (i) output.comma();
exp.print(output);
// If the final element is a hole, we need to make sure it
@@ -1345,9 +1317,9 @@ function OutputStream(options) {
if (len > 0) output.space();
});
});
- DEFPRINT(AST_Object, function(self, output){
- if (self.properties.length > 0) output.with_block(function(){
- self.properties.forEach(function(prop, i){
+ DEFPRINT(AST_Object, function(self, output) {
+ if (self.properties.length > 0) output.with_block(function() {
+ self.properties.forEach(function(prop, i) {
if (i) {
output.print(",");
output.newline();
@@ -1376,7 +1348,7 @@ function OutputStream(options) {
}
}
- DEFPRINT(AST_ObjectKeyVal, function(self, output){
+ DEFPRINT(AST_ObjectKeyVal, function(self, output) {
print_property_name(self.key, self.quote, output);
output.colon();
self.value.print(output);
@@ -1387,27 +1359,27 @@ function OutputStream(options) {
print_property_name(this.key.name, this.quote, output);
this.value._do_print(output, true);
});
- DEFPRINT(AST_ObjectSetter, function(self, output){
+ DEFPRINT(AST_ObjectSetter, function(self, output) {
self._print_getter_setter("set", output);
});
- DEFPRINT(AST_ObjectGetter, function(self, output){
+ DEFPRINT(AST_ObjectGetter, function(self, output) {
self._print_getter_setter("get", output);
});
- DEFPRINT(AST_Symbol, function(self, output){
+ DEFPRINT(AST_Symbol, function(self, output) {
var def = self.definition();
output.print_name(def ? def.mangled_name || def.name : self.name);
});
DEFPRINT(AST_Hole, noop);
- DEFPRINT(AST_This, function(self, output){
+ DEFPRINT(AST_This, function(self, output) {
output.print("this");
});
- DEFPRINT(AST_Constant, function(self, output){
+ DEFPRINT(AST_Constant, function(self, output) {
output.print(self.getValue());
});
- DEFPRINT(AST_String, function(self, output){
+ DEFPRINT(AST_String, function(self, output) {
output.print_string(self.getValue(), self.quote, in_directive);
});
- DEFPRINT(AST_Number, function(self, output){
+ DEFPRINT(AST_Number, function(self, output) {
if (use_asm && self.start && self.start.raw != null) {
output.print(self.start.raw);
} else {
@@ -1415,7 +1387,7 @@ function OutputStream(options) {
}
});
- DEFPRINT(AST_RegExp, function(self, output){
+ DEFPRINT(AST_RegExp, function(self, output) {
var regexp = self.getValue();
var str = regexp.toString();
if (regexp.raw_source) {
@@ -1487,7 +1459,7 @@ function OutputStream(options) {
output.print("{}");
else if (stmt instanceof AST_BlockStatement)
stmt.print(output);
- else output.with_block(function(){
+ else output.with_block(function() {
output.indent();
stmt.print(output);
output.newline();
diff --git a/lib/parse.js b/lib/parse.js
index 21c89676..29df370c 100644
--- a/lib/parse.js
+++ b/lib/parse.js
@@ -130,7 +130,7 @@ function is_letter(code) {
return (code >= 97 && code <= 122)
|| (code >= 65 && code <= 90)
|| (code >= 0xaa && UNICODE.letter.test(String.fromCharCode(code)));
-};
+}
function is_surrogate_pair_head(code) {
if (typeof code == "string")
@@ -146,11 +146,11 @@ function is_surrogate_pair_tail(code) {
function is_digit(code) {
return code >= 48 && code <= 57;
-};
+}
function is_alphanumeric_char(code) {
return is_digit(code) || is_letter(code);
-};
+}
function is_unicode_digit(code) {
return UNICODE.digit.test(String.fromCharCode(code));
@@ -158,19 +158,19 @@ function is_unicode_digit(code) {
function is_unicode_combining_mark(ch) {
return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch);
-};
+}
function is_unicode_connector_punctuation(ch) {
return UNICODE.connector_punctuation.test(ch);
-};
+}
function is_identifier(name) {
return !RESERVED_WORDS[name] && /^[a-z_$][a-z0-9_$]*$/i.test(name);
-};
+}
function is_identifier_start(code) {
return code == 36 || code == 95 || is_letter(code);
-};
+}
function is_identifier_char(ch) {
var code = ch.charCodeAt(0);
@@ -182,11 +182,11 @@ function is_identifier_char(ch) {
|| is_unicode_connector_punctuation(ch)
|| is_unicode_digit(code)
;
-};
+}
-function is_identifier_string(str){
+function is_identifier_string(str) {
return /^[a-z_$][a-z0-9_$]*$/i.test(str);
-};
+}
function parse_js_number(num) {
if (RE_HEX_NUMBER.test(num)) {
@@ -197,7 +197,7 @@ function parse_js_number(num) {
var val = parseFloat(num);
if (val == num) return val;
}
-};
+}
function JS_Parse_Error(message, filename, line, col, pos) {
this.message = message;
@@ -205,7 +205,7 @@ function JS_Parse_Error(message, filename, line, col, pos) {
this.line = line;
this.col = col;
this.pos = pos;
-};
+}
JS_Parse_Error.prototype = Object.create(Error.prototype);
JS_Parse_Error.prototype.constructor = JS_Parse_Error;
JS_Parse_Error.prototype.name = "SyntaxError";
@@ -213,11 +213,11 @@ configure_error_stack(JS_Parse_Error);
function js_error(message, filename, line, col, pos) {
throw new JS_Parse_Error(message, filename, line, col, pos);
-};
+}
function is_token(token, type, val) {
return token.type == type && (val == null || token.value == val);
-};
+}
var EX_EOF = {};
@@ -239,7 +239,9 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
directive_stack : []
};
- function peek() { return S.text.charAt(S.pos); };
+ function peek() {
+ return S.text.charAt(S.pos);
+ }
function next(signal_eof, in_string) {
var ch = S.text.charAt(S.pos++);
@@ -258,15 +260,15 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
++S.col;
}
return ch;
- };
+ }
function forward(i) {
while (i-- > 0) next();
- };
+ }
function looking_at(str) {
return S.text.substr(S.pos, str.length) == str;
- };
+ }
function find_eol() {
var text = S.text;
@@ -276,19 +278,19 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
return i;
}
return -1;
- };
+ }
function find(what, signal_eof) {
var pos = S.text.indexOf(what, S.pos);
if (signal_eof && pos == -1) throw EX_EOF;
return pos;
- };
+ }
function start_token() {
S.tokline = S.line;
S.tokcol = S.col;
S.tokpos = S.pos;
- };
+ }
var prev_was_dot = false;
function token(type, value, is_comment) {
@@ -321,27 +323,27 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
}
S.newline_before = false;
return new AST_Token(ret);
- };
+ }
function skip_whitespace() {
while (WHITESPACE_CHARS[peek()])
next();
- };
+ }
function read_while(pred) {
var ret = "", ch, i = 0;
while ((ch = peek()) && pred(ch, i++))
ret += next();
return ret;
- };
+ }
function parse_error(err) {
js_error(err, filename, S.tokline, S.tokcol, S.tokpos);
- };
+ }
function read_num(prefix) {
var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".";
- var num = read_while(function(ch, i){
+ var num = read_while(function(ch, i) {
var code = ch.charCodeAt(0);
switch (code) {
case 120: case 88: // xX
@@ -367,7 +369,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
} else {
parse_error("Invalid syntax: " + num);
}
- };
+ }
function read_escaped_char(in_string) {
var ch = next(true, in_string);
@@ -390,7 +392,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
if (ch >= "0" && ch <= "7")
return read_octal_escape_sequence(ch);
return ch;
- };
+ }
function read_octal_escape_sequence(ch) {
// Read
@@ -417,9 +419,9 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
num = (num << 4) | digit;
}
return num;
- };
+ }
- var read_string = with_eof_error("Unterminated string constant", function(quote_char){
+ var read_string = with_eof_error("Unterminated string constant", function(quote_char) {
var quote = next(), ret = "";
for (;;) {
var ch = next(true, true);
@@ -447,9 +449,9 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
S.comments_before.push(token(type, ret, true));
S.regex_allowed = regex_allowed;
return next_token;
- };
+ }
- var skip_multiline_comment = with_eof_error("Unterminated multiline comment", function(){
+ var skip_multiline_comment = with_eof_error("Unterminated multiline comment", function() {
var regex_allowed = S.regex_allowed;
var i = find("*/", true);
var text = S.text.substring(S.pos, i).replace(/\r\n|\r|\u2028|\u2029/g, '\n');
@@ -481,7 +483,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1);
}
return name;
- };
+ }
var read_regexp = with_eof_error("Unterminated regular expression", function(source) {
var prev_backslash = false, ch, in_class = false;
@@ -523,9 +525,9 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
} else {
return op;
}
- };
+ }
return token("operator", grow(prefix || next()));
- };
+ }
function handle_slash() {
next();
@@ -538,14 +540,14 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
return skip_multiline_comment();
}
return S.regex_allowed ? read_regexp("") : read_operator("/");
- };
+ }
function handle_dot() {
next();
return is_digit(peek().charCodeAt(0))
? read_num(".")
: token("punc", ".");
- };
+ }
function read_word() {
var word = read_name();
@@ -554,7 +556,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
: !KEYWORDS[word] ? token("name", word)
: OPERATORS[word] ? token("operator", word)
: token("keyword", word);
- };
+ }
function with_eof_error(eof_error, cont) {
return function(x) {
@@ -565,7 +567,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
else throw ex;
}
};
- };
+ }
function next_token(force_regexp) {
if (force_regexp != null)
@@ -609,7 +611,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
break;
}
parse_error("Unexpected character '" + ch + "'");
- };
+ }
next_token.context = function(nc) {
if (nc) S = nc;
@@ -645,8 +647,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
}
return next_token;
-
-};
+}
/* -----[ Parser (constants) ]----- */
@@ -666,7 +667,7 @@ var UNARY_POSTFIX = makePredicate([ "--", "++" ]);
var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]);
-var PRECEDENCE = (function(a, ret){
+var PRECEDENCE = function(a, ret) {
for (var i = 0; i < a.length; ++i) {
var b = a[i];
for (var j = 0; j < b.length; ++j) {
@@ -674,28 +675,24 @@ var PRECEDENCE = (function(a, ret){
}
}
return ret;
-})(
- [
- ["||"],
- ["&&"],
- ["|"],
- ["^"],
- ["&"],
- ["==", "===", "!=", "!=="],
- ["<", ">", "<=", ">=", "in", "instanceof"],
- [">>", "<<", ">>>"],
- ["+", "-"],
- ["*", "/", "%"]
- ],
- {}
-);
+}([
+ ["||"],
+ ["&&"],
+ ["|"],
+ ["^"],
+ ["&"],
+ ["==", "===", "!=", "!=="],
+ ["<", ">", "<=", ">=", "in", "instanceof"],
+ [">>", "<<", ">>>"],
+ ["+", "-"],
+ ["*", "/", "%"]
+], {});
var ATOMIC_START_TOKEN = makePredicate([ "atom", "num", "string", "regexp", "name" ]);
/* -----[ Parser ]----- */
function parse($TEXT, options) {
-
options = defaults(options, {
bare_returns : false,
expression : false,
@@ -724,9 +721,11 @@ function parse($TEXT, options) {
function is(type, value) {
return is_token(S.token, type, value);
- };
+ }
- function peek() { return S.peeked || (S.peeked = S.input()); };
+ function peek() {
+ return S.peeked || (S.peeked = S.input());
+ }
function next() {
S.prev = S.token;
@@ -740,11 +739,11 @@ function parse($TEXT, options) {
S.token.type == "string" || is("punc", ";")
);
return S.token;
- };
+ }
function prev() {
return S.prev;
- };
+ }
function croak(msg, line, col, pos) {
var ctx = S.input.context();
@@ -753,26 +752,28 @@ function parse($TEXT, options) {
line != null ? line : ctx.tokline,
col != null ? col : ctx.tokcol,
pos != null ? pos : ctx.tokpos);
- };
+ }
function token_error(token, msg) {
croak(msg, token.line, token.col);
- };
+ }
function unexpected(token) {
if (token == null)
token = S.token;
token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")");
- };
+ }
function expect_token(type, val) {
if (is(type, val)) {
return next();
}
token_error(S.token, "Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»");
- };
+ }
- function expect(punc) { return expect_token("punc", punc); };
+ function expect(punc) {
+ return expect_token("punc", punc);
+ }
function has_newline_before(token) {
return token.nlb || !all(token.comments_before, function(comment) {
@@ -783,19 +784,19 @@ function parse($TEXT, options) {
function can_insert_semicolon() {
return !options.strict
&& (is("eof") || is("punc", "}") || has_newline_before(S.token));
- };
+ }
function semicolon(optional) {
if (is("punc", ";")) next();
else if (!optional && !can_insert_semicolon()) unexpected();
- };
+ }
function parenthesised() {
expect("(");
var exp = expression(true);
expect(")");
return exp;
- };
+ }
function embed_tokens(parser) {
return function() {
@@ -806,14 +807,14 @@ function parse($TEXT, options) {
expr.end = end;
return expr;
};
- };
+ }
function handle_regexp() {
if (is("operator", "/") || is("operator", "/=")) {
S.peeked = null;
S.token = S.input(S.token.value.substr(1)); // force regexp
}
- };
+ }
var statement = embed_tokens(function(strict_defun) {
handle_regexp();
@@ -986,7 +987,7 @@ function parse($TEXT, options) {
// check for `continue` that refers to this label.
// those should be reported as syntax errors.
// https://github.com/mishoo/UglifyJS2/issues/287
- label.references.forEach(function(ref){
+ label.references.forEach(function(ref) {
if (ref instanceof AST_Continue) {
ref = ref.label.start;
croak("Continue label `" + label.name + "` refers to non-IterationStatement.",
@@ -995,11 +996,11 @@ function parse($TEXT, options) {
});
}
return new AST_LabeledStatement({ body: stat, label: label });
- };
+ }
function simple_statement(tmp) {
return new AST_SimpleStatement({ body: (tmp = expression(true), semicolon(), tmp) });
- };
+ }
function break_cont(type) {
var label = null, ldef;
@@ -1007,18 +1008,17 @@ function parse($TEXT, options) {
label = as_symbol(AST_LabelRef, true);
}
if (label != null) {
- ldef = find_if(function(l){ return l.name == label.name }, S.labels);
- if (!ldef)
- croak("Undefined label " + label.name);
+ ldef = find_if(function(l) {
+ return l.name == label.name;
+ }, S.labels);
+ if (!ldef) croak("Undefined label " + label.name);
label.thedef = ldef;
- }
- else if (S.in_loop == 0)
- croak(type.TYPE + " not inside a loop or switch");
+ } else if (S.in_loop == 0) croak(type.TYPE + " not inside a loop or switch");
semicolon();
var stat = new type({ label: label });
if (ldef) ldef.references.push(stat);
return stat;
- };
+ }
function for_() {
expect("(");
@@ -1039,7 +1039,7 @@ function parse($TEXT, options) {
}
}
return regular_for(init);
- };
+ }
function regular_for(init) {
expect(";");
@@ -1053,7 +1053,7 @@ function parse($TEXT, options) {
step : step,
body : in_loop(statement)
});
- };
+ }
function for_in(init) {
var obj = expression(true);
@@ -1063,7 +1063,7 @@ function parse($TEXT, options) {
object : obj,
body : in_loop(statement)
});
- };
+ }
var function_ = function(ctor) {
var in_statement = ctor === AST_Defun;
@@ -1113,7 +1113,7 @@ function parse($TEXT, options) {
body : body,
alternative : belse
});
- };
+ }
function block_(strict_defun) {
expect("{");
@@ -1124,7 +1124,7 @@ function parse($TEXT, options) {
}
next();
return a;
- };
+ }
function switch_body_() {
expect("{");
@@ -1159,7 +1159,7 @@ function parse($TEXT, options) {
if (branch) branch.end = prev();
next();
return a;
- };
+ }
function try_() {
var body = block_(), bcatch = null, bfinally = null;
@@ -1192,7 +1192,7 @@ function parse($TEXT, options) {
bcatch : bcatch,
bfinally : bfinally
});
- };
+ }
function vardefs(no_in) {
var a = [];
@@ -1208,7 +1208,7 @@ function parse($TEXT, options) {
next();
}
return a;
- };
+ }
var var_ = function(no_in) {
return new AST_Var({
@@ -1274,7 +1274,7 @@ function parse($TEXT, options) {
}
next();
return ret;
- };
+ }
var expr_atom = function(allow_calls) {
if (is("operator", "new")) {
@@ -1340,7 +1340,7 @@ function parse($TEXT, options) {
}
next();
return a;
- };
+ }
var array_ = embed_tokens(function() {
expect("[");
@@ -1417,14 +1417,14 @@ function parse($TEXT, options) {
default:
unexpected();
}
- };
+ }
function as_name() {
var tmp = S.token;
if (tmp.type != "name") unexpected();
next();
return tmp.value;
- };
+ }
function _make_symbol(type) {
var name = S.token.value;
@@ -1433,7 +1433,7 @@ function parse($TEXT, options) {
start : S.token,
end : S.token
});
- };
+ }
function strict_verify_symbol(sym) {
if (sym.name == "arguments" || sym.name == "eval")
@@ -1451,7 +1451,7 @@ function parse($TEXT, options) {
}
next();
return sym;
- };
+ }
function mark_pure(call) {
var start = call.start;
@@ -1536,7 +1536,7 @@ function parse($TEXT, options) {
break;
}
return new ctor({ operator: op, expression: expr });
- };
+ }
var expr_op = function(left, min_prec, no_in) {
var op = is("operator") ? S.token.value : null;
@@ -1558,7 +1558,7 @@ function parse($TEXT, options) {
function expr_ops(no_in) {
return expr_op(maybe_unary(true), 0, no_in);
- };
+ }
var maybe_conditional = function(no_in) {
var start = S.token;
@@ -1580,7 +1580,7 @@ function parse($TEXT, options) {
function is_assignable(expr) {
return expr instanceof AST_PropAccess || expr instanceof AST_SymbolRef;
- };
+ }
var maybe_assign = function(no_in) {
var start = S.token;
@@ -1622,13 +1622,13 @@ function parse($TEXT, options) {
var ret = cont();
--S.in_loop;
return ret;
- };
+ }
if (options.expression) {
return expression(true);
}
- return (function(){
+ return function() {
var start = S.token;
var body = [];
S.input.push_directives_stack();
@@ -1644,6 +1644,5 @@ function parse($TEXT, options) {
toplevel = new AST_Toplevel({ start: start, body: body, end: end });
}
return toplevel;
- })();
-
-};
+ }();
+}
diff --git a/lib/propmangle.js b/lib/propmangle.js
index 1bca1ad4..7ad4804d 100644
--- a/lib/propmangle.js
+++ b/lib/propmangle.js
@@ -56,7 +56,7 @@ function find_builtins(reserved) {
[ Object, Array, Function, Number,
String, Boolean, Error, Math,
Date, RegExp
- ].forEach(function(ctor){
+ ].forEach(function(ctor) {
Object.getOwnPropertyNames(ctor).map(add);
if (ctor.prototype) {
Object.getOwnPropertyNames(ctor.prototype).map(add);
@@ -136,7 +136,7 @@ function mangle_properties(ast, options) {
var unmangleable = [];
// step 1: find candidates to mangle
- ast.walk(new TreeWalker(function(node){
+ ast.walk(new TreeWalker(function(node) {
if (node instanceof AST_ObjectKeyVal) {
add(node.key);
}
@@ -157,7 +157,7 @@ function mangle_properties(ast, options) {
}));
// step 2: transform the tree, renaming properties
- return ast.transform(new TreeTransformer(function(node){
+ return ast.transform(new TreeTransformer(function(node) {
if (node instanceof AST_ObjectKeyVal) {
node.key = mangle(node.key);
}
@@ -234,7 +234,7 @@ function mangle_properties(ast, options) {
}
function mangleStrings(node) {
- return node.transform(new TreeTransformer(function(node){
+ return node.transform(new TreeTransformer(function(node) {
if (node instanceof AST_Sequence) {
var last = node.expressions.length - 1;
node.expressions[last] = mangleStrings(node.expressions[last]);
diff --git a/lib/scope.js b/lib/scope.js
index fb14480f..d4b13d12 100644
--- a/lib/scope.js
+++ b/lib/scope.js
@@ -91,7 +91,7 @@ SymbolDef.prototype = {
}
};
-AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
+AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
options = defaults(options, {
cache: null,
ie8: false,
@@ -101,7 +101,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
var self = this;
var scope = self.parent_scope = null;
var defun = null;
- var tw = new TreeWalker(function(node, descend){
+ var tw = new TreeWalker(function(node, descend) {
if (node instanceof AST_Catch) {
var save_scope = scope;
scope = new AST_Scope(node);
@@ -162,7 +162,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
// pass 2: find back references and eval
self.globals = new Dictionary();
- var tw = new TreeWalker(function(node, descend){
+ var tw = new TreeWalker(function(node, descend) {
if (node instanceof AST_LoopControl && node.label) {
node.label.thedef.references.push(node);
return true;
@@ -217,7 +217,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
}
});
-AST_Toplevel.DEFMETHOD("def_global", function(node){
+AST_Toplevel.DEFMETHOD("def_global", function(node) {
var globals = this.globals, name = node.name;
if (globals.has(name)) {
return globals.get(name);
@@ -230,7 +230,7 @@ AST_Toplevel.DEFMETHOD("def_global", function(node){
}
});
-AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope){
+AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope) {
this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
@@ -240,7 +240,7 @@ AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope){
this.cname = -1; // the current index for mangling functions/variables
});
-AST_Lambda.DEFMETHOD("init_scope_vars", function(){
+AST_Lambda.DEFMETHOD("init_scope_vars", function() {
AST_Scope.prototype.init_scope_vars.apply(this, arguments);
this.uses_arguments = false;
this.def_variable(new AST_SymbolFunarg({
@@ -270,20 +270,20 @@ AST_Symbol.DEFMETHOD("reference", function(options) {
this.mark_enclosed(options);
});
-AST_Scope.DEFMETHOD("find_variable", function(name){
+AST_Scope.DEFMETHOD("find_variable", function(name) {
if (name instanceof AST_Symbol) name = name.name;
return this.variables.get(name)
|| (this.parent_scope && this.parent_scope.find_variable(name));
});
-AST_Scope.DEFMETHOD("def_function", function(symbol, init){
+AST_Scope.DEFMETHOD("def_function", function(symbol, init) {
var def = this.def_variable(symbol, init);
if (!def.init || def.init instanceof AST_Defun) def.init = init;
this.functions.set(symbol.name, def);
return def;
});
-AST_Scope.DEFMETHOD("def_variable", function(symbol, init){
+AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
var def = this.variables.get(symbol.name);
if (def) {
def.orig.push(symbol);
@@ -390,7 +390,7 @@ function _default_mangler_options(options) {
return options;
}
-AST_Toplevel.DEFMETHOD("mangle_names", function(options){
+AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
options = _default_mangler_options(options);
// We only need to mangle declaration nodes. Special logic wired
@@ -407,7 +407,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
}
var redefined = [];
- var tw = new TreeWalker(function(node, descend){
+ var tw = new TreeWalker(function(node, descend) {
if (node instanceof AST_LabeledStatement) {
// lname is incremented when we get to the AST_Label
var save_nesting = lname;
@@ -520,7 +520,7 @@ AST_Sequence.DEFMETHOD("tail_node", function() {
return this.expressions[this.expressions.length - 1];
});
-AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
+AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) {
options = _default_mangler_options(options);
base54.reset();
try {
diff --git a/lib/sourcemap.js b/lib/sourcemap.js
index dcb8e476..2feec45d 100644
--- a/lib/sourcemap.js
+++ b/lib/sourcemap.js
@@ -46,16 +46,15 @@
// a small wrapper around fitzgen's source-map library
function SourceMap(options) {
options = defaults(options, {
- file : null,
- root : null,
- orig : null,
-
- orig_line_diff : 0,
- dest_line_diff : 0,
- });
+ file: null,
+ root: null,
+ orig: null,
+ orig_line_diff: 0,
+ dest_line_diff: 0,
+ }, true);
var generator = new MOZ_SourceMap.SourceMapGenerator({
- file : options.file,
- sourceRoot : options.root
+ file: options.file,
+ sourceRoot: options.root
});
var maps = options.orig && Object.create(null);
if (maps) for (var source in options.orig) {
@@ -68,30 +67,38 @@ function SourceMap(options) {
}
maps[source] = map;
}
-
- function add(source, gen_line, gen_col, orig_line, orig_col, name) {
- var map = maps && maps[source];
- if (map) {
- var info = map.originalPositionFor({
- line: orig_line,
- column: orig_col
+ return {
+ add: function(source, gen_line, gen_col, orig_line, orig_col, name) {
+ var map = maps && maps[source];
+ if (map) {
+ var info = map.originalPositionFor({
+ line: orig_line,
+ column: orig_col
+ });
+ if (info.source === null) return;
+ source = info.source;
+ orig_line = info.line;
+ orig_col = info.column;
+ name = info.name || name;
+ }
+ generator.addMapping({
+ name: name,
+ source: source,
+ generated: {
+ line: gen_line + options.dest_line_diff,
+ column: gen_col
+ },
+ original: {
+ line: orig_line + options.orig_line_diff,
+ column: orig_col
+ }
});
- if (info.source === null) return;
- source = info.source;
- orig_line = info.line;
- orig_col = info.column;
- name = info.name || name;
+ },
+ get: function() {
+ return generator;
+ },
+ toString: function() {
+ return JSON.stringify(generator.toJSON());
}
- generator.addMapping({
- generated : { line: gen_line + options.dest_line_diff, column: gen_col },
- original : { line: orig_line + options.orig_line_diff, column: orig_col },
- source : source,
- name : name
- });
- };
- return {
- add : add,
- get : function() { return generator },
- toString : function() { return JSON.stringify(generator.toJSON()); }
};
-};
+}
diff --git a/lib/transform.js b/lib/transform.js
index 41b24c54..5897aa77 100644
--- a/lib/transform.js
+++ b/lib/transform.js
@@ -43,8 +43,6 @@
"use strict";
-// Tree transformer helpers.
-
function TreeTransformer(before, after) {
TreeWalker.call(this);
this.before = before;
@@ -52,168 +50,136 @@ function TreeTransformer(before, after) {
}
TreeTransformer.prototype = new TreeWalker;
-(function(undefined){
-
- function _(node, descend) {
- node.DEFMETHOD("transform", function(tw, in_list){
- var x, y;
- tw.push(this);
- if (tw.before) x = tw.before(this, descend, in_list);
- if (x === undefined) {
- x = this;
- descend(x, tw);
- if (tw.after) {
- y = tw.after(x, in_list);
- if (y !== undefined) x = y;
- }
- }
- tw.pop();
- return x;
- });
- };
-
+(function(DEF) {
function do_list(list, tw) {
- return MAP(list, function(node){
+ return MAP(list, function(node) {
return node.transform(tw, true);
});
- };
+ }
- _(AST_Node, noop);
-
- _(AST_LabeledStatement, function(self, tw){
+ DEF(AST_Node, noop);
+ DEF(AST_LabeledStatement, function(self, tw) {
self.label = self.label.transform(tw);
self.body = self.body.transform(tw);
});
-
- _(AST_SimpleStatement, function(self, tw){
+ DEF(AST_SimpleStatement, function(self, tw) {
self.body = self.body.transform(tw);
});
-
- _(AST_Block, function(self, tw){
+ DEF(AST_Block, function(self, tw) {
self.body = do_list(self.body, tw);
});
-
- _(AST_Do, function(self, tw){
+ DEF(AST_Do, function(self, tw) {
self.body = self.body.transform(tw);
self.condition = self.condition.transform(tw);
});
-
- _(AST_While, function(self, tw){
+ DEF(AST_While, function(self, tw) {
self.condition = self.condition.transform(tw);
self.body = self.body.transform(tw);
});
-
- _(AST_For, function(self, tw){
+ DEF(AST_For, function(self, tw) {
if (self.init) self.init = self.init.transform(tw);
if (self.condition) self.condition = self.condition.transform(tw);
if (self.step) self.step = self.step.transform(tw);
self.body = self.body.transform(tw);
});
-
- _(AST_ForIn, function(self, tw){
+ DEF(AST_ForIn, function(self, tw) {
self.init = self.init.transform(tw);
self.object = self.object.transform(tw);
self.body = self.body.transform(tw);
});
-
- _(AST_With, function(self, tw){
+ DEF(AST_With, function(self, tw) {
self.expression = self.expression.transform(tw);
self.body = self.body.transform(tw);
});
-
- _(AST_Exit, function(self, tw){
+ DEF(AST_Exit, function(self, tw) {
if (self.value) self.value = self.value.transform(tw);
});
-
- _(AST_LoopControl, function(self, tw){
+ DEF(AST_LoopControl, function(self, tw) {
if (self.label) self.label = self.label.transform(tw);
});
-
- _(AST_If, function(self, tw){
+ DEF(AST_If, function(self, tw) {
self.condition = self.condition.transform(tw);
self.body = self.body.transform(tw);
if (self.alternative) self.alternative = self.alternative.transform(tw);
});
-
- _(AST_Switch, function(self, tw){
+ DEF(AST_Switch, function(self, tw) {
self.expression = self.expression.transform(tw);
self.body = do_list(self.body, tw);
});
-
- _(AST_Case, function(self, tw){
+ DEF(AST_Case, function(self, tw) {
self.expression = self.expression.transform(tw);
self.body = do_list(self.body, tw);
});
-
- _(AST_Try, function(self, tw){
+ DEF(AST_Try, function(self, tw) {
self.body = do_list(self.body, tw);
if (self.bcatch) self.bcatch = self.bcatch.transform(tw);
if (self.bfinally) self.bfinally = self.bfinally.transform(tw);
});
-
- _(AST_Catch, function(self, tw){
+ DEF(AST_Catch, function(self, tw) {
self.argname = self.argname.transform(tw);
self.body = do_list(self.body, tw);
});
-
- _(AST_Definitions, function(self, tw){
+ DEF(AST_Definitions, function(self, tw) {
self.definitions = do_list(self.definitions, tw);
});
-
- _(AST_VarDef, function(self, tw){
+ DEF(AST_VarDef, function(self, tw) {
self.name = self.name.transform(tw);
if (self.value) self.value = self.value.transform(tw);
});
-
- _(AST_Lambda, function(self, tw){
+ DEF(AST_Lambda, function(self, tw) {
if (self.name) self.name = self.name.transform(tw);
self.argnames = do_list(self.argnames, tw);
self.body = do_list(self.body, tw);
});
-
- _(AST_Call, function(self, tw){
+ DEF(AST_Call, function(self, tw) {
self.expression = self.expression.transform(tw);
self.args = do_list(self.args, tw);
});
-
- _(AST_Sequence, function(self, tw){
+ DEF(AST_Sequence, function(self, tw) {
self.expressions = do_list(self.expressions, tw);
});
-
- _(AST_Dot, function(self, tw){
+ DEF(AST_Dot, function(self, tw) {
self.expression = self.expression.transform(tw);
});
-
- _(AST_Sub, function(self, tw){
+ DEF(AST_Sub, function(self, tw) {
self.expression = self.expression.transform(tw);
self.property = self.property.transform(tw);
});
-
- _(AST_Unary, function(self, tw){
+ DEF(AST_Unary, function(self, tw) {
self.expression = self.expression.transform(tw);
});
-
- _(AST_Binary, function(self, tw){
+ DEF(AST_Binary, function(self, tw) {
self.left = self.left.transform(tw);
self.right = self.right.transform(tw);
});
-
- _(AST_Conditional, function(self, tw){
+ DEF(AST_Conditional, function(self, tw) {
self.condition = self.condition.transform(tw);
self.consequent = self.consequent.transform(tw);
self.alternative = self.alternative.transform(tw);
});
-
- _(AST_Array, function(self, tw){
+ DEF(AST_Array, function(self, tw) {
self.elements = do_list(self.elements, tw);
});
-
- _(AST_Object, function(self, tw){
+ DEF(AST_Object, function(self, tw) {
self.properties = do_list(self.properties, tw);
});
-
- _(AST_ObjectProperty, function(self, tw){
+ DEF(AST_ObjectProperty, function(self, tw) {
self.value = self.value.transform(tw);
});
-
-})();
+})(function(node, descend) {
+ node.DEFMETHOD("transform", function(tw, in_list) {
+ var x, y;
+ tw.push(this);
+ if (tw.before) x = tw.before(this, descend, in_list);
+ if (typeof x === "undefined") {
+ x = this;
+ descend(x, tw);
+ if (tw.after) {
+ y = tw.after(x, in_list);
+ if (typeof y !== "undefined") x = y;
+ }
+ }
+ tw.pop();
+ return x;
+ });
+});
diff --git a/lib/utils.js b/lib/utils.js
index d4d28348..ca4b2d4b 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -115,7 +115,7 @@ function return_true() { return true; }
function return_this() { return this; }
function return_null() { return null; }
-var MAP = (function(){
+var MAP = (function() {
function MAP(a, f, backwards) {
var ret = [], top = [], i;
function doit() {
@@ -138,7 +138,7 @@ var MAP = (function(){
}
}
return is_last;
- };
+ }
if (Array.isArray(a)) {
if (backwards) {
for (i = a.length; --i >= 0;) if (doit()) break;
@@ -152,14 +152,14 @@ var MAP = (function(){
for (i in a) if (HOP(a, i)) if (doit()) break;
}
return top.concat(ret);
- };
+ }
MAP.at_top = function(val) { return new AtTop(val) };
MAP.splice = function(val) { return new Splice(val) };
MAP.last = function(val) { return new Last(val) };
var skip = MAP.skip = {};
- function AtTop(val) { this.v = val };
- function Splice(val) { this.v = val };
- function Last(val) { this.v = val };
+ function AtTop(val) { this.v = val }
+ function Splice(val) { this.v = val }
+ function Last(val) { this.v = val }
return MAP;
})();
@@ -169,7 +169,7 @@ function push_uniq(array, el) {
}
function string_template(text, props) {
- return text.replace(/\{(.+?)\}/g, function(str, p){
+ return text.replace(/\{(.+?)\}/g, function(str, p) {
return props && props[p];
});
}