Move function prototypes and declarations out of the .y

This will make the code easier to edit and maintain.

BUG=none
TEST=angle_unittests,angle_end2end_tests

Change-Id: I955307d1209170fa99142103bc4d361c9eab1cc8
Reviewed-on: https://chromium-review.googlesource.com/286145
Tested-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 1d017ca..46701df 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -1813,6 +1813,166 @@
     }
 }
 
+void TParseContext::parseFunctionPrototype(const TSourceLoc &location,
+                                           TFunction *function,
+                                           TIntermAggregate **aggregateOut)
+{
+    const TSymbol *builtIn = symbolTable.findBuiltIn(function->getMangledName(), getShaderVersion());
+
+    if (builtIn)
+    {
+        error(location, "built-in functions cannot be redefined", function->getName().c_str());
+        recover();
+    }
+
+    TFunction* prevDec = static_cast<TFunction*>(symbolTable.find(function->getMangledName(), getShaderVersion()));
+    //
+    // Note:  'prevDec' could be 'function' if this is the first time we've seen function
+    // as it would have just been put in the symbol table.  Otherwise, we're looking up
+    // an earlier occurance.
+    //
+    if (prevDec->isDefined())
+    {
+        // Then this function already has a body.
+        error(location, "function already has a body", function->getName().c_str());
+        recover();
+    }
+    prevDec->setDefined();
+    //
+    // Overload the unique ID of the definition to be the same unique ID as the declaration.
+    // Eventually we will probably want to have only a single definition and just swap the
+    // arguments to be the definition's arguments.
+    //
+    function->setUniqueId(prevDec->getUniqueId());
+
+    // Raise error message if main function takes any parameters or return anything other than void
+    if (function->getName() == "main")
+    {
+        if (function->getParamCount() > 0)
+        {
+            error(location, "function cannot take any parameter(s)", function->getName().c_str());
+            recover();
+        }
+        if (function->getReturnType().getBasicType() != EbtVoid)
+        {
+            error(location, "", function->getReturnType().getBasicString(), "main function cannot return a value");
+            recover();
+        }
+    }
+
+    //
+    // Remember the return type for later checking for RETURN statements.
+    //
+    setCurrentFunctionType(&(prevDec->getReturnType()));
+    setFunctionReturnsValue(false);
+
+    //
+    // Insert parameters into the symbol table.
+    // If the parameter has no name, it's not an error, just don't insert it
+    // (could be used for unused args).
+    //
+    // Also, accumulate the list of parameters into the HIL, so lower level code
+    // knows where to find parameters.
+    //
+    TIntermAggregate *paramNodes = new TIntermAggregate;
+    for (size_t i = 0; i < function->getParamCount(); i++)
+    {
+        const TConstParameter &param = function->getParam(i);
+        if (param.name != 0)
+        {
+            TVariable *variable = new TVariable(param.name, *param.type);
+            //
+            // Insert the parameters with name in the symbol table.
+            //
+            if (!symbolTable.declare(variable)) {
+                error(location, "redefinition", variable->getName().c_str());
+                recover();
+                delete variable;
+            }
+
+            //
+            // Add the parameter to the HIL
+            //
+            TIntermSymbol *symbol = intermediate.addSymbol(variable->getUniqueId(),
+                                                           variable->getName(),
+                                                           variable->getType(), location);
+
+            paramNodes = intermediate.growAggregate(paramNodes, symbol, location);
+        }
+        else
+        {
+            paramNodes = intermediate.growAggregate(paramNodes, intermediate.addSymbol(0, "", *param.type, location), location);
+        }
+    }
+    intermediate.setAggregateOperator(paramNodes, EOpParameters, location);
+    *aggregateOut = paramNodes;
+    setLoopNestingLevel(0);
+}
+
+TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location,
+                                                  TFunction *function)
+{
+    //
+    // Multiple declarations of the same function are allowed.
+    //
+    // If this is a definition, the definition production code will check for redefinitions
+    // (we don't know at this point if it's a definition or not).
+    //
+    // Redeclarations are allowed.  But, return types and parameter qualifiers must match.
+    //
+    TFunction *prevDec = static_cast<TFunction*>(symbolTable.find(function->getMangledName(), getShaderVersion()));
+    if (prevDec)
+    {
+        if (prevDec->getReturnType() != function->getReturnType())
+        {
+            error(location,
+                  "overloaded functions must have the same return type",
+                  function->getReturnType().getBasicString());
+            recover();
+        }
+        for (size_t i = 0; i < prevDec->getParamCount(); ++i)
+        {
+            if (prevDec->getParam(i).type->getQualifier() != function->getParam(i).type->getQualifier())
+            {
+                error(location,
+                      "overloaded functions must have the same parameter qualifiers",
+                      function->getParam(i).type->getQualifierString());
+                recover();
+            }
+        }
+    }
+
+    //
+    // Check for previously declared variables using the same name.
+    //
+    TSymbol *prevSym = symbolTable.find(function->getName(), getShaderVersion());
+    if (prevSym)
+    {
+        if (!prevSym->isFunction())
+        {
+            error(location, "redefinition", function->getName().c_str(), "function");
+            recover();
+        }
+    }
+    else
+    {
+        // Insert the unmangled name to detect potential future redefinition as a variable.
+        TFunction *newFunction = new TFunction(NewPoolTString(function->getName().c_str()), &function->getReturnType());
+        symbolTable.getOuterLevel()->insertUnmangled(newFunction);
+    }
+
+    // We're at the inner scope level of the function's arguments and body statement.
+    // Add the function prototype to the surrounding scope instead.
+    symbolTable.getOuterLevel()->insert(function);
+
+    //
+    // If this is a redeclaration, it could also be a definition,
+    // in which case, we want to use the variable names from this one, and not the one that's
+    // being redeclared.  So, pass back up this declaration, not the one in the symbol table.
+    //
+    return function;
+}
+
 TFunction *TParseContext::addConstructorFunc(const TPublicType &publicTypeIn)
 {
     TPublicType publicType = publicTypeIn;