Refactor addFunctionCallOrMethod out of glslang.y

TEST=angle_unittests
BUG=angle:911

Change-Id: I6d4c0f0bfbf9e6252e241ae5bb1b6acdb463fce6
Reviewed-on: https://chromium-review.googlesource.com/255451
Tested-by: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index 74e5a07..6b90c00 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -2793,6 +2793,136 @@
     return intermediate.addBranch(op, returnValue, loc);
 }
 
+TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, TIntermNode *node,
+    const TSourceLoc &loc, bool *fatalError)
+{
+    *fatalError = false;
+    TOperator op = fnCall->getBuiltInOp();
+    TIntermTyped *callNode = nullptr;
+
+    if (op != EOpNull)
+    {
+        //
+        // Then this should be a constructor.
+        // Don't go through the symbol table for constructors.
+        // Their parameters will be verified algorithmically.
+        //
+        TType type(EbtVoid, EbpUndefined);  // use this to get the type back
+        if (!constructorErrorCheck(loc, node, *fnCall, op, &type))
+        {
+            //
+            // It's a constructor, of type 'type'.
+            //
+            callNode = addConstructor(node, &type, op, fnCall, loc);
+        }
+        else
+        {
+            recover();
+            callNode = intermediate.setAggregateOperator(nullptr, op, loc);
+        }
+        callNode->setType(type);
+    }
+    else
+    {
+        //
+        // Not a constructor.  Find it in the symbol table.
+        //
+        const TFunction* fnCandidate;
+        bool builtIn;
+        fnCandidate = findFunction(loc, fnCall, shaderVersion, &builtIn);
+        if (fnCandidate)
+        {
+            //
+            // A declared function.
+            //
+            if (builtIn && !fnCandidate->getExtension().empty() &&
+                extensionErrorCheck(loc, fnCandidate->getExtension()))
+            {
+                recover();
+            }
+            op = fnCandidate->getBuiltInOp();
+            if (builtIn && op != EOpNull)
+            {
+                //
+                // A function call mapped to a built-in operation.
+                //
+                if (fnCandidate->getParamCount() == 1)
+                {
+                    //
+                    // Treat it like a built-in unary operator.
+                    //
+                    callNode = intermediate.addUnaryMath(op, node, loc);
+                    if (callNode == nullptr)
+                    {
+                        std::stringstream extraInfoStream;
+                        extraInfoStream << "built in unary operator function.  Type: "
+                            << static_cast<TIntermTyped*>(node)->getCompleteString();
+                        std::string extraInfo = extraInfoStream.str();
+                        error(node->getLine(), " wrong operand type", "Internal Error", extraInfo.c_str());
+                        *fatalError = true;
+                        return nullptr;
+                    }
+                    const TType& returnType = fnCandidate->getReturnType();
+                    if (returnType.getBasicType() == EbtBool)
+                    {
+                        // Bool types should not have precision, so we'll override any precision
+                        // that might have been set by addUnaryMath.
+                        callNode->setType(returnType);
+                    }
+                    else
+                    {
+                        // addUnaryMath has set the precision of the node based on the operand.
+                        callNode->setTypePreservePrecision(returnType);
+                    }
+                }
+                else
+                {
+                    TIntermAggregate *aggregate = intermediate.setAggregateOperator(node, op, loc);
+                    aggregate->setType(fnCandidate->getReturnType());
+                    aggregate->setPrecisionFromChildren();
+                    callNode = aggregate;
+
+                    // Some built-in functions have out parameters too.
+                    functionCallLValueErrorCheck(fnCandidate, aggregate);
+                }
+            }
+            else
+            {
+                // This is a real function call
+
+                TIntermAggregate *aggregate = intermediate.setAggregateOperator(node, EOpFunctionCall, loc);
+                aggregate->setType(fnCandidate->getReturnType());
+
+                // this is how we know whether the given function is a builtIn function or a user defined function
+                // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also
+                // if builtIn == true, it's definitely a builtIn function with EOpNull
+                if (!builtIn)
+                    aggregate->setUserDefined();
+                aggregate->setName(fnCandidate->getMangledName());
+
+                // This needs to happen after the name is set
+                if (builtIn)
+                    aggregate->setBuiltInFunctionPrecision();
+
+                callNode = aggregate;
+
+                functionCallLValueErrorCheck(fnCandidate, aggregate);
+            }
+        }
+        else
+        {
+            // error message was put out by findFunction()
+            // Put on a dummy node for error recovery
+            ConstantUnion *unionArray = new ConstantUnion[1];
+            unionArray->setFConst(0.0f);
+            callNode = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), loc);
+            recover();
+        }
+    }
+    delete fnCall;
+    return callNode;
+}
+
 
 //
 // Parse an array of strings using yyparse.
diff --git a/src/compiler/translator/ParseContext.h b/src/compiler/translator/ParseContext.h
index ff0ba37..786f15d 100644
--- a/src/compiler/translator/ParseContext.h
+++ b/src/compiler/translator/ParseContext.h
@@ -179,6 +179,9 @@
 
     TIntermBranch *addBranch(TOperator op, const TSourceLoc &loc);
     TIntermBranch *addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc);
+
+    TIntermTyped *addFunctionCallOrMethod(TFunction *fnCall, TIntermNode *node,
+        const TSourceLoc &loc, bool *fatalError);
 };
 
 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 2b1ab6a..2e116f9 100644
--- a/src/compiler/translator/glslang.y
+++ b/src/compiler/translator/glslang.y
@@ -293,112 +293,12 @@
 
 function_call
     : function_call_or_method {
-        TFunction* fnCall = $1.function;
-        TOperator op = fnCall->getBuiltInOp();
-
-        if (op != EOpNull)
+        bool fatalError = false;
+        $$ = context->addFunctionCallOrMethod($1.function, $1.intermNode, @1, &fatalError);
+        if (fatalError)
         {
-            //
-            // Then this should be a constructor.
-            // Don't go through the symbol table for constructors.
-            // Their parameters will be verified algorithmically.
-            //
-            TType type(EbtVoid, EbpUndefined);  // use this to get the type back
-            if (context->constructorErrorCheck(@1, $1.intermNode, *fnCall, op, &type)) {
-                $$ = 0;
-            } else {
-                //
-                // It's a constructor, of type 'type'.
-                //
-                $$ = context->addConstructor($1.intermNode, &type, op, fnCall, @1);
-            }
-
-            if ($$ == 0) {
-                context->recover();
-                $$ = context->intermediate.setAggregateOperator(0, op, @1);
-            }
-            $$->setType(type);
-        } else {
-            //
-            // Not a constructor.  Find it in the symbol table.
-            //
-            const TFunction* fnCandidate;
-            bool builtIn;
-            fnCandidate = context->findFunction(@1, fnCall, context->shaderVersion, &builtIn);
-            if (fnCandidate) {
-                //
-                // A declared function.
-                //
-                if (builtIn && !fnCandidate->getExtension().empty() &&
-                    context->extensionErrorCheck(@1, fnCandidate->getExtension())) {
-                    context->recover();
-                }
-                op = fnCandidate->getBuiltInOp();
-                if (builtIn && op != EOpNull) {
-                    //
-                    // A function call mapped to a built-in operation.
-                    //
-                    if (fnCandidate->getParamCount() == 1) {
-                        //
-                        // Treat it like a built-in unary operator.
-                        //
-                        $$ = context->intermediate.addUnaryMath(op, $1.intermNode, @1);
-                        if ($$ == 0)  {
-                            std::stringstream extraInfoStream;
-                            extraInfoStream << "built in unary operator function.  Type: " << static_cast<TIntermTyped*>($1.intermNode)->getCompleteString();
-                            std::string extraInfo = extraInfoStream.str();
-                            context->error($1.intermNode->getLine(), " wrong operand type", "Internal Error", extraInfo.c_str());
-                            YYERROR;
-                        }
-                        const TType& returnType = fnCandidate->getReturnType();
-                        if (returnType.getBasicType() == EbtBool) {
-                            // Bool types should not have precision, so we'll override any precision
-                            // that might have been set by addUnaryMath.
-                            $$->setType(returnType);
-                        } else {
-                            // addUnaryMath has set the precision of the node based on the operand.
-                            $$->setTypePreservePrecision(returnType);
-                        }
-                    } else {
-                        TIntermAggregate *aggregate = context->intermediate.setAggregateOperator($1.intermAggregate, op, @1);
-                        aggregate->setType(fnCandidate->getReturnType());
-                        aggregate->setPrecisionFromChildren();
-                        $$ = aggregate;
-
-                        // Some built-in functions have out parameters too.
-                        context->functionCallLValueErrorCheck(fnCandidate, aggregate);
-                    }
-                } else {
-                    // This is a real function call
-
-                    TIntermAggregate *aggregate = context->intermediate.setAggregateOperator($1.intermAggregate, EOpFunctionCall, @1);
-                    aggregate->setType(fnCandidate->getReturnType());
-
-                    // this is how we know whether the given function is a builtIn function or a user defined function
-                    // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also
-                    // if builtIn == true, it's definitely a builtIn function with EOpNull
-                    if (!builtIn)
-                        aggregate->setUserDefined();
-                    aggregate->setName(fnCandidate->getMangledName());
-
-                    // This needs to happen after the name is set
-                    if (builtIn)
-                        aggregate->setBuiltInFunctionPrecision();
-
-                    $$ = aggregate;
-
-                    context->functionCallLValueErrorCheck(fnCandidate, aggregate);
-                }
-            } else {
-                // error message was put out by PaFindFunction()
-                // Put on a dummy node for error recovery
-                ConstantUnion *unionArray = new ConstantUnion[1];
-                unionArray->setFConst(0.0f);
-                $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), @1);
-                context->recover();
-            }
+            YYERROR;
         }
-        delete fnCall;
     }
     ;
 
diff --git a/src/compiler/translator/glslang_tab.cpp b/src/compiler/translator/glslang_tab.cpp
index 8b783f9..03a56ba 100644
--- a/src/compiler/translator/glslang_tab.cpp
+++ b/src/compiler/translator/glslang_tab.cpp
@@ -690,32 +690,32 @@
 static const yytype_uint16 yyrline[] =
 {
        0,   209,   209,   210,   213,   237,   240,   245,   250,   255,
-     260,   266,   269,   272,   275,   278,   281,   287,   295,   406,
-     409,   417,   420,   426,   430,   437,   443,   452,   460,   463,
-     473,   476,   479,   482,   492,   493,   494,   495,   503,   504,
-     507,   510,   517,   518,   521,   527,   528,   532,   539,   540,
-     543,   546,   549,   555,   556,   559,   565,   566,   573,   574,
-     581,   582,   589,   590,   596,   597,   603,   604,   610,   611,
-     628,   629,   642,   643,   644,   645,   649,   650,   651,   655,
-     659,   663,   667,   674,   677,   688,   696,   704,   731,   737,
-     748,   752,   756,   760,   767,   823,   826,   833,   841,   862,
-     883,   893,   921,   926,   936,   941,   951,   954,   957,   960,
-     966,   973,   976,   980,   984,   988,   995,   999,  1003,  1010,
-    1014,  1018,  1025,  1034,  1040,  1043,  1049,  1055,  1062,  1071,
-    1080,  1088,  1091,  1098,  1102,  1109,  1112,  1116,  1120,  1129,
-    1138,  1146,  1156,  1168,  1171,  1174,  1180,  1187,  1190,  1196,
-    1199,  1202,  1208,  1211,  1226,  1230,  1234,  1238,  1242,  1246,
-    1251,  1256,  1261,  1266,  1271,  1276,  1281,  1286,  1291,  1296,
-    1301,  1306,  1311,  1316,  1321,  1326,  1331,  1336,  1341,  1346,
-    1351,  1355,  1359,  1363,  1367,  1371,  1375,  1379,  1383,  1387,
-    1391,  1395,  1399,  1403,  1407,  1411,  1419,  1427,  1431,  1444,
-    1444,  1447,  1447,  1453,  1456,  1472,  1475,  1484,  1488,  1494,
-    1501,  1516,  1520,  1524,  1525,  1531,  1532,  1533,  1534,  1535,
-    1536,  1537,  1541,  1542,  1542,  1542,  1552,  1553,  1557,  1557,
-    1558,  1558,  1563,  1566,  1576,  1579,  1585,  1586,  1590,  1598,
-    1602,  1609,  1609,  1616,  1619,  1626,  1631,  1648,  1648,  1653,
-    1653,  1660,  1660,  1668,  1671,  1677,  1680,  1686,  1690,  1697,
-    1700,  1703,  1706,  1709,  1718,  1722,  1729,  1732,  1738,  1738
+     260,   266,   269,   272,   275,   278,   281,   287,   295,   306,
+     309,   317,   320,   326,   330,   337,   343,   352,   360,   363,
+     373,   376,   379,   382,   392,   393,   394,   395,   403,   404,
+     407,   410,   417,   418,   421,   427,   428,   432,   439,   440,
+     443,   446,   449,   455,   456,   459,   465,   466,   473,   474,
+     481,   482,   489,   490,   496,   497,   503,   504,   510,   511,
+     528,   529,   542,   543,   544,   545,   549,   550,   551,   555,
+     559,   563,   567,   574,   577,   588,   596,   604,   631,   637,
+     648,   652,   656,   660,   667,   723,   726,   733,   741,   762,
+     783,   793,   821,   826,   836,   841,   851,   854,   857,   860,
+     866,   873,   876,   880,   884,   888,   895,   899,   903,   910,
+     914,   918,   925,   934,   940,   943,   949,   955,   962,   971,
+     980,   988,   991,   998,  1002,  1009,  1012,  1016,  1020,  1029,
+    1038,  1046,  1056,  1068,  1071,  1074,  1080,  1087,  1090,  1096,
+    1099,  1102,  1108,  1111,  1126,  1130,  1134,  1138,  1142,  1146,
+    1151,  1156,  1161,  1166,  1171,  1176,  1181,  1186,  1191,  1196,
+    1201,  1206,  1211,  1216,  1221,  1226,  1231,  1236,  1241,  1246,
+    1251,  1255,  1259,  1263,  1267,  1271,  1275,  1279,  1283,  1287,
+    1291,  1295,  1299,  1303,  1307,  1311,  1319,  1327,  1331,  1344,
+    1344,  1347,  1347,  1353,  1356,  1372,  1375,  1384,  1388,  1394,
+    1401,  1416,  1420,  1424,  1425,  1431,  1432,  1433,  1434,  1435,
+    1436,  1437,  1441,  1442,  1442,  1442,  1452,  1453,  1457,  1457,
+    1458,  1458,  1463,  1466,  1476,  1479,  1485,  1486,  1490,  1498,
+    1502,  1509,  1509,  1516,  1519,  1526,  1531,  1548,  1548,  1553,
+    1553,  1560,  1560,  1568,  1571,  1577,  1580,  1586,  1590,  1597,
+    1600,  1603,  1606,  1609,  1618,  1622,  1629,  1632,  1638,  1638
 };
 #endif
 
@@ -2442,112 +2442,12 @@
   case 18:
 
     {
-        TFunction* fnCall = (yyvsp[0].interm).function;
-        TOperator op = fnCall->getBuiltInOp();
-
-        if (op != EOpNull)
+        bool fatalError = false;
+        (yyval.interm.intermTypedNode) = context->addFunctionCallOrMethod((yyvsp[0].interm).function, (yyvsp[0].interm).intermNode, (yylsp[0]), &fatalError);
+        if (fatalError)
         {
-            //
-            // Then this should be a constructor.
-            // Don't go through the symbol table for constructors.
-            // Their parameters will be verified algorithmically.
-            //
-            TType type(EbtVoid, EbpUndefined);  // use this to get the type back
-            if (context->constructorErrorCheck((yylsp[0]), (yyvsp[0].interm).intermNode, *fnCall, op, &type)) {
-                (yyval.interm.intermTypedNode) = 0;
-            } else {
-                //
-                // It's a constructor, of type 'type'.
-                //
-                (yyval.interm.intermTypedNode) = context->addConstructor((yyvsp[0].interm).intermNode, &type, op, fnCall, (yylsp[0]));
-            }
-
-            if ((yyval.interm.intermTypedNode) == 0) {
-                context->recover();
-                (yyval.interm.intermTypedNode) = context->intermediate.setAggregateOperator(0, op, (yylsp[0]));
-            }
-            (yyval.interm.intermTypedNode)->setType(type);
-        } else {
-            //
-            // Not a constructor.  Find it in the symbol table.
-            //
-            const TFunction* fnCandidate;
-            bool builtIn;
-            fnCandidate = context->findFunction((yylsp[0]), fnCall, context->shaderVersion, &builtIn);
-            if (fnCandidate) {
-                //
-                // A declared function.
-                //
-                if (builtIn && !fnCandidate->getExtension().empty() &&
-                    context->extensionErrorCheck((yylsp[0]), fnCandidate->getExtension())) {
-                    context->recover();
-                }
-                op = fnCandidate->getBuiltInOp();
-                if (builtIn && op != EOpNull) {
-                    //
-                    // A function call mapped to a built-in operation.
-                    //
-                    if (fnCandidate->getParamCount() == 1) {
-                        //
-                        // Treat it like a built-in unary operator.
-                        //
-                        (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(op, (yyvsp[0].interm).intermNode, (yylsp[0]));
-                        if ((yyval.interm.intermTypedNode) == 0)  {
-                            std::stringstream extraInfoStream;
-                            extraInfoStream << "built in unary operator function.  Type: " << static_cast<TIntermTyped*>((yyvsp[0].interm).intermNode)->getCompleteString();
-                            std::string extraInfo = extraInfoStream.str();
-                            context->error((yyvsp[0].interm).intermNode->getLine(), " wrong operand type", "Internal Error", extraInfo.c_str());
-                            YYERROR;
-                        }
-                        const TType& returnType = fnCandidate->getReturnType();
-                        if (returnType.getBasicType() == EbtBool) {
-                            // Bool types should not have precision, so we'll override any precision
-                            // that might have been set by addUnaryMath.
-                            (yyval.interm.intermTypedNode)->setType(returnType);
-                        } else {
-                            // addUnaryMath has set the precision of the node based on the operand.
-                            (yyval.interm.intermTypedNode)->setTypePreservePrecision(returnType);
-                        }
-                    } else {
-                        TIntermAggregate *aggregate = context->intermediate.setAggregateOperator((yyvsp[0].interm).intermAggregate, op, (yylsp[0]));
-                        aggregate->setType(fnCandidate->getReturnType());
-                        aggregate->setPrecisionFromChildren();
-                        (yyval.interm.intermTypedNode) = aggregate;
-
-                        // Some built-in functions have out parameters too.
-                        context->functionCallLValueErrorCheck(fnCandidate, aggregate);
-                    }
-                } else {
-                    // This is a real function call
-
-                    TIntermAggregate *aggregate = context->intermediate.setAggregateOperator((yyvsp[0].interm).intermAggregate, EOpFunctionCall, (yylsp[0]));
-                    aggregate->setType(fnCandidate->getReturnType());
-
-                    // this is how we know whether the given function is a builtIn function or a user defined function
-                    // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also
-                    // if builtIn == true, it's definitely a builtIn function with EOpNull
-                    if (!builtIn)
-                        aggregate->setUserDefined();
-                    aggregate->setName(fnCandidate->getMangledName());
-
-                    // This needs to happen after the name is set
-                    if (builtIn)
-                        aggregate->setBuiltInFunctionPrecision();
-
-                    (yyval.interm.intermTypedNode) = aggregate;
-
-                    context->functionCallLValueErrorCheck(fnCandidate, aggregate);
-                }
-            } else {
-                // error message was put out by PaFindFunction()
-                // Put on a dummy node for error recovery
-                ConstantUnion *unionArray = new ConstantUnion[1];
-                unionArray->setFConst(0.0f);
-                (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), (yylsp[0]));
-                context->recover();
-            }
+            YYERROR;
         }
-        delete fnCall;
     }
 
     break;