From 9cfca0235fde4dd9837e9f9fe4b27302a512425e Mon Sep 17 00:00:00 2001 From: Simon Lydell Date: Mon, 26 Sep 2016 16:33:57 +0200 Subject: [PATCH] Handle very large hexadecimal number literals correctly Very large decimal number literals, binary number literals and octal literals are lexed into an INFINITY token (instead of a NUMBER token) and compiled into `2e308`. That is is supposed to be the case for very large hexdecimal dumber literals as well, but previously wasn't. Before: $ node -p 'require("./").tokens(`0x${Array(256 + 1).join("f")}`)[0][0]' NUMBER After: $ node -p 'require("./").tokens(`0x${Array(256 + 1).join("f")}`)[0][0]' INFINITY This commit also cleans up `numberToken` in lexer.coffee a bit. --- lib/coffee-script/lexer.js | 59 ++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/lib/coffee-script/lexer.js b/lib/coffee-script/lexer.js index f5649a3d13..f022de68e3 100644 --- a/lib/coffee-script/lexer.js +++ b/lib/coffee-script/lexer.js @@ -174,37 +174,48 @@ }; Lexer.prototype.numberToken = function() { - var binaryLiteral, lexedLength, match, number, numberValue, octalLiteral, tag; + var base, lexedLength, match, number, numberValue, ref2, tag; if (!(match = NUMBER.exec(this.chunk))) { return 0; } number = match[0]; lexedLength = number.length; - if (/^0[BOX]/.test(number)) { - this.error("radix prefix in '" + number + "' must be lowercase", { - offset: 1 - }); - } else if (/E/.test(number) && !/^0x/.test(number)) { - this.error("exponential notation in '" + number + "' must be indicated with a lowercase 'e'", { - offset: number.indexOf('E') - }); - } else if (/^0\d*[89]/.test(number)) { - this.error("decimal literal '" + number + "' must not be prefixed with '0'", { - length: lexedLength - }); - } else if (/^0\d+/.test(number)) { - this.error("octal literal '" + number + "' must be prefixed with '0o'", { - length: lexedLength - }); + switch (false) { + case !/^0[BOX]/.test(number): + this.error("radix prefix in '" + number + "' must be lowercase", { + offset: 1 + }); + break; + case !/^(?!0x).*E/.test(number): + this.error("exponential notation in '" + number + "' must be indicated with a lowercase 'e'", { + offset: number.indexOf('E') + }); + break; + case !/^0\d*[89]/.test(number): + this.error("decimal literal '" + number + "' must not be prefixed with '0'", { + length: lexedLength + }); + break; + case !/^0\d+/.test(number): + this.error("octal literal '" + number + "' must be prefixed with '0o'", { + length: lexedLength + }); } - if (octalLiteral = /^0o([0-7]+)/.exec(number)) { - numberValue = parseInt(octalLiteral[1], 8); - number = "0x" + (numberValue.toString(16)); - } else if (binaryLiteral = /^0b([01]+)/.exec(number)) { - numberValue = parseInt(binaryLiteral[1], 2); + base = (function() { + switch (number.charAt(1)) { + case 'b': + return 2; + case 'o': + return 8; + case 'x': + return 16; + default: + return null; + } + })(); + numberValue = base != null ? parseInt(number.slice(2), base) : parseFloat(number); + if ((ref2 = number.charAt(1)) === 'b' || ref2 === 'o') { number = "0x" + (numberValue.toString(16)); - } else { - numberValue = parseFloat(number); } tag = numberValue === 2e308 ? 'INFINITY' : 'NUMBER'; this.token(tag, number, 0, lexedLength);