feat: backport bigint support to uglify-es from #4583

This commit is contained in:
Mark Vayngrib 2023-10-31 14:31:45 +08:00
parent 569757d14d
commit fd35571f37
No known key found for this signature in database
GPG Key ID: AA48332BE2806A28
7 changed files with 83 additions and 24 deletions

View File

@ -1068,7 +1068,23 @@ var AST_Number = DEFNODE("Number", "value literal", {
$propdoc: { $propdoc: {
value: "[number] the numeric value", value: "[number] the numeric value",
literal: "[string] numeric value as string (optional)" literal: "[string] numeric value as string (optional)"
} },
_validate: function() {
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);
var AST_RegExp = DEFNODE("RegExp", "value", { var AST_RegExp = DEFNODE("RegExp", "value", {

View File

@ -865,13 +865,11 @@ 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.getValue();
if (value < 0 || /^0/.test(make_num(value))) {
return true;
}
}
}); });
PARENS([ AST_Assign, AST_Conditional ], function(output){ PARENS([ AST_Assign, AST_Conditional ], function(output){

View File

@ -377,9 +377,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;
}; };
@ -389,7 +388,7 @@ 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 98: case 66: // bB case 98: case 66: // bB
@ -399,9 +398,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
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;
@ -413,11 +410,9 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
parse_error("Legacy octal literals are not allowed in strict mode"); parse_error("Legacy octal literals are not allowed in strict mode");
} }
var valid = parse_js_number(num); var valid = parse_js_number(num);
if (!isNaN(valid)) { if (isNaN(valid)) parse_error("Invalid syntax: " + num);
return token("num", valid); if (has_dot || has_e || peek() != "n") return token("num", valid);
} else { return token("bigint", num.toLowerCase() + next());
parse_error("Invalid syntax: " + num);
}
}; };
function read_escaped_char(in_string) { function read_escaped_char(in_string) {
@ -847,7 +842,7 @@ var PRECEDENCE = (function(a, ret){
{} {}
); );
var ATOMIC_START_TOKEN = makePredicate([ "atom", "num", "string", "regexp", "name" ]); var ATOMIC_START_TOKEN = makePredicate([ "atom", "bigint", "num", "string", "regexp", "name" ]);
/* -----[ Parser ]----- */ /* -----[ Parser ]----- */
@ -1003,6 +998,7 @@ function parse($TEXT, options) {
return dir ? new AST_Directive(stat.body) : stat; return dir ? new AST_Directive(stat.body) : stat;
case "template_head": case "template_head":
case "num": case "num":
case "bigint":
case "regexp": case "regexp":
case "operator": case "operator":
case "atom": case "atom":
@ -1935,6 +1931,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

@ -15,7 +15,7 @@ holes_and_undefined: {
} }
} }
constant_join: { constant_join_1: {
options = { options = {
unsafe : true, unsafe : true,
evaluate : true evaluate : true
@ -37,7 +37,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, null, undefined, "foo", "bar", baz() ].join(); var c6 = [ 1, 2, null, undefined, "foo", "bar", baz() ].join();
var d = [ "foo", 1 + 2 + "bar", "baz" ].join("-"); var d = [ "foo", 1 + 2 + "bar", "baz" ].join("-");
var e = [].join(foo + bar); var e = (foo, bar, "");
var f = [].join(""); var f = [].join("");
var g = [].join("foo"); var g = [].join("foo");
} }

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

@ -13,7 +13,7 @@ issue_269_1: {
} }
expect: { expect: {
f( f(
x + '', +x, !!x, '' + x, +('' + x), !!x,
'', 0, false '', 0, false
); );
} }

View File

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