NumericLiteralSuffix.js 5.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  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. // https://tc39.github.io/ecma262/#sec-reserved-words
  7. let keywords = ['await', 'break', 'case', 'catch', 'class', 'const', 'continue', 'debugger', 'default', 'delete', 'do', 'else', 'export', 'extends', 'finally', 'for', 'function', 'if', 'import', 'in', 'instanceof', 'new', 'return', 'super', 'switch', 'this', 'throw', 'try', 'typeof', 'var', 'void', 'while', 'with', 'yield'];
  8. let futureReservedWords = ['enum', 'implements', 'package', 'protected ', 'interface', 'private', 'public'];
  9. // https://tc39.github.io/ecma262/#sec-names-and-keywords
  10. let idStarts = ["\u{50}", '$', '_', "\\u{50}"];
  11. // https://tc39.github.io/ecma262/#sec-literals-numeric-literals
  12. let literalClasses = {
  13. 'Decimal Integer Literal': [
  14. '0', '1', '123',
  15. '0.1', '1.1', '123.1', '123.123',
  16. '0e1', '1e1', '1e+1', '1e-1',
  17. '0E1', '1E1', '1E+1', '1E-1',
  18. '123e123', '123e+123', '123e-123',
  19. '123E123', '123E+123', '123E-123'
  20. ],
  21. 'Binary Integer Literal': [
  22. '0b0', '0b1', '0b010101',
  23. '0B0', '0B1', '0B010101',
  24. ],
  25. 'Octal Integer Literal': [
  26. '0o0', '0o1', '0o123',
  27. '0O0', '0O1', '0O123'
  28. ],
  29. 'Hex Integer Literal': [
  30. '0x0', '0x1', '0x123', '0xabc', '0xABC', '0x123abc', '0x123ABC',
  31. '0X0', '0X1', '0X123', '0Xabc', '0XABC', '0X123abc', '0X123ABC'
  32. ]
  33. };
  34. var tests = [
  35. {
  36. name: "Numeric literal followed by an identifier start throws",
  37. body: function () {
  38. for (let literalClass in literalClasses) {
  39. for (let literal of literalClasses[literalClass]) {
  40. for (let idStart of idStarts) {
  41. for (let keyword of keywords) {
  42. assert.throws(function () { eval(`${literal}${keyword}`); }, SyntaxError, `Keyword '${keyword}' directly after ${literalClass} '${literal}' throws`, "Unexpected identifier after numeric literal");
  43. }
  44. for (let futureReservedWord of futureReservedWords) {
  45. assert.throws(function () { eval(`${literal}${futureReservedWord}`); }, SyntaxError, `Future reserved word '${futureReservedWord}' directly after ${literalClass} '${literal}' throws`, "Unexpected identifier after numeric literal");
  46. }
  47. for (let idStart of idStarts) {
  48. assert.throws(function () { eval(`${literal}${idStart}`); }, SyntaxError, `Identifier start '${idStart}' directly after ${literalClass} '${literal}' throws`, "Unexpected identifier after numeric literal");
  49. }
  50. }
  51. }
  52. }
  53. }
  54. },
  55. {
  56. name: "Numeric literal followed by invalid digit throws",
  57. body: function () {
  58. let nonOctalDigits = ['8', '9'];
  59. for (let literal of literalClasses['Octal Integer Literal']) {
  60. for (let nonOctalDigit of nonOctalDigits) {
  61. assert.throws(function () { eval(`${literal}${nonOctalDigit}`); }, SyntaxError, `Non-octal digit '${nonOctalDigit}' directly after Octal Integer Literal '${literal}' throws`, "Invalid number");
  62. }
  63. }
  64. let nonBinaryDigits = ['2', '3', '4', '5', '6', '7', '8', '9'];
  65. for (let literal of literalClasses['Binary Integer Literal']) {
  66. for (let nonBinaryDigit of nonBinaryDigits) {
  67. assert.throws(function () { eval(`${literal}${nonBinaryDigit}`); }, SyntaxError, `Non-binary digit '${nonBinaryDigit}' directly after Binary Integer Literal '${literal}' throws`, "Invalid number");
  68. }
  69. }
  70. }
  71. },
  72. {
  73. name: "Multi-unit whitespace is ignored after numeric identifier",
  74. body: function () {
  75. var result = 0;
  76. eval("\u2028var\u2028x\u2028=\u20281234\u2028; result = x;");
  77. assert.areEqual(1234, result, "Mutli-unit whitespace after numeric literal does not affect literal value");
  78. }
  79. },
  80. {
  81. name: "Multi-unit count updated in the middle of a token",
  82. body: function () {
  83. if (WScript.Platform.INTL_LIBRARY === "winglob" || WScript.Platform.INTL_LIBRARY === "icu") {
  84. assert.throws(() => eval('\u20091a'), SyntaxError, 'Multi-unit whitespace followed by numeric literal followed by identifier', 'Unexpected identifier after numeric literal');
  85. assert.throws(() => eval('\u20091\\u0065'), SyntaxError, 'Multi-unit whitespace followed by numeric literal followed by unicode escape sequence', 'Unexpected identifier after numeric literal');
  86. assert.throws(() => eval('\u20090o1239'), SyntaxError, 'Multi-unit whitespace followed by invalid octal numeric literal', 'Invalid number');
  87. }
  88. }
  89. }
  90. ];
  91. testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });