support BigInt literals (#4583)

This commit is contained in:
Alex Lam S.L
2021-01-24 01:51:18 +00:00
committed by GitHub
parent ef9f7ca3e7
commit 8bfd891c09
10 changed files with 251 additions and 176 deletions

View File

@@ -249,7 +249,7 @@ var AST_BlockScope = DEFNODE("BlockScope", "enclosed functions make_def parent_s
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes", enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
functions: "[Object/S] like `variables`, but only lists function declarations", functions: "[Object/S] like `variables`, but only lists function declarations",
parent_scope: "[AST_Scope?/S] link to the parent scope", parent_scope: "[AST_Scope?/S] link to the parent scope",
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope", variables: "[Object/S] a map of name ---> SymbolDef for all variables/functions defined in this scope",
}, },
clone: function(deep) { clone: function(deep) {
var node = this._clone(deep); var node = this._clone(deep);
@@ -472,7 +472,7 @@ var AST_Scope = DEFNODE("Scope", "uses_eval uses_with", {
var AST_Toplevel = DEFNODE("Toplevel", "globals", { var AST_Toplevel = DEFNODE("Toplevel", "globals", {
$documentation: "The toplevel scope", $documentation: "The toplevel scope",
$propdoc: { $propdoc: {
globals: "[Object/S] a map of name -> SymbolDef for all undeclared names", globals: "[Object/S] a map of name ---> SymbolDef for all undeclared names",
}, },
wrap: function(name) { wrap: function(name) {
var body = this.body; var body = this.body;
@@ -1440,6 +1440,19 @@ var AST_Number = DEFNODE("Number", "value", {
}, },
_validate: function() { _validate: function() {
if (typeof this.value != "number") throw new Error("value must be number"); if (typeof this.value != "number") throw new Error("value must be number");
if (!isFinite(this.value)) throw new Error("value must be finite");
if (this.value < 0) throw new Error("value cannot be negative");
},
}, AST_Constant);
var AST_BigInt = DEFNODE("BigInt", "value", {
$documentation: "A BigInt literal",
$propdoc: {
value: "[string] the numeric representation",
},
_validate: function() {
if (typeof this.value != "string") throw new Error("value must be string");
if (this.value[0] == "-") throw new Error("value cannot be negative");
}, },
}, AST_Constant); }, AST_Constant);

View File

@@ -729,7 +729,7 @@ merge(Compressor.prototype, {
if (aborts) push(tw); if (aborts) push(tw);
reset_variables(tw, compressor, fn); reset_variables(tw, compressor, fn);
// Virtually turn IIFE parameters into variable definitions: // Virtually turn IIFE parameters into variable definitions:
// (function(a,b) {...})(c,d) => (function() {var a=c,b=d; ...})() // (function(a,b) {...})(c,d) ---> (function() {var a=c,b=d; ...})()
// So existing transformation rules can work on them. // So existing transformation rules can work on them.
var safe = !fn.uses_arguments || tw.has_directive("use strict"); var safe = !fn.uses_arguments || tw.has_directive("use strict");
fn.argnames.forEach(function(arg, i) { fn.argnames.forEach(function(arg, i) {
@@ -2742,7 +2742,7 @@ merge(Compressor.prototype, {
var in_bool = stat.body.in_bool || next instanceof AST_Return && next.in_bool; var in_bool = stat.body.in_bool || next instanceof AST_Return && next.in_bool;
//--- //---
// pretty silly case, but: // pretty silly case, but:
// if (foo()) return; return; => foo(); return; // if (foo()) return; return; ---> foo(); return;
if (!value && !stat.alternative if (!value && !stat.alternative
&& (in_lambda && !next || next instanceof AST_Return && !next.value)) { && (in_lambda && !next || next instanceof AST_Return && !next.value)) {
CHANGED = true; CHANGED = true;
@@ -2752,7 +2752,7 @@ merge(Compressor.prototype, {
continue; continue;
} }
//--- //---
// if (foo()) return x; return y; => return foo() ? x : y; // if (foo()) return x; return y; ---> return foo() ? x : y;
if (!stat.alternative && next instanceof AST_Return) { if (!stat.alternative && next instanceof AST_Return) {
CHANGED = true; CHANGED = true;
stat = stat.clone(); stat = stat.clone();
@@ -2762,7 +2762,7 @@ merge(Compressor.prototype, {
continue; continue;
} }
//--- //---
// if (foo()) return x; [ return ; ] => return foo() ? x : undefined; // if (foo()) return x; [ return ; ] ---> return foo() ? x : undefined;
if (!stat.alternative && !next && in_lambda && (in_bool || value && multiple_if_returns)) { if (!stat.alternative && !next && in_lambda && (in_bool || value && multiple_if_returns)) {
CHANGED = true; CHANGED = true;
stat = stat.clone(); stat = stat.clone();
@@ -2773,7 +2773,7 @@ merge(Compressor.prototype, {
continue; continue;
} }
//--- //---
// if (a) return b; if (c) return d; e; => return a ? b : c ? d : void e; // if (a) return b; if (c) return d; e; ---> return a ? b : c ? d : void e;
// //
// if sequences is not enabled, this can lead to an endless loop (issue #866). // if sequences is not enabled, this can lead to an endless loop (issue #866).
// however, with sequences on this helps producing slightly better output for // however, with sequences on this helps producing slightly better output for
@@ -3970,6 +3970,7 @@ merge(Compressor.prototype, {
throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start)); throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
}); });
def(AST_Accessor, return_this); def(AST_Accessor, return_this);
def(AST_BigInt, return_this);
def(AST_Node, return_this); def(AST_Node, return_this);
def(AST_Constant, function() { def(AST_Constant, function() {
return this.value; return this.value;
@@ -4172,7 +4173,7 @@ merge(Compressor.prototype, {
&& typeof result == "number" && typeof result == "number"
&& (this.operator == "+" || this.operator == "-")) { && (this.operator == "+" || this.operator == "-")) {
var digits = Math.max(0, decimals(left), decimals(right)); var digits = Math.max(0, decimals(left), decimals(right));
// 53-bit significand => 15.95 decimal places // 53-bit significand ---> 15.95 decimal places
if (digits < 16) return +result.toFixed(digits); if (digits < 16) return +result.toFixed(digits);
} }
return result; return result;
@@ -7944,6 +7945,7 @@ merge(Compressor.prototype, {
if (compressor.option("unsafe")) { if (compressor.option("unsafe")) {
if (is_undeclared_ref(exp)) switch (exp.name) { if (is_undeclared_ref(exp)) switch (exp.name) {
case "Array": case "Array":
// Array(n) ---> [ , , ... , ]
if (self.args.length == 1) { if (self.args.length == 1) {
var first = self.args[0]; var first = self.args[0];
if (first instanceof AST_Number) try { if (first instanceof AST_Number) try {
@@ -7951,9 +7953,7 @@ merge(Compressor.prototype, {
if (length > 6) break; if (length > 6) break;
var elements = Array(length); var elements = Array(length);
for (var i = 0; i < length; i++) elements[i] = make_node(AST_Hole, self); for (var i = 0; i < length; i++) elements[i] = make_node(AST_Hole, self);
return make_node(AST_Array, self, { return make_node(AST_Array, self, { elements: elements });
elements: elements
});
} catch (ex) { } catch (ex) {
AST_Node.warn("Invalid array length: {length} [{file}:{line},{col}]", { AST_Node.warn("Invalid array length: {length} [{file}:{line},{col}]", {
length: length, length: length,
@@ -7965,81 +7965,90 @@ merge(Compressor.prototype, {
} }
if (!first.is_boolean(compressor) && !first.is_string(compressor)) break; if (!first.is_boolean(compressor) && !first.is_string(compressor)) break;
} }
return make_node(AST_Array, self, { // Array(...) ---> [ ... ]
elements: self.args return make_node(AST_Array, self, { elements: self.args });
});
case "Object": case "Object":
if (self.args.length == 0) { // Object() ---> {}
return make_node(AST_Object, self, { if (self.args.length == 0) return make_node(AST_Object, self, { properties: [] });
properties: []
});
}
break; break;
case "String": case "String":
if (self.args.length == 0) return make_node(AST_String, self, { // String() ---> ""
value: "" if (self.args.length == 0) return make_node(AST_String, self, { value: "" });
}); // String(x) ---> "" + x
if (self.args.length <= 1) return make_node(AST_Binary, self, { if (self.args.length == 1) return make_node(AST_Binary, self, {
left: self.args[0],
operator: "+", operator: "+",
right: make_node(AST_String, self, { value: "" }) left: make_node(AST_String, self, { value: "" }),
right: self.args[0],
}).optimize(compressor); }).optimize(compressor);
break; break;
case "Number": case "Number":
if (self.args.length == 0) return make_node(AST_Number, self, { // Number() ---> 0
value: 0 if (self.args.length == 0) return make_node(AST_Number, self, { value: 0 });
}); // Number(x) ---> +("" + x)
if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, { if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {
expression: self.args[0], operator: "+",
operator: "+" expression: make_node(AST_Binary, self, {
}).optimize(compressor); operator: "+",
case "Boolean": left: make_node(AST_String, self, { value: "" }),
if (self.args.length == 0) return make_node(AST_False, self); right: self.args[0],
if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, { }),
expression: make_node(AST_UnaryPrefix, self, { }).optimize(compressor);
expression: self.args[0], break;
operator: "!" case "Boolean":
// Boolean() ---> false
if (self.args.length == 0) return make_node(AST_False, self).optimize(compressor);
// Boolean(x) ---> !!x
if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {
operator: "!",
expression: make_node(AST_UnaryPrefix, self, {
operator: "!",
expression: self.args[0],
}), }),
operator: "!"
}).optimize(compressor); }).optimize(compressor);
break; break;
case "RegExp": case "RegExp":
// attempt to convert RegExp(...) to literal
var params = []; var params = [];
if (all(self.args, function(arg) { if (all(self.args, function(arg) {
var value = arg.evaluate(compressor); var value = arg.evaluate(compressor);
params.unshift(value); params.unshift(value);
return arg !== value; return arg !== value;
})) { })) try {
try { return best_of(compressor, self, make_node(AST_RegExp, self, {
return best_of(compressor, self, make_node(AST_RegExp, self, { value: RegExp.apply(RegExp, params),
value: RegExp.apply(RegExp, params), }));
})); } catch (ex) {
} catch (ex) { AST_Node.warn("Error converting {expr} [{file}:{line},{col}]", {
AST_Node.warn("Error converting {expr} [{file}:{line},{col}]", { expr: self,
expr: self, file: self.start.file,
file: self.start.file, line: self.start.line,
line: self.start.line, col: self.start.col,
col: self.start.col, });
});
}
} }
break; break;
} else if (exp instanceof AST_Dot) switch(exp.property) { } else if (exp instanceof AST_Dot) switch (exp.property) {
case "toString": case "toString":
// x.toString() ---> "" + x
if (self.args.length == 0 && !exp.expression.may_throw_on_access(compressor)) { if (self.args.length == 0 && !exp.expression.may_throw_on_access(compressor)) {
return make_node(AST_Binary, self, { return make_node(AST_Binary, self, {
left: make_node(AST_String, self, { value: "" }),
operator: "+", operator: "+",
right: exp.expression left: make_node(AST_String, self, { value: "" }),
right: exp.expression,
}).optimize(compressor); }).optimize(compressor);
} }
break; break;
case "join": case "join":
if (exp.expression instanceof AST_Array) EXIT: { if (exp.expression instanceof AST_Array && self.args.length < 2) EXIT: {
var separator; var separator = self.args[0];
if (self.args.length > 0) { // [].join() ---> ""
separator = self.args[0].evaluate(compressor); // [].join(x) ---> (x, "")
if (separator === self.args[0]) break EXIT; // not a constant if (exp.expression.elements.length == 0) return separator ? make_sequence(self, [
separator,
make_node(AST_String, self, { value: "" }),
]).optimize(compressor) : make_node(AST_String, self, { value: "" });
if (separator) {
separator = separator.evaluate(compressor);
if (separator instanceof AST_Node) break EXIT; // not a constant
} }
var elements = []; var elements = [];
var consts = []; var consts = [];
@@ -8050,45 +8059,46 @@ merge(Compressor.prototype, {
} else { } else {
if (consts.length > 0) { if (consts.length > 0) {
elements.push(make_node(AST_String, self, { elements.push(make_node(AST_String, self, {
value: consts.join(separator) value: consts.join(separator),
})); }));
consts.length = 0; consts.length = 0;
} }
elements.push(el); elements.push(el);
} }
}); });
if (consts.length > 0) { if (consts.length > 0) elements.push(make_node(AST_String, self, {
elements.push(make_node(AST_String, self, { value: consts.join(separator),
value: consts.join(separator) }));
})); // [ x ].join() ---> "" + x
} // [ x ].join(".") ---> "" + x
if (elements.length == 0) return make_node(AST_String, self, { value: "" }); // [ 1, 2, 3 ].join() ---> "1,2,3"
// [ 1, 2, 3 ].join(".") ---> "1.2.3"
if (elements.length == 1) { if (elements.length == 1) {
if (elements[0].is_string(compressor)) { if (elements[0].is_string(compressor)) return elements[0];
return elements[0];
}
return make_node(AST_Binary, elements[0], { return make_node(AST_Binary, elements[0], {
operator : "+", operator: "+",
left : make_node(AST_String, self, { value: "" }), left: make_node(AST_String, self, { value: "" }),
right : elements[0] right: elements[0],
}); });
} }
// [ 1, 2, a, 3 ].join("") ---> "12" + a + "3"
if (separator == "") { if (separator == "") {
var first; var first;
if (elements[0].is_string(compressor) if (elements[0].is_string(compressor) || elements[1].is_string(compressor)) {
|| elements[1].is_string(compressor)) {
first = elements.shift(); first = elements.shift();
} else { } else {
first = make_node(AST_String, self, { value: "" }); 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, { return make_node(AST_Binary, el, {
operator : "+", operator: "+",
left : prev, left: prev,
right : el right: el,
}); });
}, first).optimize(compressor); }, first).optimize(compressor);
} }
// [ x, "foo", "bar", y ].join() ---> [ x, "foo,bar", y ].join()
// [ x, "foo", "bar", y ].join("-") ---> [ x, "foo-bar", y ].join("-")
// need this awkward cloning to not affect original element // need this awkward cloning to not affect original element
// best_of will decide which one to get through. // best_of will decide which one to get through.
var node = self.clone(); var node = self.clone();
@@ -8152,7 +8162,7 @@ merge(Compressor.prototype, {
if (compressor.option("unsafe_Function") if (compressor.option("unsafe_Function")
&& is_undeclared_ref(exp) && is_undeclared_ref(exp)
&& exp.name == "Function") { && exp.name == "Function") {
// new Function() => function(){} // new Function() ---> function(){}
if (self.args.length == 0) return make_node(AST_Function, self, { if (self.args.length == 0) return make_node(AST_Function, self, {
argnames: [], argnames: [],
body: [] body: []
@@ -8780,8 +8790,8 @@ merge(Compressor.prototype, {
return self; return self;
}); });
// (a = b, x && a = c) => a = x ? c : b // (a = b, x && a = c) ---> a = x ? c : b
// (a = b, x || a = c) => a = x ? b : c // (a = b, x || a = c) ---> a = x ? b : c
function to_conditional_assignment(compressor, def, value, node) { function to_conditional_assignment(compressor, def, value, node) {
if (!(node instanceof AST_Binary)) return; if (!(node instanceof AST_Binary)) return;
if (!lazy_op[node.operator]) return; if (!lazy_op[node.operator]) return;
@@ -8912,7 +8922,7 @@ merge(Compressor.prototype, {
} else if (compressor.in_boolean_context()) switch (op) { } else if (compressor.in_boolean_context()) switch (op) {
case "!": case "!":
if (exp instanceof AST_UnaryPrefix && exp.operator == "!") { if (exp instanceof AST_UnaryPrefix && exp.operator == "!") {
// !!foo => foo, if we're in boolean context // !!foo ---> foo, if we're in boolean context
return exp.expression; return exp.expression;
} }
if (exp instanceof AST_Binary) { if (exp instanceof AST_Binary) {
@@ -9077,8 +9087,8 @@ merge(Compressor.prototype, {
} }
if (compressor.option("assignments") && lazy_op[self.operator]) { if (compressor.option("assignments") && lazy_op[self.operator]) {
var assign = self.right; var assign = self.right;
// a || (a = x) => a = a || x // a || (a = x) ---> a = a || x
// a && (a = x) => a = a && x // a && (a = x) ---> a = a && x
if (self.left instanceof AST_SymbolRef if (self.left instanceof AST_SymbolRef
&& assign instanceof AST_Assign && assign instanceof AST_Assign
&& assign.operator == "=" && assign.operator == "="
@@ -9108,11 +9118,11 @@ merge(Compressor.prototype, {
// XXX: intentionally falling down to the next case // XXX: intentionally falling down to the next case
case "==": case "==":
case "!=": case "!=":
// void 0 == x => null == x // void 0 == x ---> null == x
if (!is_strict_comparison && is_undefined(self.left, compressor)) { if (!is_strict_comparison && is_undefined(self.left, compressor)) {
self.left = make_node(AST_Null, self.left); self.left = make_node(AST_Null, self.left);
} }
// "undefined" == typeof x => undefined === x // "undefined" == typeof x ---> undefined === x
else if (compressor.option("typeofs") else if (compressor.option("typeofs")
&& self.left instanceof AST_String && self.left instanceof AST_String
&& self.left.value == "undefined" && self.left.value == "undefined"
@@ -9126,7 +9136,7 @@ merge(Compressor.prototype, {
if (self.operator.length == 2) self.operator += "="; if (self.operator.length == 2) self.operator += "=";
} }
} }
// obj !== obj => false // obj !== obj ---> false
else if (self.left instanceof AST_SymbolRef else if (self.left instanceof AST_SymbolRef
&& self.right instanceof AST_SymbolRef && self.right instanceof AST_SymbolRef
&& self.left.definition() === self.right.definition() && self.left.definition() === self.right.definition()
@@ -9136,8 +9146,8 @@ merge(Compressor.prototype, {
break; break;
case "&&": case "&&":
case "||": case "||":
// void 0 !== x && null !== x => null != x // void 0 !== x && null !== x ---> null != x
// void 0 === x || null === x => null == x // void 0 === x || null === x ---> null == x
var lhs = self.left; var lhs = self.left;
if (lhs.operator == self.operator) { if (lhs.operator == self.operator) {
lhs = lhs.right; lhs = lhs.right;
@@ -9214,8 +9224,8 @@ merge(Compressor.prototype, {
case ">=": reverse("<="); break; case ">=": reverse("<="); break;
} }
} }
// x && (y && z) => x && y && z // x && (y && z) ---> x && y && z
// x || (y || z) => x || y || z // x || (y || z) ---> x || y || z
if (compressor.option("conditionals") if (compressor.option("conditionals")
&& lazy_op[self.operator] && lazy_op[self.operator]
&& self.right instanceof AST_Binary && self.right instanceof AST_Binary
@@ -9223,19 +9233,19 @@ merge(Compressor.prototype, {
swap_chain(); swap_chain();
} }
if (compressor.option("strings") && self.operator == "+") { if (compressor.option("strings") && self.operator == "+") {
// "foo" + 42 + "" => "foo" + 42 // "foo" + 42 + "" ---> "foo" + 42
if (self.right instanceof AST_String if (self.right instanceof AST_String
&& self.right.value == "" && self.right.value == ""
&& self.left.is_string(compressor)) { && self.left.is_string(compressor)) {
return self.left.optimize(compressor); return self.left.optimize(compressor);
} }
// "" + ("foo" + 42) => "foo" + 42 // "" + ("foo" + 42) ---> "foo" + 42
if (self.left instanceof AST_String if (self.left instanceof AST_String
&& self.left.value == "" && self.left.value == ""
&& self.right.is_string(compressor)) { && self.right.is_string(compressor)) {
return self.right.optimize(compressor); return self.right.optimize(compressor);
} }
// "" + 42 + "foo" => 42 + "foo" // "" + 42 + "foo" ---> 42 + "foo"
if (self.left instanceof AST_Binary if (self.left instanceof AST_Binary
&& self.left.operator == "+" && self.left.operator == "+"
&& self.left.left instanceof AST_String && self.left.left instanceof AST_String
@@ -9244,8 +9254,8 @@ merge(Compressor.prototype, {
self.left = self.left.right; self.left = self.left.right;
return self.optimize(compressor); return self.optimize(compressor);
} }
// "x" + (y + "z") => "x" + y + "z" // "x" + (y + "z") ---> "x" + y + "z"
// x + ("y" + z) => x + "y" + z // x + ("y" + z) ---> x + "y" + z
if (self.right instanceof AST_Binary if (self.right instanceof AST_Binary
&& self.operator == self.right.operator && self.operator == self.right.operator
&& (self.left.is_string(compressor) && self.right.is_string(compressor) && (self.left.is_string(compressor) && self.right.is_string(compressor)
@@ -9281,7 +9291,7 @@ merge(Compressor.prototype, {
return self.left.optimize(compressor); return self.left.optimize(compressor);
} }
} }
// (x || false) && y => x ? y : false // (x || false) && y ---> x ? y : false
if (self.left.operator == "||") { if (self.left.operator == "||") {
var lr = self.left.right.evaluate(compressor, true); var lr = self.left.right.evaluate(compressor, true);
if (!lr) return make_node(AST_Conditional, self, { if (!lr) return make_node(AST_Conditional, self, {
@@ -9315,7 +9325,7 @@ merge(Compressor.prototype, {
]).optimize(compressor); ]).optimize(compressor);
} else self.truthy = true; } else self.truthy = true;
} }
// x && true || y => x ? true : y // x && true || y ---> x ? true : y
if (self.left.operator == "&&") { if (self.left.operator == "&&") {
var lr = self.left.right.is_truthy() || self.left.right.evaluate(compressor, true); var lr = self.left.right.is_truthy() || self.left.right.evaluate(compressor, true);
if (lr && !(lr instanceof AST_Node)) return make_node(AST_Conditional, self, { if (lr && !(lr instanceof AST_Node)) return make_node(AST_Conditional, self, {
@@ -9326,7 +9336,7 @@ merge(Compressor.prototype, {
} }
break; break;
case "+": case "+":
// "foo" + ("bar" + x) => "foobar" + x // "foo" + ("bar" + x) ---> "foobar" + x
if (self.left instanceof AST_Constant if (self.left instanceof AST_Constant
&& self.right instanceof AST_Binary && self.right instanceof AST_Binary
&& self.right.operator == "+" && self.right.operator == "+"
@@ -9342,7 +9352,7 @@ merge(Compressor.prototype, {
right: self.right.right right: self.right.right
}); });
} }
// (x + "foo") + "bar" => x + "foobar" // (x + "foo") + "bar" ---> x + "foobar"
if (self.right instanceof AST_Constant if (self.right instanceof AST_Constant
&& self.left instanceof AST_Binary && self.left instanceof AST_Binary
&& self.left.operator == "+" && self.left.operator == "+"
@@ -9358,7 +9368,7 @@ merge(Compressor.prototype, {
}) })
}); });
} }
// a + -b => a - b // a + -b ---> a - b
if (self.right instanceof AST_UnaryPrefix if (self.right instanceof AST_UnaryPrefix
&& self.right.operator == "-" && self.right.operator == "-"
&& self.left.is_number(compressor)) { && self.left.is_number(compressor)) {
@@ -9369,7 +9379,7 @@ merge(Compressor.prototype, {
}); });
break; break;
} }
// -a + b => b - a // -a + b ---> b - a
if (self.left instanceof AST_UnaryPrefix if (self.left instanceof AST_UnaryPrefix
&& self.left.operator == "-" && self.left.operator == "-"
&& reversible() && reversible()
@@ -9381,7 +9391,7 @@ merge(Compressor.prototype, {
}); });
break; break;
} }
// (a + b) + 3 => 3 + (a + b) // (a + b) + 3 ---> 3 + (a + b)
if (compressor.option("unsafe_math") if (compressor.option("unsafe_math")
&& self.left instanceof AST_Binary && self.left instanceof AST_Binary
&& PRECEDENCE[self.left.operator] == PRECEDENCE[self.operator] && PRECEDENCE[self.left.operator] == PRECEDENCE[self.operator]
@@ -9402,7 +9412,7 @@ merge(Compressor.prototype, {
break; break;
} }
case "-": case "-":
// a - -b => a + b // a - -b ---> a + b
if (self.right instanceof AST_UnaryPrefix if (self.right instanceof AST_UnaryPrefix
&& self.right.operator == "-" && self.right.operator == "-"
&& self.left.is_number(compressor) && self.left.is_number(compressor)
@@ -9417,8 +9427,8 @@ merge(Compressor.prototype, {
case "*": case "*":
case "/": case "/":
associative = compressor.option("unsafe_math"); associative = compressor.option("unsafe_math");
// +a - b => a - b // +a - b ---> a - b
// a - +b => a - b // a - +b ---> a - b
if (self.operator != "+") [ "left", "right" ].forEach(function(operand) { if (self.operator != "+") [ "left", "right" ].forEach(function(operand) {
var node = self[operand]; var node = self[operand];
if (node instanceof AST_UnaryPrefix && node.operator == "+") { if (node instanceof AST_UnaryPrefix && node.operator == "+") {
@@ -9431,7 +9441,7 @@ merge(Compressor.prototype, {
case "&": case "&":
case "|": case "|":
case "^": case "^":
// a + +b => +b + a // a + +b ---> +b + a
if (self.operator != "-" if (self.operator != "-"
&& self.operator != "/" && self.operator != "/"
&& (self.left.is_boolean(compressor) || self.left.is_number(compressor)) && (self.left.is_boolean(compressor) || self.left.is_number(compressor))
@@ -9453,7 +9463,7 @@ merge(Compressor.prototype, {
} }
} }
if (!associative || !self.is_number(compressor)) break; if (!associative || !self.is_number(compressor)) break;
// a + (b + c) => (a + b) + c // a + (b + c) ---> (a + b) + c
if (self.right instanceof AST_Binary if (self.right instanceof AST_Binary
&& self.right.operator != "%" && self.right.operator != "%"
&& PRECEDENCE[self.right.operator] == PRECEDENCE[self.operator] && PRECEDENCE[self.right.operator] == PRECEDENCE[self.operator]
@@ -9485,8 +9495,8 @@ merge(Compressor.prototype, {
}); });
} }
} }
// (2 * n) * 3 => 6 * n // (2 * n) * 3 ---> 6 * n
// (n + 2) + 3 => n + 5 // (n + 2) + 3 ---> n + 5
if (self.right instanceof AST_Constant if (self.right instanceof AST_Constant
&& self.left instanceof AST_Binary && self.left instanceof AST_Binary
&& self.left.operator != "%" && self.left.operator != "%"
@@ -9511,7 +9521,7 @@ merge(Compressor.prototype, {
} }
if (!(parent instanceof AST_UnaryPrefix && parent.operator == "delete")) { if (!(parent instanceof AST_UnaryPrefix && parent.operator == "delete")) {
if (self.left instanceof AST_Number && !self.right.is_constant()) switch (self.operator) { if (self.left instanceof AST_Number && !self.right.is_constant()) switch (self.operator) {
// 0 + n => n // 0 + n ---> n
case "+": case "+":
if (self.left.value == 0) { if (self.left.value == 0) {
if (self.right.is_boolean(compressor)) return make_node(AST_UnaryPrefix, self, { if (self.right.is_boolean(compressor)) return make_node(AST_UnaryPrefix, self, {
@@ -9521,7 +9531,7 @@ merge(Compressor.prototype, {
if (self.right.is_number(compressor) && !self.right.is_negative_zero()) return self.right; if (self.right.is_number(compressor) && !self.right.is_negative_zero()) return self.right;
} }
break; break;
// 1 * n => n // 1 * n ---> n
case "*": case "*":
if (self.left.value == 1) { if (self.left.value == 1) {
return self.right.is_number(compressor) ? self.right : make_node(AST_UnaryPrefix, self, { return self.right.is_number(compressor) ? self.right : make_node(AST_UnaryPrefix, self, {
@@ -9532,7 +9542,7 @@ merge(Compressor.prototype, {
break; break;
} }
if (self.right instanceof AST_Number && !self.left.is_constant()) switch (self.operator) { if (self.right instanceof AST_Number && !self.left.is_constant()) switch (self.operator) {
// n + 0 => n // n + 0 ---> n
case "+": case "+":
if (self.right.value == 0) { if (self.right.value == 0) {
if (self.left.is_boolean(compressor)) return make_node(AST_UnaryPrefix, self, { if (self.left.is_boolean(compressor)) return make_node(AST_UnaryPrefix, self, {
@@ -9542,7 +9552,7 @@ merge(Compressor.prototype, {
if (self.left.is_number(compressor) && !self.left.is_negative_zero()) return self.left; if (self.left.is_number(compressor) && !self.left.is_negative_zero()) return self.left;
} }
break; break;
// n - 0 => n // n - 0 ---> n
case "-": case "-":
if (self.right.value == 0) { if (self.right.value == 0) {
return self.left.is_number(compressor) ? self.left : make_node(AST_UnaryPrefix, self, { return self.left.is_number(compressor) ? self.left : make_node(AST_UnaryPrefix, self, {
@@ -9551,7 +9561,7 @@ merge(Compressor.prototype, {
}).optimize(compressor); }).optimize(compressor);
} }
break; break;
// n / 1 => n // n / 1 ---> n
case "/": case "/":
if (self.right.value == 1) { if (self.right.value == 1) {
return self.left.is_number(compressor) ? self.left : make_node(AST_UnaryPrefix, self, { return self.left.is_number(compressor) ? self.left : make_node(AST_UnaryPrefix, self, {
@@ -9674,16 +9684,16 @@ merge(Compressor.prototype, {
function is_indexOf_match_pattern() { function is_indexOf_match_pattern() {
switch (self.operator) { switch (self.operator) {
case "<=": case "<=":
// 0 <= array.indexOf(string) => !!~array.indexOf(string) // 0 <= array.indexOf(string) ---> !!~array.indexOf(string)
return indexRight && self.left instanceof AST_Number && self.left.value == 0; return indexRight && self.left instanceof AST_Number && self.left.value == 0;
case "<": case "<":
// array.indexOf(string) < 0 => !~array.indexOf(string) // array.indexOf(string) < 0 ---> !~array.indexOf(string)
if (indexLeft && self.right instanceof AST_Number && self.right.value == 0) return true; if (indexLeft && self.right instanceof AST_Number && self.right.value == 0) return true;
// -1 < array.indexOf(string) => !!~array.indexOf(string) // -1 < array.indexOf(string) ---> !!~array.indexOf(string)
case "==": case "==":
case "!=": case "!=":
// -1 == array.indexOf(string) => !~array.indexOf(string) // -1 == array.indexOf(string) ---> !~array.indexOf(string)
// -1 != array.indexOf(string) => !!~array.indexOf(string) // -1 != array.indexOf(string) ---> !!~array.indexOf(string)
if (!indexRight) return false; if (!indexRight) return false;
return self.left instanceof AST_Number && self.left.value == -1 return self.left instanceof AST_Number && self.left.value == -1
|| self.left instanceof AST_UnaryPrefix && self.left.operator == "-" || self.left instanceof AST_UnaryPrefix && self.left.operator == "-"
@@ -10037,7 +10047,7 @@ merge(Compressor.prototype, {
if (self.right.left instanceof AST_SymbolRef if (self.right.left instanceof AST_SymbolRef
&& self.right.left.name == self.left.name && self.right.left.name == self.left.name
&& ASSIGN_OPS[self.right.operator]) { && ASSIGN_OPS[self.right.operator]) {
// x = x - 2 => x -= 2 // x = x - 2 ---> x -= 2
return make_node(AST_Assign, self, { return make_node(AST_Assign, self, {
operator: self.right.operator + "=", operator: self.right.operator + "=",
left: self.left, left: self.left,
@@ -10048,7 +10058,7 @@ merge(Compressor.prototype, {
&& self.right.right.name == self.left.name && self.right.right.name == self.left.name
&& ASSIGN_OPS_COMMUTATIVE[self.right.operator] && ASSIGN_OPS_COMMUTATIVE[self.right.operator]
&& !self.right.left.has_side_effects(compressor)) { && !self.right.left.has_side_effects(compressor)) {
// x = 2 & x => x &= 2 // x = 2 & x ---> x &= 2
return make_node(AST_Assign, self, { return make_node(AST_Assign, self, {
operator: self.right.operator + "=", operator: self.right.operator + "=",
left: self.left, left: self.left,
@@ -10122,13 +10132,13 @@ merge(Compressor.prototype, {
var consequent = self.consequent; var consequent = self.consequent;
var alternative = self.alternative; var alternative = self.alternative;
if (repeatable(compressor, condition)) { if (repeatable(compressor, condition)) {
// x ? x : y => x || y // x ? x : y ---> x || y
if (condition.equivalent_to(consequent)) return make_node(AST_Binary, self, { if (condition.equivalent_to(consequent)) return make_node(AST_Binary, self, {
operator: "||", operator: "||",
left: condition, left: condition,
right: alternative, right: alternative,
}).optimize(compressor); }).optimize(compressor);
// x ? y : x => x && y // x ? y : x ---> x && y
if (condition.equivalent_to(alternative)) return make_node(AST_Binary, self, { if (condition.equivalent_to(alternative)) return make_node(AST_Binary, self, {
operator: "&&", operator: "&&",
left: condition, left: condition,
@@ -10162,17 +10172,17 @@ merge(Compressor.prototype, {
}); });
} }
} }
// x ? y : y => x, y // x ? y : y ---> x, y
if (consequent.equivalent_to(alternative)) return make_sequence(self, [ if (consequent.equivalent_to(alternative)) return make_sequence(self, [
condition, condition,
consequent consequent
]).optimize(compressor); ]).optimize(compressor);
// x ? y.p : z.p => (x ? y : z).p // x ? y.p : z.p ---> (x ? y : z).p
// x ? y(a) : z(a) => (x ? y : z)(a) // x ? y(a) : z(a) ---> (x ? y : z)(a)
// x ? y.f(a) : z.f(a) => (x ? y : z).f(a) // x ? y.f(a) : z.f(a) ---> (x ? y : z).f(a)
var combined = combine_tail(consequent, alternative, true); var combined = combine_tail(consequent, alternative, true);
if (combined) return combined; if (combined) return combined;
// x ? y(a) : y(b) => y(x ? a : b) // x ? y(a) : y(b) ---> y(x ? a : b)
var arg_index; var arg_index;
if (consequent instanceof AST_Call if (consequent instanceof AST_Call
&& alternative.TYPE == consequent.TYPE && alternative.TYPE == consequent.TYPE
@@ -10195,7 +10205,7 @@ merge(Compressor.prototype, {
}); });
return node; return node;
} }
// x ? (y ? a : b) : b => x && y ? a : b // x ? (y ? a : b) : b ---> x && y ? a : b
if (consequent instanceof AST_Conditional if (consequent instanceof AST_Conditional
&& consequent.alternative.equivalent_to(alternative)) { && consequent.alternative.equivalent_to(alternative)) {
return make_node(AST_Conditional, self, { return make_node(AST_Conditional, self, {
@@ -10208,7 +10218,7 @@ merge(Compressor.prototype, {
alternative: alternative alternative: alternative
}); });
} }
// x ? (y ? a : b) : a => !x || y ? a : b // x ? (y ? a : b) : a ---> !x || y ? a : b
if (consequent instanceof AST_Conditional if (consequent instanceof AST_Conditional
&& consequent.consequent.equivalent_to(alternative)) { && consequent.consequent.equivalent_to(alternative)) {
return make_node(AST_Conditional, self, { return make_node(AST_Conditional, self, {
@@ -10221,7 +10231,7 @@ merge(Compressor.prototype, {
alternative: consequent.alternative alternative: consequent.alternative
}); });
} }
// x ? a : (y ? a : b) => x || y ? a : b // x ? a : (y ? a : b) ---> x || y ? a : b
if (alternative instanceof AST_Conditional if (alternative instanceof AST_Conditional
&& consequent.equivalent_to(alternative.consequent)) { && consequent.equivalent_to(alternative.consequent)) {
return make_node(AST_Conditional, self, { return make_node(AST_Conditional, self, {
@@ -10234,7 +10244,7 @@ merge(Compressor.prototype, {
alternative: alternative.alternative alternative: alternative.alternative
}); });
} }
// x ? b : (y ? a : b) => !x && y ? a : b // x ? b : (y ? a : b) ---> !x && y ? a : b
if (alternative instanceof AST_Conditional if (alternative instanceof AST_Conditional
&& consequent.equivalent_to(alternative.alternative)) { && consequent.equivalent_to(alternative.alternative)) {
return make_node(AST_Conditional, self, { return make_node(AST_Conditional, self, {
@@ -10247,7 +10257,7 @@ merge(Compressor.prototype, {
alternative: consequent alternative: consequent
}); });
} }
// x ? (a, c) : (b, c) => x ? a : b, c // x ? (a, c) : (b, c) ---> x ? a : b, c
if ((consequent instanceof AST_Sequence || alternative instanceof AST_Sequence) if ((consequent instanceof AST_Sequence || alternative instanceof AST_Sequence)
&& consequent.tail_node().equivalent_to(alternative.tail_node())) { && consequent.tail_node().equivalent_to(alternative.tail_node())) {
return make_sequence(self, [ return make_sequence(self, [
@@ -10259,7 +10269,7 @@ merge(Compressor.prototype, {
consequent.tail_node() consequent.tail_node()
]).optimize(compressor); ]).optimize(compressor);
} }
// x ? y && a : a => (!x || y) && a // x ? y && a : a ---> (!x || y) && a
if (consequent instanceof AST_Binary if (consequent instanceof AST_Binary
&& consequent.operator == "&&" && consequent.operator == "&&"
&& consequent.right.equivalent_to(alternative)) { && consequent.right.equivalent_to(alternative)) {
@@ -10273,7 +10283,7 @@ merge(Compressor.prototype, {
right: alternative right: alternative
}).optimize(compressor); }).optimize(compressor);
} }
// x ? y || a : a => x && y || a // x ? y || a : a ---> x && y || a
if (consequent instanceof AST_Binary if (consequent instanceof AST_Binary
&& consequent.operator == "||" && consequent.operator == "||"
&& consequent.right.equivalent_to(alternative)) { && consequent.right.equivalent_to(alternative)) {
@@ -10287,7 +10297,7 @@ merge(Compressor.prototype, {
right: alternative right: alternative
}).optimize(compressor); }).optimize(compressor);
} }
// x ? a : y && a => (x || y) && a // x ? a : y && a ---> (x || y) && a
if (alternative instanceof AST_Binary if (alternative instanceof AST_Binary
&& alternative.operator == "&&" && alternative.operator == "&&"
&& alternative.right.equivalent_to(consequent)) { && alternative.right.equivalent_to(consequent)) {
@@ -10301,7 +10311,7 @@ merge(Compressor.prototype, {
right: consequent right: consequent
}).optimize(compressor); }).optimize(compressor);
} }
// x ? a : y || a => !x && y || a // x ? a : y || a ---> !x && y || a
if (alternative instanceof AST_Binary if (alternative instanceof AST_Binary
&& alternative.operator == "||" && alternative.operator == "||"
&& alternative.right.equivalent_to(consequent)) { && alternative.right.equivalent_to(consequent)) {
@@ -10318,10 +10328,10 @@ merge(Compressor.prototype, {
var in_bool = compressor.option("booleans") && compressor.in_boolean_context(); var in_bool = compressor.option("booleans") && compressor.in_boolean_context();
if (is_true(consequent)) { if (is_true(consequent)) {
if (is_false(alternative)) { if (is_false(alternative)) {
// c ? true : false => !!c // c ? true : false ---> !!c
return booleanize(condition); return booleanize(condition);
} }
// c ? true : x => !!c || x // c ? true : x ---> !!c || x
return make_node(AST_Binary, self, { return make_node(AST_Binary, self, {
operator: "||", operator: "||",
left: booleanize(condition), left: booleanize(condition),
@@ -10330,10 +10340,10 @@ merge(Compressor.prototype, {
} }
if (is_false(consequent)) { if (is_false(consequent)) {
if (is_true(alternative)) { if (is_true(alternative)) {
// c ? false : true => !c // c ? false : true ---> !c
return booleanize(condition.negate(compressor)); return booleanize(condition.negate(compressor));
} }
// c ? false : x => !c && x // c ? false : x ---> !c && x
return make_node(AST_Binary, self, { return make_node(AST_Binary, self, {
operator: "&&", operator: "&&",
left: booleanize(condition.negate(compressor)), left: booleanize(condition.negate(compressor)),
@@ -10341,7 +10351,7 @@ merge(Compressor.prototype, {
}); });
} }
if (is_true(alternative)) { if (is_true(alternative)) {
// c ? x : true => !c || x // c ? x : true ---> !c || x
return make_node(AST_Binary, self, { return make_node(AST_Binary, self, {
operator: "||", operator: "||",
left: booleanize(condition.negate(compressor)), left: booleanize(condition.negate(compressor)),
@@ -10349,7 +10359,7 @@ merge(Compressor.prototype, {
}); });
} }
if (is_false(alternative)) { if (is_false(alternative)) {
// c ? x : false => !!c && x // c ? x : false ---> !!c && x
return make_node(AST_Binary, self, { return make_node(AST_Binary, self, {
operator: "&&", operator: "&&",
left: booleanize(condition), left: booleanize(condition),

View File

@@ -689,32 +689,32 @@ function OutputStream(options) {
PARENS(AST_Sequence, function(output) { PARENS(AST_Sequence, function(output) {
var p = output.parent(); var p = output.parent();
// [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ] // [ 1, (2, 3), 4 ] ---> [ 1, 3, 4 ]
return p instanceof AST_Array return p instanceof AST_Array
// () => (foo, bar) // () ---> (foo, bar)
|| is_arrow(p) && p.value === this || is_arrow(p) && p.value === this
// await (foo, bar) // await (foo, bar)
|| p instanceof AST_Await || p instanceof AST_Await
// 1 + (2, 3) + 4 ==> 8 // 1 + (2, 3) + 4 ---> 8
|| p instanceof AST_Binary || p instanceof AST_Binary
// new (foo, bar) or foo(1, (2, 3), 4) // new (foo, bar) or foo(1, (2, 3), 4)
|| p instanceof AST_Call || p instanceof AST_Call
// (false, true) ? (a = 10, b = 20) : (c = 30) // (false, true) ? (a = 10, b = 20) : (c = 30)
// ==> 20 (side effect, set a := 10 and b := 20) // ---> 20 (side effect, set a := 10 and b := 20)
|| p instanceof AST_Conditional || p instanceof AST_Conditional
// [ a = (1, 2) ] = [] ==> a == 2 // [ a = (1, 2) ] = [] ---> a == 2
|| p instanceof AST_DefaultValue || p instanceof AST_DefaultValue
// { [(1, 2)]: 3 }[2] ==> 3 // { [(1, 2)]: 3 }[2] ---> 3
// { foo: (1, 2) }.foo ==> 2 // { foo: (1, 2) }.foo ---> 2
|| p instanceof AST_DestructuredKeyVal || p instanceof AST_DestructuredKeyVal
|| p instanceof AST_ObjectProperty || p instanceof AST_ObjectProperty
// (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2 // (1, {foo:2}).foo or (1, {foo:2})["foo"] ---> 2
|| p instanceof AST_PropAccess && p.expression === this || p instanceof AST_PropAccess && p.expression === this
// ...(foo, bar, baz) // ...(foo, bar, baz)
|| p instanceof AST_Spread || p instanceof AST_Spread
// !(foo, bar, baz) // !(foo, bar, baz)
|| p instanceof AST_Unary || p instanceof AST_Unary
// var a = (1, 2), b = a + a; ==> b == 4 // var a = (1, 2), b = a + a; ---> b == 4
|| p instanceof AST_VarDef; || p instanceof AST_VarDef;
}); });
@@ -777,14 +777,10 @@ function OutputStream(options) {
}); });
PARENS(AST_Number, function(output) { PARENS(AST_Number, function(output) {
if (!output.option("galio")) return false;
// https://github.com/mishoo/UglifyJS/pull/1009
var p = output.parent(); var p = output.parent();
if (p instanceof AST_PropAccess && p.expression === this) { return p instanceof AST_PropAccess && p.expression === this && /^0/.test(make_num(this.value));
var value = this.value;
// https://github.com/mishoo/UglifyJS/issues/115
return value < 0
// https://github.com/mishoo/UglifyJS/pull/1009
|| output.option("galio") && /^0/.test(make_num(value));
}
}); });
function needs_parens_assign_cond(self, output) { function needs_parens_assign_cond(self, output) {
@@ -807,8 +803,8 @@ function OutputStream(options) {
}); });
PARENS(AST_Assign, function(output) { PARENS(AST_Assign, function(output) {
if (needs_parens_assign_cond(this, output)) return true; if (needs_parens_assign_cond(this, output)) return true;
// v8 parser bug => workaround // v8 parser bug ---> workaround
// f([1], [a] = []) => f([1], ([a] = [])) // f([1], [a] = []) ---> f([1], ([a] = []))
if (output.option("v8")) return this.left instanceof AST_Destructured; if (output.option("v8")) return this.left instanceof AST_Destructured;
// ({ p: a } = o); // ({ p: a } = o);
if (this.left instanceof AST_DestructuredObject) return needs_parens_obj(output); if (this.left instanceof AST_DestructuredObject) return needs_parens_obj(output);

View File

@@ -280,9 +280,8 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
} }
function read_while(pred) { function read_while(pred) {
var ret = "", ch, i = 0; var ret = "", ch;
while ((ch = peek()) && pred(ch, i++)) while ((ch = peek()) && pred(ch)) ret += next();
ret += next();
return ret; return ret;
} }
@@ -292,16 +291,14 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
function read_num(prefix) { function read_num(prefix) {
var has_e = false, after_e = false, has_x = false, has_dot = 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) {
var code = ch.charCodeAt(0); var code = ch.charCodeAt(0);
switch (code) { switch (code) {
case 120: case 88: // xX case 120: case 88: // xX
return has_x ? false : (has_x = true); return has_x ? false : (has_x = true);
case 101: case 69: // eE case 101: case 69: // eE
return has_x ? true : has_e ? false : (has_e = after_e = true); return has_x ? true : has_e ? false : (has_e = after_e = true);
case 45: // - case 43: case 45: // +-
return after_e || (i == 0 && !prefix);
case 43: // +
return after_e; return after_e;
case (after_e = false, 46): // . case (after_e = false, 46): // .
return (!has_dot && !has_x && !has_e) ? (has_dot = true) : false; return (!has_dot && !has_x && !has_e) ? (has_dot = true) : false;
@@ -315,8 +312,9 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
num = num.replace(has_x ? /([1-9a-f]|.0)_(?=[0-9a-f])/gi : /([1-9]|.0)_(?=[0-9])/gi, "$1"); num = num.replace(has_x ? /([1-9a-f]|.0)_(?=[0-9a-f])/gi : /([1-9]|.0)_(?=[0-9])/gi, "$1");
} }
var valid = parse_js_number(num); var valid = parse_js_number(num);
if (!isNaN(valid)) return token("num", valid); if (isNaN(valid)) parse_error("Invalid syntax: " + num);
parse_error("Invalid syntax: " + num); if (has_dot || has_e || peek() != "n") return token("num", valid);
return token("bigint", num.toLowerCase() + next());
} }
function read_escaped_char(in_string) { function read_escaped_char(in_string) {
@@ -635,7 +633,7 @@ var PRECEDENCE = function(a, ret) {
["*", "/", "%"] ["*", "/", "%"]
], {}); ], {});
var ATOMIC_START_TOKEN = makePredicate("atom num regexp string"); var ATOMIC_START_TOKEN = makePredicate("atom bigint num regexp string");
/* -----[ Parser ]----- */ /* -----[ Parser ]----- */
@@ -783,6 +781,7 @@ function parse($TEXT, options) {
semicolon(); semicolon();
return dir ? new AST_Directive(body) : new AST_SimpleStatement({ body: body }); return dir ? new AST_Directive(body) : new AST_SimpleStatement({ body: body });
case "num": case "num":
case "bigint":
case "regexp": case "regexp":
case "operator": case "operator":
case "atom": case "atom":
@@ -1361,6 +1360,9 @@ function parse($TEXT, options) {
case "num": case "num":
ret = new AST_Number({ start: tok, end: tok, value: tok.value }); ret = new AST_Number({ start: tok, end: tok, value: tok.value });
break; break;
case "bigint":
ret = new AST_BigInt({ start: tok, end: tok, value: tok.value });
break;
case "string": case "string":
ret = new AST_String({ ret = new AST_String({
start : tok, start : tok,

View File

@@ -228,7 +228,7 @@ function mangle_properties(ast, options) {
var mangled = cache.get(name); var mangled = cache.get(name);
if (!mangled) { if (!mangled) {
if (debug) { if (debug) {
// debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_. // debug mode: use a prefix and suffix to preserve readability, e.g. o.foo ---> o._$foo$NNN_.
var debug_mangled = "_$" + name + "$" + debug_suffix + "_"; var debug_mangled = "_$" + name + "$" + debug_suffix + "_";
if (can_mangle(debug_mangled)) mangled = debug_mangled; if (can_mangle(debug_mangled)) mangled = debug_mangled;
} }

View File

@@ -13,9 +13,10 @@ holes_and_undefined: {
} }
} }
constant_join: { constant_join_1: {
options = { options = {
evaluate: true, evaluate: true,
side_effects: true,
strings: true, strings: true,
unsafe: true, unsafe: true,
} }
@@ -57,7 +58,7 @@ constant_join: {
var c5 = [ boo() + bar() + "foo", 1, 2, 3, "bar", bar() + "foo" ].join(); var c5 = [ boo() + bar() + "foo", 1, 2, 3, "bar", bar() + "foo" ].join();
var c6 = [ "1,2,,,foo,bar", baz() ].join(); var c6 = [ "1,2,,,foo,bar", baz() ].join();
var d = "foo-3bar-baz"; var d = "foo-3bar-baz";
var e = [].join(foo + bar); var e = (foo, bar, "");
var f = ""; var f = "";
var g = ""; var g = "";
} }

46
test/compress/bigint.js Normal file
View File

@@ -0,0 +1,46 @@
arithmetic: {
input: {
console.log(((1n + 0x2n) * (0o3n - -4n)) >> (5n - 6n));
}
expect_exact: "console.log((1n+0x2n)*(0o3n- -4n)>>5n-6n);"
expect_stdout: "42n"
node_version: ">=10"
}
minus_dot: {
input: {
console.log(typeof -42n.toString(), typeof (-42n).toString());
}
expect_exact: "console.log(typeof-42n.toString(),typeof(-42n).toString());"
expect_stdout: "number string"
node_version: ">=10"
}
evaluate: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log((0xDEAD_BEEFn).toString(16));
}
expect: {
console.log(0xdeadbeefn.toString(16));
}
expect_stdout: "deadbeef"
node_version: ">=10"
}
Number: {
options = {
unsafe: true,
}
input: {
console.log(Number(-0xfeed_dead_beef_badn));
}
expect: {
console.log(+("" + -0xfeed_dead_beef_badn));
}
expect_stdout: "-1148098955808013200"
node_version: ">=10"
}

View File

@@ -17,7 +17,7 @@ issue_269_1: {
expect: { expect: {
var x = {}; var x = {};
console.log( console.log(
x + "", +x, !!x, "" + x, +("" + x), !!x,
"", 0, false "", 0, false
); );
} }

View File

@@ -338,7 +338,7 @@ evaluate_3: {
console.log(1 + Number(x) + 2); console.log(1 + Number(x) + 2);
} }
expect: { expect: {
console.log(+x + 3); console.log(+("" + x) + 3);
} }
} }

View File

@@ -134,6 +134,7 @@ var SUPPORT = function(matrix) {
}({ }({
arrow: "a => 0;", arrow: "a => 0;",
async: "async function f(){}", async: "async function f(){}",
bigint: "42n",
catch_omit_var: "try {} catch {}", catch_omit_var: "try {} catch {}",
computed_key: "({[0]: 0});", computed_key: "({[0]: 0});",
const_block: "var a; { const a = 0; }", const_block: "var a; { const a = 0; }",
@@ -188,6 +189,12 @@ var VALUES = [
'"function"', '"function"',
"this", "this",
]; ];
if (SUPPORT.bigint) VALUES = VALUES.concat([
"!0o644n",
"([3n][0] > 2)",
"(-42n).toString()",
"Number(0XDEADn << 16n | 0xbeefn)",
]);
var BINARY_OPS = [ var BINARY_OPS = [
" + ", // spaces needed to disambiguate with ++ cases (could otherwise cause syntax errors) " + ", // spaces needed to disambiguate with ++ cases (could otherwise cause syntax errors)