NumericSeparator.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
  6. var tests = [
  7. {
  8. name: "Decimal literal support",
  9. body: function () {
  10. assert.areEqual(1234, 1_234, "1234 === 1_234");
  11. assert.areEqual(1234, 1_2_3_4, "1234 === 1_2_3_4");
  12. assert.areEqual(1234.567, 1_2_3_4.5_6_7, "1234.567 === 1_2_3_4.5_6_7");
  13. assert.areEqual(-1234, -1_2_34, "-1234 === -1_2_34");
  14. assert.areEqual(-12.34, -1_2.3_4, "-12.34 === -1_2.3_4");
  15. }
  16. },
  17. {
  18. name: "Decimal literal with exponent",
  19. body: function () {
  20. assert.areEqual(1e100, 1e1_00, "1e100 === 1e1_00");
  21. assert.areEqual(Infinity, 1e1_0_0_0, "Infinity === 1e1_0_0_0");
  22. assert.areEqual(123.456e23, 1_2_3.4_5_6e2_3, "123.456e23 === 1_2_3.4_5_6e2_3");
  23. assert.areEqual(123.456e001, 1_2_3.4_5_6e0_0_1, "123.456e001 === 1_2_3.4_5_6e0_0_1");
  24. }
  25. },
  26. {
  27. name: "Decimal literal bad syntax",
  28. body: function () {
  29. // Decimal left-part only with numeric separators
  30. assert.throws(()=>eval('1__2'), SyntaxError, "Multiple numeric separators in a row are not allowed");
  31. assert.throws(()=>eval('1_2____3'), SyntaxError, "Multiple numeric separators in a row are not allowed");
  32. assert.throws(()=>eval('1_'), SyntaxError, "Decimal may not end in a numeric separator");
  33. assert.throws(()=>eval('1__'), SyntaxError, "Decimal may not end in a numeric separator");
  34. assert.throws(()=>eval('__1'), ReferenceError, "Decimal may not begin with a numeric separator");
  35. assert.throws(()=>eval('_1'), ReferenceError, "Decimal may not begin with a numeric separator");
  36. // Decimal with right-part with numeric separators
  37. assert.throws(()=>eval('1.0__0'), SyntaxError, "Decimal right-part may not contain multiple contiguous numeric separators");
  38. assert.throws(()=>eval('1.0_0__2'), SyntaxError, "Decimal right-part may not contain multiple contiguous numeric separators");
  39. assert.throws(()=>eval('1._'), SyntaxError, "Decimal right-part may not be a single numeric separator");
  40. assert.throws(()=>eval('1.__'), SyntaxError, "Decimal right-part may not be multiple numeric separators");
  41. assert.throws(()=>eval('1._0'), SyntaxError, "Decimal right-part may not begin with a numeric separator");
  42. assert.throws(()=>eval('1.__0'), SyntaxError, "Decimal right-part may not begin with a numeric separator");
  43. assert.throws(()=>eval('1.0_'), SyntaxError, "Decimal right-part may not end with a numeric separator");
  44. assert.throws(()=>eval('1.0__'), SyntaxError, "Decimal right-part may not end with a numeric separator");
  45. // Decimal with both parts with numeric separators
  46. assert.throws(()=>eval('1_.0'), SyntaxError, "Decimal left-part may not end in numeric separator");
  47. assert.throws(()=>eval('1__.0'), SyntaxError, "Decimal left-part may not end in numeric separator");
  48. assert.throws(()=>eval('1__2.0'), SyntaxError, "Decimal left-part may not contain multiple contiguous numeric separators");
  49. // Decimal with exponent with numeric separators
  50. assert.throws(()=>eval('1_e10'), SyntaxError, "Decimal left-part may not end in numeric separator");
  51. assert.throws(()=>eval('1e_1'), SyntaxError, "Exponent may not begin with numeric separator");
  52. assert.throws(()=>eval('1e__1'), SyntaxError, "Exponent may not begin with numeric separator");
  53. assert.throws(()=>eval('1e1_'), SyntaxError, "Exponent may not end with numeric separator");
  54. assert.throws(()=>eval('1e1__'), SyntaxError, "Exponent may not end with numeric separator");
  55. assert.throws(()=>eval('1e1__2'), SyntaxError, "Exponent may not contain multiple contiguous numeric separators");
  56. // Decimal big ints with numeric separators
  57. assert.throws(()=>eval('1_n'), SyntaxError);
  58. }
  59. },
  60. {
  61. name: "Strings parsed as number do not support numeric separators for decimal literals",
  62. body: function () {
  63. assert.areEqual(NaN, Number('12_34'), "NaN === Number('12_34')");
  64. assert.areEqual(NaN, Number('12e3_4'), "NaN === Number('12e3_4')");
  65. assert.areEqual(NaN, Number('1234.45_67'), "NaN === Number('1234.45_67')");
  66. assert.areEqual(NaN, Number('1234.45e6_7'), "NaN === Number('1234.45e6_7')");
  67. assert.areEqual(1, parseInt('1_2'), "1 === parseInt('1_2')");
  68. assert.areEqual(1, parseInt('1e2_3'), "1 === parseInt('1e2_3')");
  69. assert.areEqual(12, parseInt('12.3_4'), "1 === parseInt('12.3_4')");
  70. assert.areEqual(12, parseInt('12.34e5_6'), "1 === parseInt('12.34e5_6')");
  71. assert.areEqual(1, parseFloat('1_2'), "1 === parseFloat('1_2')");
  72. assert.areEqual(1e2, parseFloat('1e2_3'), "1 === parseFloat('1e2_3')");
  73. assert.areEqual(12.3, parseFloat('12.3_4'), "1 === parseFloat('12.3_4')");
  74. assert.areEqual(12.34e5, parseFloat('12.34e5_6'), "1 === parseFloat('12.34e5_6')");
  75. }
  76. },
  77. {
  78. name: "Binary literal support",
  79. body: function () {
  80. assert.areEqual(0b00, 0b0_0, "0b00 === 0b0_0");
  81. assert.areEqual(0b11, 0b1_1, "0b11 === 0b1_1");
  82. assert.areEqual(0b10, 0b1_0, "0b10 === 0b1_0");
  83. assert.areEqual(0b01, 0b0_1, "0b01 === 0b0_1");
  84. assert.areEqual(0b0001, 0b000_1, "0b0001 === 0b000_1");
  85. assert.areEqual(0b0000, 0b000_0, "0b0000 === 0b000_0");
  86. assert.areEqual(0b000011110000, 0b0000_1111_0000, "0b000011110000 === 0b0000_1111_0000");
  87. assert.areEqual(0b000011110000, 0b0_0_0_0_1_111_00_00, "0b000011110000 === 0b0_0_0_0_1_111_00_00");
  88. }
  89. },
  90. {
  91. name: "Binary literal bad syntax",
  92. body: function () {
  93. assert.throws(()=>eval('0b_'), SyntaxError, "'_' cannot immediately follow 0b");
  94. assert.throws(()=>eval('0b__'), SyntaxError, "'_' cannot immediately follow 0b");
  95. assert.throws(()=>eval('0b_1'), SyntaxError, "Binary literal may not begin with numeric separator");
  96. assert.throws(()=>eval('0b_0'), SyntaxError, "Binary literal may not begin with numeric separator");
  97. assert.throws(()=>eval('0b__1'), SyntaxError, "Binary literal may not begin with numeric separator");
  98. assert.throws(()=>eval('0b__0'), SyntaxError, "Binary literal may not begin with numeric separator");
  99. assert.throws(()=>eval('0b1_'), SyntaxError, "Binary literal may not end with numeric separator");
  100. assert.throws(()=>eval('0b0_'), SyntaxError, "Binary literal may not end with numeric separator");
  101. assert.throws(()=>eval('0b1__'), SyntaxError, "Binary literal may not end with numeric separator");
  102. assert.throws(()=>eval('0b0__'), SyntaxError, "Binary literal may not end with numeric separator");
  103. assert.throws(()=>eval('0b1__1'), SyntaxError, "Multiple numeric separator characters may not follow each other");
  104. assert.throws(()=>eval('0b0__0'), SyntaxError, "Multiple numeric separator characters may not follow each other");
  105. assert.throws(()=>eval('0b000__1'), SyntaxError, "Multiple numeric separator characters may not follow each other");
  106. assert.throws(()=>eval('0b000_a'), SyntaxError, "After initial zeroes, a numeric separator followed by an invalid character");
  107. }
  108. },
  109. {
  110. name: "Strings parsed as number do not support numeric separators for binary literals",
  111. body: function () {
  112. assert.areEqual(NaN, Number('0b0_1'), "NaN === Number('0b0_1')");
  113. assert.areEqual(NaN, Number('0b1_0'), "NaN === Number('0b1_0')");
  114. assert.areEqual(NaN, Number('0b0_0'), "NaN === Number('0b0_0')");
  115. assert.areEqual(NaN, Number('0b1_1'), "NaN === Number('0b1_1')");
  116. assert.areEqual(0, parseInt('0b1_0'), "0 === parseInt('0b1_0')");
  117. assert.areEqual(0, parseFloat('0b1_0'), "0 === parseFloat('0b1_0')");
  118. }
  119. },
  120. {
  121. name: "Hex numeric literal support",
  122. body: function () {
  123. assert.areEqual(0x00, 0x0_0, "0x00 === 0x0_0");
  124. assert.areEqual(0x1f, 0x1_f, "0x1f === 0x1_f");
  125. assert.areEqual(0x000000Ae1, 0x00_0_000_A_e1, "0x000000Ae1 === 0x00_0_000_A_e1");
  126. assert.areEqual(0xaabbccdd, 0xaa_bb_cc_dd, "0xaabbccdd === 0xaa_bb_cc_dd");
  127. }
  128. },
  129. {
  130. name: "Hex numeric literal bad syntax",
  131. body: function () {
  132. assert.throws(()=>eval('0x_'), SyntaxError, "'_' cannot immediately follow 0x");
  133. assert.throws(()=>eval('0x__'), SyntaxError, "'_' cannot immediately follow 0x");
  134. assert.throws(()=>eval('0x_1'), SyntaxError, "Hex literal may not begin with numeric separator");
  135. assert.throws(()=>eval('0x_0'), SyntaxError, "Hex literal may not begin with numeric separator");
  136. assert.throws(()=>eval('0x__1'), SyntaxError, "Hex literal may not begin with numeric separator");
  137. assert.throws(()=>eval('0x__0'), SyntaxError, "Hex literal may not begin with numeric separator");
  138. assert.throws(()=>eval('0x1_'), SyntaxError, "Hex literal may not end with numeric separator");
  139. assert.throws(()=>eval('0x0_'), SyntaxError, "Hex literal may not end with numeric separator");
  140. assert.throws(()=>eval('0x1__'), SyntaxError, "Hex literal may not end with numeric separator");
  141. assert.throws(()=>eval('0x0__'), SyntaxError, "Hex literal may not end with numeric separator");
  142. assert.throws(()=>eval('0x1__1'), SyntaxError, "Multiple numeric separator characters may not follow each other");
  143. assert.throws(()=>eval('0x0__0'), SyntaxError, "Multiple numeric separator characters may not follow each other");
  144. assert.throws(()=>eval('0x000__1'), SyntaxError, "Multiple numeric separator characters may not follow each other");
  145. assert.throws(()=>eval('0x000_q'), SyntaxError, "After initial zeroes, a numeric separator followed by an invalid character");
  146. }
  147. },
  148. {
  149. name: "Strings parsed as number do not support numeric separators for hex literals",
  150. body: function () {
  151. assert.areEqual(NaN, Number('0x0_ff'), "NaN === Number('0x0_ff')");
  152. assert.areEqual(NaN, Number('0xF_F'), "NaN === Number('0xF_F')");
  153. assert.areEqual(0, parseInt('0x0_ff'), "0 === parseInt('0x0_ff')");
  154. assert.areEqual(15, parseInt('0xf_00f'), "15 === parseInt('0xf_00f')");
  155. assert.areEqual(0, parseFloat('0x0_ff'), "0 === parseFloat('0x0_ff')");
  156. assert.areEqual(0, parseFloat('0x1_fe'), "0 === parseFloat('0x1_fe')");
  157. }
  158. },
  159. {
  160. name: "Octal literal support",
  161. body: function () {
  162. assert.areEqual(0o00, 0o0_0, "0o00 === 0o0_0");
  163. assert.areEqual(0o11, 0o1_1, "0o11 === 0o1_1");
  164. assert.areEqual(0o10, 0o1_0, "0o10 === 0o1_0");
  165. assert.areEqual(0o01, 0o0_1, "0o01 === 0o0_1");
  166. assert.areEqual(0o0001, 0o000_1, "0o0001 === 0o000_1");
  167. assert.areEqual(0o0000, 0o000_0, "0o0000 === 0o000_0");
  168. assert.areEqual(0o000011110000, 0o0000_1111_0000, "0o000011110000 === 0o0000_1111_0000");
  169. assert.areEqual(0o000011110000, 0o0_0_0_0_1_111_00_00, "0o000011110000 === 0o0_0_0_0_1_111_00_00");
  170. }
  171. },
  172. {
  173. name: "Octal literal bad syntax",
  174. body: function () {
  175. assert.throws(()=>eval('0o_'), SyntaxError, "'_' cannot immediately follow 0o");
  176. assert.throws(()=>eval('0o__'), SyntaxError, "'_' cannot immediately follow 0o");
  177. assert.throws(()=>eval('0o_1'), SyntaxError, "Octal literal may not begin with numeric separator");
  178. assert.throws(()=>eval('0o_0'), SyntaxError, "Octal literal may not begin with numeric separator");
  179. assert.throws(()=>eval('0o__1'), SyntaxError, "Octal literal may not begin with numeric separator");
  180. assert.throws(()=>eval('0o__0'), SyntaxError, "Octal literal may not begin with numeric separator");
  181. assert.throws(()=>eval('0o1_'), SyntaxError, "Octal literal may not end with numeric separator");
  182. assert.throws(()=>eval('0o0_'), SyntaxError, "Octal literal may not end with numeric separator");
  183. assert.throws(()=>eval('0o1__'), SyntaxError, "Octal literal may not end with numeric separator");
  184. assert.throws(()=>eval('0o0__'), SyntaxError, "Octal literal may not end with numeric separator");
  185. assert.throws(()=>eval('0o1__1'), SyntaxError, "Multiple numeric separator characters may not follow each other");
  186. assert.throws(()=>eval('0o0__0'), SyntaxError, "Multiple numeric separator characters may not follow each other");
  187. assert.throws(()=>eval('0o000__1'), SyntaxError, "Multiple numeric separator characters may not follow each other");
  188. assert.throws(()=>eval('0o000_a'), SyntaxError, "After initial zeroes, a numeric separator followed by an invalid character");
  189. }
  190. },
  191. {
  192. name: "Strings parsed as number do not support numeric separators for octal literals",
  193. body: function () {
  194. assert.areEqual(NaN, Number('0o0_1'), "NaN === Number('0o0_1')");
  195. assert.areEqual(NaN, Number('0o1_0'), "NaN === Number('0o1_0')");
  196. assert.areEqual(NaN, Number('0o0_0'), "NaN === Number('0o0_0')");
  197. assert.areEqual(NaN, Number('0o1_1'), "NaN === Number('0o1_1')");
  198. assert.areEqual(0, parseInt('0b1_0'), "0 === parseInt('0b1_0')");
  199. assert.areEqual(0, parseFloat('0b1_0'), "0 === parseFloat('0b1_0')");
  200. }
  201. },
  202. {
  203. name: "Legacy octal numeric literals do not support numeric separators",
  204. body: function () {
  205. assert.throws(()=>eval('0_1'), SyntaxError, "'_' cannot immediately follow 0 in legacy octal numeric literal");
  206. assert.throws(()=>eval('07_7'), SyntaxError, "Legacy octal numeric literals do not support numeric separator");
  207. }
  208. },
  209. ];
  210. testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });