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 9bdb71d69cfdbca857795d8ffff308d5eac96e14..088121792a38fb6684b3819ef7d13f45d2bb17bf 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 ac7f974a6f3f1b06effbac90ad064debbb33fe4c..af6b7fa37571686310d9360b9c3c475b1e9336f0 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 81bc8de777f8cf28b193500d936b3c29ca06e237..cd09e6a0103d0fc3542102ad7379d51d61072da1 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 e0c71d452b7b651ed9331c69687882f7f2c4999f..397e6d123f19f4311ca619afdbfaf3a2b1e85ccc 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 8c3fa09028e5973df443a777db7bc5f705ef2062..479d87e99460c8e32201df62882837eec8577e1e 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 ddc0a69cb97cabbfc924a33e18320f4dced1a808..cbb8b95539df65d130061d2cd017a975863687bf 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 7a5e9ff986f782ccea35a9476b9efdbdcfcdc04d..a3185ab1dc5244ae8f800e58b2c9cf0edcc3a214 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 6b69ec159b4333128342c85990b9586439721123..32372abbcd8051c7f6e7244f94d32a0119f32db2 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 c7088e71928cc2be5879609bb30908c1e5834559..ecaead9baf7b09342d0714c42ae0d831f64066a9 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 bde4b0ee1283ec0a1d333f9cef5cde083a09f5a0..3dff8e49b3057c4991445f6fc4ed42c9f3465ac8 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