/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // Simple cases, not using eval. { let \u{61} = 123; assertEq(a, 123); let \u{6A} = 123; assertEq(j, 123); let a\u{62} = 456; assertEq(ab, 456); let \u{63}\u{6b} = 789; assertEq(ck, 789); } const leadingZeros = [0, 1, 2, 3, 4, 100].map(c => "0".repeat(c)); // From DerivedCoreProperties.txt (Unicode 9): // Derived Property: ID_Start // Characters that can start an identifier. // Generated from: // Lu + Ll + Lt + Lm + Lo + Nl // + Other_ID_Start // - Pattern_Syntax // - Pattern_White_Space const idStart = [ 0x0041, // LATIN CAPITAL LETTER A, Gc=Lu 0x006A, // LATIN SMALL LETTER J, Gc=Ll 0x00C9, // LATIN CAPITAL LETTER E WITH ACUTE, Gc=Lu 0x00FF, // LATIN SMALL LETTER Y WITH DIAERESIS, Gc=Ll 0x01C5, // LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON, Gc=Lt 0x0294, // LATIN LETTER GLOTTAL STOP, Gc=Lo 0x037A, // GREEK YPOGEGRAMMENI, Gc=Lm 0x16EE, // RUNIC ARLAUG SYMBOL, Gc=Nl 0xFF70, // HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK, Gc=Lm ]; const idStartSupplemental = [ 0x10140, // GREEK ACROPHONIC ATTIC ONE QUARTER, Gc=Nl 0x10300, // OLD ITALIC LETTER A, Gc=Lo 0x10400, // DESERET CAPITAL LETTER LONG I, Gc=Lu 0x10430, // DESERET SMALL LETTER SHORT A, Gc=Ll 0x16B40, // PAHAWH HMONG SIGN VOS SEEV, Gc=Lm ]; // From PropList.txt (Unicode 9): const otherIdStart = [ 0x1885, // MONGOLIAN LETTER ALI GALI BALUDA, Gc=Mn 0x1886, // MONGOLIAN LETTER ALI GALI THREE BALUDA, Gc=Mn 0x2118, // SCRIPT CAPITAL P, Gc=Sm 0x212E, // ESTIMATED SYMBOL, Gc=So 0x309B, // KATAKANA-HIRAGANA VOICED SOUND MARK, Gc=Sk 0x309C, // KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK, Gc=Sk ]; // From DerivedCoreProperties.txt (Unicode 9): // Derived Property: ID_Continue // Characters that can continue an identifier. // Generated from: // ID_Start // + Mn + Mc + Nd + Pc // + Other_ID_Continue // - Pattern_Syntax // - Pattern_White_Space const idContinue = [ 0x0030, // DIGIT ZERO, Gc=Nd 0x0300, // COMBINING GRAVE ACCENT, Gc=Mn 0x0660, // ARABIC-INDIC DIGIT ZERO, Gc=Nd 0x0903, // DEVANAGARI SIGN VISARGA, Gc=Mc 0xFF10, // FULLWIDTH DIGIT ZERO, Gc=Nd 0xFF3F, // FULLWIDTH LOW LINE, Gc=Pc ]; const idContinueSupplemental = [ 0x101FD, // PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE, Gc=Mn 0x104A0, // OSMANYA DIGIT ZERO, Gc=Nd 0x11000, // BRAHMI SIGN CANDRABINDU, Gc=Mc ]; // From PropList.txt (Unicode 9): const otherIdContinue = [ 0x00B7, // MIDDLE DOT, Gc=Po 0x0387, // GREEK ANO TELEIA, Gc=Po 0x1369, // ETHIOPIC DIGIT ONE, Gc=No 0x136A, // ETHIOPIC DIGIT TWO, Gc=No 0x136B, // ETHIOPIC DIGIT THREE, Gc=No 0x136C, // ETHIOPIC DIGIT FOUR, Gc=No 0x136D, // ETHIOPIC DIGIT FIVE, Gc=No 0x136E, // ETHIOPIC DIGIT SIX, Gc=No 0x136F, // ETHIOPIC DIGIT SEVEN, Gc=No 0x1370, // ETHIOPIC DIGIT EIGHT, Gc=No 0x1371, // ETHIOPIC DIGIT NINE, Gc=No 0x19DA, // NEW TAI LUE THAM DIGIT ONE, Gc=No ]; for (let ident of [...idStart, ...otherIdStart, ...idStartSupplemental]) { for (let count of leadingZeros) { let zeros = "0".repeat(count); eval(` let \\u{${zeros}${ident.toString(16)}} = 123; assertEq(${String.fromCodePoint(ident)}, 123); `); } } for (let ident of [...idContinue, ...idContinueSupplemental, ...otherIdContinue]) { for (let zeros of leadingZeros) { assertThrowsInstanceOf(() => eval(`\\u{${zeros}${ident.toString(16)}}`), SyntaxError); } } for (let ident of [...idStart, ...otherIdStart, ...idContinue, ...otherIdContinue, ...idStartSupplemental, ...idContinueSupplemental]) { for (let zeros of leadingZeros) { eval(` let A\\u{${zeros}${ident.toString(16)}} = 123; assertEq(${String.fromCodePoint(0x41, ident)}, 123); `); } } const notIdentifiers = [ 0x0000, // NULL, Gc=Cc 0x000A, // LINE FEED (LF), Gc=Cc 0x005E, // CIRCUMFLEX ACCENT, Gc=Sk 0x00B1, // PLUS-MINUS SIGN, Gc=Sm 0xFF61, // HALFWIDTH IDEOGRAPHIC FULL STOP, Gc=Po 0x10061, // Not assigned. 0x10100, // AEGEAN WORD SEPARATOR LINE, Gc=Po 0x100061, // , Gc=Co ]; for (let ident of notIdentifiers) { for (let zeros of leadingZeros) { assertThrowsInstanceOf(() => eval(`\\u{${zeros}${ident.toString(16)}}`), SyntaxError); } } const incompleteEscapes = [ "\\u{", "\\u{6", "\\u{61", "\\u{061", "\\u{0061", "\\u{00061", "\\u{000061", "\\u{0000061", "\\u}", ]; for (let invalid of incompleteEscapes) { // Ends with EOF. assertThrowsInstanceOf(() => eval(invalid), SyntaxError); // Ends with EOL. assertThrowsInstanceOf(() => eval(invalid + "\n"), SyntaxError); // Ends with space. assertThrowsInstanceOf(() => eval(invalid + " "), SyntaxError); } const invalidEscapes = [ // Empty escape. "", // Not hexadecimal characters. "\0", "G", "Z", "\uFFFF", "\uDBFF\uDFFF", // Has space characters. " 61", "61 ", // Has newline characters. "\n61", "61\n", // Exceeds 0x10FFFF, six characters. "110000", "110001", "fffffe", "ffffff", // Exceeds 0x10FFFF, more than six characters. "10ffff0", "10ffffabcdef", ]; for (let invalid of invalidEscapes) { for (let zeros of leadingZeros) { assertThrowsInstanceOf(() => eval(`\\u{${zeros}${invalid}}`), SyntaxError); assertThrowsInstanceOf(() => eval(`var \\u{${zeros}${invalid}}`), SyntaxError); } } if (typeof reportCompare === "function") reportCompare(0, 0, "ok");