aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Lam S.L <alexlamsl@gmail.com>2020-10-04 17:05:03 +0100
committerGitHub <noreply@github.com>2020-10-05 00:05:03 +0800
commit58ac5b9bd5e5d37a4afd2c435973dd8c56449ffb (patch)
treeca9564980237c9efd50054ce259bdbe4b768af04
parent66140b459e65e0540e567966f8dbefdbc2016f9e (diff)
downloadtracifyjs-58ac5b9bd5e5d37a4afd2c435973dd8c56449ffb.tar.gz
tracifyjs-58ac5b9bd5e5d37a4afd2c435973dd8c56449ffb.zip
extend support for numeral literals (#4176)
-rw-r--r--lib/parse.js31
-rw-r--r--test/mocha/number-literal.js61
2 files changed, 75 insertions, 17 deletions
diff --git a/lib/parse.js b/lib/parse.js
index d57baccb..3989ae65 100644
--- a/lib/parse.js
+++ b/lib/parse.js
@@ -60,8 +60,9 @@ KEYWORDS_ATOM = makePredicate(KEYWORDS_ATOM);
var OPERATOR_CHARS = makePredicate(characters("+-*&%=<>!?|~^"));
-var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i;
-var RE_OCT_NUMBER = /^0[0-7]+$/;
+var RE_BIN_NUMBER = /^0b([01]+)$/i;
+var RE_HEX_NUMBER = /^0x([0-9a-f]+)$/i;
+var RE_OCT_NUMBER = /^0o?([0-7]+)$/i;
var OPERATORS = makePredicate([
"in",
@@ -147,10 +148,6 @@ function is_digit(code) {
return code >= 48 && code <= 57;
}
-function is_alphanumeric_char(code) {
- return is_digit(code) || is_letter(code);
-}
-
function is_unicode_digit(code) {
return UNICODE.digit.test(String.fromCharCode(code));
}
@@ -184,14 +181,12 @@ function is_identifier_string(str) {
}
function parse_js_number(num) {
- if (RE_HEX_NUMBER.test(num)) {
- return parseInt(num.substr(2), 16);
- } else if (RE_OCT_NUMBER.test(num)) {
- return parseInt(num.substr(1), 8);
- } else {
- var val = parseFloat(num);
- if (val == num) return val;
- }
+ var match;
+ if (match = RE_BIN_NUMBER.exec(num)) return parseInt(match[1], 2);
+ if (match = RE_HEX_NUMBER.exec(num)) return parseInt(match[1], 16);
+ if (match = RE_OCT_NUMBER.exec(num)) return parseInt(match[1], 8);
+ var val = parseFloat(num);
+ if (val == num) return val;
}
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): // .
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 (RE_OCT_NUMBER.test(num) && next_token.has_directive("use strict")) {
- parse_error("Legacy octal literals are not allowed in strict mode");
+ if (/^0[0-7_]+$/.test(num)) {
+ 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);
if (!isNaN(valid)) return token("num", valid);
diff --git a/test/mocha/number-literal.js b/test/mocha/number-literal.js
index b87c88bb..a2b16a9e 100644
--- a/test/mocha/number-literal.js
+++ b/test/mocha/number-literal.js
@@ -28,4 +28,65 @@ describe("Number literals", function() {
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);
+ });
+ });
});