2010-12-29 14:06:57 -05:00
|
|
|
# Number Literals
|
|
|
|
# ---------------
|
|
|
|
|
|
|
|
# * Decimal Integer Literals
|
|
|
|
# * Octal Integer Literals
|
|
|
|
# * Hexadecimal Integer Literals
|
|
|
|
# * Scientific Notation Integer Literals
|
|
|
|
# * Scientific Notation Non-Integer Literals
|
|
|
|
# * Non-Integer Literals
|
2011-10-21 14:44:56 -04:00
|
|
|
# * Binary Integer Literals
|
2010-12-30 22:48:31 -05:00
|
|
|
|
|
|
|
|
2011-10-21 14:44:56 -04:00
|
|
|
# Binary Integer Literals
|
|
|
|
# Binary notation is understood as would be decimal notation.
|
|
|
|
|
|
|
|
test "Parser recognises binary numbers", ->
|
2011-10-21 15:27:08 -04:00
|
|
|
eq 4, 0b100
|
2011-10-21 14:44:56 -04:00
|
|
|
|
2011-03-11 21:41:12 -05:00
|
|
|
# Decimal Integer Literals
|
2010-12-30 22:48:31 -05:00
|
|
|
|
|
|
|
test "call methods directly on numbers", ->
|
|
|
|
eq 4, 4.valueOf()
|
|
|
|
eq '11', 4.toString 3
|
|
|
|
|
|
|
|
eq -1, 3 -4
|
|
|
|
|
|
|
|
#764: Numbers should be indexable
|
|
|
|
eq Number::toString, 42['toString']
|
|
|
|
|
|
|
|
eq Number::toString, 42.toString
|
|
|
|
|
Refactor `Literal` into several subtypes
Previously, the parser created `Literal` nodes for many things. This resulted in
information loss. Instead of being able to check the node type, we had to use
regexes to tell the different types of `Literal`s apart. That was a bit like
parsing literals twice: Once in the lexer, and once (or more) in the compiler.
It also caused problems, such as `` `this` `` and `this` being indistinguishable
(fixes #2009).
Instead returning `new Literal` in the grammar, subtypes of it are now returned
instead, such as `NumberLiteral`, `StringLiteral` and `IdentifierLiteral`. `new
Literal` by itself is only used to represent code chunks that fit no category.
(While mentioning `NumberLiteral`, there's also `InfinityLiteral` now, which is
a subtype of `NumberLiteral`.)
`StringWithInterpolations` has been added as a subtype of `Parens`, and
`RegexWithInterpolations` as a subtype of `Call`. This makes it easier for other
programs to make use of CoffeeScript's "AST" (nodes). For example, it is now
possible to distinguish between `"a #{b} c"` and `"a " + b + " c"`. Fixes #4192.
`SuperCall` has been added as a subtype of `Call`.
Note, though, that some information is still lost, especially in the lexer. For
example, there is no way to distinguish a heredoc from a regular string, or a
heregex without interpolations from a regular regex. Binary and octal number
literals are indistinguishable from hexadecimal literals.
After the new subtypes were added, they were taken advantage of, removing most
regexes in nodes.coffee. `SIMPLENUM` (which matches non-hex integers) had to be
kept, though, because such numbers need special handling in JavaScript (for
example in `1..toString()`).
An especially nice hack to get rid of was using `new String()` for the token
value for reserved identifiers (to be able to set a property on them which could
survive through the parser). Now it's a good old regular string.
In range literals, slices, splices and for loop steps when number literals
are involved, CoffeeScript can do some optimizations, such as precomputing the
value of, say, `5 - 3` (outputting `2` instead of `5 - 3` literally). As a side
bonus, this now also works with hexadecimal number literals, such as `0x02`.
Finally, this also improves the output of `coffee --nodes`:
# Before:
$ bin/coffee -ne 'while true
"#{a}"
break'
Block
While
Value
Bool
Block
Value
Parens
Block
Op +
Value """"
Value
Parens
Block
Value "a" "break"
# After:
$ bin/coffee -ne 'while true
"#{a}"
break'
Block
While
Value BooleanLiteral: true
Block
Value
StringWithInterpolations
Block
Op +
Value StringLiteral: ""
Value
Parens
Block
Value IdentifierLiteral: a
StatementLiteral: break
2016-01-31 14:24:31 -05:00
|
|
|
eq Number::toString, 2e308['toString'] # Infinity
|
|
|
|
|
2010-12-30 22:48:31 -05:00
|
|
|
|
2011-03-11 21:41:12 -05:00
|
|
|
# Non-Integer Literals
|
2010-12-30 22:48:31 -05:00
|
|
|
|
|
|
|
# Decimal number literals.
|
|
|
|
value = .25 + .75
|
|
|
|
ok value is 1
|
|
|
|
value = 0.0 + -.25 - -.75 + 0.0
|
|
|
|
ok value is 0.5
|
|
|
|
|
|
|
|
#764: Numbers should be indexable
|
2011-05-24 16:27:07 -04:00
|
|
|
eq Number::toString, 4['toString']
|
2010-12-30 22:48:31 -05:00
|
|
|
eq Number::toString, 4.2['toString']
|
|
|
|
eq Number::toString, .42['toString']
|
2011-05-24 16:27:07 -04:00
|
|
|
eq Number::toString, (4)['toString']
|
2010-12-30 22:48:31 -05:00
|
|
|
|
2011-05-24 16:27:07 -04:00
|
|
|
eq Number::toString, 4.toString
|
2010-12-30 22:48:31 -05:00
|
|
|
eq Number::toString, 4.2.toString
|
|
|
|
eq Number::toString, .42.toString
|
2011-05-24 16:27:07 -04:00
|
|
|
eq Number::toString, (4).toString
|
2011-02-27 02:11:12 -05:00
|
|
|
|
|
|
|
test '#1168: leading floating point suppresses newline', ->
|
2012-02-03 19:33:03 -05:00
|
|
|
eq 1, do ->
|
|
|
|
1
|
|
|
|
.5 + 0.5
|
2012-01-12 15:32:14 -05:00
|
|
|
|
|
|
|
test "Python-style octal literal notation '0o777'", ->
|
|
|
|
eq 511, 0o777
|
|
|
|
eq 1, 0o1
|
|
|
|
eq 1, 0o00001
|
|
|
|
eq parseInt('0777', 8), 0o777
|
|
|
|
eq '777', 0o777.toString 8
|
|
|
|
eq 4, 0o4.valueOf()
|
|
|
|
eq Number::toString, 0o777['toString']
|
|
|
|
eq Number::toString, 0o777.toString
|
2012-01-20 17:23:50 -05:00
|
|
|
|
|
|
|
test "#2060: Disallow uppercase radix prefixes and exponential notation", ->
|
|
|
|
for char in ['b', 'o', 'x', 'e']
|
|
|
|
program = "0#{char}0"
|
|
|
|
doesNotThrow -> CoffeeScript.compile program, bare: yes
|
|
|
|
throws -> CoffeeScript.compile program.toUpperCase(), bare: yes
|
2012-03-27 21:31:20 -04:00
|
|
|
|
|
|
|
test "#2224: hex literals with 0b or B or E", ->
|
|
|
|
eq 176, 0x0b0
|
|
|
|
eq 177, 0x0B1
|
|
|
|
eq 225, 0xE1
|
Refactor `Literal` into several subtypes
Previously, the parser created `Literal` nodes for many things. This resulted in
information loss. Instead of being able to check the node type, we had to use
regexes to tell the different types of `Literal`s apart. That was a bit like
parsing literals twice: Once in the lexer, and once (or more) in the compiler.
It also caused problems, such as `` `this` `` and `this` being indistinguishable
(fixes #2009).
Instead returning `new Literal` in the grammar, subtypes of it are now returned
instead, such as `NumberLiteral`, `StringLiteral` and `IdentifierLiteral`. `new
Literal` by itself is only used to represent code chunks that fit no category.
(While mentioning `NumberLiteral`, there's also `InfinityLiteral` now, which is
a subtype of `NumberLiteral`.)
`StringWithInterpolations` has been added as a subtype of `Parens`, and
`RegexWithInterpolations` as a subtype of `Call`. This makes it easier for other
programs to make use of CoffeeScript's "AST" (nodes). For example, it is now
possible to distinguish between `"a #{b} c"` and `"a " + b + " c"`. Fixes #4192.
`SuperCall` has been added as a subtype of `Call`.
Note, though, that some information is still lost, especially in the lexer. For
example, there is no way to distinguish a heredoc from a regular string, or a
heregex without interpolations from a regular regex. Binary and octal number
literals are indistinguishable from hexadecimal literals.
After the new subtypes were added, they were taken advantage of, removing most
regexes in nodes.coffee. `SIMPLENUM` (which matches non-hex integers) had to be
kept, though, because such numbers need special handling in JavaScript (for
example in `1..toString()`).
An especially nice hack to get rid of was using `new String()` for the token
value for reserved identifiers (to be able to set a property on them which could
survive through the parser). Now it's a good old regular string.
In range literals, slices, splices and for loop steps when number literals
are involved, CoffeeScript can do some optimizations, such as precomputing the
value of, say, `5 - 3` (outputting `2` instead of `5 - 3` literally). As a side
bonus, this now also works with hexadecimal number literals, such as `0x02`.
Finally, this also improves the output of `coffee --nodes`:
# Before:
$ bin/coffee -ne 'while true
"#{a}"
break'
Block
While
Value
Bool
Block
Value
Parens
Block
Op +
Value """"
Value
Parens
Block
Value "a" "break"
# After:
$ bin/coffee -ne 'while true
"#{a}"
break'
Block
While
Value BooleanLiteral: true
Block
Value
StringWithInterpolations
Block
Op +
Value StringLiteral: ""
Value
Parens
Block
Value IdentifierLiteral: a
StatementLiteral: break
2016-01-31 14:24:31 -05:00
|
|
|
|
|
|
|
test "Infinity", ->
|
|
|
|
eq Infinity, CoffeeScript.eval "0b#{Array(1024 + 1).join('1')}"
|
|
|
|
eq Infinity, CoffeeScript.eval "0o#{Array(342 + 1).join('7')}"
|
|
|
|
eq Infinity, CoffeeScript.eval "0x#{Array(256 + 1).join('f')}"
|
|
|
|
eq Infinity, CoffeeScript.eval Array(500 + 1).join('9')
|
|
|
|
eq Infinity, 2e308
|
2016-03-05 15:32:20 -05:00
|
|
|
|
|
|
|
test "NaN", ->
|
|
|
|
ok isNaN 1/NaN
|