extend support for numeral literals (#4176)

This commit is contained in:
Alex Lam S.L 2020-10-04 17:05:03 +01:00 committed by GitHub
parent 66140b459e
commit 58ac5b9bd5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 75 additions and 17 deletions

View File

@ -60,8 +60,9 @@ KEYWORDS_ATOM = makePredicate(KEYWORDS_ATOM);
var OPERATOR_CHARS = makePredicate(characters("+-*&%=<>!?|~^")); var OPERATOR_CHARS = makePredicate(characters("+-*&%=<>!?|~^"));
var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i; var RE_BIN_NUMBER = /^0b([01]+)$/i;
var RE_OCT_NUMBER = /^0[0-7]+$/; var RE_HEX_NUMBER = /^0x([0-9a-f]+)$/i;
var RE_OCT_NUMBER = /^0o?([0-7]+)$/i;
var OPERATORS = makePredicate([ var OPERATORS = makePredicate([
"in", "in",
@ -147,10 +148,6 @@ function is_digit(code) {
return code >= 48 && code <= 57; return code >= 48 && code <= 57;
} }
function is_alphanumeric_char(code) {
return is_digit(code) || is_letter(code);
}
function is_unicode_digit(code) { function is_unicode_digit(code) {
return UNICODE.digit.test(String.fromCharCode(code)); return UNICODE.digit.test(String.fromCharCode(code));
} }
@ -184,14 +181,12 @@ function is_identifier_string(str) {
} }
function parse_js_number(num) { function parse_js_number(num) {
if (RE_HEX_NUMBER.test(num)) { var match;
return parseInt(num.substr(2), 16); if (match = RE_BIN_NUMBER.exec(num)) return parseInt(match[1], 2);
} else if (RE_OCT_NUMBER.test(num)) { if (match = RE_HEX_NUMBER.exec(num)) return parseInt(match[1], 16);
return parseInt(num.substr(1), 8); if (match = RE_OCT_NUMBER.exec(num)) return parseInt(match[1], 8);
} else { var val = parseFloat(num);
var val = parseFloat(num); if (val == num) return val;
if (val == num) return val;
}
} }
function JS_Parse_Error(message, filename, line, col, pos) { function JS_Parse_Error(message, filename, line, col, pos) {
@ -347,11 +342,13 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
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;
} }
return is_alphanumeric_char(code); return is_digit(code) || is_letter(code) || ch == "_";
}); });
if (prefix) num = prefix + num; if (prefix) num = prefix + num;
if (RE_OCT_NUMBER.test(num) && next_token.has_directive("use strict")) { if (/^0[0-7_]+$/.test(num)) {
parse_error("Legacy octal literals are not allowed in strict mode"); if (next_token.has_directive("use strict")) parse_error("Legacy octal literals are not allowed in strict mode");
} else {
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)) return token("num", valid);

View File

@ -28,4 +28,65 @@ describe("Number literals", function() {
assert.throws(test(inputs[i]), error, inputs[i]); assert.throws(test(inputs[i]), error, inputs[i]);
} }
}); });
it("Should parse binary, hexadecimal, octal and underscore correctly", function() {
[
"42",
"4_2",
"052",
"0o52",
"0O52",
"0o5_2",
"0x2a",
"0X2A",
"0x2_a",
"0b101010",
"0B101010",
"0b101_010",
"0.0000000042e+10",
"0.0000000042E+10",
"0.0_000000042e+10",
"0.0000000042e+1_0",
"0.000_000_004_2e+1_0",
"0.000_000_004_2e+1_0-0B101_010+0x2_A-0o5_2+4_2",
].forEach(function(code) {
var result = UglifyJS.minify(code, {
compress: {
expression: true,
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, "42;");
});
});
it("Should reject invalid use of underscore", function() {
[
"_42",
"_+42",
"+_42",
].forEach(function(code) {
var node = UglifyJS.parse(code, {
expression: true,
});
assert.ok(!node.is_constant(), code);
assert.ok(!(node instanceof UglifyJS.AST_Statement), code);
});
[
"42_",
"4__2",
"0_52",
"05_2",
"0_o52",
"0o_52",
"0.0000000042_e10",
"0.0000000042e_10",
"0.0000000042e_+10",
"0.0000000042e+_10",
].forEach(function(code) {
assert.throws(function() {
UglifyJS.parse(code);
}, function(e) {
return e instanceof UglifyJS.JS_Parse_Error;
}, code);
});
});
}); });