Bug 883333, part 8 - Refactor return statement parsing. r=Waldo.
authorJason Orendorff <jorendorff@mozilla.com>
Fri, 21 Jun 2013 08:17:59 -0500
changeset 147463 983bb55ac8dbaf34b62dce03f160656567f55e09
parent 147462 2c7f6627fbd01d45a21dc8f0ea2838cd6017b9b6
child 147464 d8cce0fb9d9abae1038c95efa989ab0a01399c11
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo
bugs883333
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 883333, part 8 - Refactor return statement parsing. r=Waldo.
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -4396,78 +4396,80 @@ Parser<ParseHandler>::breakStatement()
     if (!MatchOrInsertSemicolon(context, &tokenStream))
         return null();
 
     return handler.newBreakStatement(label, TokenPos::make(begin, pos().end));
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::returnOrYield(bool useAssignExpr)
-{
-    TokenKind tt = tokenStream.currentToken().type;
+Parser<ParseHandler>::returnStatementOrYieldExpression()
+{
+    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_RETURN) ||
+              tokenStream.isCurrentTokenType(TOK_YIELD));
+    bool isYield = tokenStream.isCurrentTokenType(TOK_YIELD);
+    uint32_t begin = pos().begin;
+
     if (!pc->sc->isFunctionBox()) {
         report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD,
-               (tt == TOK_RETURN) ? js_return_str : js_yield_str);
+               isYield ? js_yield_str : js_return_str);
         return null();
     }
 
-    bool isYield = (tt == TOK_YIELD);
-    uint32_t begin = pos().begin;
-
-#if JS_HAS_GENERATORS
     if (isYield) {
+        JS_ASSERT(JS_HAS_GENERATORS);
         if (!abortIfSyntaxParser())
             return null();
 
-        /*
-         * If we're within parens, we won't know if this is a generator expression until we see
-         * a |for| token, so we have to delay flagging the current function.
-         */
+        // If we're within parens, we won't know if this is a generator
+        // expression until we see a |for| token, so we have to delay flagging
+        // the current function.
         if (pc->parenDepth == 0) {
             pc->sc->asFunctionBox()->setIsGenerator();
         } else {
             pc->yieldCount++;
             pc->yieldOffset = begin;
         }
     }
-#endif
-
-    /* This is ugly, but we don't want to require a semicolon. */
-    TokenKind tt2 = tokenStream.peekTokenSameLine(TSF_OPERAND);
-    if (tt2 == TOK_ERROR)
+
+    // Parse an optional operand.
+    //
+    // Checking whether yield has an operand is especially wonky since
+    // there is not a mandatory semicolon.
+    //
+    // ES6 does not permit yield without an operand. We will have to sunset
+    // this extension in order to conform to the ES6 syntax, which treats
+    // "yield \n expr;" as a single ExpressionStatement.
+    Node exprNode;
+    TokenKind next = tokenStream.peekTokenSameLine(TSF_OPERAND);
+    if (next == TOK_ERROR)
         return null();
-
-    Node pn2;
-    if (tt2 != TOK_EOF && tt2 != TOK_EOL && tt2 != TOK_SEMI && tt2 != TOK_RC
-#if JS_HAS_GENERATORS
-        && (!isYield ||
-            (tt2 != tt && tt2 != TOK_RB && tt2 != TOK_RP &&
-             tt2 != TOK_COLON && tt2 != TOK_COMMA))
-#endif
-        )
+    if (next == TOK_EOF || next == TOK_EOL || next == TOK_SEMI || next == TOK_RC ||
+        (isYield && (next == TOK_YIELD || next == TOK_RB || next == TOK_RP ||
+                     next == TOK_COLON || next == TOK_COMMA)))
     {
-        pn2 = useAssignExpr ? assignExpr() : expr();
-        if (!pn2)
+        exprNode = null();
+        if (!isYield)
+            pc->funHasReturnVoid = true;
+    } else {
+        exprNode = isYield ? assignExpr() : expr();
+        if (!exprNode)
             return null();
-#if JS_HAS_GENERATORS
-        if (tt == TOK_RETURN)
-#endif
+        if (!isYield)
             pc->funHasReturnExpr = true;
-    } else {
-        pn2 = null();
-#if JS_HAS_GENERATORS
-        if (tt == TOK_RETURN)
-#endif
-            pc->funHasReturnVoid = true;
+    }
+
+    if (!isYield) {
+        if (!MatchOrInsertSemicolon(context, &tokenStream))
+            return null();
     }
 
     Node pn = isYield
-              ? handler.newUnary(PNK_YIELD, JSOP_YIELD, begin, pn2)
-              : handler.newReturnStatement(pn2, TokenPos::make(begin, pos().end));
+              ? handler.newUnary(PNK_YIELD, JSOP_YIELD, begin, exprNode)
+              : handler.newReturnStatement(exprNode, TokenPos::make(begin, pos().end));
     if (!pn)
         return null();
 
     if (pc->funHasReturnExpr && pc->sc->asFunctionBox()->isGenerator()) {
         /* As in Python (see PEP-255), disallow return v; in generators. */
         reportBadReturn(pn, ParseError, JSMSG_BAD_GENERATOR_RETURN,
                         JSMSG_BAD_ANON_GENERATOR_RETURN);
         return null();
@@ -4821,20 +4823,17 @@ Parser<ParseHandler>::statement(bool can
 
       case TOK_CONTINUE:
         return continueStatement();
 
       case TOK_BREAK:
         return breakStatement();
 
       case TOK_RETURN:
-        pn = returnOrYield(false);
-        if (!pn)
-            return null();
-        break;
+        return returnStatementOrYieldExpression();
 
       case TOK_WITH:
         return withStatement();
 
       case TOK_THROW:
       {
         uint32_t begin = pos().begin;
 
@@ -5193,17 +5192,17 @@ Parser<SyntaxParseHandler>::setAssignmen
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::assignExpr()
 {
     JS_CHECK_RECURSION(context, return null());
 
 #if JS_HAS_GENERATORS
     if (tokenStream.matchToken(TOK_YIELD, TSF_OPERAND))
-        return returnOrYield(true);
+        return returnStatementOrYieldExpression();
     if (tokenStream.hadError())
         return null();
 #endif
 
     // Save the tokenizer state in case we find an arrow function and have to
     // rewind.
     TokenStream::Position start(keepAtoms);
     tokenStream.tell(&start);
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -419,16 +419,17 @@ struct Parser : private AutoGCRooter, pu
 
     Node ifStatement();
     Node doWhileStatement();
     Node whileStatement();
     Node forStatement();
     Node switchStatement();
     Node continueStatement();
     Node breakStatement();
+    Node returnStatementOrYieldExpression();
     Node withStatement();
     Node labeledStatement();
     Node tryStatement();
 #if JS_HAS_BLOCK_SCOPE
     Node letStatement();
 #endif
     Node expressionStatement();
     Node variables(ParseNodeKind kind, bool *psimple = NULL,
@@ -461,17 +462,16 @@ struct Parser : private AutoGCRooter, pu
     Node comprehensionTail(Node kid, unsigned blockid, bool isGenexp,
                            ParseContext<ParseHandler> *outerpc,
                            ParseNodeKind kind = PNK_SEMI, JSOp op = JSOP_NOP);
     bool arrayInitializerComprehensionTail(Node pn);
     Node generatorExpr(Node kid);
     bool argumentList(Node listNode);
     Node bracketedExpr();
     Node letBlock(LetContext letContext);
-    Node returnOrYield(bool useAssignExpr);
     Node destructuringExpr(BindData<ParseHandler> *data, TokenKind tt);
 
     Node identifierName();
 
     bool allowsForEachIn() {
 #if !JS_HAS_FOR_EACH_IN
         return false;
 #else