Skip to content

Commit

Permalink
Handle very large hexadecimal number literals correctly
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
lydell committed Sep 26, 2016
1 parent 3204180 commit 57f5297
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 40 deletions.
59 changes: 35 additions & 24 deletions lib/coffee-script/lexer.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 21 additions & 16 deletions src/lexer.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -191,25 +191,30 @@ exports.Lexer = class Lexer
# Be careful not to interfere with ranges-in-progress.
numberToken: ->
return 0 unless match = NUMBER.exec @chunk

number = match[0]
lexedLength = number.length
if /^0[BOX]/.test number
@error "radix prefix in '#{number}' must be lowercase", offset: 1
else if /E/.test(number) and not /^0x/.test number
@error "exponential notation in '#{number}' must be indicated with a lowercase 'e'",
offset: number.indexOf('E')
else if /^0\d*[89]/.test number
@error "decimal literal '#{number}' must not be prefixed with '0'", length: lexedLength
else if /^0\d+/.test number
@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)

switch
when /^0[BOX]/.test number
@error "radix prefix in '#{number}' must be lowercase", offset: 1
when /^(?!0x).*E/.test number
@error "exponential notation in '#{number}' must be indicated with a lowercase 'e'",
offset: number.indexOf('E')
when /^0\d*[89]/.test number
@error "decimal literal '#{number}' must not be prefixed with '0'", length: lexedLength
when /^0\d+/.test number
@error "octal literal '#{number}' must be prefixed with '0o'", length: lexedLength

base = switch number.charAt 1
when 'b' then 2
when 'o' then 8
when 'x' then 16
else null
numberValue = if base? then parseInt(number[2..], base) else parseFloat(number)
if number.charAt(1) in ['b', 'o']
number = "0x#{numberValue.toString 16}"
else
numberValue = parseFloat(number)

tag = if numberValue is Infinity then 'INFINITY' else 'NUMBER'
@token tag, number, 0, lexedLength
lexedLength
Expand Down

0 comments on commit 57f5297

Please sign in to comment.