Remove most of the remaining logic from glslang.y

Move most of the logic in glslang.y to ParseContext. This will make it
easier to change the code in the future.

Only a few specific bits of logic are kept in glslang.y:

* Disabling a parsing rule when a given shading language version is
  being parsed. This makes it easier to check the grammar against the
  grammar in the GLSL ES specs.
* Scoping calls that need to be paired with another call. It's much
  easier to check these for correctness when the paired calls are next
  to each other.

BUG=angleproject:911
TEST=angle_unittests

Change-Id: I52f42a1fc0f28463ca4b237dc6e88345e5173064
Reviewed-on: https://chromium-review.googlesource.com/539640
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index 73994f6..975fade 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -67,6 +67,25 @@
     return "image";
 }
 
+bool CanSetDefaultPrecisionOnType(const TPublicType &type)
+{
+    if (!SupportsPrecision(type.getBasicType()))
+    {
+        return false;
+    }
+    if (type.getBasicType() == EbtUInt)
+    {
+        // ESSL 3.00.4 section 4.5.4
+        return false;
+    }
+    if (type.isAggregate())
+    {
+        // Not allowed to set for aggregate types
+        return false;
+    }
+    return true;
+}
+
 }  // namespace
 
 // This tracks each binding point's current default offset for inheritance of subsequent
@@ -1030,6 +1049,7 @@
     const TTypeQualifierBuilder &typeQualifierBuilder,
     TType *type)
 {
+    // The only parameter qualifiers a parameter can have are in, out, inout or const.
     TTypeQualifier typeQualifier = typeQualifierBuilder.getParameterTypeQualifier(mDiagnostics);
 
     if (typeQualifier.qualifier == EvqOut || typeQualifier.qualifier == EvqInOut)
@@ -1839,11 +1859,22 @@
     }
     if (cond == nullptr || typedCond)
     {
+        if (type == ELoopDoWhile)
+        {
+            checkIsScalarBool(line, typedCond);
+        }
+        // In the case of other loops, it was checked before that the condition is a scalar boolean.
+        ASSERT(mDiagnostics->numErrors() > 0 || typedCond == nullptr ||
+               (typedCond->getBasicType() == EbtBool && !typedCond->isArray() &&
+                !typedCond->isVector()));
+
         node = new TIntermLoop(type, init, typedCond, expr, TIntermediate::EnsureBlock(body));
         node->setLine(line);
         return node;
     }
 
+    ASSERT(type != ELoopDoWhile);
+
     TIntermDeclaration *declaration = cond->getAsDeclarationNode();
     ASSERT(declaration);
     TIntermBinary *declarator = declaration->getSequence()->front()->getAsBinaryNode();
@@ -1868,6 +1899,32 @@
     return block;
 }
 
+TIntermNode *TParseContext::addIfElse(TIntermTyped *cond,
+                                      TIntermNodePair code,
+                                      const TSourceLoc &loc)
+{
+    checkIsScalarBool(loc, cond);
+
+    // For compile time constant conditions, prune the code now.
+    if (cond->getAsConstantUnion())
+    {
+        if (cond->getAsConstantUnion()->getBConst(0) == true)
+        {
+            return TIntermediate::EnsureBlock(code.node1);
+        }
+        else
+        {
+            return TIntermediate::EnsureBlock(code.node2);
+        }
+    }
+
+    TIntermIfElse *node = new TIntermIfElse(cond, TIntermediate::EnsureBlock(code.node1),
+                                            TIntermediate::EnsureBlock(code.node2));
+    node->setLine(loc);
+
+    return node;
+}
+
 void TParseContext::addFullySpecifiedType(TPublicType *typeSpecifier)
 {
     checkPrecisionSpecified(typeSpecifier->getLine(), typeSpecifier->precision,
@@ -2514,6 +2571,25 @@
     mAtomicCounterBindingStates[layoutQualifier.binding].setDefaultOffset(layoutQualifier.offset);
 }
 
+void TParseContext::parseDefaultPrecisionQualifier(const TPrecision precision,
+                                                   const TPublicType &type,
+                                                   const TSourceLoc &loc)
+{
+    if ((precision == EbpHigh) && (getShaderType() == GL_FRAGMENT_SHADER) &&
+        !getFragmentPrecisionHigh())
+    {
+        error(loc, "precision is not supported in fragment shader", "highp");
+    }
+
+    if (!CanSetDefaultPrecisionOnType(type))
+    {
+        error(loc, "illegal type argument for default precision qualifier",
+              getBasicString(type.getBasicType()));
+        return;
+    }
+    symbolTable.setDefaultPrecision(type.getBasicType(), precision);
+}
+
 void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder)
 {
     TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics);
@@ -2919,8 +2995,20 @@
     return new TFunction(name, new TType(type));
 }
 
+TFunction *TParseContext::addNonConstructorFunc(const TString *name, const TSourceLoc &loc)
+{
+    checkIsNotReserved(loc, *name);
+    const TType *returnType = TCache::getType(EbtVoid, EbpUndefined);
+    return new TFunction(name, returnType);
+}
+
 TFunction *TParseContext::addConstructorFunc(const TPublicType &publicType)
 {
+    if (mShaderVersion < 300 && publicType.array)
+    {
+        error(publicType.getLine(), "array constructor supported in GLSL ES 3.00 and above only",
+              "[]");
+    }
     if (publicType.isStructSpecifier())
     {
         error(publicType.getLine(), "constructor can't be a structure definition",
@@ -2938,6 +3026,32 @@
     return new TFunction(nullptr, type, EOpConstruct);
 }
 
+TParameter TParseContext::parseParameterDeclarator(const TPublicType &publicType,
+                                                   const TString *name,
+                                                   const TSourceLoc &nameLoc)
+{
+    if (publicType.getBasicType() == EbtVoid)
+    {
+        error(nameLoc, "illegal use of type 'void'", name->c_str());
+    }
+    checkIsNotReserved(nameLoc, *name);
+    TType *type      = new TType(publicType);
+    TParameter param = {name, type};
+    return param;
+}
+
+TParameter TParseContext::parseParameterArrayDeclarator(const TString *identifier,
+                                                        const TSourceLoc &identifierLoc,
+                                                        TIntermTyped *arraySize,
+                                                        const TSourceLoc &arrayLoc,
+                                                        TPublicType *type)
+{
+    checkIsValidTypeForArray(arrayLoc, *type);
+    unsigned int size = checkIsValidArraySize(arrayLoc, arraySize);
+    type->setArraySize(size);
+    return parseParameterDeclarator(*type, identifier, identifierLoc);
+}
+
 // This function is used to test for the correctness of the parameters passed to various constructor
 // functions and also convert them to the right datatype if it is allowed and required.
 //
@@ -3695,6 +3809,77 @@
         mShaderVersion);
 }
 
+TStorageQualifierWrapper *TParseContext::parseGlobalStorageQualifier(TQualifier qualifier,
+                                                                     const TSourceLoc &loc)
+{
+    checkIsAtGlobalLevel(loc, getQualifierString(qualifier));
+    return new TStorageQualifierWrapper(qualifier, loc);
+}
+
+TStorageQualifierWrapper *TParseContext::parseVaryingQualifier(const TSourceLoc &loc)
+{
+    if (getShaderType() == GL_VERTEX_SHADER)
+    {
+        return parseGlobalStorageQualifier(EvqVaryingOut, loc);
+    }
+    return parseGlobalStorageQualifier(EvqVaryingIn, loc);
+}
+
+TStorageQualifierWrapper *TParseContext::parseInQualifier(const TSourceLoc &loc)
+{
+    if (declaringFunction())
+    {
+        return new TStorageQualifierWrapper(EvqIn, loc);
+    }
+    if (getShaderType() == GL_FRAGMENT_SHADER)
+    {
+        if (mShaderVersion < 300)
+        {
+            error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "in");
+        }
+        return new TStorageQualifierWrapper(EvqFragmentIn, loc);
+    }
+    if (getShaderType() == GL_VERTEX_SHADER)
+    {
+        if (mShaderVersion < 300 && !isMultiviewExtensionEnabled())
+        {
+            error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "in");
+        }
+        return new TStorageQualifierWrapper(EvqVertexIn, loc);
+    }
+    return new TStorageQualifierWrapper(EvqComputeIn, loc);
+}
+
+TStorageQualifierWrapper *TParseContext::parseOutQualifier(const TSourceLoc &loc)
+{
+    if (declaringFunction())
+    {
+        return new TStorageQualifierWrapper(EvqOut, loc);
+    }
+    if (mShaderVersion < 300)
+    {
+        error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "out");
+    }
+    if (getShaderType() != GL_VERTEX_SHADER && getShaderType() != GL_FRAGMENT_SHADER)
+    {
+        error(loc, "storage qualifier supported in vertex and fragment shaders only", "out");
+    }
+    if (getShaderType() == GL_VERTEX_SHADER)
+    {
+        return new TStorageQualifierWrapper(EvqVertexOut, loc);
+    }
+    return new TStorageQualifierWrapper(EvqFragmentOut, loc);
+}
+
+TStorageQualifierWrapper *TParseContext::parseInOutQualifier(const TSourceLoc &loc)
+{
+    if (!declaringFunction())
+    {
+        error(loc, "invalid qualifier: can be only used with function parameters", "inout");
+    }
+    return new TStorageQualifierWrapper(EvqInOut, loc);
+}
+
 TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier,
                                                      TLayoutQualifier rightQualifier,
                                                      const TSourceLoc &rightQualifierLocation)
@@ -3703,6 +3888,27 @@
                                     mDiagnostics);
 }
 
+TField *TParseContext::parseStructDeclarator(TString *identifier, const TSourceLoc &loc)
+{
+    checkIsNotReserved(loc, *identifier);
+    TType *type = new TType(EbtVoid, EbpUndefined);
+    return new TField(type, identifier, loc);
+}
+
+TField *TParseContext::parseStructArrayDeclarator(TString *identifier,
+                                                  const TSourceLoc &loc,
+                                                  TIntermTyped *arraySize,
+                                                  const TSourceLoc &arraySizeLoc)
+{
+    checkIsNotReserved(loc, *identifier);
+
+    TType *type       = new TType(EbtVoid, EbpUndefined);
+    unsigned int size = checkIsValidArraySize(arraySizeLoc, arraySize);
+    type->setArraySize(size);
+
+    return new TField(type, identifier, loc);
+}
+
 TFieldList *TParseContext::combineStructFieldLists(TFieldList *processedFields,
                                                    const TFieldList *newlyAddedFields,
                                                    const TSourceLoc &location)
@@ -3837,9 +4043,7 @@
     }
 
     TTypeSpecifierNonArray typeSpecifierNonArray;
-    typeSpecifierNonArray.initialize(EbtStruct, structLine);
-    typeSpecifierNonArray.userDef           = structureType;
-    typeSpecifierNonArray.isStructSpecifier = true;
+    typeSpecifierNonArray.initializeStruct(structureType, true, structLine);
     exitStructDeclaration();
 
     return typeSpecifierNonArray;
@@ -3979,6 +4183,7 @@
 
 TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc)
 {
+    ASSERT(op != EOpNull);
     TIntermTyped *node = createUnaryMath(op, child, loc);
     if (node == nullptr)
     {
@@ -4397,6 +4602,7 @@
                                        TIntermTyped *right,
                                        const TSourceLoc &loc)
 {
+    checkCanBeLValue(loc, "assign", left);
     TIntermTyped *node = createAssign(op, left, right, loc);
     if (node == nullptr)
     {
@@ -4447,28 +4653,39 @@
                 error(loc, "non-void function must return a value", "return");
             }
             break;
+        case EOpKill:
+            if (mShaderType != GL_FRAGMENT_SHADER)
+            {
+                error(loc, "discard supported in fragment shaders only", "discard");
+            }
+            break;
         default:
-            // No checks for discard
+            UNREACHABLE();
             break;
     }
-    return intermediate.addBranch(op, loc);
+    return addBranch(op, nullptr, loc);
 }
 
 TIntermBranch *TParseContext::addBranch(TOperator op,
-                                        TIntermTyped *returnValue,
+                                        TIntermTyped *expression,
                                         const TSourceLoc &loc)
 {
-    ASSERT(op == EOpReturn);
-    mFunctionReturnsValue = true;
-    if (mCurrentFunctionType->getBasicType() == EbtVoid)
+    if (expression != nullptr)
     {
-        error(loc, "void function cannot return a value", "return");
+        ASSERT(op == EOpReturn);
+        mFunctionReturnsValue = true;
+        if (mCurrentFunctionType->getBasicType() == EbtVoid)
+        {
+            error(loc, "void function cannot return a value", "return");
+        }
+        else if (*mCurrentFunctionType != expression->getType())
+        {
+            error(loc, "function return is not matching type:", "return");
+        }
     }
-    else if (*mCurrentFunctionType != returnValue->getType())
-    {
-        error(loc, "function return is not matching type:", "return");
-    }
-    return intermediate.addBranch(op, returnValue, loc);
+    TIntermBranch *node = new TIntermBranch(op, expression);
+    node->setLine(loc);
+    return node;
 }
 
 void TParseContext::checkTextureOffsetConst(TIntermAggregate *functionCall)