return self;
});
- AST_Scope.DEFMETHOD("make_var_name", function(prefix) {
- var var_names = this.var_names;
+ AST_Scope.DEFMETHOD("var_names", function() {
+ var var_names = this._var_names;
if (!var_names) {
- this.var_names = var_names = Object.create(null);
+ this._var_names = var_names = Object.create(null);
this.enclosed.forEach(function(def) {
var_names[def.name] = true;
});
var_names[name] = true;
});
}
+ return var_names;
+ });
+
+ AST_Scope.DEFMETHOD("make_var_name", function(prefix) {
+ var var_names = this.var_names();
prefix = prefix.replace(/[^a-z_$]+/ig, "_");
var name = prefix;
for (var i = 0; var_names[name]; i++) name = prefix + "$" + i;
}
}
if (fn instanceof AST_Function) {
- var def;
+ var def, scope, value;
if (compressor.option("inline")
&& !fn.uses_arguments
&& !fn.uses_eval
: compressor.option("unused")
&& (def = exp.definition()).references.length == 1
&& !recursive_ref(compressor, def))
+ && !self.has_pure_annotation(compressor)
&& !fn.contains_this()
- && all(fn.argnames, function(arg) {
- return arg.__unused;
- })
- && !self.has_pure_annotation(compressor)) {
- var value;
- if (stat instanceof AST_Return) {
- value = stat.value;
- } else if (stat instanceof AST_SimpleStatement) {
- value = make_node(AST_UnaryPrefix, stat, {
- operator: "void",
- expression: stat.body
- });
- }
- if (value) {
- var args = self.args.concat(value);
- return make_sequence(self, args).optimize(compressor);
- }
+ && (scope = can_flatten_args(fn))
+ && (value = flatten_body(stat))) {
+ var expressions = flatten_args(fn, scope);
+ expressions.push(value);
+ return make_sequence(self, expressions).optimize(compressor);
}
if (compressor.option("side_effects") && all(fn.body, is_empty)) {
var args = self.args.concat(make_node(AST_Undefined, self));
return best_of(compressor, ev, self);
}
return self;
+
+ function can_flatten_args(fn) {
+ var scope = compressor.find_parent(AST_Scope);
+ var safe_to_inject = compressor.toplevel.vars || !(scope instanceof AST_Toplevel);
+ return all(fn.argnames, function(arg) {
+ return arg.__unused || safe_to_inject && !scope.var_names()[arg.name];
+ }) && scope;
+ }
+
+ function flatten_args(fn, scope) {
+ var decls = [];
+ var expressions = [];
+ for (var len = fn.argnames.length, i = len; --i >= 0;) {
+ var name = fn.argnames[i];
+ var value = self.args[i];
+ if (name.__unused) {
+ if (value || expressions.length) {
+ expressions.unshift(value || make_node(AST_Undefined, self));
+ }
+ } else {
+ decls.unshift(make_node(AST_VarDef, name, {
+ name: name,
+ value: null
+ }));
+ var sym = make_node(AST_SymbolRef, name, name);
+ name.definition().references.push(sym);
+ expressions.unshift(make_node(AST_Assign, self, {
+ operator: "=",
+ left: sym,
+ right: value || make_node(AST_Undefined, self)
+ }));
+ }
+ }
+ for (i = len, len = self.args.length; i < len; i++) {
+ expressions.push(self.args[i]);
+ }
+ if (decls.length) {
+ for (i = 0; compressor.parent(i) !== scope;) i++;
+ i = scope.body.indexOf(compressor.parent(i - 1)) + 1;
+ scope.body.splice(i, 0, make_node(AST_Var, fn, {
+ definitions: decls
+ }));
+ }
+ return expressions;
+ }
+
+ function flatten_body(stat) {
+ if (stat instanceof AST_Return) {
+ return stat.value;
+ } else if (stat instanceof AST_SimpleStatement) {
+ return make_node(AST_UnaryPrefix, stat, {
+ operator: "void",
+ expression: stat.body
+ });
+ }
+ }
});
OPT(AST_New, function(self, compressor){