summaryrefslogtreecommitdiffstats
path: root/js/src/tests/non262/reflect-parse/classes.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--js/src/tests/non262/reflect-parse/classes.js551
1 files changed, 551 insertions, 0 deletions
diff --git a/js/src/tests/non262/reflect-parse/classes.js b/js/src/tests/non262/reflect-parse/classes.js
new file mode 100644
index 0000000000..b855c5d741
--- /dev/null
+++ b/js/src/tests/non262/reflect-parse/classes.js
@@ -0,0 +1,551 @@
+// |reftest| slow skip-if(!xulRuntime.shell)
+// Classes
+function testClasses() {
+ function methodFun(id, kind, generator, args, body = []) {
+ assertEq(generator && kind === "method", generator);
+ assertEq(typeof id === 'string' || id === null, true);
+ let methodName;
+ switch (kind) {
+ case "method":
+ methodName = typeof id === 'string' ? ident(id) : null;
+ break;
+ case "get":
+ case "set":
+ methodName = ident(`${kind} ${typeof id === 'string' ? id : ""}`);
+ break;
+ default:
+ methodName = null;
+ break;
+ }
+ return generator
+ ? genFunExpr("es6", methodName, args.map(ident), blockStmt(body))
+ : funExpr(methodName, args.map(ident), blockStmt(body));
+ }
+
+ function simpleMethod(id, kind, generator, args = [], isStatic = false) {
+ return classMethod(ident(id),
+ methodFun(id, kind, generator, args),
+ kind, isStatic);
+ }
+ function ctorWithName(id, body = []) {
+ return classMethod(ident("constructor"),
+ methodFun(id, "method", false, [], body),
+ "method", false);
+ }
+ function emptyCPNMethod(id, isStatic) {
+ return classMethod(computedName(lit(id)),
+ funExpr(null, [], blockStmt([])),
+ "method", isStatic);
+ }
+
+ function assertClassExpr(str, methods, heritage = null, name = null) {
+ let template = classExpr(name, heritage, methods);
+ assertExpr("(" + str + ")", template);
+ }
+
+ // FunctionExpression of constructor has class name as its id.
+ // FIXME: Implement ES6 function "name" property semantics (bug 883377).
+ let ctorPlaceholder = {};
+ function assertClass(str, methods, heritage = null, constructorBody = []) {
+ let namelessStr = str.replace("NAME", "");
+ let namedStr = str.replace("NAME", "Foo");
+ let namedCtor = ctorWithName("Foo", constructorBody);
+ let namelessCtor = ctorWithName(null, constructorBody);
+ let namelessMethods = methods.map(x => x == ctorPlaceholder ? namelessCtor : x);
+ let namedMethods = methods.map(x => x == ctorPlaceholder ? namedCtor : x);
+ assertClassExpr(namelessStr, namelessMethods, heritage);
+ assertClassExpr(namedStr, namedMethods, heritage, ident("Foo"));
+
+ let template = classStmt(ident("Foo"), heritage, namedMethods);
+ assertStmt(namedStr, template);
+ }
+ function assertNamedClassError(str, error) {
+ assertError(str, error);
+ assertError("(" + str + ")", error);
+ }
+ function assertClassError(str, error) {
+ assertNamedClassError(str, error);
+ assertError("(" + str.replace("NAME", "") + ")", error);
+ }
+
+ /* Trivial classes */
+ // Unnamed class statements are forbidden, but unnamed class expressions are
+ // just fine.
+ assertError("class { constructor() { } }", SyntaxError);
+ assertClass("class NAME { constructor() { } }", [ctorPlaceholder]);
+
+ // A class name must actually be a name
+ assertNamedClassError("class x.y { constructor() {} }", SyntaxError);
+ assertNamedClassError("class [] { constructor() {} }", SyntaxError);
+ assertNamedClassError("class {x} { constructor() {} }", SyntaxError);
+ assertNamedClassError("class for { constructor() {} }", SyntaxError);
+
+ // Allow methods and accessors
+ assertClass("class NAME { constructor() { } method() { } }",
+ [ctorPlaceholder, simpleMethod("method", "method", false)]);
+
+ assertClass("class NAME { constructor() { } get method() { } }",
+ [ctorPlaceholder, simpleMethod("method", "get", false)]);
+
+ assertClass("class NAME { constructor() { } set method(x) { } }",
+ [ctorPlaceholder, simpleMethod("method", "set", false, ["x"])]);
+
+ /* Static */
+ assertClass(`class NAME {
+ constructor() { };
+ static method() { };
+ static *methodGen() { };
+ static get getter() { };
+ static set setter(x) { }
+ }`,
+ [ctorPlaceholder,
+ simpleMethod("method", "method", false, [], true),
+ simpleMethod("methodGen", "method", true, [], true),
+ simpleMethod("getter", "get", false, [], true),
+ simpleMethod("setter", "set", false, ["x"], true)]);
+
+ // It's not an error to have a method named static, static, or not.
+ assertClass("class NAME { constructor() { } static() { } }",
+ [ctorPlaceholder, simpleMethod("static", "method", false)]);
+ assertClass("class NAME { static static() { }; constructor() { } }",
+ [simpleMethod("static", "method", false, [], true), ctorPlaceholder]);
+ assertClass("class NAME { static get static() { }; constructor() { } }",
+ [simpleMethod("static", "get", false, [], true), ctorPlaceholder]);
+ assertClass("class NAME { constructor() { }; static set static(x) { } }",
+ [ctorPlaceholder, simpleMethod("static", "set", false, ["x"], true)]);
+
+ // You do, however, have to put static in the right spot
+ assertClassError("class NAME { constructor() { }; get static foo() { } }", SyntaxError);
+
+ // Spec disallows "prototype" as a static member in a class, since that
+ // one's important to make the desugaring work
+ assertClassError("class NAME { constructor() { } static prototype() { } }", SyntaxError);
+ assertClassError("class NAME { constructor() { } static *prototype() { } }", SyntaxError);
+ assertClassError("class NAME { static get prototype() { }; constructor() { } }", SyntaxError);
+ assertClassError("class NAME { static set prototype(x) { }; constructor() { } }", SyntaxError);
+
+ // You are, however, allowed to have a CPN called prototype as a static
+ assertClass("class NAME { constructor() { }; static [\"prototype\"]() { } }",
+ [ctorPlaceholder, emptyCPNMethod("prototype", true)]);
+
+ /* Constructor */
+ // Allow default constructors
+ assertClass("class NAME { }", []);
+ assertClass("class NAME extends null { }", [], lit(null));
+
+ // Derived class constructor must have curly brackets
+ assertClassError("class NAME extends null { constructor() 1 }", SyntaxError);
+
+ // It is an error to have two methods named constructor, but not other
+ // names, regardless if one is an accessor or a generator or static.
+ assertClassError("class NAME { constructor() { } constructor(a) { } }", SyntaxError);
+ let methods = [["method() { }", simpleMethod("method", "method", false)],
+ ["*method() { }", simpleMethod("method", "method", true)],
+ ["get method() { }", simpleMethod("method", "get", false)],
+ ["set method(x) { }", simpleMethod("method", "set", false, ["x"])],
+ ["static method() { }", simpleMethod("method", "method", false, [], true)],
+ ["static *method() { }", simpleMethod("method", "method", true, [], true)],
+ ["static get method() { }", simpleMethod("method", "get", false, [], true)],
+ ["static set method(x) { }", simpleMethod("method", "set", false, ["x"], true)]];
+ let i, j;
+ for (i = 0; i < methods.length; i++) {
+ for (j = 0; j < methods.length; j++) {
+ let str = "class NAME { constructor() { } " +
+ methods[i][0] + " " + methods[j][0] +
+ " }";
+ assertClass(str, [ctorPlaceholder, methods[i][1], methods[j][1]]);
+ }
+ }
+
+ // It is, however, not an error to have a constructor, and a method with a
+ // computed property name 'constructor'
+ assertClass("class NAME { constructor () { } [\"constructor\"] () { } }",
+ [ctorPlaceholder, emptyCPNMethod("constructor", false)]);
+
+ // It is an error to have a generator or accessor named constructor
+ assertClassError("class NAME { *constructor() { } }", SyntaxError);
+ assertClassError("class NAME { get constructor() { } }", SyntaxError);
+ assertClassError("class NAME { set constructor() { } }", SyntaxError);
+
+ /* Semicolons */
+ // Allow Semicolons in Class Definitions
+ assertClass("class NAME { constructor() { }; }", [ctorPlaceholder]);
+
+ // Allow more than one semicolon, even in otherwise trivial classses
+ assertClass("class NAME { ;;; constructor() { } }", [ctorPlaceholder]);
+
+ // Semicolons are optional, even if the methods share a line
+ assertClass("class NAME { method() { } constructor() { } }",
+ [simpleMethod("method", "method", false), ctorPlaceholder]);
+
+ /* Generators */
+ // No yield as a class name inside a generator
+ assertError(`function *foo() {
+ class yield {
+ constructor() { }
+ }
+ }`, SyntaxError);
+ assertError(`function *foo() {
+ (class yield {
+ constructor() { }
+ })
+ }`, SyntaxError);
+
+ // No legacy generators for methods.
+ assertClassError(`class NAME {
+ constructor() { yield 2; }
+ }`, SyntaxError);
+ assertClassError(`class NAME {
+ method() { yield 2; }
+ }`, SyntaxError);
+ assertClassError(`class NAME {
+ get method() { yield 2; }
+ }`, SyntaxError);
+ assertClassError(`class NAME {
+ set method() { yield 2; }
+ }`, SyntaxError);
+
+ // Methods may be generators, but not accessors
+ assertClassError("class NAME { constructor() { } *get foo() { } }", SyntaxError);
+ assertClassError("class NAME { constructor() { } *set foo() { } }", SyntaxError);
+
+ assertClass("class NAME { *method() { } constructor() { } }",
+ [simpleMethod("method", "method", true), ctorPlaceholder]);
+
+ /* Strictness */
+ // yield is a strict-mode keyword, and class definitions are always strict.
+ assertClassError("class NAME { constructor() { var yield; } }", SyntaxError);
+
+ // Beware of the strictness of computed property names. Here use bareword
+ // deletion (a deprecated action) to check.
+ assertClassError("class NAME { constructor() { } [delete bar]() { }}", SyntaxError);
+
+ /* Bindings */
+ // Class statements bind lexically, so they should collide with other
+ // in-block lexical bindings, but class expressions don't.
+ let FooCtor = ctorWithName("Foo");
+ assertError("{ let Foo; class Foo { constructor() { } } }", SyntaxError);
+ assertStmt("{ let Foo; (class Foo { constructor() { } }) }",
+ blockStmt([letDecl([{ id: ident("Foo"), init: null }]),
+ exprStmt(classExpr(ident("Foo"), null, [FooCtor]))]));
+ assertError("{ const Foo = 0; class Foo { constructor() { } } }", SyntaxError);
+ assertStmt("{ const Foo = 0; (class Foo { constructor() { } }) }",
+ blockStmt([constDecl([{ id: ident("Foo"), init: lit(0) }]),
+ exprStmt(classExpr(ident("Foo"), null, [FooCtor]))]));
+ assertError("{ class Foo { constructor() { } } class Foo { constructor() { } } }", SyntaxError);
+ assertStmt(`{
+ (class Foo {
+ constructor() { }
+ },
+ class Foo {
+ constructor() { }
+ });
+ }`,
+ blockStmt([exprStmt(seqExpr([classExpr(ident("Foo"), null, [FooCtor]),
+ classExpr(ident("Foo"), null, [FooCtor])]))]));
+ assertStmt(`{
+ var x = class Foo { constructor() { } };
+ class Foo { constructor() { } }
+ }`,
+ blockStmt([varDecl([{
+ id: ident("x"),
+ init: classExpr(ident("Foo"), null, [FooCtor])
+ }]),
+ classStmt(ident("Foo"), null, [FooCtor])]));
+
+
+ // Can't make a lexical binding without a block.
+ assertError("if (1) class Foo { constructor() { } }", SyntaxError);
+
+ /* Heritage Expressions */
+ // It's illegal to have things that look like "multiple inheritance":
+ // non-parenthesized comma expressions.
+ assertClassError("class NAME extends null, undefined { constructor() { } }", SyntaxError);
+
+ // Again check for strict-mode in heritage expressions
+ assertClassError("class NAME extends (delete x) { constructor() { } }", SyntaxError);
+
+ // You must specify an inheritance if you say "extends"
+ assertClassError("class NAME extends { constructor() { } }", SyntaxError);
+
+ // "extends" is still a valid name for a method
+ assertClass("class NAME { constructor() { }; extends() { } }",
+ [ctorPlaceholder, simpleMethod("extends", "method", false)]);
+
+ // Immediate expression
+ assertClass("class NAME extends null { constructor() { } }",
+ [ctorPlaceholder], lit(null));
+
+ // Sequence expresson
+ assertClass("class NAME extends (undefined, undefined) { constructor() { } }",
+ [ctorPlaceholder], seqExpr([ident("undefined"), ident("undefined")]));
+
+ // Function expression
+ let emptyFunction = funExpr(null, [], blockStmt([]));
+ assertClass("class NAME extends function(){ } { constructor() { } }",
+ [ctorPlaceholder], emptyFunction);
+
+ // New expression
+ assertClass("class NAME extends new function(){ }() { constructor() { } }",
+ [ctorPlaceholder], newExpr(emptyFunction, []));
+
+ // Call expression
+ assertClass("class NAME extends function(){ }() { constructor() { } }",
+ [ctorPlaceholder], callExpr(emptyFunction, []));
+
+ // Dot expression
+ assertClass("class NAME extends {}.foo { constructor() { } }",
+ [ctorPlaceholder], dotExpr(objExpr([]), ident("foo")));
+
+ // Member expression
+ assertClass("class NAME extends {}[foo] { constructor() { } }",
+ [ctorPlaceholder], memExpr(objExpr([]), ident("foo")));
+
+ // #constructor is an invalid private method name.
+ assertClassError("class NAME { #constructor() { } }", SyntaxError);
+
+ const method = ["#method() { }", simpleMethod("#method", "method", false)];
+ const generator = ["*#method() { }", simpleMethod("#method", "method", true)];
+ const getter = ["get #method() { }", simpleMethod("#method", "get", false)];
+ const setter = ["set #method(x) { }", simpleMethod("#method", "set", false, ["x"])];
+ for (const [source, parsed] of [method, generator, getter, setter]) {
+ assertClass(`class NAME { constructor() { } ${source} }`, [ctorPlaceholder, parsed]);
+ }
+
+ // Private getters and setters of the same name are allowed.
+ assertClass(`class NAME { constructor() { } ${getter[0]} ${setter[0]} }`,
+ [ctorPlaceholder, getter[1], setter[1]]);
+ assertClass(`class NAME { constructor() { } ${setter[0]} ${getter[0]} }`,
+ [ctorPlaceholder, setter[1], getter[1]]);
+
+ // Private method names can't be used multiple times, other than for a getter/setter pair.
+ for (const [source1, _] of [method, generator, getter, setter]) {
+ for (const [source2, _] of [method, generator]) {
+ assertClassError(`class NAME { constructor() { } ${source1} ${source2} }`, SyntaxError);
+ }
+ }
+
+ assertClassError(`class NAME { constructor() { } ${setter[0]} ${setter[0]} }`, SyntaxError);
+ assertClassError(`class NAME { constructor() { } ${getter[0]} ${getter[0]} }`, SyntaxError);
+
+
+ /* SuperProperty */
+ // NOTE: Some of these tests involve object literals, as SuperProperty is a
+ // valid production in any method definition, including in objectl
+ // litterals. These tests still fall here, as |super| is not implemented in
+ // any form without classes.
+
+ function assertValidSuperProps(assertion, makeStr, makeExpr, type, generator, args, static,
+ extending) {
+ let superProperty = superProp(ident("prop"));
+ let superMember = superElem(lit("prop"));
+
+ let situations = [
+ ["super.prop", superProperty],
+ ["super['prop']", superMember],
+ ["super.prop()", callExpr(superProperty, [])],
+ ["super['prop']()", callExpr(superMember, [])],
+ ["new super.prop()", newExpr(superProperty, [])],
+ ["new super['prop']()", newExpr(superMember, [])],
+ ["delete super.prop", unExpr("delete", superProperty)],
+ ["delete super['prop']", unExpr("delete", superMember)],
+ ["++super.prop", updExpr("++", superProperty, true)],
+ ["super['prop']--", updExpr("--", superMember, false)],
+ ["super.prop = 4", aExpr("=", superProperty, lit(4))],
+ ["super['prop'] = 4", aExpr("=", superMember, lit(4))],
+ ["super.prop += 4", aExpr("+=", superProperty, lit(4))],
+ ["super['prop'] += 4", aExpr("+=", superMember, lit(4))],
+ ["super.prop -= 4", aExpr("-=", superProperty, lit(4))],
+ ["super['prop'] -= 4", aExpr("-=", superMember, lit(4))],
+ ["super.prop *= 4", aExpr("*=", superProperty, lit(4))],
+ ["super['prop'] *= 4", aExpr("*=", superMember, lit(4))],
+ ["super.prop /= 4", aExpr("/=", superProperty, lit(4))],
+ ["super['prop'] /= 4", aExpr("/=", superMember, lit(4))],
+ ["super.prop %= 4", aExpr("%=", superProperty, lit(4))],
+ ["super['prop'] %= 4", aExpr("%=", superMember, lit(4))],
+ ["super.prop <<= 4", aExpr("<<=", superProperty, lit(4))],
+ ["super['prop'] <<= 4", aExpr("<<=", superMember, lit(4))],
+ ["super.prop >>= 4", aExpr(">>=", superProperty, lit(4))],
+ ["super['prop'] >>= 4", aExpr(">>=", superMember, lit(4))],
+ ["super.prop >>>= 4", aExpr(">>>=", superProperty, lit(4))],
+ ["super['prop'] >>>= 4", aExpr(">>>=", superMember, lit(4))],
+ ["super.prop |= 4", aExpr("|=", superProperty, lit(4))],
+ ["super['prop'] |= 4", aExpr("|=", superMember, lit(4))],
+ ["super.prop ^= 4", aExpr("^=", superProperty, lit(4))],
+ ["super['prop'] ^= 4", aExpr("^=", superMember, lit(4))],
+ ["super.prop &= 4", aExpr("&=", superProperty, lit(4))],
+ ["super['prop'] &= 4", aExpr("&=", superMember, lit(4))],
+
+ // We can also use super from inside arrow functions in method
+ // definitions
+ ["()=>super.prop", arrowExpr([], superProperty)],
+ ["()=>super['prop']", arrowExpr([], superMember)]];
+
+ for (let situation of situations) {
+ let sitStr = situation[0];
+ let sitExpr = situation[1];
+
+ let fun = methodFun("method", type, generator, args, [exprStmt(sitExpr)]);
+ let str = makeStr(sitStr, type, generator, args, static, extending);
+ assertion(str, makeExpr(fun, type, static), extending);
+ }
+ }
+
+ function assertValidSuperPropTypes(assertion, makeStr, makeExpr, static, extending) {
+ for (let type of ["method", "get", "set"]) {
+ if (type === "method") {
+ // methods can also be generators
+ assertValidSuperProps(assertion, makeStr, makeExpr, type, true, [], static, extending);
+ assertValidSuperProps(assertion, makeStr, makeExpr, type, false, [], static, extending);
+ continue;
+ }
+
+ // Setters require 1 argument, and getters require 0
+ assertValidSuperProps(assertion, makeStr, makeExpr, type, false,
+ type === "set" ? ["x"] : [], static, extending);
+ }
+ }
+
+ function makeSuperPropMethodStr(propStr, type, generator, args) {
+ return `${type === "method" ? "" : type} ${generator ? "*" : ""} method(${args.join(",")})
+ {
+ ${propStr};
+ }`;
+ }
+
+ function makeClassSuperPropStr(propStr, type, generator, args, static, extending) {
+ return `class NAME ${extending ? "extends null" : ""} {
+ constructor() { };
+ ${static ? "static" : ""} ${makeSuperPropMethodStr(propStr, type, generator, args)}
+ }`;
+ }
+ function makeClassSuperPropExpr(fun, type, static) {
+ // We are going right into assertClass, so we don't have to build the
+ // entire statement.
+ return [ctorPlaceholder,
+ classMethod(ident("method"), fun, type, static)];
+ }
+ function doClassSuperPropAssert(str, expr, extending) {
+ assertClass(str, expr, extending ? lit(null) : null);
+ }
+ function assertValidClassSuperPropExtends(extending) {
+ // super.prop and super[prop] are valid, regardless of whether the
+ // method is static or not
+ assertValidSuperPropTypes(doClassSuperPropAssert, makeClassSuperPropStr, makeClassSuperPropExpr,
+ false, extending);
+ assertValidSuperPropTypes(doClassSuperPropAssert, makeClassSuperPropStr, makeClassSuperPropExpr,
+ true, extending);
+ }
+ function assertValidClassSuperProps() {
+ // super.prop and super[prop] are valid, regardless of class heritage
+ assertValidClassSuperPropExtends(false);
+ assertValidClassSuperPropExtends(true);
+ }
+
+ function makeOLSuperPropStr(propStr, type, generator, args) {
+ let str = `({ ${makeSuperPropMethodStr(propStr, type, generator, args)} })`;
+ return str;
+ }
+ function makeOLSuperPropExpr(fun) {
+ return objExpr([{ type: "Property", key: ident("method"), value: fun }]);
+ }
+ function assertValidOLSuperProps() {
+ assertValidSuperPropTypes(assertExpr, makeOLSuperPropStr, makeOLSuperPropExpr);
+ }
+
+
+ // Check all valid uses of SuperProperty
+ assertValidClassSuperProps();
+ assertValidOLSuperProps();
+
+ // SuperProperty is forbidden outside of method definitions.
+ assertError("function foo () { super.prop; }", SyntaxError);
+ assertError("(function () { super.prop; }", SyntaxError);
+ assertError("(()=>super.prop)", SyntaxError);
+ assertError("function *foo() { super.prop; }", SyntaxError);
+ assertError("super.prop", SyntaxError);
+ assertError("function foo () { super['prop']; }", SyntaxError);
+ assertError("(function () { super['prop']; }", SyntaxError);
+ assertError("(()=>super['prop'])", SyntaxError);
+ assertError("function *foo() { super['prop']; }", SyntaxError);
+ assertError("super['prop']", SyntaxError);
+
+ // Or inside functions inside method definitions...
+ assertClassError("class NAME { constructor() { function nested() { super.prop; }}}", SyntaxError);
+
+ // Bare super is forbidden
+ assertError("super", SyntaxError);
+
+ // Even where super is otherwise allowed
+ assertError("{ foo() { super } }", SyntaxError);
+ assertClassError("class NAME { constructor() { super; } }", SyntaxError);
+
+ /* SuperCall */
+
+ // SuperCall is invalid outside derived class constructors.
+ assertError("super()", SyntaxError);
+ assertError("(function() { super(); })", SyntaxError);
+
+
+ // Even in class constructors
+ assertClassError("class NAME { constructor() { super(); } }", SyntaxError);
+
+ function superConstructor(args) {
+ return classMethod(ident("constructor"),
+ methodFun("NAME", "method", false,
+ [], [exprStmt(superCallExpr(args))]),
+ "method", false);
+ }
+
+ function superCallBody(args) {
+ return [exprStmt(superCallExpr(args))];
+ }
+
+ // SuperCall works with various argument configurations.
+ assertClass("class NAME extends null { constructor() { super() } }",
+ [ctorPlaceholder], lit(null), superCallBody([]));
+ assertClass("class NAME extends null { constructor() { super(1) } }",
+ [ctorPlaceholder], lit(null), superCallBody([lit(1)]));
+ assertClass("class NAME extends null { constructor() { super(1, a) } }",
+ [ctorPlaceholder], lit(null), superCallBody([lit(1), ident("a")]));
+ assertClass("class NAME extends null { constructor() { super(...[]) } }",
+ [ctorPlaceholder], lit(null), superCallBody([spread(arrExpr([]))]));
+
+ /* EOF */
+ // Clipped classes should throw a syntax error
+ assertClassError("class NAME {", SyntaxError);
+ assertClassError("class NAME {;", SyntaxError);
+ assertClassError("class NAME { constructor", SyntaxError);
+ assertClassError("class NAME { constructor(", SyntaxError);
+ assertClassError("class NAME { constructor()", SyntaxError);
+ assertClassError("class NAME { constructor()", SyntaxError);
+ assertClassError("class NAME { constructor() {", SyntaxError);
+ assertClassError("class NAME { constructor() { }", SyntaxError);
+ assertClassError("class NAME { static", SyntaxError);
+ assertClassError("class NAME { static y", SyntaxError);
+ assertClassError("class NAME { static *", SyntaxError);
+ assertClassError("class NAME { static *y", SyntaxError);
+ assertClassError("class NAME { static get", SyntaxError);
+ assertClassError("class NAME { static get y", SyntaxError);
+ assertClassError("class NAME { static ;", SyntaxError);
+ assertClassError("class NAME extends", SyntaxError);
+ assertClassError("class NAME { constructor() { super", SyntaxError);
+ assertClassError("class NAME { constructor() { super.", SyntaxError);
+ assertClassError("class NAME { constructor() { super.x", SyntaxError);
+ assertClassError("class NAME { constructor() { super.m(", SyntaxError);
+ assertClassError("class NAME { constructor() { super[", SyntaxError);
+ assertClassError("class NAME { constructor() { super(", SyntaxError);
+
+ // Can not omit curly brackets
+ assertClassError("class NAME { constructor() ({}) }", SyntaxError);
+ assertClassError("class NAME { constructor() void 0 }", SyntaxError);
+ assertClassError("class NAME { constructor() 1 }", SyntaxError);
+ assertClassError("class NAME { constructor() false }", SyntaxError);
+ assertClassError("class NAME { constructor() {} a() ({}) }", SyntaxError);
+ assertClassError("class NAME { constructor() {} a() void 0 }", SyntaxError);
+ assertClassError("class NAME { constructor() {} a() 1 }", SyntaxError);
+ assertClassError("class NAME { constructor() {} a() false }", SyntaxError);
+
+}
+
+runtest(testClasses);