Class syntax should allow string and numeric identifiers for method names
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 2 May 2015 02:23:01 +0000 (02:23 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 2 May 2015 02:23:01 +0000 (02:23 +0000)
https://bugs.webkit.org/show_bug.cgi?id=144254

Reviewed by Darin Adler.

Source/JavaScriptCore:

Added the support for string and numeric identifiers in class syntax.

* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseFunctionInfo): Instead of using ConstructorKind to indicate whether we're
inside a class or not, use the newly added SuperBinding argument instead. ConstructorKind is now None
outside a class constructor as it should be.
(JSC::Parser<LexerType>::parseFunctionDeclaration):
(JSC::Parser<LexerType>::parseClass): No longer expects an identifier at the beginning of every class
element to allow numeric and string method names. For both of those method names, parse it here instead
of parseFunctionInfo since it doesn't support either type. Also pass in SuperBinding::Needed.
(JSC::Parser<LexerType>::parsePropertyMethod): Call parseFunctionInfo with SuperBinding::NotNeeded since
this function is never used to parse a class method.
(JSC::Parser<LexerType>::parseGetterSetter): Pass in superBinding argument to parseFunctionInfo.
(JSC::Parser<LexerType>::parsePrimaryExpression): Call parseFunctionInfo with SuperBinding::NotNeeded.
* parser/Parser.h:
* parser/SyntaxChecker.h:
(JSC::SyntaxChecker::createProperty):

LayoutTests:

Added a test and rebaselined other tests per syntax error message change.

* js/class-syntax-declaration-expected.txt:
* js/class-syntax-expression-expected.txt:
* js/class-syntax-string-and-numeric-names-expected.txt: Added.
* js/class-syntax-string-and-numeric-names.html: Added.
* js/class-syntax-super-expected.txt:
* js/script-tests/class-syntax-declaration.js:
* js/script-tests/class-syntax-expression.js:
* js/script-tests/class-syntax-string-and-numeric-names.js: Added.
* js/script-tests/class-syntax-super.js:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@183709 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
LayoutTests/ChangeLog
LayoutTests/js/class-syntax-declaration-expected.txt
LayoutTests/js/class-syntax-expression-expected.txt
LayoutTests/js/class-syntax-string-and-numeric-names-expected.txt [new file with mode: 0644]
LayoutTests/js/class-syntax-string-and-numeric-names.html [new file with mode: 0644]
LayoutTests/js/class-syntax-super-expected.txt
LayoutTests/js/script-tests/class-syntax-declaration.js
LayoutTests/js/script-tests/class-syntax-expression.js
LayoutTests/js/script-tests/class-syntax-string-and-numeric-names.js [new file with mode: 0644]
LayoutTests/js/script-tests/class-syntax-super.js
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/parser/Parser.cpp
Source/JavaScriptCore/parser/Parser.h

index 9bdb71d..0881217 100644 (file)
@@ -1,3 +1,22 @@
+2015-05-01  Ryosuke Niwa  <rniwa@webkit.org>
+
+        Class syntax should allow string and numeric identifiers for method names
+        https://bugs.webkit.org/show_bug.cgi?id=144254
+
+        Reviewed by Darin Adler.
+
+        Added a test and rebaselined other tests per syntax error message change.
+
+        * js/class-syntax-declaration-expected.txt:
+        * js/class-syntax-expression-expected.txt:
+        * js/class-syntax-string-and-numeric-names-expected.txt: Added.
+        * js/class-syntax-string-and-numeric-names.html: Added.
+        * js/class-syntax-super-expected.txt:
+        * js/script-tests/class-syntax-declaration.js:
+        * js/script-tests/class-syntax-expression.js:
+        * js/script-tests/class-syntax-string-and-numeric-names.js: Added.
+        * js/script-tests/class-syntax-super.js:
+
 2015-05-01  Brent Fulgham  <bfulgham@apple.com>
 
         Create a set of initial scroll snap point tests
index ac7f974..af6b7fa 100644 (file)
@@ -19,7 +19,7 @@ PASS class threw exception SyntaxError: Unexpected end of script.
 PASS class [ threw exception SyntaxError: Unexpected token '['.
 PASS class { threw exception SyntaxError: Class statements must have a name..
 PASS class X { threw exception SyntaxError: Unexpected end of script.
-PASS class X { ( } threw exception SyntaxError: Unexpected token '('. Expected an identifier..
+PASS class X { ( } threw exception SyntaxError: Unexpected token '('.
 PASS class X {} did not throw exception.
 PASS class X { constructor() {} constructor() {} } threw exception SyntaxError: Cannot declare multiple constructors in a single class..
 PASS class X { get constructor() {} } threw exception SyntaxError: Cannot declare a getter or setter named 'constructor'..
index 81bc8de..cd09e6a 100644 (file)
@@ -17,7 +17,7 @@ PASS (new A).__proto__ is A.prototype
 PASS A.prototype.constructor is A
 PASS x = class threw exception SyntaxError: Unexpected end of script.
 PASS x = class { threw exception SyntaxError: Unexpected end of script.
-PASS x = class { ( } threw exception SyntaxError: Unexpected token '('. Expected an identifier..
+PASS x = class { ( } threw exception SyntaxError: Unexpected token '('.
 PASS x = class {} did not throw exception.
 PASS x = class { constructor() {} constructor() {} } threw exception SyntaxError: Cannot declare multiple constructors in a single class..
 PASS x = class { get constructor() {} } threw exception SyntaxError: Cannot declare a getter or setter named 'constructor'..
diff --git a/LayoutTests/js/class-syntax-string-and-numeric-names-expected.txt b/LayoutTests/js/class-syntax-string-and-numeric-names-expected.txt
new file mode 100644 (file)
index 0000000..d4352d8
--- /dev/null
@@ -0,0 +1,46 @@
+Tests for string and numeric method names for ES6 class syntax
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS constructorCallCount = 0; new (class { "constructor"() { constructorCallCount++; } }); constructorCallCount is 1
+PASS class A { 'constructor'() { constructorCallCount++; } }; new A; constructorCallCount is 2
+PASS new (class { constructor() {} "constructor"() {} }); threw exception SyntaxError: Cannot declare multiple constructors in a single class..
+PASS new (class { constructor() {} static "prototype"() {} }); threw exception SyntaxError: Cannot declare a static method named 'prototype'..
+PASS class A { 'foo'() { return 3; } }; (new A).foo() is 3
+PASS class A { get 'foo'() { return 4; } }; (new A).foo is 4
+PASS class A { get 'foo'() { return 4; } }; A.foo is undefined
+PASS class A { static get 'foo'() { return 5; } }; A.foo is 5
+PASS class A { static get 'foo'() { return 5; } }; (new A).foo is undefined
+PASS fooValue = 0; X = class { set 'foo'(value) { fooValue = value; } }; (new X).foo = 6; fooValue is 6
+PASS X.foo = 7; fooValue is 6
+PASS fooValue = 0; X = class { static set 'foo'(value) { fooValue = value; } }; X.foo = 8; fooValue is 8
+PASS (new X).foo = 7; fooValue is 8
+PASS X = class { get 'foo'() { return 9 } set 'foo'(x) { } }; x = new X; x.foo is 9
+PASS X.foo is undefined
+PASS fooValue = 0; X = class { get 'foo'() { } set 'foo'(x) { fooValue = x } }; (new X).foo = 9; fooValue is 9
+PASS X.foo = 10; fooValue is 9
+PASS X = class { static set 'foo'(x) { } static get 'foo'() { return 10 } }; X.foo is 10
+PASS (new X).foo is undefined
+PASS fooValue = 0; X = class { static set 'foo'(x) { fooValue = x } static get 'foo'() { } }; X.foo = 11; fooValue is 11
+PASS (new X).foo = 12; fooValue is 11
+PASS class A { get 0() { return 20; } }; (new A)[0] is 20
+PASS class A { get 0() { return 20; } }; A[0] is undefined
+PASS class A { static get 1() { return 21; } }; A[1] is 21
+PASS class A { static get 1() { return 21; } }; (new A)[1] is undefined
+FAIL setterValue = 0; X = class { set 2(x) { setterValue = x; } }; (new X)[2] = 22; setterValue should be 22. Was 0.
+FAIL X[2] = 23; setterValue should be 22. Was 0.
+PASS setterValue = 0; X = class { static set 3(x) { setterValue = x; } }; X[3] = 23; setterValue is 23
+PASS (new X)[3] = 23; setterValue is 23
+PASS X = class { get 4() { return 24 } set 4(x) { } }; x = new X; x[4] is 24
+PASS X[4] is undefined
+FAIL setterValue = 0; X = class { get 5() { } set 5(x) { setterValue = x; } }; (new X)[5] = 25; setterValue should be 25. Was 0.
+FAIL X[5] = 26; setterValue should be 25. Was 0.
+PASS X = class { static set 6(x) { } static get 6() { return 26 } }; X[6] is 26
+PASS (new X)[6] is undefined
+PASS setterValue = 0; X = class { static set 7(x) { setterValue = x } static get 7() { } }; X[7] = 27; setterValue is 27
+PASS (new X)[7] = 28; setterValue is 27
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/class-syntax-string-and-numeric-names.html b/LayoutTests/js/class-syntax-string-and-numeric-names.html
new file mode 100644 (file)
index 0000000..0dfb1e7
--- /dev/null
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="../resources/js-test-pre.js"></script>
+<script src="script-tests/class-syntax-string-and-numeric-names.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
index e0c71d4..397e6d1 100644 (file)
@@ -13,7 +13,7 @@ PASS (new Derived).baseMethodInGetterSetter is (new Base).baseMethod
 PASS (new Derived).baseMethodInGetterSetter = 1; valueInSetter is (new Base).baseMethod
 PASS Derived.staticMethod() is "base3"
 PASS (new SecondDerived).chainMethod() is ["base", "derived", "secondDerived"]
-PASS x = class extends Base { constructor() { super(); } super() {} } threw exception SyntaxError: Unexpected keyword 'super'. Expected an identifier..
+PASS x = class extends Base { constructor() { super(); } super() {} } threw exception SyntaxError: Unexpected keyword 'super'.
 PASS x = class extends Base { constructor() { super(); } method() { super() } } threw exception SyntaxError: Cannot call super() outside of a class constructor..
 PASS x = class extends Base { constructor() { super(); } method() { super } } threw exception SyntaxError: Cannot reference super..
 PASS x = class extends Base { constructor() { super(); } method() { return new super } } did not throw exception.
index 8c3fa09..479d87e 100644 (file)
@@ -33,7 +33,7 @@ shouldThrow("class", "'SyntaxError: Unexpected end of script'");
 shouldThrow("class [", "'SyntaxError: Unexpected token \\'[\\''");
 shouldThrow("class {", "'SyntaxError: Class statements must have a name.'");
 shouldThrow("class X {", "'SyntaxError: Unexpected end of script'");
-shouldThrow("class X { ( }", "'SyntaxError: Unexpected token \\'(\\'. Expected an identifier.'");
+shouldThrow("class X { ( }", "'SyntaxError: Unexpected token \\'(\\''");
 shouldNotThrow("class X {}");
 
 shouldThrow("class X { constructor() {} constructor() {} }", "'SyntaxError: Cannot declare multiple constructors in a single class.'");
index ddc0a69..cbb8b95 100644 (file)
@@ -31,7 +31,7 @@ shouldBe("A.prototype.constructor", "A");
 
 shouldThrow("x = class", "'SyntaxError: Unexpected end of script'");
 shouldThrow("x = class {", "'SyntaxError: Unexpected end of script'");
-shouldThrow("x = class { ( }", "'SyntaxError: Unexpected token \\'(\\'. Expected an identifier.'");
+shouldThrow("x = class { ( }", "'SyntaxError: Unexpected token \\'(\\''");
 shouldNotThrow("x = class {}");
 
 shouldThrow("x = class { constructor() {} constructor() {} }", "'SyntaxError: Cannot declare multiple constructors in a single class.'");
diff --git a/LayoutTests/js/script-tests/class-syntax-string-and-numeric-names.js b/LayoutTests/js/script-tests/class-syntax-string-and-numeric-names.js
new file mode 100644 (file)
index 0000000..1bc6a4c
--- /dev/null
@@ -0,0 +1,53 @@
+description('Tests for string and numeric method names for ES6 class syntax');
+
+shouldBe("constructorCallCount = 0; new (class { \"constructor\"() { constructorCallCount++; } }); constructorCallCount", "1");
+shouldBe("class A { 'constructor'() { constructorCallCount++; } }; new A; constructorCallCount", "2");
+shouldThrow("new (class { constructor() {} \"constructor\"() {} });", "'SyntaxError: Cannot declare multiple constructors in a single class.'");
+shouldThrow("new (class { constructor() {} static \"prototype\"() {} });", "'SyntaxError: Cannot declare a static method named \\'prototype\\'.'");
+
+shouldBe("class A { 'foo'() { return 3; } }; (new A).foo()", "3");
+
+shouldBe("class A { get 'foo'() { return 4; } }; (new A).foo", "4");
+shouldBe("class A { get 'foo'() { return 4; } }; A.foo", "undefined");
+shouldBe("class A { static get 'foo'() { return 5; } }; A.foo", "5");
+shouldBe("class A { static get 'foo'() { return 5; } }; (new A).foo", "undefined");
+
+shouldBe("fooValue = 0; X = class { set 'foo'(value) { fooValue = value; } }; (new X).foo = 6; fooValue", "6");
+shouldBe("X.foo = 7; fooValue", "6");
+shouldBe("fooValue = 0; X = class { static set 'foo'(value) { fooValue = value; } }; X.foo = 8; fooValue", "8");
+shouldBe("(new X).foo = 7; fooValue", "8");
+
+shouldBe("X = class { get 'foo'() { return 9 } set 'foo'(x) { } }; x = new X; x.foo", "9");
+shouldBe("X.foo", "undefined");
+shouldBe("fooValue = 0; X = class { get 'foo'() { } set 'foo'(x) { fooValue = x } }; (new X).foo = 9; fooValue", "9");
+shouldBe("X.foo = 10; fooValue", "9");
+
+shouldBe("X = class { static set 'foo'(x) { } static get 'foo'() { return 10 } }; X.foo", "10");
+shouldBe("(new X).foo", "undefined");
+shouldBe("fooValue = 0; X = class { static set 'foo'(x) { fooValue = x } static get 'foo'() { } }; X.foo = 11; fooValue", "11");
+shouldBe("(new X).foo = 12; fooValue", "11");
+
+
+shouldBe("class A { get 0() { return 20; } }; (new A)[0]", "20");
+shouldBe("class A { get 0() { return 20; } }; A[0]", "undefined");
+shouldBe("class A { static get 1() { return 21; } }; A[1]", "21");
+shouldBe("class A { static get 1() { return 21; } }; (new A)[1]", "undefined");
+
+// FIXME: This test case fails due to webkit.org/b/144252.
+shouldBe("setterValue = 0; X = class { set 2(x) { setterValue = x; } }; (new X)[2] = 22; setterValue", "22");
+shouldBe("X[2] = 23; setterValue", "22");
+
+shouldBe("setterValue = 0; X = class { static set 3(x) { setterValue = x; } }; X[3] = 23; setterValue", "23");
+shouldBe("(new X)[3] = 23; setterValue", "23");
+
+shouldBe("X = class { get 4() { return 24 } set 4(x) { } }; x = new X; x[4]", "24");
+shouldBe("X[4]", "undefined");
+
+// FIXME: This test case fails due to webkit.org/b/144252.
+shouldBe("setterValue = 0; X = class { get 5() { } set 5(x) { setterValue = x; } }; (new X)[5] = 25; setterValue", "25");
+shouldBe("X[5] = 26; setterValue", "25");
+
+shouldBe("X = class { static set 6(x) { } static get 6() { return 26 } }; X[6]", "26");
+shouldBe("(new X)[6]", "undefined");
+shouldBe("setterValue = 0; X = class { static set 7(x) { setterValue = x } static get 7() { } }; X[7] = 27; setterValue", "27");
+shouldBe("(new X)[7] = 28; setterValue", "27");
index 7a5e9ff..a3185ab 100644 (file)
@@ -37,7 +37,7 @@ shouldBe('(new Derived).baseMethodInGetterSetter', '(new Base).baseMethod');
 shouldBe('(new Derived).baseMethodInGetterSetter = 1; valueInSetter', '(new Base).baseMethod');
 shouldBe('Derived.staticMethod()', '"base3"');
 shouldBe('(new SecondDerived).chainMethod()', '["base", "derived", "secondDerived"]');
-shouldThrow('x = class extends Base { constructor() { super(); } super() {} }', '"SyntaxError: Unexpected keyword \'super\'. Expected an identifier."');
+shouldThrow('x = class extends Base { constructor() { super(); } super() {} }', '"SyntaxError: Unexpected keyword \'super\'"');
 shouldThrow('x = class extends Base { constructor() { super(); } method() { super() } }',
     '"SyntaxError: Cannot call super() outside of a class constructor."');
 shouldThrow('x = class extends Base { constructor() { super(); } method() { super } }', '"SyntaxError: Cannot reference super."');
index 6b69ec1..32372ab 100644 (file)
@@ -1,3 +1,28 @@
+2015-05-01  Ryosuke Niwa  <rniwa@webkit.org>
+
+        Class syntax should allow string and numeric identifiers for method names
+        https://bugs.webkit.org/show_bug.cgi?id=144254
+
+        Reviewed by Darin Adler.
+
+        Added the support for string and numeric identifiers in class syntax.
+
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::parseFunctionInfo): Instead of using ConstructorKind to indicate whether we're
+        inside a class or not, use the newly added SuperBinding argument instead. ConstructorKind is now None
+        outside a class constructor as it should be.
+        (JSC::Parser<LexerType>::parseFunctionDeclaration):
+        (JSC::Parser<LexerType>::parseClass): No longer expects an identifier at the beginning of every class
+        element to allow numeric and string method names. For both of those method names, parse it here instead
+        of parseFunctionInfo since it doesn't support either type. Also pass in SuperBinding::Needed.
+        (JSC::Parser<LexerType>::parsePropertyMethod): Call parseFunctionInfo with SuperBinding::NotNeeded since
+        this function is never used to parse a class method.
+        (JSC::Parser<LexerType>::parseGetterSetter): Pass in superBinding argument to parseFunctionInfo.
+        (JSC::Parser<LexerType>::parsePrimaryExpression): Call parseFunctionInfo with SuperBinding::NotNeeded.
+        * parser/Parser.h:
+        * parser/SyntaxChecker.h:
+        (JSC::SyntaxChecker::createProperty):
+
 2015-05-01  Filip Pizlo  <fpizlo@apple.com>
 
         FTL should use AI more
index c7088e7..ecaead9 100644 (file)
@@ -1312,7 +1312,7 @@ static const char* stringForFunctionMode(FunctionParseMode mode)
 
 template <typename LexerType>
 template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuilder& context, FunctionRequirements requirements, FunctionParseMode mode,
-    bool nameIsInContainingScope, ConstructorKind ownerClassKind, int functionKeywordStart, ParserFunctionInfo<TreeBuilder>& info)
+    bool nameIsInContainingScope, ConstructorKind constructorKind, SuperBinding expectedSuperBinding, int functionKeywordStart, ParserFunctionInfo<TreeBuilder>& info)
 {
     AutoPopScopeRef functionScope(this, pushScope());
     functionScope->setIsFunction();
@@ -1359,12 +1359,11 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
 
     // BytecodeGenerator emits code to throw TypeError when a class constructor is "call"ed.
     // Set ConstructorKind to None for non-constructor methods of classes.
-    bool isClassConstructor = mode == MethodMode && info.name && *info.name == m_vm->propertyNames->constructor;
     if (m_defaultConstructorKind != ConstructorKind::None) {
-        ownerClassKind = m_defaultConstructorKind;
-        isClassConstructor = true;
+        constructorKind = m_defaultConstructorKind;
+        expectedSuperBinding = m_defaultConstructorKind == ConstructorKind::Derived ? SuperBinding::Needed : SuperBinding::NotNeeded;
     }
-    ConstructorKind constructorKind = isClassConstructor ? ownerClassKind : ConstructorKind::None;
+    bool isClassConstructor = constructorKind != ConstructorKind::None;
 
     info.openBraceOffset = m_token.m_data.offset;
     info.bodyStartLine = tokenLine();
@@ -1424,10 +1423,10 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
     }
     if (functionScope->hasDirectSuper()) {
         semanticFailIfTrue(!isClassConstructor, "Cannot call super() outside of a class constructor");
-        semanticFailIfTrue(ownerClassKind != ConstructorKind::Derived, "Cannot call super() in a base class constructor");
+        semanticFailIfTrue(constructorKind != ConstructorKind::Derived, "Cannot call super() in a base class constructor");
     }
     if (functionScope->needsSuperBinding())
-        semanticFailIfTrue(ownerClassKind != ConstructorKind::Derived, "super can only be used in a method of a derived class");
+        semanticFailIfTrue(expectedSuperBinding == SuperBinding::NotNeeded, "super can only be used in a method of a derived class");
 
     info.closeBraceOffset = m_token.m_data.offset;
     unsigned closeBraceLine = m_token.m_data.line;
@@ -1468,7 +1467,8 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseFunctionDecla
     unsigned functionKeywordStart = tokenStart();
     next();
     ParserFunctionInfo<TreeBuilder> info;
-    failIfFalse((parseFunctionInfo(context, FunctionNeedsName, FunctionMode, true, ConstructorKind::None, functionKeywordStart, info)), "Cannot parse this function");
+    failIfFalse((parseFunctionInfo(context, FunctionNeedsName, FunctionMode, true, ConstructorKind::None, SuperBinding::NotNeeded,
+        functionKeywordStart, info)), "Cannot parse this function");
     failIfFalse(info.name, "Function statements must have a name");
     failIfFalseIfStrict(declareVariable(info.name), "Cannot declare a function named '", info.name->impl(), "' in strict mode");
     return context.createFuncDeclStatement(location, info);
@@ -1550,28 +1550,44 @@ template <class TreeBuilder> TreeClassExpression Parser<LexerType>::parseClass(T
         if (isStaticMethod)
             next();
 
-        matchOrFail(IDENT, "Expected an identifier");
-
+        // FIXME: Figure out a way to share more code with parseProperty.
         const CommonIdentifiers& propertyNames = *m_vm->propertyNames;
-        const Identifier& ident = *m_token.m_data.ident;
-        bool isGetter = ident == propertyNames.get;
-        bool isSetter = ident == propertyNames.set;
+        const Identifier* ident = nullptr;
+        bool isGetter = false;
+        bool isSetter = false;
+        switch (m_token.m_type) {
+        case STRING:
+            ident = m_token.m_data.ident;
+            next();
+            break;
+        case IDENT:
+            ident = m_token.m_data.ident;
+            isGetter = *ident == propertyNames.get;
+            isSetter = *ident == propertyNames.set;
+            break;
+        case DOUBLE:
+        case INTEGER:
+            ident = &m_parserArena.identifierArena().makeNumericIdentifier(const_cast<VM*>(m_vm), m_token.m_data.doubleValue);
+            next();
+            break;
+        default:
+            failDueToUnexpectedToken();
+        }
 
         TreeProperty property;
         const bool alwaysStrictInsideClass = true;
         if (isGetter || isSetter) {
             nextExpectIdentifier(LexerFlagsIgnoreReservedWords);
-            property = parseGetterSetter(context, alwaysStrictInsideClass, isGetter ? PropertyNode::Getter : PropertyNode::Setter, methodStart, constructorKind, SuperBinding::Needed);
+            property = parseGetterSetter(context, alwaysStrictInsideClass, isGetter ? PropertyNode::Getter : PropertyNode::Setter, methodStart,
+                ConstructorKind::None, SuperBinding::Needed);
             failIfFalse(property, "Cannot parse this method");
         } else {
             ParserFunctionInfo<TreeBuilder> methodInfo;
-            failIfFalse((parseFunctionInfo(context, FunctionNeedsName, isStaticMethod ? FunctionMode : MethodMode, false, constructorKind, methodStart, methodInfo)), "Cannot parse this method");
-            failIfFalse(methodInfo.name, "method must have a name");
-            failIfFalse(declareVariable(methodInfo.name), "Cannot declare a method named '", methodInfo.name->impl(), "'");
-
-            bool isConstructor = !isStaticMethod && *methodInfo.name == propertyNames.constructor;
-            if (isConstructor)
-                methodInfo.name = className;
+            bool isConstructor = !isStaticMethod && *ident == propertyNames.constructor;
+            failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, isStaticMethod ? FunctionMode : MethodMode, false,
+                isConstructor ? constructorKind : ConstructorKind::None, SuperBinding::Needed, methodStart, methodInfo)), "Cannot parse this method");
+            failIfFalse(ident && declareVariable(ident), "Cannot declare a method named '", methodInfo.name->impl(), "'");
+            methodInfo.name = isConstructor ? className : ident;
 
             TreeExpression method = context.createFunctionExpr(methodLocation, methodInfo);
             if (isConstructor) {
@@ -1581,7 +1597,7 @@ template <class TreeBuilder> TreeClassExpression Parser<LexerType>::parseClass(T
             }
 
             // FIXME: Syntax error when super() is called
-            semanticFailIfTrue(isStaticMethod && *methodInfo.name == propertyNames.prototype,
+            semanticFailIfTrue(isStaticMethod && methodInfo.name && *methodInfo.name == propertyNames.prototype,
                 "Cannot declare a static method named 'prototype'");
             property = context.createProperty(methodInfo.name, method, PropertyNode::Constant, PropertyNode::Unknown, alwaysStrictInsideClass, SuperBinding::Needed);
         }
@@ -2068,7 +2084,8 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parsePropertyMeth
     JSTokenLocation methodLocation(tokenLocation());
     unsigned methodStart = tokenStart();
     ParserFunctionInfo<TreeBuilder> methodInfo;
-    failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, MethodMode, false, ConstructorKind::None, methodStart, methodInfo)), "Cannot parse this method");
+    failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, MethodMode, false, ConstructorKind::None, SuperBinding::NotNeeded,
+        methodStart, methodInfo)), "Cannot parse this method");
     methodInfo.name = methodName;
     return context.createFunctionExpr(methodLocation, methodInfo);
 }
@@ -2094,10 +2111,12 @@ template <class TreeBuilder> TreeProperty Parser<LexerType>::parseGetterSetter(T
     ParserFunctionInfo<TreeBuilder> info;
     if (type == PropertyNode::Getter) {
         failIfFalse(match(OPENPAREN), "Expected a parameter list for getter definition");
-        failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, GetterMode, false, constructorKind, getterOrSetterStartOffset, info)), "Cannot parse getter definition");
+        failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, GetterMode, false, constructorKind, superBinding,
+            getterOrSetterStartOffset, info)), "Cannot parse getter definition");
     } else {
         failIfFalse(match(OPENPAREN), "Expected a parameter list for setter definition");
-        failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, SetterMode, false, constructorKind, getterOrSetterStartOffset, info)), "Cannot parse setter definition");
+        failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, SetterMode, false, constructorKind, superBinding,
+            getterOrSetterStartOffset, info)), "Cannot parse setter definition");
     }
     if (stringPropertyName)
         return context.createGetterOrSetterProperty(location, type, strict, stringPropertyName, info, superBinding);
@@ -2346,7 +2365,8 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parsePrimaryExpre
         next();
         ParserFunctionInfo<TreeBuilder> info;
         info.name = &m_vm->propertyNames->nullIdentifier;
-        failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, FunctionMode, false, ConstructorKind::None, functionKeywordStart, info)), "Cannot parse function expression");
+        failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, FunctionMode, false, ConstructorKind::None, SuperBinding::NotNeeded,
+            functionKeywordStart, info)), "Cannot parse function expression");
         return context.createFunctionExpr(location, info);
     }
 #if ENABLE(ES6_CLASS_SYNTAX)
index bde4b0e..3dff8e4 100644 (file)
@@ -772,7 +772,7 @@ private:
     template <class TreeBuilder> NEVER_INLINE TreeDeconstructionPattern parseDeconstructionPattern(TreeBuilder&, DeconstructionKind, int depth = 0);
     template <class TreeBuilder> NEVER_INLINE TreeDeconstructionPattern tryParseDeconstructionPatternExpression(TreeBuilder&);
 
-    template <class TreeBuilder> NEVER_INLINE bool parseFunctionInfo(TreeBuilder&, FunctionRequirements, FunctionParseMode, bool nameIsInContainingScope, ConstructorKind, int functionKeywordStart, ParserFunctionInfo<TreeBuilder>&);
+    template <class TreeBuilder> NEVER_INLINE bool parseFunctionInfo(TreeBuilder&, FunctionRequirements, FunctionParseMode, bool nameIsInContainingScope, ConstructorKind, SuperBinding, int functionKeywordStart, ParserFunctionInfo<TreeBuilder>&);
 #if ENABLE(ES6_CLASS_SYNTAX)
     template <class TreeBuilder> NEVER_INLINE TreeClassExpression parseClass(TreeBuilder&, FunctionRequirements, ParserClassInfo<TreeBuilder>&);
 #endif