diff options
Diffstat (limited to 'js/src/tests/ecma_6/Syntax')
13 files changed, 836 insertions, 0 deletions
diff --git a/js/src/tests/ecma_6/Syntax/browser.js b/js/src/tests/ecma_6/Syntax/browser.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/ecma_6/Syntax/browser.js diff --git a/js/src/tests/ecma_6/Syntax/declaration-forbidden-in-label.js b/js/src/tests/ecma_6/Syntax/declaration-forbidden-in-label.js new file mode 100644 index 000000000..53acb3996 --- /dev/null +++ b/js/src/tests/ecma_6/Syntax/declaration-forbidden-in-label.js @@ -0,0 +1,34 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 1288459; +var summary = + "Properly implement the spec's distinctions between StatementListItem and " + + "Statement grammar productions and their uses"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +assertThrowsInstanceOf(() => Function("a: let x;"), SyntaxError); +assertThrowsInstanceOf(() => Function("b: const y = 3;"), SyntaxError); +assertThrowsInstanceOf(() => Function("c: class z {};"), SyntaxError); + +assertThrowsInstanceOf(() => Function("'use strict'; d: function w() {};"), SyntaxError); + +// Annex B.3.2 allows this in non-strict mode code. +Function("e: function x() {};"); + +assertThrowsInstanceOf(() => Function("f: function* y() {}"), SyntaxError); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/Syntax/escaped-let-static-identifier.js b/js/src/tests/ecma_6/Syntax/escaped-let-static-identifier.js new file mode 100644 index 000000000..a4353a516 --- /dev/null +++ b/js/src/tests/ecma_6/Syntax/escaped-let-static-identifier.js @@ -0,0 +1,57 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 1288460; +var summary = + "|let| and |static| are forbidden as Identifier only in strict mode code, " + + "and it's permissible to use them as Identifier (with or without " + + "containing escapes) in non-strict code"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +function t(code) +{ + var strictSemi = " 'use strict'; " + code; + var strictASI = " 'use strict' \n " + code; + + var creationFunctions = [Function]; + if (typeof evaluate === "function") + creationFunctions.push(evaluate); + if (typeof parseModule === "function") + creationFunctions.push(parseModule); + + for (var func of creationFunctions) + { + if (typeof parseModule === "function" && func === parseModule) + assertThrowsInstanceOf(() => func(code), SyntaxError); + else + func(code); + + assertThrowsInstanceOf(() => func(strictSemi), SyntaxError); + assertThrowsInstanceOf(() => func(strictASI), SyntaxError); + } +} + +t("l\\u0065t: 42;"); +t("if (1) l\\u0065t: 42;"); +t("l\\u0065t = 42;"); +t("if (1) l\\u0065t = 42;"); + +t("st\\u0061tic: 42;"); +t("if (1) st\\u0061tic: 42;"); +t("st\\u0061tic = 42;"); +t("if (1) st\\u0061tic = 42;"); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/Syntax/escaped-strict-reserved-words-and-yield.js b/js/src/tests/ecma_6/Syntax/escaped-strict-reserved-words-and-yield.js new file mode 100644 index 000000000..9d683bd97 --- /dev/null +++ b/js/src/tests/ecma_6/Syntax/escaped-strict-reserved-words-and-yield.js @@ -0,0 +1,105 @@ +/* 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/. */ + +const testCases = [ + // Label identifier. + id => `${id}: ;`, + + // Binding identifier. + id => `var ${id};`, + id => `let ${id};`, + id => `const ${id} = 0;`, + + // Binding identifier in binding pattern. + id => `var [${id}] = [];`, + id => `var [${id} = 0] = [];`, + id => `var [...${id}] = [];`, + id => `var {a: ${id}} = {};`, + id => `var {${id}} = {};`, + id => `var {${id} = 0} = {};`, + + id => `let [${id}] = [];`, + id => `let [${id} = 0] = [];`, + id => `let [...${id}] = [];`, + id => `let {a: ${id}} = {};`, + id => `let {${id}} = {};`, + id => `let {${id} = 0} = {};`, + + id => `const [${id}] = [];`, + id => `const [${id} = 0] = [];`, + id => `const [...${id}] = [];`, + id => `const {a: ${id}} = {};`, + id => `const {${id}} = {};`, + id => `const {${id} = 0} = {};`, + + // Identifier reference. + id => `void ${id};`, +]; + +const strictReservedWords = [ + "implements", + "interface", + "package", + "private", + "protected", + "public", +]; + +function escapeWord(s) { + return "\\u00" + s.charCodeAt(0).toString(16) + s.substring(1); +} + +for (let strictReservedWordOrYield of [...strictReservedWords, "yield"]) { + let escapedStrictReservedWordOrYield = escapeWord(strictReservedWordOrYield); + + for (let testCase of testCases) { + eval(testCase(strictReservedWordOrYield)); + eval(testCase(escapedStrictReservedWordOrYield)); + + assertThrowsInstanceOf(() => eval(String.raw` + "use strict"; + ${testCase(strictReservedWordOrYield)} + `), SyntaxError); + + assertThrowsInstanceOf(() => eval(String.raw` + "use strict"; + ${testCase(escapedStrictReservedWordOrYield)} + `), SyntaxError); + } +} + +// |yield| is always a keyword in generator functions. +for (let testCase of testCases) { + let yield = "yield"; + let escapedYield = escapeWord("yield"); + + assertThrowsInstanceOf(() => eval(String.raw` + function* g() { + ${testCase(yield)} + } + `), SyntaxError); + + assertThrowsInstanceOf(() => eval(String.raw` + function* g() { + ${testCase(escapedYield)} + } + `), SyntaxError); + + assertThrowsInstanceOf(() => eval(String.raw` + "use strict"; + function* g() { + ${testCase(yield)} + } + `), SyntaxError); + + assertThrowsInstanceOf(() => eval(String.raw` + "use strict"; + function* g() { + ${testCase(escapedYield)} + } + `), SyntaxError); +} + +if (typeof reportCompare === "function") + reportCompare(0, 0, "ok"); diff --git a/js/src/tests/ecma_6/Syntax/identifier_vertical_tilde.js b/js/src/tests/ecma_6/Syntax/identifier_vertical_tilde.js new file mode 100644 index 000000000..94fb55f63 --- /dev/null +++ b/js/src/tests/ecma_6/Syntax/identifier_vertical_tilde.js @@ -0,0 +1,20 @@ +/* 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/. */ + +// U+2E2F (VERTICAL TILDE) is in Gc=Lm, but also in [:Pattern_Syntax:]. +// http://www.unicode.org/reports/tr31/ +const verticalTilde = 0x2E2F; + +// Leading character in identifier. +assertThrowsInstanceOf(() => eval(`${String.fromCodePoint(verticalTilde)}`), SyntaxError); +assertThrowsInstanceOf(() => eval(`\\u${verticalTilde.toString(16).padStart(4, "0")}`), SyntaxError); +assertThrowsInstanceOf(() => eval(`\\u{${verticalTilde.toString(16)}}`), SyntaxError); + +// Not leading character in identifier. +assertThrowsInstanceOf(() => eval(`A${String.fromCodePoint(verticalTilde)}`), SyntaxError); +assertThrowsInstanceOf(() => eval(`A\\u${verticalTilde.toString(16).padStart(4, "0")}`), SyntaxError); +assertThrowsInstanceOf(() => eval(`A\\u{${verticalTilde.toString(16)}}`), SyntaxError); + +if (typeof reportCompare === "function") + reportCompare(0, 0, "ok"); diff --git a/js/src/tests/ecma_6/Syntax/identifiers-with-extended-unicode-escape.js b/js/src/tests/ecma_6/Syntax/identifiers-with-extended-unicode-escape.js new file mode 100644 index 000000000..8e0a05fb5 --- /dev/null +++ b/js/src/tests/ecma_6/Syntax/identifiers-with-extended-unicode-escape.js @@ -0,0 +1,222 @@ +/* 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]) { + for (let count of leadingZeros) { + let zeros = "0".repeat(count); + eval(` + let \\u{${zeros}${ident.toString(16)}} = 123; + assertEq(${String.fromCodePoint(ident)}, 123); + `); + } +} + +// Move this to the loop above when Bug 1197230 is fixed. +for (let ident of [...idStartSupplemental]) { + for (let zeros of leadingZeros) { + assertThrowsInstanceOf(() => eval(`\\u{${zeros}${ident.toString(16)}}`), SyntaxError); + } +} + +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]) { + for (let zeros of leadingZeros) { + eval(` + let A\\u{${zeros}${ident.toString(16)}} = 123; + assertEq(${String.fromCodePoint(0x41, ident)}, 123); + `); + } +} + +// Move this to the loop above when Bug 1197230 is fixed. +for (let ident of [...idStartSupplemental, ...idContinueSupplemental]) { + for (let zeros of leadingZeros) { + assertThrowsInstanceOf(() => eval(`\\u{${zeros}${ident.toString(16)}}`), SyntaxError); + } +} + + +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, // <Plane 16 Private Use>, 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"); diff --git a/js/src/tests/ecma_6/Syntax/keyword-unescaped-requirement.js b/js/src/tests/ecma_6/Syntax/keyword-unescaped-requirement.js new file mode 100644 index 000000000..eb6edd57d --- /dev/null +++ b/js/src/tests/ecma_6/Syntax/keyword-unescaped-requirement.js @@ -0,0 +1,68 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 1204027; +var summary = + "Escape sequences aren't allowed in bolded grammar tokens (that is, in " + + "keywords, possibly contextual keywords)"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +function memberVariants(code) +{ + return ["(class { constructor() {} " + code + " });", + "({ " + code + " })"]; +} + +var badScripts = + [ + "class { st\\u0061tic m() { return 0; } }", + "class { st\\u0061tic get foo() { return 0; } }", + "class { st\\u0061tic set foo(v) {} }", + "class { st\\u0061tic get ['hi']() { return 0; } }", + "class { st\\u0061tic set ['hi'](v) {} }", + "class { st\\u0061tic get 'hi'() { return 0; } }", + "class { st\\u0061tic set 'hi'(v) {} }", + "class { st\\u0061tic get 42() { return 0; } }", + "class { st\\u0061tic set 42(v) {} }", + ...memberVariants("\\u0067et foo() { return 0; }"), + ...memberVariants("\\u0073et foo() {}"), + ...memberVariants("g\\u0065t foo() { return 0; }"), + ...memberVariants("s\\u0065t foo() {}"), + ...memberVariants("g\\u0065t ['hi']() { return 0; }"), + ...memberVariants("s\\u0065t ['hi']() {}"), + ...memberVariants("g\\u0065t 'hi'() { return 0; }"), + ...memberVariants("s\\u0065t 'hi'() {}"), + ...memberVariants("g\\u0065t 42() { return 0; }"), + ...memberVariants("s\\u0065t 42() {}"), + "for (var foo o\\u0066 [1]) ;", + "for (var foo \\u006ff [1]) ;", + "for (var foo i\\u006e [1]) ;", + "for (var foo \\u0069n [1]) ;", + "function f() { return n\\u0065w.target }", + "function f() { return \\u006eew.target }", + "function f() { return new.t\\u0061rget }", + "function f() { return new.\\u0074arget }", + "function f() { return n\\u0065w Array }", + "function f() { return \\u006eew Array }", + "\\u0064o { } while (0)", + "[for (x \\u006ff [1]) x]", + "[for (x o\\u0066 [1]) x]", + ]; + +for (var script of badScripts) + assertThrowsInstanceOf(() => Function(script), SyntaxError); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/Syntax/let-as-label.js b/js/src/tests/ecma_6/Syntax/let-as-label.js new file mode 100644 index 000000000..a01ad556e --- /dev/null +++ b/js/src/tests/ecma_6/Syntax/let-as-label.js @@ -0,0 +1,35 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 1288459; +var summary = "let can't be used as a label in strict mode code"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +Function("let: 42"); +Function("l\\u0065t: 42"); +assertThrowsInstanceOf(() => Function(" 'use strict'; let: 42"), SyntaxError); +assertThrowsInstanceOf(() => Function(" 'use strict' \n let: 42"), SyntaxError); +assertThrowsInstanceOf(() => Function(" 'use strict'; l\\u0065t: 42"), SyntaxError); +assertThrowsInstanceOf(() => Function(" 'use strict' \n l\\u0065t: 42"), SyntaxError); + +eval("let: 42"); +eval("l\\u0065t: 42"); +assertThrowsInstanceOf(() => eval(" 'use strict'; let: 42"), SyntaxError); +assertThrowsInstanceOf(() => eval(" 'use strict' \n let: 42;"), SyntaxError); +assertThrowsInstanceOf(() => eval(" 'use strict'; l\\u0065t: 42"), SyntaxError); +assertThrowsInstanceOf(() => eval(" 'use strict' \n l\\u0065t: 42;"), SyntaxError); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/Syntax/shell.js b/js/src/tests/ecma_6/Syntax/shell.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/ecma_6/Syntax/shell.js diff --git a/js/src/tests/ecma_6/Syntax/statement-versus-statementlistitem.js b/js/src/tests/ecma_6/Syntax/statement-versus-statementlistitem.js new file mode 100644 index 000000000..d0565353d --- /dev/null +++ b/js/src/tests/ecma_6/Syntax/statement-versus-statementlistitem.js @@ -0,0 +1,148 @@ +// |reftest| skip-if(!xulRuntime.shell) -- needs evaluate, parseModule +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 1288459; +var summary = + "Properly implement the spec's distinctions between StatementListItem and " + + "Statement grammar productions and their uses"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var counter = 0; + +// Test all the different contexts that expect a Statement. + +function contextAcceptsStatement(pat) +{ + var goodCode = +`function f${counter++}() +{ + ${pat.replace("@@@", "let \n {} \n ;")} +} +`; + + evaluate(goodCode); + + var badCode = +`function f${counter++}() +{ + ${pat.replace("@@@", "let {} \n ;")} +} +`; + + try + { + evaluate(badCode); + throw new Error("didn't throw"); + } + catch (e) + { + assertEq(e instanceof SyntaxError, true, + "didn't get a syntax error, instead got: " + e); + } +} + +contextAcceptsStatement("if (0) @@@"); +contextAcceptsStatement("if (0) ; else @@@"); +contextAcceptsStatement("if (0) ; else if (0) @@@"); +contextAcceptsStatement("if (0) ; else if (0) ; else @@@"); +// Can't test do-while loops this way because the Statement isn't in trailing +// position, so 'let' followed by newline *must* be followed by 'while'. +contextAcceptsStatement("while (1) @@@"); +contextAcceptsStatement("for (1; 1; 0) @@@"); +contextAcceptsStatement("for (var x; 1; 0) @@@"); +contextAcceptsStatement("for (let x; 1; 0) @@@"); +contextAcceptsStatement("for (const x = 1; 1; 0) @@@"); +contextAcceptsStatement("for (x in 0) @@@"); +contextAcceptsStatement("for (var x in 0) @@@"); +contextAcceptsStatement("for (let x in 0) @@@"); +contextAcceptsStatement("for (const x in 0) @@@"); +contextAcceptsStatement("for (x of []) @@@"); +contextAcceptsStatement("for (var x of []) @@@"); +contextAcceptsStatement("for (let x of []) @@@"); +contextAcceptsStatement("for (const x of []) @@@"); +contextAcceptsStatement("with (1) @@@"); +contextAcceptsStatement("foo: @@@"); + +// Test all the different contexts that expect a StatementListItem. + +function contextAcceptsStatementListItem(pat) +{ + var goodCode = +`function f${counter++}() +{ + ${pat.replace("@@@", "let \n [] = [] ;")} +} +`; + + evaluate(goodCode); + + var moarGoodCode = pat.replace("@@@", "let \n [] = [] ;"); + evaluate(moarGoodCode); + + var goodModuleCode = pat.replace("@@@", "let \n [] = [] ;"); + parseModule(goodModuleCode); + + var badCode = +`function f${counter++}() +{ + ${pat.replace("@@@", "let \n let = 3 ;")} +} +`; + + try + { + evaluate(badCode); + throw new Error("didn't throw"); + } + catch (e) + { + assertEq(e instanceof SyntaxError, true, + "didn't get a syntax error, instead got: " + e); + } +} + +contextAcceptsStatementListItem("{ @@@ }"); +contextAcceptsStatementListItem("switch (1) { case 1: @@@ }"); +contextAcceptsStatementListItem("switch (1) { default: @@@ }"); +contextAcceptsStatementListItem("switch (1) { case 0: case 1: @@@ }"); +contextAcceptsStatementListItem("switch (1) { case 0: break; case 1: @@@ }"); +contextAcceptsStatementListItem("switch (1) { default: @@@ case 2: }"); +contextAcceptsStatementListItem("try { @@@ } catch (e) { }"); +contextAcceptsStatementListItem("try { @@@ } finally { }"); +contextAcceptsStatementListItem("try { @@@ } catch (e) { } finally { }"); +contextAcceptsStatementListItem("try { } catch (e) { @@@ }"); +contextAcceptsStatementListItem("try { } finally { @@@ }"); +contextAcceptsStatementListItem("try { } catch (e) { @@@ } finally { }"); +contextAcceptsStatementListItem("try { } catch (e) { } finally { @@@ }"); +contextAcceptsStatementListItem("_ => { @@@ }"); +contextAcceptsStatementListItem("function q() { @@@ }"); +contextAcceptsStatementListItem("function* q() { @@@ }"); +contextAcceptsStatementListItem("(function() { @@@ })"); +contextAcceptsStatementListItem("(function*() { @@@ })"); +contextAcceptsStatementListItem("({ *q() { @@@ } })"); +contextAcceptsStatementListItem("({ q() { @@@ } })"); +contextAcceptsStatementListItem("({ get q() { @@@ } })"); +contextAcceptsStatementListItem("({ set q(v) { @@@ } })"); +contextAcceptsStatementListItem("(class { f() { @@@ } })"); +contextAcceptsStatementListItem("(class { static f() { @@@ } })"); +contextAcceptsStatementListItem("(class { static *f() { @@@ } })"); +contextAcceptsStatementListItem("(class { static get f() { @@@ } })"); +contextAcceptsStatementListItem("(class { static set f(v) { @@@ } })"); +contextAcceptsStatementListItem("(class { static() { @@@ } })"); +contextAcceptsStatementListItem("@@@"); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/Syntax/unicode_other_id_continue.js b/js/src/tests/ecma_6/Syntax/unicode_other_id_continue.js new file mode 100644 index 000000000..03dd09b71 --- /dev/null +++ b/js/src/tests/ecma_6/Syntax/unicode_other_id_continue.js @@ -0,0 +1,45 @@ +/* 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/. */ + +// 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 +]; + +// Leading character in identifier. +for (let ident of [...otherIdContinue]) { + assertThrowsInstanceOf(() => eval(`${String.fromCodePoint(ident)}`), SyntaxError); + assertThrowsInstanceOf(() => eval(`\\u${ident.toString(16).padStart(4, "0")}`), SyntaxError); + assertThrowsInstanceOf(() => eval(`\\u{${ident.toString(16)}}`), SyntaxError); +} + +// Not leading character in identifier. +for (let ident of [...otherIdContinue]) { + eval(` + let A${String.fromCodePoint(ident)} = 123; + assertEq(${String.fromCodePoint(0x41, ident)}, 123); + `); + eval(` + let A\\u${ident.toString(16).padStart(4, "0")} = 123; + assertEq(${String.fromCodePoint(0x41, ident)}, 123); + `); + eval(` + let A\\u{${ident.toString(16)}} = 123; + assertEq(${String.fromCodePoint(0x41, ident)}, 123); + `); +} + +if (typeof reportCompare === "function") + reportCompare(0, 0, "ok"); diff --git a/js/src/tests/ecma_6/Syntax/unicode_other_id_start.js b/js/src/tests/ecma_6/Syntax/unicode_other_id_start.js new file mode 100644 index 000000000..86790dd00 --- /dev/null +++ b/js/src/tests/ecma_6/Syntax/unicode_other_id_start.js @@ -0,0 +1,48 @@ +/* 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/. */ + +// 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 +]; + +// Leading character in identifier. +for (let ident of otherIdStart) { + eval(` + let ${String.fromCodePoint(ident)} = 123; + assertEq(${String.fromCodePoint(ident)}, 123); + `); + eval(` + let \\u${ident.toString(16).padStart(4, "0")} = 123; + assertEq(${String.fromCodePoint(ident)}, 123); + `); + eval(` + let \\u{${ident.toString(16)}} = 123; + assertEq(${String.fromCodePoint(ident)}, 123); + `); +} + +// Not leading character in identifier. +for (let ident of otherIdStart) { + eval(` + let A${String.fromCodePoint(ident)} = 123; + assertEq(${String.fromCodePoint(0x41, ident)}, 123); + `); + eval(` + let A\\u${ident.toString(16).padStart(4, "0")} = 123; + assertEq(${String.fromCodePoint(0x41, ident)}, 123); + `); + eval(` + let A\\u{${ident.toString(16)}} = 123; + assertEq(${String.fromCodePoint(0x41, ident)}, 123); + `); +} + +if (typeof reportCompare === "function") + reportCompare(0, 0, "ok"); diff --git a/js/src/tests/ecma_6/Syntax/yield-as-identifier.js b/js/src/tests/ecma_6/Syntax/yield-as-identifier.js new file mode 100644 index 000000000..665b0b11c --- /dev/null +++ b/js/src/tests/ecma_6/Syntax/yield-as-identifier.js @@ -0,0 +1,54 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 1288459; +var summary = "|yield| is sometimes a valid identifier"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +function t(code) +{ + var strictSemi = " 'use strict'; " + code; + var strictASI = " 'use strict' \n " + code; + + var creationFunctions = ["Function"]; + if (typeof evaluate === "function") + creationFunctions.push("evaluate"); + if (typeof parseModule === "function") + creationFunctions.push("parseModule"); + + for (var func of creationFunctions) + { + var g = newGlobal(); + var f = g[func]; + + if (func === "parseModule") + assertThrowsInstanceOf(() => f(code), g.SyntaxError); + else + f(code); + + assertThrowsInstanceOf(() => f(strictSemi), g.SyntaxError); + assertThrowsInstanceOf(() => f(strictASI), g.SyntaxError); + } +} + +t("var yield = 3;"); +t("let yield = 3;"); +t("const yield = 3;"); +t("for (var yield = 3; ; ) break;"); +t("for (let yield = 3; ; ) break;"); +t("for (const yield = 3; ; ) break;"); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); |