From e79580725fde4cf868ac58606cdde223fad943a1 Mon Sep 17 00:00:00 2001 From: Eric Faust Date: Thu, 26 Feb 2015 15:05:23 -0800 Subject: [PATCH] Bug 1066238 - Part 1: Parser support for static class methods. (r=jorendorff) --- js/src/frontend/FullParseHandler.h | 6 ++-- js/src/frontend/Parser.cpp | 44 ++++++++++++++++++++++------ js/src/frontend/Parser.h | 3 +- js/src/frontend/SyntaxParseHandler.h | 2 +- js/src/jsatom.cpp | 1 - js/src/vm/CommonPropertyNames.h | 1 + 6 files changed, 42 insertions(+), 15 deletions(-) diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index a7f4857c951f..ee31f6589e1c 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -349,7 +349,8 @@ class FullParseHandler return true; } - bool addClassMethodDefinition(ParseNode *methodList, ParseNode *key, ParseNode *fn, JSOp op) + bool addClassMethodDefinition(ParseNode *methodList, ParseNode *key, ParseNode *fn, JSOp op, + bool isStatic) { MOZ_ASSERT(methodList->isKind(PNK_CLASSMETHODLIST)); MOZ_ASSERT(key->isKind(PNK_NUMBER) || @@ -357,8 +358,7 @@ class FullParseHandler key->isKind(PNK_STRING) || key->isKind(PNK_COMPUTED_NAME)); - // For now, there's no such thing as static methods. - ParseNode *classMethod = new_(key, fn, op, false); + ParseNode *classMethod = new_(key, fn, op, isStatic); if (!classMethod) return false; methodList->append(classMethod); diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 7502ad57365c..6e4ca6935e5d 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -8029,8 +8029,19 @@ Parser::propertyList(PropListType type) if (ltok == TOK_RC) break; - if (type == ClassBody && ltok == TOK_SEMI) - continue; + bool isStatic = false; + if (type == ClassBody) { + if (ltok == TOK_SEMI) + continue; + + if (ltok == TOK_NAME && + tokenStream.currentName() == context->names().static_) + { + isStatic = true; + if (!tokenStream.getToken(<ok, TokenStream::KeywordIsName)) + return null(); + } + } bool isGenerator = false; if (ltok == TOK_MUL) { @@ -8143,12 +8154,23 @@ Parser::propertyList(PropListType type) } default: - report(ParseError, false, null(), JSMSG_BAD_PROP_ID); - return null(); + // There is never a case in which |static *(| can make a meaningful method definition. + if (isStatic && !isGenerator) { + // Turns out it wasn't static. Put it back and pretend it was a name all along. + isStatic = false; + tokenStream.ungetToken(); + atom = tokenStream.currentName(); + propname = handler.newObjectLiteralPropertyName(atom->asPropertyName(), pos()); + if (!propname) + return null(); + } else { + report(ParseError, false, null(), JSMSG_BAD_PROP_ID); + return null(); + } } if (type == ClassBody) { - if (atom == context->names().constructor) { + if (!isStatic && atom == context->names().constructor) { if (isGenerator || op != JSOP_INITPROP) { report(ParseError, false, propname, JSMSG_BAD_METHOD_DEF); return null(); @@ -8158,6 +8180,9 @@ Parser::propertyList(PropListType type) return null(); } seenConstructor = true; + } else if (isStatic && atom == context->names().prototype) { + report(ParseError, false, propname, JSMSG_BAD_METHOD_DEF); + return null(); } } @@ -8231,7 +8256,7 @@ Parser::propertyList(PropListType type) } else if (tt == TOK_LP) { tokenStream.ungetToken(); if (!methodDefinition(type, propList, propname, Normal, Method, - isGenerator ? StarGenerator : NotGenerator, op)) { + isGenerator ? StarGenerator : NotGenerator, isStatic, op)) { return null(); } } else { @@ -8241,7 +8266,7 @@ Parser::propertyList(PropListType type) } else { /* NB: Getter function in { get x(){} } is unnamed. */ if (!methodDefinition(type, propList, propname, op == JSOP_INITPROP_GETTER ? Getter : Setter, - Expression, NotGenerator, op)) { + Expression, NotGenerator, isStatic, op)) { return null(); } } @@ -8273,7 +8298,8 @@ template bool Parser::methodDefinition(PropListType listType, Node propList, Node propname, FunctionType type, FunctionSyntaxKind kind, - GeneratorKind generatorKind, JSOp op) + GeneratorKind generatorKind, + bool isStatic, JSOp op) { RootedPropertyName funName(context); if (kind == Method && tokenStream.isCurrentTokenType(TOK_NAME)) @@ -8286,7 +8312,7 @@ Parser::methodDefinition(PropListType listType, Node propList, Nod return false; if (listType == ClassBody) - return handler.addClassMethodDefinition(propList, propname, fn, op); + return handler.addClassMethodDefinition(propList, propname, fn, op, isStatic); MOZ_ASSERT(listType == ObjectLiteral); return handler.addObjectMethodDefinition(propList, propname, fn, op); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index de6862d8cb08..0585c8f4ac7c 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -577,7 +577,8 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter Node exprInParens(); bool methodDefinition(PropListType listType, Node propList, Node propname, FunctionType type, - FunctionSyntaxKind kind, GeneratorKind generatorKind, JSOp Op); + FunctionSyntaxKind kind, GeneratorKind generatorKind, + bool isStatic, JSOp Op); /* * Additional JS parsers. diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index d9c81f2bdbf9..696c81455444 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -191,7 +191,7 @@ class SyntaxParseHandler bool addPropertyDefinition(Node literal, Node name, Node expr) { return true; } bool addShorthand(Node literal, Node name, Node expr) { return true; } bool addObjectMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; } - bool addClassMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; } + bool addClassMethodDefinition(Node literal, Node name, Node fn, JSOp op, bool isStatic) { return true; } Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeUnparenthesizedYieldExpr; } Node newYieldStarExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; } diff --git a/js/src/jsatom.cpp b/js/src/jsatom.cpp index c873d588453d..5e748ac05cbe 100644 --- a/js/src/jsatom.cpp +++ b/js/src/jsatom.cpp @@ -83,7 +83,6 @@ const char js_protected_str[] = "protected"; const char js_public_str[] = "public"; const char js_send_str[] = "send"; const char js_setter_str[] = "setter"; -const char js_static_str[] = "static"; const char js_super_str[] = "super"; const char js_switch_str[] = "switch"; const char js_this_str[] = "this"; diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index 5e11c893a648..d26b5cd18fa9 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -180,6 +180,7 @@ macro(signMask, signMask, "signMask") \ macro(source, source, "source") \ macro(stack, stack, "stack") \ + macro(static, static_, "static") \ macro(sticky, sticky, "sticky") \ macro(strings, strings, "strings") \ macro(StructType, StructType, "StructType") \