support logical assignment operators (#4813)
This commit is contained in:
@@ -821,35 +821,19 @@ merge(Compressor.prototype, {
|
|||||||
} else if (!(left instanceof AST_Destructured || left instanceof AST_SymbolRef)) {
|
} else if (!(left instanceof AST_Destructured || left instanceof AST_SymbolRef)) {
|
||||||
mark_assignment_to_arguments(left);
|
mark_assignment_to_arguments(left);
|
||||||
return;
|
return;
|
||||||
} else if (node.operator == "=") {
|
} else switch (node.operator) {
|
||||||
node.right.walk(tw);
|
case "=":
|
||||||
scan_declaration(tw, compressor, left, function() {
|
walk_assign();
|
||||||
return node.right;
|
break;
|
||||||
}, function(sym, fixed, walk) {
|
case "&&=":
|
||||||
if (!(sym instanceof AST_SymbolRef)) {
|
case "||=":
|
||||||
mark_assignment_to_arguments(sym);
|
case "??=":
|
||||||
walk();
|
left.walk(tw);
|
||||||
return;
|
push(tw);
|
||||||
}
|
walk_assign();
|
||||||
var d = sym.definition();
|
pop(tw);
|
||||||
d.assignments++;
|
break;
|
||||||
if (fixed
|
default:
|
||||||
&& !is_modified(compressor, tw, node, node.right, 0)
|
|
||||||
&& !sym.in_arg
|
|
||||||
&& safe_to_assign(tw, d)) {
|
|
||||||
push_ref(d, sym);
|
|
||||||
mark(tw, d);
|
|
||||||
if (d.single_use && left instanceof AST_Destructured) d.single_use = false;
|
|
||||||
tw.loop_ids[d.id] = tw.in_loop;
|
|
||||||
mark_escaped(tw, d, sym.scope, node, node.right, 0, 1);
|
|
||||||
sym.fixed = d.fixed = fixed;
|
|
||||||
sym.fixed.assigns = [ node ];
|
|
||||||
} else {
|
|
||||||
walk();
|
|
||||||
d.fixed = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
var d = left.definition();
|
var d = left.definition();
|
||||||
d.assignments++;
|
d.assignments++;
|
||||||
var fixed = d.fixed;
|
var fixed = d.fixed;
|
||||||
@@ -900,6 +884,36 @@ merge(Compressor.prototype, {
|
|||||||
lhs.walk(tw);
|
lhs.walk(tw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function walk_assign() {
|
||||||
|
node.right.walk(tw);
|
||||||
|
scan_declaration(tw, compressor, left, function() {
|
||||||
|
return node.right;
|
||||||
|
}, function(sym, fixed, walk) {
|
||||||
|
if (!(sym instanceof AST_SymbolRef)) {
|
||||||
|
mark_assignment_to_arguments(sym);
|
||||||
|
walk();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var d = sym.definition();
|
||||||
|
d.assignments++;
|
||||||
|
if (fixed
|
||||||
|
&& !is_modified(compressor, tw, node, node.right, 0)
|
||||||
|
&& !sym.in_arg
|
||||||
|
&& safe_to_assign(tw, d)) {
|
||||||
|
push_ref(d, sym);
|
||||||
|
mark(tw, d);
|
||||||
|
if (d.single_use && left instanceof AST_Destructured) d.single_use = false;
|
||||||
|
tw.loop_ids[d.id] = tw.in_loop;
|
||||||
|
mark_escaped(tw, d, sym.scope, node, node.right, 0, 1);
|
||||||
|
sym.fixed = d.fixed = fixed;
|
||||||
|
sym.fixed.assigns = [ node ];
|
||||||
|
} else {
|
||||||
|
walk();
|
||||||
|
d.fixed = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
def(AST_Binary, function(tw) {
|
def(AST_Binary, function(tw) {
|
||||||
if (!lazy_op[this.operator]) return;
|
if (!lazy_op[this.operator]) return;
|
||||||
@@ -1979,7 +1993,9 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
function should_stop(node, parent) {
|
function should_stop(node, parent) {
|
||||||
if (node === rvalue) return true;
|
if (node === rvalue) return true;
|
||||||
if (parent instanceof AST_For) return node !== parent.init;
|
if (parent instanceof AST_For) {
|
||||||
|
if (node !== parent.init) return true;
|
||||||
|
}
|
||||||
if (node instanceof AST_Assign) {
|
if (node instanceof AST_Assign) {
|
||||||
return node.operator != "=" && lhs.equivalent_to(node.left);
|
return node.operator != "=" && lhs.equivalent_to(node.left);
|
||||||
}
|
}
|
||||||
@@ -2014,7 +2030,8 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function in_conditional(node, parent) {
|
function in_conditional(node, parent) {
|
||||||
if (parent instanceof AST_Binary) return lazy_op[parent.operator] && parent.left !== node;
|
if (parent instanceof AST_Assign) return parent.left !== node && lazy_op[parent.operator.slice(0, -1)];
|
||||||
|
if (parent instanceof AST_Binary) return parent.left !== node && lazy_op[parent.operator];
|
||||||
if (parent instanceof AST_Case) return parent.expression !== node;
|
if (parent instanceof AST_Case) return parent.expression !== node;
|
||||||
if (parent instanceof AST_Conditional) return parent.condition !== node;
|
if (parent instanceof AST_Conditional) return parent.condition !== node;
|
||||||
return parent instanceof AST_If && parent.condition !== node;
|
return parent instanceof AST_If && parent.condition !== node;
|
||||||
@@ -7211,11 +7228,10 @@ merge(Compressor.prototype, {
|
|||||||
if (compressor.has_directive("use strict") && expr.is_constant()) return this;
|
if (compressor.has_directive("use strict") && expr.is_constant()) return this;
|
||||||
}
|
}
|
||||||
if (left.has_side_effects(compressor)) return this;
|
if (left.has_side_effects(compressor)) return this;
|
||||||
this.write_only = true;
|
var right = this.right;
|
||||||
if (root_expr(left).is_constant_expression(compressor.find_parent(AST_Scope))) {
|
this.write_only = !(lazy_op[this.operator.slice(0, -1)] && right.has_side_effects(compressor));
|
||||||
return this.right.drop_side_effect_free(compressor);
|
if (!root_expr(left).is_constant_expression(compressor.find_parent(AST_Scope))) return this;
|
||||||
}
|
return right.drop_side_effect_free(compressor);
|
||||||
return this;
|
|
||||||
});
|
});
|
||||||
def(AST_Await, function(compressor) {
|
def(AST_Await, function(compressor) {
|
||||||
if (!compressor.option("awaits")) return this;
|
if (!compressor.option("awaits")) return this;
|
||||||
|
|||||||
@@ -104,12 +104,15 @@ var OPERATORS = makePredicate([
|
|||||||
">>=",
|
">>=",
|
||||||
"<<=",
|
"<<=",
|
||||||
">>>=",
|
">>>=",
|
||||||
|
"&=",
|
||||||
"|=",
|
"|=",
|
||||||
"^=",
|
"^=",
|
||||||
"&=",
|
|
||||||
"&&",
|
"&&",
|
||||||
"||",
|
"||",
|
||||||
"??",
|
"??",
|
||||||
|
"&&=",
|
||||||
|
"||=",
|
||||||
|
"??=",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var NEWLINE_CHARS = "\n\r\u2028\u2029";
|
var NEWLINE_CHARS = "\n\r\u2028\u2029";
|
||||||
@@ -653,7 +656,7 @@ var UNARY_PREFIX = makePredicate("typeof void delete -- ++ ! ~ - +");
|
|||||||
|
|
||||||
var UNARY_POSTFIX = makePredicate("-- ++");
|
var UNARY_POSTFIX = makePredicate("-- ++");
|
||||||
|
|
||||||
var ASSIGNMENT = makePredicate("= += -= /= *= %= **= >>= <<= >>>= |= ^= &=");
|
var ASSIGNMENT = makePredicate("= += -= /= *= %= **= >>= <<= >>>= &= |= ^= &&= ||= ??=");
|
||||||
|
|
||||||
var PRECEDENCE = function(a, ret) {
|
var PRECEDENCE = function(a, ret) {
|
||||||
for (var i = 0; i < a.length;) {
|
for (var i = 0; i < a.length;) {
|
||||||
|
|||||||
@@ -475,3 +475,77 @@ issue_4521: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "42"
|
expect_stdout: "42"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logical_assignments: {
|
||||||
|
input: {
|
||||||
|
var a = 42, b = null, c;
|
||||||
|
a &&= "foo";
|
||||||
|
b ||= "bar";
|
||||||
|
c ??= "baz";
|
||||||
|
console.log(a, b, c);
|
||||||
|
}
|
||||||
|
expect_exact: 'var a=42,b=null,c;a&&="foo";b||="bar";c??="baz";console.log(a,b,c);'
|
||||||
|
expect_stdout: "foo bar baz"
|
||||||
|
node_version: ">=15"
|
||||||
|
}
|
||||||
|
|
||||||
|
logical_collapse_vars: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "FAIL", b = false;
|
||||||
|
a = "PASS";
|
||||||
|
b ??= a;
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "FAIL", b = false;
|
||||||
|
a = "PASS";
|
||||||
|
b ??= a;
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=15"
|
||||||
|
}
|
||||||
|
|
||||||
|
logical_reduce_vars: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "PASS", b = 42;
|
||||||
|
b ??= a = "FAIL";
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "PASS", b = 42;
|
||||||
|
b ??= a = "FAIL";
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=15"
|
||||||
|
}
|
||||||
|
|
||||||
|
logical_side_effects: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "PASS", b = 42;
|
||||||
|
b ??= a = "FAIL";
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "PASS", b = 42;
|
||||||
|
b ??= a = "FAIL";
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=15"
|
||||||
|
}
|
||||||
|
|||||||
@@ -2868,7 +2868,7 @@ lvalues_def: {
|
|||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
compound_assignment: {
|
compound_assignment_1: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
}
|
}
|
||||||
@@ -2887,6 +2887,23 @@ compound_assignment: {
|
|||||||
expect_stdout: "4"
|
expect_stdout: "4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compound_assignment_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a;
|
||||||
|
a = 1;
|
||||||
|
for (a += a + 2; console.log(a););
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a;
|
||||||
|
a = 1;
|
||||||
|
for (a += a + 2; console.log(a););
|
||||||
|
}
|
||||||
|
expect_stdout: "4"
|
||||||
|
}
|
||||||
|
|
||||||
issue_2187_1: {
|
issue_2187_1: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ var SUPPORT = function(matrix) {
|
|||||||
for_of: "for (var a of []);",
|
for_of: "for (var a of []);",
|
||||||
generator: "function* f(){}",
|
generator: "function* f(){}",
|
||||||
let: "let a;",
|
let: "let a;",
|
||||||
|
logical_assignment: "[].p ??= 0;",
|
||||||
new_target: "function f() { new.target; }",
|
new_target: "function f() { new.target; }",
|
||||||
nullish: "0 ?? 0",
|
nullish: "0 ?? 0",
|
||||||
rest: "var [...a] = [];",
|
rest: "var [...a] = [];",
|
||||||
@@ -262,10 +263,13 @@ ASSIGNMENTS = ASSIGNMENTS.concat([
|
|||||||
">>=",
|
">>=",
|
||||||
">>>=",
|
">>>=",
|
||||||
]);
|
]);
|
||||||
if (SUPPORT.exponentiation) {
|
ASSIGNMENTS = ASSIGNMENTS.concat(ASSIGNMENTS);
|
||||||
ASSIGNMENTS = ASSIGNMENTS.concat(ASSIGNMENTS);
|
if (SUPPORT.exponentiation) ASSIGNMENTS.push("**=");
|
||||||
ASSIGNMENTS.push("**=");
|
if (SUPPORT.logical_assignment) ASSIGNMENTS = ASSIGNMENTS.concat([
|
||||||
}
|
"&&=",
|
||||||
|
"||=",
|
||||||
|
"??=",
|
||||||
|
]);
|
||||||
|
|
||||||
var UNARY_SAFE = [
|
var UNARY_SAFE = [
|
||||||
"+",
|
"+",
|
||||||
|
|||||||
Reference in New Issue
Block a user