summaryrefslogtreecommitdiffstats
path: root/js/src/tests/ecma_6/Syntax
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/tests/ecma_6/Syntax')
-rw-r--r--js/src/tests/ecma_6/Syntax/browser.js0
-rw-r--r--js/src/tests/ecma_6/Syntax/declaration-forbidden-in-label.js34
-rw-r--r--js/src/tests/ecma_6/Syntax/escaped-let-static-identifier.js57
-rw-r--r--js/src/tests/ecma_6/Syntax/escaped-strict-reserved-words-and-yield.js105
-rw-r--r--js/src/tests/ecma_6/Syntax/identifier_vertical_tilde.js20
-rw-r--r--js/src/tests/ecma_6/Syntax/identifiers-with-extended-unicode-escape.js222
-rw-r--r--js/src/tests/ecma_6/Syntax/keyword-unescaped-requirement.js68
-rw-r--r--js/src/tests/ecma_6/Syntax/let-as-label.js35
-rw-r--r--js/src/tests/ecma_6/Syntax/shell.js0
-rw-r--r--js/src/tests/ecma_6/Syntax/statement-versus-statementlistitem.js148
-rw-r--r--js/src/tests/ecma_6/Syntax/unicode_other_id_continue.js45
-rw-r--r--js/src/tests/ecma_6/Syntax/unicode_other_id_start.js48
-rw-r--r--js/src/tests/ecma_6/Syntax/yield-as-identifier.js54
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");