improve handling of non-trivial assignment values (#5227)
This commit is contained in:
335
lib/compress.js
335
lib/compress.js
@@ -1397,9 +1397,7 @@ Compressor.prototype.compress = function(node) {
|
||||
operator: "+",
|
||||
expression: make_ref(exp, fixed)
|
||||
}),
|
||||
right: make_node(AST_Number, node, {
|
||||
value: 1
|
||||
})
|
||||
right: make_node(AST_Number, node, { value: 1 }),
|
||||
});
|
||||
};
|
||||
d.fixed.assigns = fixed && fixed.assigns ? fixed.assigns.slice() : [];
|
||||
@@ -1410,7 +1408,7 @@ Compressor.prototype.compress = function(node) {
|
||||
exp.fixed = function() {
|
||||
return make_node(AST_UnaryPrefix, node, {
|
||||
operator: "+",
|
||||
expression: make_ref(exp, fixed)
|
||||
expression: make_ref(exp, fixed),
|
||||
});
|
||||
};
|
||||
exp.fixed.assigns = fixed && fixed.assigns;
|
||||
@@ -1501,11 +1499,11 @@ Compressor.prototype.compress = function(node) {
|
||||
var fixed = this.definition().fixed;
|
||||
if (fixed) {
|
||||
if (this.fixed) fixed = this.fixed;
|
||||
return fixed instanceof AST_Node ? fixed : fixed();
|
||||
return (fixed instanceof AST_Node ? fixed : fixed()).tail_node();
|
||||
}
|
||||
fixed = fixed === 0 && this.fixed;
|
||||
if (!fixed) return fixed;
|
||||
var value = fixed instanceof AST_Node ? fixed : fixed();
|
||||
var value = (fixed instanceof AST_Node ? fixed : fixed()).tail_node();
|
||||
return value.is_constant() && value;
|
||||
});
|
||||
|
||||
@@ -1699,7 +1697,7 @@ Compressor.prototype.compress = function(node) {
|
||||
|
||||
function merge_sequence(array, node) {
|
||||
if (node instanceof AST_Sequence) {
|
||||
array.push.apply(array, node.expressions);
|
||||
[].push.apply(array, node.expressions);
|
||||
} else {
|
||||
array.push(node);
|
||||
}
|
||||
@@ -1813,6 +1811,31 @@ Compressor.prototype.compress = function(node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Certain combination of unused name + side effect leads to invalid AST:
|
||||
// https://github.com/mishoo/UglifyJS/issues/44
|
||||
// https://github.com/mishoo/UglifyJS/issues/1838
|
||||
// https://github.com/mishoo/UglifyJS/issues/3371
|
||||
// We fix it at this stage by moving the `var` outside the `for`.
|
||||
function patch_for_init(node, in_list) {
|
||||
var block;
|
||||
if (node.init instanceof AST_BlockStatement) {
|
||||
block = node.init;
|
||||
node.init = block.body.pop();
|
||||
block.body.push(node);
|
||||
}
|
||||
if (node.init instanceof AST_Defun) {
|
||||
if (!block) block = make_node(AST_BlockStatement, node, { body: [ node ] });
|
||||
block.body.splice(-1, 0, node.init);
|
||||
node.init = null;
|
||||
} else if (node.init instanceof AST_SimpleStatement) {
|
||||
node.init = node.init.body;
|
||||
} else if (is_empty(node.init)) {
|
||||
node.init = null;
|
||||
}
|
||||
if (!block) return;
|
||||
return in_list ? List.splice(block.body) : block;
|
||||
}
|
||||
|
||||
function tighten_body(statements, compressor) {
|
||||
var in_lambda = last_of(compressor, function(node) {
|
||||
return node instanceof AST_Lambda;
|
||||
@@ -1972,12 +1995,12 @@ Compressor.prototype.compress = function(node) {
|
||||
var def = candidate.name.definition();
|
||||
if (def.references.length - def.replaced == 1 && !compressor.exposed(def)) {
|
||||
def.replaced++;
|
||||
return maintain_this_binding(compressor, parent, node, candidate.value);
|
||||
return maintain_this_binding(compressor, parent, node, rvalue);
|
||||
}
|
||||
return make_node(AST_Assign, candidate, {
|
||||
operator: "=",
|
||||
left: make_node(AST_SymbolRef, candidate.name, candidate.name),
|
||||
right: candidate.value,
|
||||
right: rvalue,
|
||||
});
|
||||
}
|
||||
var assign = candidate;
|
||||
@@ -1986,7 +2009,9 @@ Compressor.prototype.compress = function(node) {
|
||||
if (!(assign instanceof AST_Assign)) break;
|
||||
assign = assign.right;
|
||||
}
|
||||
return candidate;
|
||||
assign = candidate.clone();
|
||||
assign.right = rvalue;
|
||||
return assign;
|
||||
}
|
||||
// These node types have child nodes that execute sequentially,
|
||||
// but are otherwise not safe to scan into or beyond them.
|
||||
@@ -2083,7 +2108,9 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
// Skip (non-executed) functions and (leading) default case in switch statements
|
||||
if (node instanceof AST_Default || node instanceof AST_Scope) return node;
|
||||
}, patch_sequence);
|
||||
}, function(node) {
|
||||
return patch_sequence(node, multi_replacer);
|
||||
});
|
||||
while (--stat_index >= 0) {
|
||||
// Treat parameters as collapsible in IIFE, i.e.
|
||||
// function(a, b){ ... }(x());
|
||||
@@ -2122,7 +2149,14 @@ Compressor.prototype.compress = function(node) {
|
||||
var well_defined = true;
|
||||
var lvalues = get_lvalues(candidate);
|
||||
var lhs_local = is_lhs_local(lhs);
|
||||
var rvalue = get_rvalue(candidate);
|
||||
var rhs_value = get_rvalue(candidate);
|
||||
var rvalue;
|
||||
if (rhs_value instanceof AST_Sequence
|
||||
&& !(candidate instanceof AST_Assign && candidate.operator != "=")) {
|
||||
rvalue = rhs_value.tail_node();
|
||||
} else {
|
||||
rvalue = rhs_value;
|
||||
}
|
||||
if (!side_effects) side_effects = value_has_side_effects();
|
||||
var check_destructured = in_try || !lhs_local ? function(node) {
|
||||
return node instanceof AST_Destructured;
|
||||
@@ -2163,7 +2197,7 @@ Compressor.prototype.compress = function(node) {
|
||||
value_def.single_use = false;
|
||||
changed = true;
|
||||
}
|
||||
if (replaced && !remove_candidate(candidate)) statements.splice(stat_index, 1);
|
||||
if (replaced) remove_candidate(candidate);
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
@@ -2768,6 +2802,7 @@ Compressor.prototype.compress = function(node) {
|
||||
return;
|
||||
}
|
||||
if (remaining < 1) return;
|
||||
rhs = rhs.tail_node();
|
||||
var value = rhs instanceof AST_Assign && rhs.operator == "=" ? rhs.left : rhs;
|
||||
if (!(value instanceof AST_SymbolRef)) return;
|
||||
var def = value.definition();
|
||||
@@ -3002,24 +3037,21 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
|
||||
function remove_candidate(expr) {
|
||||
var value = rvalue === rhs_value ? null : make_sequence(rhs_value, rhs_value.expressions.slice(0, -1));
|
||||
var index = expr.name_index;
|
||||
if (index >= 0) {
|
||||
var argname = scope.argnames[index];
|
||||
if (argname instanceof AST_DefaultValue) {
|
||||
argname.value = make_node(AST_Number, argname, {
|
||||
value: 0
|
||||
});
|
||||
argname.value = value || make_node(AST_Number, argname, { value: 0 });
|
||||
argname.name.definition().fixed = false;
|
||||
} else {
|
||||
var args = compressor.parent().args;
|
||||
if (args[index]) {
|
||||
args[index] = make_node(AST_Number, args[index], {
|
||||
value: 0
|
||||
});
|
||||
args[index] = value || make_node(AST_Number, args[index], { value: 0 });
|
||||
argname.definition().fixed = false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
var end = hit_stack.length - 1;
|
||||
if (hit_stack[end - 1].body === hit_stack[end]) end--;
|
||||
@@ -3034,20 +3066,46 @@ Compressor.prototype.compress = function(node) {
|
||||
if (value_def) value_def.replaced++;
|
||||
node = node.clone();
|
||||
node.value = null;
|
||||
return node;
|
||||
return value ? List.splice([ value, node ]) : node;
|
||||
}
|
||||
return in_list ? List.skip : null;
|
||||
}, patch_sequence);
|
||||
if (!value) return in_list ? List.skip : null;
|
||||
return is_statement(node) ? make_node(AST_SimpleStatement, value, { body: value }) : value;
|
||||
}, function(node, in_list) {
|
||||
if (node instanceof AST_Definitions) {
|
||||
var body = [], defns = node.definitions;
|
||||
for (var index = 0, pos = 0; index < defns.length; index++) {
|
||||
var defn = defns[index];
|
||||
if (defn instanceof AST_VarDef) continue;
|
||||
flush();
|
||||
pos = index + 1;
|
||||
body.push(make_node(AST_SimpleStatement, defn, { body: defn }));
|
||||
}
|
||||
if (pos == 0) return;
|
||||
flush();
|
||||
if (body.length == 1) return body[0];
|
||||
return in_list ? List.splice(body) : make_node(AST_BlockStatement, node, { body: body });
|
||||
}
|
||||
if (node instanceof AST_For) return patch_for_init(node, in_list);
|
||||
return patch_sequence(node, this);
|
||||
|
||||
function flush() {
|
||||
if (pos < index) {
|
||||
var cropped = node.clone();
|
||||
cropped.definitions = defns.slice(pos, index);
|
||||
body.push(cropped);
|
||||
}
|
||||
}
|
||||
});
|
||||
abort = false;
|
||||
hit = false;
|
||||
hit_index = 0;
|
||||
return statements[stat_index].transform(tt);
|
||||
if (!(statements[stat_index] = statements[stat_index].transform(tt))) statements.splice(stat_index, 1);
|
||||
}
|
||||
|
||||
function patch_sequence(node) {
|
||||
function patch_sequence(node, tt) {
|
||||
if (node instanceof AST_Sequence) switch (node.expressions.length) {
|
||||
case 0: return null;
|
||||
case 1: return maintain_this_binding(compressor, this.parent(), node, node.expressions[0]);
|
||||
case 1: return maintain_this_binding(compressor, tt.parent(), node, node.expressions[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3779,11 +3837,18 @@ Compressor.prototype.compress = function(node) {
|
||||
} else if (stat instanceof AST_If) {
|
||||
stat.condition = join_assigns_expr(stat.condition);
|
||||
} else if (stat instanceof AST_SimpleStatement) {
|
||||
var exprs = join_assigns(prev, stat.body);
|
||||
var exprs = join_assigns(prev, stat.body), next;
|
||||
if (exprs) {
|
||||
changed = true;
|
||||
if (!exprs.length) continue;
|
||||
stat.body = make_sequence(stat.body, exprs);
|
||||
} else if (prev instanceof AST_Definitions
|
||||
&& (next = statements[i + 1])
|
||||
&& prev.TYPE == next.TYPE
|
||||
&& (next = next.definitions[0]).value) {
|
||||
changed = true;
|
||||
next.value = make_sequence(stat, [ stat.body, next.value ]);
|
||||
continue;
|
||||
}
|
||||
} else if (stat instanceof AST_Switch) {
|
||||
stat.expression = join_assigns_expr(stat.expression);
|
||||
@@ -6690,7 +6755,7 @@ Compressor.prototype.compress = function(node) {
|
||||
value = null;
|
||||
trim_defns.push(def);
|
||||
}
|
||||
var old_def;
|
||||
var old_def, fn;
|
||||
if (!value && !(node instanceof AST_Let)) {
|
||||
if (parent instanceof AST_ExportDeclaration) {
|
||||
flush();
|
||||
@@ -6704,17 +6769,18 @@ Compressor.prototype.compress = function(node) {
|
||||
} else if (compressor.option("functions")
|
||||
&& !compressor.option("ie")
|
||||
&& drop_sym
|
||||
&& value
|
||||
&& var_defs[sym.id] == 1
|
||||
&& sym.assignments == 0
|
||||
&& value instanceof AST_LambdaExpression
|
||||
&& (fn = value.tail_node()) instanceof AST_LambdaExpression
|
||||
&& !is_arguments(sym)
|
||||
&& !is_arrow(value)
|
||||
&& assigned_once(value, sym.references)
|
||||
&& can_declare_defun(value)
|
||||
&& (old_def = rename_def(value, def.name.name)) !== false) {
|
||||
&& !is_arrow(fn)
|
||||
&& assigned_once(fn, sym.references)
|
||||
&& can_declare_defun(fn)
|
||||
&& (old_def = rename_def(fn, def.name.name)) !== false) {
|
||||
AST_Node.warn("Declaring {name} as function [{file}:{line},{col}]", template(def.name));
|
||||
var ctor;
|
||||
switch (value.CTOR) {
|
||||
switch (fn.CTOR) {
|
||||
case AST_AsyncFunction:
|
||||
ctor = AST_AsyncDefun;
|
||||
break;
|
||||
@@ -6728,7 +6794,7 @@ Compressor.prototype.compress = function(node) {
|
||||
ctor = AST_GeneratorDefun;
|
||||
break;
|
||||
}
|
||||
var defun = make_node(ctor, def, value);
|
||||
var defun = make_node(ctor, def, fn);
|
||||
defun.name = make_node(AST_SymbolDefun, def.name, def.name);
|
||||
var name_def = def.name.scope.resolve().def_function(defun.name);
|
||||
if (old_def) old_def.forEach(function(node) {
|
||||
@@ -6737,6 +6803,7 @@ Compressor.prototype.compress = function(node) {
|
||||
node.reference();
|
||||
});
|
||||
body.push(defun);
|
||||
if (value !== fn) [].push.apply(side_effects, value.expressions.slice(0, -1));
|
||||
} else {
|
||||
if (drop_sym
|
||||
&& var_defs[sym.id] > 1
|
||||
@@ -6759,7 +6826,7 @@ Compressor.prototype.compress = function(node) {
|
||||
head.push(def);
|
||||
}
|
||||
} else {
|
||||
value = value && !value.single_use && value.drop_side_effect_free(compressor);
|
||||
value = value && value.drop_side_effect_free(compressor);
|
||||
if (value) {
|
||||
AST_Node.warn("Side effects in initialization of unused variable {name} [{file}:{line},{col}]", template(def.name));
|
||||
side_effects.push(value);
|
||||
@@ -6867,13 +6934,18 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
}
|
||||
default:
|
||||
var seq;
|
||||
if (tail.length > 0 && (seq = tail[0].value) instanceof AST_Sequence) {
|
||||
tail[0].value = seq.tail_node();
|
||||
body.push(make_node(AST_SimpleStatement, node, {
|
||||
body: make_sequence(seq, seq.expressions.slice(0, -1)),
|
||||
}));
|
||||
}
|
||||
node.definitions = head.concat(tail);
|
||||
body.push(node);
|
||||
}
|
||||
if (side_effects.length > 0) {
|
||||
body.push(make_node(AST_SimpleStatement, node, {
|
||||
body: make_sequence(node, side_effects)
|
||||
}));
|
||||
body.push(make_node(AST_SimpleStatement, node, { body: make_sequence(node, side_effects) }));
|
||||
}
|
||||
return insert_statements(body, node, in_list);
|
||||
}
|
||||
@@ -6922,33 +6994,7 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
}, function(node, in_list) {
|
||||
if (node instanceof AST_BlockStatement) return trim_block(node, tt.parent(), in_list);
|
||||
// Certain combination of unused name + side effect leads to invalid AST:
|
||||
// https://github.com/mishoo/UglifyJS/issues/44
|
||||
// https://github.com/mishoo/UglifyJS/issues/1838
|
||||
// https://github.com/mishoo/UglifyJS/issues/3371
|
||||
// We fix it at this stage by moving the `var` outside the `for`.
|
||||
if (node instanceof AST_For) {
|
||||
var block;
|
||||
if (node.init instanceof AST_BlockStatement) {
|
||||
block = node.init;
|
||||
node.init = block.body.pop();
|
||||
block.body.push(node);
|
||||
}
|
||||
if (node.init instanceof AST_Defun) {
|
||||
if (!block) {
|
||||
block = make_node(AST_BlockStatement, node, {
|
||||
body: [ node ]
|
||||
});
|
||||
}
|
||||
block.body.splice(-1, 0, node.init);
|
||||
node.init = null;
|
||||
} else if (node.init instanceof AST_SimpleStatement) {
|
||||
node.init = node.init.body;
|
||||
} else if (is_empty(node.init)) {
|
||||
node.init = null;
|
||||
}
|
||||
return !block ? node : in_list ? List.splice(block.body) : block;
|
||||
}
|
||||
if (node instanceof AST_For) return patch_for_init(node, in_list);
|
||||
if (node instanceof AST_ForIn) {
|
||||
if (!drop_vars || !compressor.option("loops")) return;
|
||||
if (!is_empty(node.body)) return;
|
||||
@@ -8749,15 +8795,21 @@ Compressor.prototype.compress = function(node) {
|
||||
var body = [], var_defs = [], refs = [];
|
||||
var body_exprs = sequencesize(self.body, body, var_defs, refs);
|
||||
var alt_exprs = sequencesize(self.alternative, body, var_defs, refs);
|
||||
if (body_exprs && alt_exprs) {
|
||||
if (body_exprs instanceof AST_BlockStatement || alt_exprs instanceof AST_BlockStatement) {
|
||||
if (var_defs.length > 0) body.push(make_node(AST_Var, self, { definitions: var_defs }));
|
||||
body.push(self);
|
||||
if (body_exprs instanceof AST_BlockStatement) self.body = body_exprs;
|
||||
if (alt_exprs instanceof AST_BlockStatement) self.alternative = alt_exprs;
|
||||
return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
|
||||
} else if (body_exprs && alt_exprs) {
|
||||
if (var_defs.length > 0) body.push(make_node(AST_Var, self, { definitions: var_defs }));
|
||||
if (body_exprs.length == 0) {
|
||||
body.push(make_node(AST_SimpleStatement, self.condition, {
|
||||
body: alt_exprs.length > 0 ? make_node(AST_Binary, self, {
|
||||
operator : "||",
|
||||
left : self.condition,
|
||||
right : make_sequence(self.alternative, alt_exprs)
|
||||
}).transform(compressor) : self.condition.clone()
|
||||
operator: "||",
|
||||
left: self.condition,
|
||||
right: make_sequence(self.alternative, alt_exprs),
|
||||
}).transform(compressor) : self.condition.clone(),
|
||||
}).optimize(compressor));
|
||||
} else if (alt_exprs.length == 0) {
|
||||
if (self_condition_length === negated_length && !negated_is_best
|
||||
@@ -8769,79 +8821,64 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
body.push(make_node(AST_SimpleStatement, self, {
|
||||
body: make_node(AST_Binary, self, {
|
||||
operator : negated_is_best ? "||" : "&&",
|
||||
left : negated_is_best ? negated : self.condition,
|
||||
right : make_sequence(self.body, body_exprs)
|
||||
}).transform(compressor)
|
||||
operator: negated_is_best ? "||" : "&&",
|
||||
left: negated_is_best ? negated : self.condition,
|
||||
right: make_sequence(self.body, body_exprs),
|
||||
}).transform(compressor),
|
||||
}).optimize(compressor));
|
||||
} else {
|
||||
body.push(make_node(AST_SimpleStatement, self, {
|
||||
body: make_node(AST_Conditional, self, {
|
||||
condition : self.condition,
|
||||
consequent : make_sequence(self.body, body_exprs),
|
||||
alternative : make_sequence(self.alternative, alt_exprs)
|
||||
})
|
||||
condition: self.condition,
|
||||
consequent: make_sequence(self.body, body_exprs),
|
||||
alternative: make_sequence(self.alternative, alt_exprs),
|
||||
}),
|
||||
}).optimize(compressor));
|
||||
}
|
||||
refs.forEach(function(ref) {
|
||||
ref.definition().references.push(ref);
|
||||
});
|
||||
return make_node(AST_BlockStatement, self, {
|
||||
body: body
|
||||
}).optimize(compressor);
|
||||
return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
|
||||
}
|
||||
if (is_empty(self.body)) {
|
||||
self = make_node(AST_If, self, {
|
||||
condition: negated,
|
||||
body: self.alternative,
|
||||
alternative: null
|
||||
});
|
||||
}
|
||||
if (self.body instanceof AST_Exit
|
||||
&& self.alternative instanceof AST_Exit
|
||||
&& self.body.TYPE == self.alternative.TYPE) {
|
||||
if (is_empty(self.body)) self = make_node(AST_If, self, {
|
||||
condition: negated,
|
||||
body: self.alternative,
|
||||
alternative: null,
|
||||
});
|
||||
if (self.alternative instanceof AST_Exit && self.body.TYPE == self.alternative.TYPE) {
|
||||
var exit = make_node(self.body.CTOR, self, {
|
||||
value: make_node(AST_Conditional, self, {
|
||||
condition : self.condition,
|
||||
consequent : self.body.value || make_node(AST_Undefined, self.body).transform(compressor),
|
||||
alternative : self.alternative.value || make_node(AST_Undefined, self.alternative).transform(compressor)
|
||||
})
|
||||
condition: self.condition,
|
||||
consequent: self.body.value || make_node(AST_Undefined, self.body).transform(compressor),
|
||||
alternative: self.alternative.value
|
||||
|| make_node(AST_Undefined, self.alternative).transform(compressor),
|
||||
}),
|
||||
});
|
||||
if (exit instanceof AST_Return) {
|
||||
exit.in_bool = self.body.in_bool || self.alternative.in_bool;
|
||||
}
|
||||
if (exit instanceof AST_Return) exit.in_bool = self.body.in_bool || self.alternative.in_bool;
|
||||
return exit;
|
||||
}
|
||||
if (self.body instanceof AST_If
|
||||
&& !self.body.alternative
|
||||
&& !self.alternative) {
|
||||
if (self.body instanceof AST_If && !self.body.alternative && !self.alternative) {
|
||||
self = make_node(AST_If, self, {
|
||||
condition: make_node(AST_Binary, self.condition, {
|
||||
operator: "&&",
|
||||
left: self.condition,
|
||||
right: self.body.condition
|
||||
right: self.body.condition,
|
||||
}),
|
||||
body: self.body.body,
|
||||
alternative: null
|
||||
alternative: null,
|
||||
});
|
||||
}
|
||||
if (aborts(self.body)) {
|
||||
if (self.alternative) {
|
||||
var alt = self.alternative;
|
||||
self.alternative = null;
|
||||
return make_node(AST_BlockStatement, self, {
|
||||
body: [ self, alt ]
|
||||
}).optimize(compressor);
|
||||
}
|
||||
if (aborts(self.body) && self.alternative) {
|
||||
var alt = self.alternative;
|
||||
self.alternative = null;
|
||||
return make_node(AST_BlockStatement, self, { body: [ self, alt ] }).optimize(compressor);
|
||||
}
|
||||
if (aborts(self.alternative)) {
|
||||
var body = self.body;
|
||||
self.body = self.alternative;
|
||||
self.condition = negated_is_best ? negated : self.condition.negate(compressor);
|
||||
self.alternative = null;
|
||||
return make_node(AST_BlockStatement, self, {
|
||||
body: [ self, body ]
|
||||
}).optimize(compressor);
|
||||
return make_node(AST_BlockStatement, self, { body: [ self, body ] }).optimize(compressor);
|
||||
}
|
||||
if (compressor.option("typeofs")) mark_locally_defined(self.condition, self.body, self.alternative);
|
||||
return self;
|
||||
@@ -8852,10 +8889,19 @@ Compressor.prototype.compress = function(node) {
|
||||
var exprs = [];
|
||||
for (var i = 0; i < stat.body.length; i++) {
|
||||
var line = stat.body[i];
|
||||
if (line instanceof AST_EmptyStatement) continue;
|
||||
if (line instanceof AST_Exit) {
|
||||
if (exprs.length == 0) return;
|
||||
line = line.clone();
|
||||
exprs.push(line.value || make_node(AST_Undefined, line).transform(compressor));
|
||||
line.value = make_sequence(stat, exprs);
|
||||
var block = stat.clone();
|
||||
block.body = block.body.slice(i + 1);
|
||||
block.body.unshift(line);
|
||||
return block;
|
||||
}
|
||||
if (line instanceof AST_LambdaDefinition) {
|
||||
defuns.push(line);
|
||||
} else if (line instanceof AST_EmptyStatement) {
|
||||
continue;
|
||||
} else if (line instanceof AST_SimpleStatement) {
|
||||
if (!compressor.option("sequences") && exprs.length > 0) return;
|
||||
exprs.push(line.body);
|
||||
@@ -9320,9 +9366,7 @@ Compressor.prototype.compress = function(node) {
|
||||
args[pos++] = make_sequence(call, side_effects);
|
||||
side_effects = [];
|
||||
} else {
|
||||
args[pos++] = make_node(AST_Number, args[i], {
|
||||
value: 0
|
||||
});
|
||||
args[pos++] = make_node(AST_Number, args[i], { value: 0 });
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -9924,10 +9968,14 @@ Compressor.prototype.compress = function(node) {
|
||||
for (var i = 0; i < len; i++) {
|
||||
var line = fn.body[i];
|
||||
if (line instanceof AST_Var) {
|
||||
var assigned = var_assigned || !declarations_only(line);
|
||||
if (assigned) {
|
||||
if (var_assigned) {
|
||||
if (!stat) continue;
|
||||
if (!(stat instanceof AST_SimpleStatement)) return false;
|
||||
if (!declarations_only(line)) stat = null;
|
||||
} else if (!declarations_only(line)) {
|
||||
if (stat && !(stat instanceof AST_SimpleStatement)) return false;
|
||||
stat = null;
|
||||
var_assigned = true;
|
||||
if (stat) return false;
|
||||
}
|
||||
} else if (line instanceof AST_AsyncDefun
|
||||
|| line instanceof AST_Defun
|
||||
@@ -10191,7 +10239,7 @@ Compressor.prototype.compress = function(node) {
|
||||
|
||||
function flatten_vars(decls, expressions) {
|
||||
var args = [ insert, 0 ];
|
||||
var decl_var = [], expr_var = [], expr_loop = [];
|
||||
var decl_var = [], expr_var = [], expr_loop = [], exprs = [];
|
||||
for (var i = 0; i < fn.body.length; i++) {
|
||||
var stat = fn.body[i];
|
||||
if (stat instanceof AST_LambdaDefinition) {
|
||||
@@ -10209,11 +10257,20 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!(stat instanceof AST_Var)) continue;
|
||||
if (!(stat instanceof AST_Var)) {
|
||||
if (stat instanceof AST_SimpleStatement) exprs.push(stat.body);
|
||||
continue;
|
||||
}
|
||||
for (var j = 0; j < stat.definitions.length; j++) {
|
||||
var var_def = stat.definitions[j];
|
||||
var name = flatten_var(var_def.name);
|
||||
append_var(decl_var, expr_var, name, var_def.value);
|
||||
var value = var_def.value;
|
||||
if (value && exprs.length > 0) {
|
||||
exprs.push(value);
|
||||
value = make_sequence(var_def, exprs);
|
||||
exprs = [];
|
||||
}
|
||||
append_var(decl_var, expr_var, name, value);
|
||||
if (in_loop && !arg_used.has(name.name)) {
|
||||
var def = fn.variables.get(name.name);
|
||||
var sym = make_node(AST_SymbolRef, name, name);
|
||||
@@ -12211,9 +12268,7 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
|
||||
function pop_seq(node) {
|
||||
if (!(node instanceof AST_Sequence)) return make_node(AST_Number, node, {
|
||||
value: 0
|
||||
});
|
||||
if (!(node instanceof AST_Sequence)) return make_node(AST_Number, node, { value: 0 });
|
||||
return make_sequence(node, node.expressions.slice(0, -1));
|
||||
}
|
||||
});
|
||||
@@ -12526,35 +12581,25 @@ Compressor.prototype.compress = function(node) {
|
||||
var exp = self.expression.expression;
|
||||
if (is_undeclared_ref(exp)) switch (exp.name) {
|
||||
case "Array":
|
||||
self.expression = make_node(AST_Array, self.expression, {
|
||||
elements: []
|
||||
});
|
||||
self.expression = make_node(AST_Array, self.expression, { elements: [] });
|
||||
break;
|
||||
case "Function":
|
||||
self.expression = make_node(AST_Function, self.expression, {
|
||||
argnames: [],
|
||||
body: []
|
||||
body: [],
|
||||
}).init_vars(exp.scope);
|
||||
break;
|
||||
case "Number":
|
||||
self.expression = make_node(AST_Number, self.expression, {
|
||||
value: 0
|
||||
});
|
||||
self.expression = make_node(AST_Number, self.expression, { value: 0 });
|
||||
break;
|
||||
case "Object":
|
||||
self.expression = make_node(AST_Object, self.expression, {
|
||||
properties: []
|
||||
});
|
||||
self.expression = make_node(AST_Object, self.expression, { properties: [] });
|
||||
break;
|
||||
case "RegExp":
|
||||
self.expression = make_node(AST_RegExp, self.expression, {
|
||||
value: /t/
|
||||
});
|
||||
self.expression = make_node(AST_RegExp, self.expression, { value: /t/ });
|
||||
break;
|
||||
case "String":
|
||||
self.expression = make_node(AST_String, self.expression, {
|
||||
value: ""
|
||||
});
|
||||
self.expression = make_node(AST_String, self.expression, { value: "" });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user