Refactor validating jump statements out of glslang.y

Move the logic to ParseContext. This will simplify changing the logic for
the break statement that is needed to implement switch.

BUG=angle:921, angle:911
TEST=WebGL conformance tests

Change-Id: Ib8bbc7075c05d345e90377202b5446fb3307f94c
Reviewed-on: https://chromium-review.googlesource.com/251522
Tested-by: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index beac6b7..5c89a3b 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -2655,6 +2655,56 @@
     return node;
 }
 
+TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc)
+{
+    switch (op)
+    {
+      case EOpContinue:
+        if (mLoopNestingLevel <= 0)
+        {
+            error(loc, "continue statement only allowed in loops", "");
+            recover();
+        }
+        break;
+      case EOpBreak:
+        if (mLoopNestingLevel <= 0)
+        {
+            error(loc, "break statement only allowed in loops", "");
+            recover();
+        }
+        break;
+      case EOpReturn:
+        if (currentFunctionType->getBasicType() != EbtVoid)
+        {
+            error(loc, "non-void function must return a value", "return");
+            recover();
+        }
+        break;
+      default:
+        // No checks for discard
+        break;
+    }
+    return intermediate.addBranch(op, loc);
+}
+
+TIntermBranch *TParseContext::addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc)
+{
+    ASSERT(op == EOpReturn);
+    mFunctionReturnsValue = true;
+    if (currentFunctionType->getBasicType() == EbtVoid)
+    {
+        error(loc, "void function cannot return a value", "return");
+        recover();
+    }
+    else if (*currentFunctionType != returnValue->getType())
+    {
+        error(loc, "function return is not matching type:", "return");
+        recover();
+    }
+    return intermediate.addBranch(op, returnValue, loc);
+}
+
+
 //
 // Parse an array of strings using yyparse.
 //
diff --git a/src/compiler/translator/ParseContext.h b/src/compiler/translator/ParseContext.h
index 2890bd0..b712730 100644
--- a/src/compiler/translator/ParseContext.h
+++ b/src/compiler/translator/ParseContext.h
@@ -32,10 +32,10 @@
             shaderSpec(spec),
             compileOptions(options),
             treeRoot(0),
-            loopNestingLevel(0),
+            mLoopNestingLevel(0),
             structNestingLevel(0),
             currentFunctionType(NULL),
-            functionReturnsValue(false),
+            mFunctionReturnsValue(false),
             checksPrecisionErrors(checksPrecErrors),
             defaultMatrixPacking(EmpColumnMajor),
             defaultBlockStorage(EbsShared),
@@ -51,10 +51,10 @@
     int shaderVersion;
     int compileOptions;
     TIntermNode* treeRoot;       // root of parse tree being created
-    int loopNestingLevel;        // 0 if outside all loops
+    int mLoopNestingLevel;       // 0 if outside all loops
     int structNestingLevel;      // incremented while parsing a struct declaration
     const TType* currentFunctionType;  // the return type of the function that's currently being parsed
-    bool functionReturnsValue;   // true if a non-void function has a return
+    bool mFunctionReturnsValue;  // true if a non-void function has a return
     bool checksPrecisionErrors;  // true if an error will be generated when a variable is declared without precision, explicit or implicit.
     bool fragmentPrecisionHigh;  // true if highp precision is supported in the fragment language.
     TLayoutMatrixPacking defaultMatrixPacking;
@@ -170,6 +170,9 @@
         const TSourceLoc &);
     TIntermTyped *addBinaryMathBooleanResult(TOperator op, TIntermTyped *left, TIntermTyped *right,
         const TSourceLoc &);
+
+    TIntermBranch *addBranch(TOperator op, const TSourceLoc &loc);
+    TIntermBranch *addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc);
 };
 
 int PaParseStrings(size_t count, const char* const string[], const int length[],
diff --git a/src/compiler/translator/glslang.y b/src/compiler/translator/glslang.y
index 3d857a1..12a410e 100644
--- a/src/compiler/translator/glslang.y
+++ b/src/compiler/translator/glslang.y
@@ -1625,22 +1625,22 @@
     ;
 
 iteration_statement
-    : WHILE LEFT_PAREN { context->symbolTable.push(); ++context->loopNestingLevel; } condition RIGHT_PAREN statement_no_new_scope {
+    : WHILE LEFT_PAREN { context->symbolTable.push(); ++context->mLoopNestingLevel; } condition RIGHT_PAREN statement_no_new_scope {
         context->symbolTable.pop();
         $$ = context->intermediate.addLoop(ELoopWhile, 0, $4, 0, $6, @1);
-        --context->loopNestingLevel;
+        --context->mLoopNestingLevel;
     }
-    | DO { ++context->loopNestingLevel; } statement_with_scope WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON {
+    | DO { ++context->mLoopNestingLevel; } statement_with_scope WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON {
         if (context->boolErrorCheck(@8, $6))
             context->recover();
 
         $$ = context->intermediate.addLoop(ELoopDoWhile, 0, $6, 0, $3, @4);
-        --context->loopNestingLevel;
+        --context->mLoopNestingLevel;
     }
-    | FOR LEFT_PAREN { context->symbolTable.push(); ++context->loopNestingLevel; } for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope {
+    | FOR LEFT_PAREN { context->symbolTable.push(); ++context->mLoopNestingLevel; } for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope {
         context->symbolTable.pop();
         $$ = context->intermediate.addLoop(ELoopFor, $4, reinterpret_cast<TIntermTyped*>($5.node1), reinterpret_cast<TIntermTyped*>($5.node2), $7, @1);
-        --context->loopNestingLevel;
+        --context->mLoopNestingLevel;
     }
     ;
 
@@ -1675,40 +1675,20 @@
 
 jump_statement
     : CONTINUE SEMICOLON {
-        if (context->loopNestingLevel <= 0) {
-            context->error(@1, "continue statement only allowed in loops", "");
-            context->recover();
-        }
-        $$ = context->intermediate.addBranch(EOpContinue, @1);
+        $$ = context->addBranch(EOpContinue, @1);
     }
     | BREAK SEMICOLON {
-        if (context->loopNestingLevel <= 0) {
-            context->error(@1, "break statement only allowed in loops", "");
-            context->recover();
-        }
-        $$ = context->intermediate.addBranch(EOpBreak, @1);
+        $$ = context->addBranch(EOpBreak, @1);
     }
     | RETURN SEMICOLON {
-        $$ = context->intermediate.addBranch(EOpReturn, @1);
-        if (context->currentFunctionType->getBasicType() != EbtVoid) {
-            context->error(@1, "non-void function must return a value", "return");
-            context->recover();
-        }
+        $$ = context->addBranch(EOpReturn, @1);
     }
     | RETURN expression SEMICOLON {
-        $$ = context->intermediate.addBranch(EOpReturn, $2, @1);
-        context->functionReturnsValue = true;
-        if (context->currentFunctionType->getBasicType() == EbtVoid) {
-            context->error(@1, "void function cannot return a value", "return");
-            context->recover();
-        } else if (*(context->currentFunctionType) != $2->getType()) {
-            context->error(@1, "function return is not matching type:", "return");
-            context->recover();
-        }
+        $$ = context->addBranch(EOpReturn, $2, @1);
     }
     | DISCARD SEMICOLON {
         FRAG_ONLY("discard", @1);
-        $$ = context->intermediate.addBranch(EOpKill, @1);
+        $$ = context->addBranch(EOpKill, @1);
     }
     ;
 
@@ -1779,7 +1759,7 @@
         // Remember the return type for later checking for RETURN statements.
         //
         context->currentFunctionType = &(prevDec->getReturnType());
-        context->functionReturnsValue = false;
+        context->mFunctionReturnsValue = false;
 
         //
         // Insert parameters into the symbol table.
@@ -1818,12 +1798,12 @@
         }
         context->intermediate.setAggregateOperator(paramNodes, EOpParameters, @1);
         $1.intermAggregate = paramNodes;
-        context->loopNestingLevel = 0;
+        context->mLoopNestingLevel = 0;
     }
     compound_statement_no_new_scope {
         //?? Check that all paths return a value if return type != void ?
         //   May be best done as post process phase on intermediate code
-        if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->functionReturnsValue) {
+        if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->mFunctionReturnsValue) {
             context->error(@1, "function does not return a value:", "", $1.function->getName().c_str());
             context->recover();
         }
diff --git a/src/compiler/translator/glslang_tab.cpp b/src/compiler/translator/glslang_tab.cpp
index 711bc52..2f85c46 100644
--- a/src/compiler/translator/glslang_tab.cpp
+++ b/src/compiler/translator/glslang_tab.cpp
@@ -712,8 +712,8 @@
     1535,  1536,  1536,  1536,  1546,  1547,  1551,  1551,  1552,  1552,
     1557,  1560,  1570,  1573,  1579,  1580,  1584,  1592,  1596,  1606,
     1611,  1628,  1628,  1633,  1633,  1640,  1640,  1648,  1651,  1657,
-    1660,  1666,  1670,  1677,  1684,  1691,  1698,  1709,  1718,  1722,
-    1729,  1732,  1738,  1738
+    1660,  1666,  1670,  1677,  1680,  1683,  1686,  1689,  1698,  1702,
+    1709,  1712,  1718,  1718
 };
 #endif
 
@@ -4687,7 +4687,7 @@
 
   case 241:
 
-    { context->symbolTable.push(); ++context->loopNestingLevel; }
+    { context->symbolTable.push(); ++context->mLoopNestingLevel; }
 
     break;
 
@@ -4696,14 +4696,14 @@
     {
         context->symbolTable.pop();
         (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopWhile, 0, (yyvsp[-2].interm.intermTypedNode), 0, (yyvsp[0].interm.intermNode), (yylsp[-5]));
-        --context->loopNestingLevel;
+        --context->mLoopNestingLevel;
     }
 
     break;
 
   case 243:
 
-    { ++context->loopNestingLevel; }
+    { ++context->mLoopNestingLevel; }
 
     break;
 
@@ -4714,14 +4714,14 @@
             context->recover();
 
         (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopDoWhile, 0, (yyvsp[-2].interm.intermTypedNode), 0, (yyvsp[-5].interm.intermNode), (yylsp[-4]));
-        --context->loopNestingLevel;
+        --context->mLoopNestingLevel;
     }
 
     break;
 
   case 245:
 
-    { context->symbolTable.push(); ++context->loopNestingLevel; }
+    { context->symbolTable.push(); ++context->mLoopNestingLevel; }
 
     break;
 
@@ -4730,7 +4730,7 @@
     {
         context->symbolTable.pop();
         (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopFor, (yyvsp[-3].interm.intermNode), reinterpret_cast<TIntermTyped*>((yyvsp[-2].interm.nodePair).node1), reinterpret_cast<TIntermTyped*>((yyvsp[-2].interm.nodePair).node2), (yyvsp[0].interm.intermNode), (yylsp[-6]));
-        --context->loopNestingLevel;
+        --context->mLoopNestingLevel;
     }
 
     break;
@@ -4788,11 +4788,7 @@
   case 253:
 
     {
-        if (context->loopNestingLevel <= 0) {
-            context->error((yylsp[-1]), "continue statement only allowed in loops", "");
-            context->recover();
-        }
-        (yyval.interm.intermNode) = context->intermediate.addBranch(EOpContinue, (yylsp[-1]));
+        (yyval.interm.intermNode) = context->addBranch(EOpContinue, (yylsp[-1]));
     }
 
     break;
@@ -4800,11 +4796,7 @@
   case 254:
 
     {
-        if (context->loopNestingLevel <= 0) {
-            context->error((yylsp[-1]), "break statement only allowed in loops", "");
-            context->recover();
-        }
-        (yyval.interm.intermNode) = context->intermediate.addBranch(EOpBreak, (yylsp[-1]));
+        (yyval.interm.intermNode) = context->addBranch(EOpBreak, (yylsp[-1]));
     }
 
     break;
@@ -4812,11 +4804,7 @@
   case 255:
 
     {
-        (yyval.interm.intermNode) = context->intermediate.addBranch(EOpReturn, (yylsp[-1]));
-        if (context->currentFunctionType->getBasicType() != EbtVoid) {
-            context->error((yylsp[-1]), "non-void function must return a value", "return");
-            context->recover();
-        }
+        (yyval.interm.intermNode) = context->addBranch(EOpReturn, (yylsp[-1]));
     }
 
     break;
@@ -4824,15 +4812,7 @@
   case 256:
 
     {
-        (yyval.interm.intermNode) = context->intermediate.addBranch(EOpReturn, (yyvsp[-1].interm.intermTypedNode), (yylsp[-2]));
-        context->functionReturnsValue = true;
-        if (context->currentFunctionType->getBasicType() == EbtVoid) {
-            context->error((yylsp[-2]), "void function cannot return a value", "return");
-            context->recover();
-        } else if (*(context->currentFunctionType) != (yyvsp[-1].interm.intermTypedNode)->getType()) {
-            context->error((yylsp[-2]), "function return is not matching type:", "return");
-            context->recover();
-        }
+        (yyval.interm.intermNode) = context->addBranch(EOpReturn, (yyvsp[-1].interm.intermTypedNode), (yylsp[-2]));
     }
 
     break;
@@ -4841,7 +4821,7 @@
 
     {
         FRAG_ONLY("discard", (yylsp[-1]));
-        (yyval.interm.intermNode) = context->intermediate.addBranch(EOpKill, (yylsp[-1]));
+        (yyval.interm.intermNode) = context->addBranch(EOpKill, (yylsp[-1]));
     }
 
     break;
@@ -4926,7 +4906,7 @@
         // Remember the return type for later checking for RETURN statements.
         //
         context->currentFunctionType = &(prevDec->getReturnType());
-        context->functionReturnsValue = false;
+        context->mFunctionReturnsValue = false;
 
         //
         // Insert parameters into the symbol table.
@@ -4965,7 +4945,7 @@
         }
         context->intermediate.setAggregateOperator(paramNodes, EOpParameters, (yylsp[0]));
         (yyvsp[0].interm).intermAggregate = paramNodes;
-        context->loopNestingLevel = 0;
+        context->mLoopNestingLevel = 0;
     }
 
     break;
@@ -4975,7 +4955,7 @@
     {
         //?? Check that all paths return a value if return type != void ?
         //   May be best done as post process phase on intermediate code
-        if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->functionReturnsValue) {
+        if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->mFunctionReturnsValue) {
             context->error((yylsp[-2]), "function does not return a value:", "", (yyvsp[-2].interm).function->getName().c_str());
             context->recover();
         }