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",
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));
}
}
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) {
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);
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);
+ });
+ });
});