Move function parsing code to ParseContext

This change is pure refactoring. It will make it easier to fix bugs
related to function declarations.

BUG=angleproject:911
BUG=angleproject:1067
BUG=angleproject:1068
TEST=angle_unittests

Change-Id: I031783dc02612d9cf3ff7a9c8291cf8ab33577aa
Reviewed-on: https://chromium-review.googlesource.com/320081
Tryjob-Request: Olli Etuaho <oetuaho@nvidia.com>
Tested-by: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index 4a61281..a51d8a0 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -1925,6 +1925,62 @@
     }
 }
 
+TIntermAggregate *TParseContext::addFunctionPrototypeDeclaration(const TFunction &function,
+                                                                 const TSourceLoc &location)
+{
+    TIntermAggregate *prototype = new TIntermAggregate;
+    prototype->setType(function.getReturnType());
+    prototype->setName(function.getMangledName());
+    prototype->setFunctionId(function.getUniqueId());
+
+    for (size_t i = 0; i < function.getParamCount(); i++)
+    {
+        const TConstParameter &param = function.getParam(i);
+        if (param.name != 0)
+        {
+            TVariable variable(param.name, *param.type);
+
+            TIntermSymbol *paramSymbol = intermediate.addSymbol(
+                variable.getUniqueId(), variable.getName(), variable.getType(), location);
+            prototype = intermediate.growAggregate(prototype, paramSymbol, location);
+        }
+        else
+        {
+            TIntermSymbol *paramSymbol = intermediate.addSymbol(0, "", *param.type, location);
+            prototype                  = intermediate.growAggregate(prototype, paramSymbol, location);
+        }
+    }
+
+    prototype->setOp(EOpPrototype);
+
+    symbolTable.pop();
+    return prototype;
+}
+
+TIntermAggregate *TParseContext::addFunctionDefinition(const TFunction &function,
+                                                       TIntermAggregate *functionPrototype,
+                                                       TIntermAggregate *functionBody,
+                                                       const TSourceLoc &location)
+{
+    //?? Check that all paths return a value if return type != void ?
+    //   May be best done as post process phase on intermediate code
+    if (mCurrentFunctionType->getBasicType() != EbtVoid && !mFunctionReturnsValue)
+    {
+        error(location, "function does not return a value:", "", function.getName().c_str());
+        recover();
+    }
+
+    TIntermAggregate *aggregate =
+        intermediate.growAggregate(functionPrototype, functionBody, location);
+    intermediate.setAggregateOperator(aggregate, EOpFunction, location);
+    aggregate->setName(function.getMangledName().c_str());
+    aggregate->setType(function.getReturnType());
+    aggregate->setFunctionId(function.getUniqueId());
+
+    symbolTable.pop();
+    return aggregate;
+}
+
 void TParseContext::parseFunctionPrototype(const TSourceLoc &location,
                                            TFunction *function,
                                            TIntermAggregate **aggregateOut)
@@ -1978,8 +2034,8 @@
     //
     // Remember the return type for later checking for RETURN statements.
     //
-    setCurrentFunctionType(&(prevDec->getReturnType()));
-    setFunctionReturnsValue(false);
+    mCurrentFunctionType  = &(prevDec->getReturnType());
+    mFunctionReturnsValue = false;
 
     //
     // Insert parameters into the symbol table.