Edit

kc3-lang/angle/src/compiler/translator/ParseContext.h

Branch :

  • Show log

    Commit

  • Author : Kimmo Kinnunen
    Date : 2024-11-20 14:38:30
    Hash : 8409b41e
    Message : Report error on unsized interface block array GLSL of forms: uniform S{...} a[]; in R{...} b[]; out Q{...} c[]; Should produce error unless the shader is tesselation or geometry shader. Fix the errors for VS and FS. GS and TS likely need more work. Bug: angleproject:379996129 Change-Id: Ib31c9a81717a8cd1c984eb4ce2e993d563bb3c4f Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/6038333 Reviewed-by: Geoff Lang <geofflang@chromium.org> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Auto-Submit: Kimmo Kinnunen <kkinnunen@apple.com> Commit-Queue: Kimmo Kinnunen <kkinnunen@apple.com>

  • src/compiler/translator/ParseContext.h
  • //
    // Copyright 2002 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    #ifndef COMPILER_TRANSLATOR_PARSECONTEXT_H_
    #define COMPILER_TRANSLATOR_PARSECONTEXT_H_
    
    #include "compiler/preprocessor/Preprocessor.h"
    #include "compiler/translator/Compiler.h"
    #include "compiler/translator/Declarator.h"
    #include "compiler/translator/Diagnostics.h"
    #include "compiler/translator/DirectiveHandler.h"
    #include "compiler/translator/FunctionLookup.h"
    #include "compiler/translator/QualifierTypes.h"
    #include "compiler/translator/SymbolTable.h"
    
    namespace sh
    {
    
    struct TMatrixFields
    {
        bool wholeRow;
        bool wholeCol;
        int row;
        int col;
    };
    
    //
    // The following are extra variables needed during parsing, grouped together so
    // they can be passed to the parser without needing a global.
    //
    class TParseContext : angle::NonCopyable
    {
      public:
        TParseContext(TSymbolTable &symt,
                      TExtensionBehavior &ext,
                      sh::GLenum type,
                      ShShaderSpec spec,
                      const ShCompileOptions &options,
                      TDiagnostics *diagnostics,
                      const ShBuiltInResources &resources,
                      ShShaderOutput outputType);
        ~TParseContext();
    
        bool anyMultiviewExtensionAvailable();
        const angle::pp::Preprocessor &getPreprocessor() const { return mPreprocessor; }
        angle::pp::Preprocessor &getPreprocessor() { return mPreprocessor; }
        void *getScanner() const { return mScanner; }
        void setScanner(void *scanner) { mScanner = scanner; }
        int getShaderVersion() const { return mShaderVersion; }
        sh::GLenum getShaderType() const { return mShaderType; }
        ShShaderSpec getShaderSpec() const { return mShaderSpec; }
        int numErrors() const { return mDiagnostics->numErrors(); }
        void error(const TSourceLoc &loc, const char *reason, const char *token);
        void error(const TSourceLoc &loc, const char *reason, const ImmutableString &token);
        void warning(const TSourceLoc &loc, const char *reason, const char *token);
    
        // If isError is false, a warning will be reported instead.
        void outOfRangeError(bool isError,
                             const TSourceLoc &loc,
                             const char *reason,
                             const char *token);
    
        TIntermBlock *getTreeRoot() const { return mTreeRoot; }
        void setTreeRoot(TIntermBlock *treeRoot);
    
        bool getFragmentPrecisionHigh() const
        {
            return mFragmentPrecisionHighOnESSL1 || mShaderVersion >= 300;
        }
        void setFragmentPrecisionHighOnESSL1(bool fragmentPrecisionHigh)
        {
            mFragmentPrecisionHighOnESSL1 = fragmentPrecisionHigh;
        }
    
        bool usesDerivatives() const { return mUsesDerivatives; }
        bool isEarlyFragmentTestsSpecified() const { return mEarlyFragmentTestsSpecified; }
        bool hasDiscard() const { return mHasDiscard; }
        bool isSampleQualifierSpecified() const { return mSampleQualifierSpecified; }
    
        void setLoopNestingLevel(int loopNestintLevel) { mLoopNestingLevel = loopNestintLevel; }
    
        void incrLoopNestingLevel(const TSourceLoc &line)
        {
            ++mLoopNestingLevel;
            checkNestingLevel(line);
        }
        void decrLoopNestingLevel() { --mLoopNestingLevel; }
    
        void incrSwitchNestingLevel(const TSourceLoc &line)
        {
            ++mSwitchNestingLevel;
            checkNestingLevel(line);
        }
        void decrSwitchNestingLevel() { --mSwitchNestingLevel; }
    
        bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; }
        sh::WorkGroupSize getComputeShaderLocalSize() const;
    
        int getNumViews() const { return mNumViews; }
    
        const std::map<int, ShPixelLocalStorageFormat> &pixelLocalStorageFormats() const
        {
            return mPLSFormats;
        }
    
        void enterFunctionDeclaration() { mDeclaringFunction = true; }
    
        void exitFunctionDeclaration() { mDeclaringFunction = false; }
    
        bool declaringFunction() const { return mDeclaringFunction; }
    
        TIntermConstantUnion *addScalarLiteral(const TConstantUnion *constantUnion,
                                               const TSourceLoc &line);
    
        // This method is guaranteed to succeed, even if no variable with 'name' exists.
        const TVariable *getNamedVariable(const TSourceLoc &location,
                                          const ImmutableString &name,
                                          const TSymbol *symbol);
        TIntermTyped *parseVariableIdentifier(const TSourceLoc &location,
                                              const ImmutableString &name,
                                              const TSymbol *symbol);
    
        // Look at a '.' field selector string and change it into offsets for a vector.
        bool parseVectorFields(const TSourceLoc &line,
                               const ImmutableString &compString,
                               int vecSize,
                               TVector<int> *fieldOffsets);
    
        void assignError(const TSourceLoc &line, const char *op, const TType &left, const TType &right);
        void unaryOpError(const TSourceLoc &line, const char *op, const TType &operand);
        void binaryOpError(const TSourceLoc &line,
                           const char *op,
                           const TType &left,
                           const TType &right);
    
        // Check functions - the ones that return bool return false if an error was generated.
    
        void checkIsValidExpressionStatement(const TSourceLoc &line, TIntermTyped *expr);
        bool checkIsNotReserved(const TSourceLoc &line, const ImmutableString &identifier);
        void checkPrecisionSpecified(const TSourceLoc &line, TPrecision precision, TBasicType type);
        bool checkCanBeLValue(const TSourceLoc &line, const char *op, TIntermTyped *node);
        void checkIsConst(TIntermTyped *node);
        void checkIsScalarInteger(TIntermTyped *node, const char *token);
        bool checkIsAtGlobalLevel(const TSourceLoc &line, const char *token);
        bool checkConstructorArguments(const TSourceLoc &line,
                                       const TIntermSequence &arguments,
                                       const TType &type);
    
        // Returns a sanitized array size to use (the size is at least 1).
        unsigned int checkIsValidArraySize(const TSourceLoc &line, TIntermTyped *expr);
        bool checkIsValidArrayDimension(const TSourceLoc &line, TVector<unsigned int> *arraySizes);
        bool checkIsValidQualifierForArray(const TSourceLoc &line, const TPublicType &elementQualifier);
        bool checkArrayElementIsNotArray(const TSourceLoc &line, const TPublicType &elementType);
        bool checkArrayOfArraysInOut(const TSourceLoc &line,
                                     const TPublicType &elementType,
                                     const TType &arrayType);
        bool checkIsNonVoid(const TSourceLoc &line,
                            const ImmutableString &identifier,
                            const TBasicType &type);
        bool checkIsScalarBool(const TSourceLoc &line, const TIntermTyped *type);
        void checkIsScalarBool(const TSourceLoc &line, const TPublicType &pType);
        bool checkIsNotOpaqueType(const TSourceLoc &line,
                                  const TTypeSpecifierNonArray &pType,
                                  const char *reason);
        void checkDeclaratorLocationIsNotSpecified(const TSourceLoc &line, const TPublicType &pType);
        void checkLocationIsNotSpecified(const TSourceLoc &location,
                                         const TLayoutQualifier &layoutQualifier);
        void checkStd430IsForShaderStorageBlock(const TSourceLoc &location,
                                                const TLayoutBlockStorage &blockStorage,
                                                const TQualifier &qualifier);
    
        // Check if at least one of the specified extensions can be used, and generate error/warning as
        // appropriate according to the spec.
        // This function is only needed for a few different small constant sizes of extension array, and
        // we want to avoid unnecessary dynamic allocations. That's why checkCanUseOneOfExtensions is a
        // template function rather than one taking a vector.
        template <size_t size>
        bool checkCanUseOneOfExtensions(const TSourceLoc &line,
                                        const std::array<TExtension, size> &extensions);
        bool checkCanUseExtension(const TSourceLoc &line, TExtension extension);
    
        // Done for all declarations, whether empty or not.
        void declarationQualifierErrorCheck(const sh::TQualifier qualifier,
                                            const sh::TLayoutQualifier &layoutQualifier,
                                            const TSourceLoc &location);
        // Done for the first non-empty declarator in a declaration.
        void nonEmptyDeclarationErrorCheck(const TPublicType &publicType,
                                           const TSourceLoc &identifierLocation);
        // Done only for empty declarations.
        void emptyDeclarationErrorCheck(const TType &type, const TSourceLoc &location);
    
        void checkCanUseLayoutQualifier(const TSourceLoc &location);
        bool checkLayoutQualifierSupported(const TSourceLoc &location,
                                           const ImmutableString &layoutQualifierName,
                                           int versionRequired);
        bool checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location,
                                              const TLayoutQualifier &layoutQualifier);
        void functionCallRValueLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *fnCall);
        void checkInvariantVariableQualifier(bool invariant,
                                             const TQualifier qualifier,
                                             const TSourceLoc &invariantLocation);
        void checkInputOutputTypeIsValidES3(const TQualifier qualifier,
                                            const TPublicType &type,
                                            const TSourceLoc &qualifierLocation);
        void checkLocalVariableConstStorageQualifier(const TQualifierWrapperBase &qualifier);
        void checkTCSOutVarIndexIsValid(TIntermBinary *binaryExpression, const TSourceLoc &location);
    
        void checkAdvancedBlendEquationsNotSpecified(
            const TSourceLoc &location,
            const AdvancedBlendEquations &advancedBlendEquations,
            const TQualifier &qualifier);
    
        const TPragma &pragma() const { return mDirectiveHandler.pragma(); }
        const TExtensionBehavior &extensionBehavior() const
        {
            return mDirectiveHandler.extensionBehavior();
        }
    
        bool isExtensionEnabled(TExtension extension) const;
        void handleExtensionDirective(const TSourceLoc &loc, const char *extName, const char *behavior);
        void handlePragmaDirective(const TSourceLoc &loc,
                                   const char *name,
                                   const char *value,
                                   bool stdgl);
    
        // For built-ins that can be redeclared, adjusts the type qualifier so transformations can
        // identify them correctly.
        void adjustRedeclaredBuiltInType(const TSourceLoc &line,
                                         const ImmutableString &identifier,
                                         TType *type);
    
        // Returns true on success. *initNode may still be nullptr on success in case the initialization
        // is not needed in the AST.
        bool executeInitializer(const TSourceLoc &line,
                                const ImmutableString &identifier,
                                TType *type,
                                TIntermTyped *initializer,
                                TIntermBinary **initNode);
        TIntermNode *addConditionInitializer(const TPublicType &pType,
                                             const ImmutableString &identifier,
                                             TIntermTyped *initializer,
                                             const TSourceLoc &loc);
        TIntermNode *addLoop(TLoopType type,
                             TIntermNode *init,
                             TIntermNode *cond,
                             TIntermTyped *expr,
                             TIntermNode *body,
                             const TSourceLoc &loc);
    
        // For "if" test nodes. There are three children: a condition, a true path, and a false path.
        // The two paths are in TIntermNodePair code.
        TIntermNode *addIfElse(TIntermTyped *cond, TIntermNodePair code, const TSourceLoc &loc);
    
        void addFullySpecifiedType(TPublicType *typeSpecifier);
        TPublicType addFullySpecifiedType(const TTypeQualifierBuilder &typeQualifierBuilder,
                                          const TPublicType &typeSpecifier);
    
        TIntermDeclaration *parseSingleDeclaration(TPublicType &publicType,
                                                   const TSourceLoc &identifierOrTypeLocation,
                                                   const ImmutableString &identifier);
        TIntermDeclaration *parseSingleArrayDeclaration(TPublicType &elementType,
                                                        const TSourceLoc &identifierLocation,
                                                        const ImmutableString &identifier,
                                                        const TSourceLoc &indexLocation,
                                                        const TVector<unsigned int> &arraySizes);
        TIntermDeclaration *parseSingleInitDeclaration(const TPublicType &publicType,
                                                       const TSourceLoc &identifierLocation,
                                                       const ImmutableString &identifier,
                                                       const TSourceLoc &initLocation,
                                                       TIntermTyped *initializer);
    
        // Parse a declaration like "type a[n] = initializer"
        // Note that this does not apply to declarations like "type[n] a = initializer"
        TIntermDeclaration *parseSingleArrayInitDeclaration(TPublicType &elementType,
                                                            const TSourceLoc &identifierLocation,
                                                            const ImmutableString &identifier,
                                                            const TSourceLoc &indexLocation,
                                                            const TVector<unsigned int> &arraySizes,
                                                            const TSourceLoc &initLocation,
                                                            TIntermTyped *initializer);
    
        TIntermGlobalQualifierDeclaration *parseGlobalQualifierDeclaration(
            const TTypeQualifierBuilder &typeQualifierBuilder,
            const TSourceLoc &identifierLoc,
            const ImmutableString &identifier,
            const TSymbol *symbol);
    
        void parseDeclarator(TPublicType &publicType,
                             const TSourceLoc &identifierLocation,
                             const ImmutableString &identifier,
                             TIntermDeclaration *declarationOut);
        void parseArrayDeclarator(TPublicType &elementType,
                                  const TSourceLoc &identifierLocation,
                                  const ImmutableString &identifier,
                                  const TSourceLoc &arrayLocation,
                                  const TVector<unsigned int> &arraySizes,
                                  TIntermDeclaration *declarationOut);
        void parseInitDeclarator(const TPublicType &publicType,
                                 const TSourceLoc &identifierLocation,
                                 const ImmutableString &identifier,
                                 const TSourceLoc &initLocation,
                                 TIntermTyped *initializer,
                                 TIntermDeclaration *declarationOut);
    
        // Parse a declarator like "a[n] = initializer"
        void parseArrayInitDeclarator(const TPublicType &elementType,
                                      const TSourceLoc &identifierLocation,
                                      const ImmutableString &identifier,
                                      const TSourceLoc &indexLocation,
                                      const TVector<unsigned int> &arraySizes,
                                      const TSourceLoc &initLocation,
                                      TIntermTyped *initializer,
                                      TIntermDeclaration *declarationOut);
    
        TIntermNode *addEmptyStatement(const TSourceLoc &location);
    
        void parseDefaultPrecisionQualifier(const TPrecision precision,
                                            const TPublicType &type,
                                            const TSourceLoc &loc);
        void parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder);
    
        TIntermFunctionPrototype *addFunctionPrototypeDeclaration(const TFunction &parsedFunction,
                                                                  const TSourceLoc &location);
        TIntermFunctionDefinition *addFunctionDefinition(TIntermFunctionPrototype *functionPrototype,
                                                         TIntermBlock *functionBody,
                                                         const TSourceLoc &location);
        void parseFunctionDefinitionHeader(const TSourceLoc &location,
                                           const TFunction *function,
                                           TIntermFunctionPrototype **prototypeOut);
        TFunction *parseFunctionDeclarator(const TSourceLoc &location, TFunction *function);
        TFunction *parseFunctionHeader(const TPublicType &type,
                                       const ImmutableString &name,
                                       const TSourceLoc &location);
    
        TFunctionLookup *addNonConstructorFunc(const ImmutableString &name, const TSymbol *symbol);
        TFunctionLookup *addConstructorFunc(const TPublicType &publicType);
    
        TParameter parseParameterDeclarator(const TPublicType &type,
                                            const ImmutableString &name,
                                            const TSourceLoc &nameLoc);
        TParameter parseParameterArrayDeclarator(const TPublicType &elementType,
                                                 const ImmutableString &name,
                                                 const TSourceLoc &nameLoc,
                                                 TVector<unsigned int> *arraySizes,
                                                 const TSourceLoc &arrayLoc);
        void parseParameterQualifier(const TSourceLoc &line,
                                     const TTypeQualifierBuilder &typeQualifierBuilder,
                                     TPublicType &type);
    
        TIntermTyped *addIndexExpression(TIntermTyped *baseExpression,
                                         const TSourceLoc &location,
                                         TIntermTyped *indexExpression);
        TIntermTyped *addFieldSelectionExpression(TIntermTyped *baseExpression,
                                                  const TSourceLoc &dotLocation,
                                                  const ImmutableString &fieldString,
                                                  const TSourceLoc &fieldLocation);
    
        // Parse declarator for a single field
        TDeclarator *parseStructDeclarator(const ImmutableString &identifier, const TSourceLoc &loc);
        TDeclarator *parseStructArrayDeclarator(const ImmutableString &identifier,
                                                const TSourceLoc &loc,
                                                const TVector<unsigned int> *arraySizes);
    
        void checkDoesNotHaveDuplicateFieldNames(const TFieldList *fields, const TSourceLoc &location);
        void checkDoesNotHaveTooManyFields(const ImmutableString &name,
                                           const TFieldList *fields,
                                           const TSourceLoc &location);
        TFieldList *addStructFieldList(TFieldList *fields, const TSourceLoc &location);
        TFieldList *combineStructFieldLists(TFieldList *processedFields,
                                            const TFieldList *newlyAddedFields,
                                            const TSourceLoc &location);
        TFieldList *addStructDeclaratorListWithQualifiers(
            const TTypeQualifierBuilder &typeQualifierBuilder,
            TPublicType *typeSpecifier,
            const TDeclaratorList *declaratorList);
        TFieldList *addStructDeclaratorList(const TPublicType &typeSpecifier,
                                            const TDeclaratorList *declaratorList);
        TTypeSpecifierNonArray addStructure(const TSourceLoc &structLine,
                                            const TSourceLoc &nameLine,
                                            const ImmutableString &structName,
                                            TFieldList *fieldList);
    
        TIntermDeclaration *addInterfaceBlock(const TTypeQualifierBuilder &typeQualifierBuilder,
                                              const TSourceLoc &nameLine,
                                              const ImmutableString &blockName,
                                              TFieldList *fieldList,
                                              const ImmutableString &instanceName,
                                              const TSourceLoc &instanceLine,
                                              const TVector<unsigned int> *arraySizes,
                                              const TSourceLoc &arraySizesLine);
    
        void parseLocalSize(const ImmutableString &qualifierType,
                            const TSourceLoc &qualifierTypeLine,
                            int intValue,
                            const TSourceLoc &intValueLine,
                            const std::string &intValueString,
                            size_t index,
                            sh::WorkGroupSize *localSize);
        void parseNumViews(int intValue,
                           const TSourceLoc &intValueLine,
                           const std::string &intValueString,
                           int *numViews);
        void parseInvocations(int intValue,
                              const TSourceLoc &intValueLine,
                              const std::string &intValueString,
                              int *numInvocations);
        void parseMaxVertices(int intValue,
                              const TSourceLoc &intValueLine,
                              const std::string &intValueString,
                              int *numMaxVertices);
        void parseVertices(int intValue,
                           const TSourceLoc &intValueLine,
                           const std::string &intValueString,
                           int *numVertices);
        void parseIndexLayoutQualifier(int intValue,
                                       const TSourceLoc &intValueLine,
                                       const std::string &intValueString,
                                       int *index);
        TLayoutQualifier parseLayoutQualifier(const ImmutableString &qualifierType,
                                              const TSourceLoc &qualifierTypeLine);
        TLayoutQualifier parseLayoutQualifier(const ImmutableString &qualifierType,
                                              const TSourceLoc &qualifierTypeLine,
                                              int intValue,
                                              const TSourceLoc &intValueLine);
        TTypeQualifierBuilder *createTypeQualifierBuilder(const TSourceLoc &loc);
        TStorageQualifierWrapper *parseGlobalStorageQualifier(TQualifier qualifier,
                                                              const TSourceLoc &loc);
        TStorageQualifierWrapper *parseVaryingQualifier(const TSourceLoc &loc);
        TStorageQualifierWrapper *parseInQualifier(const TSourceLoc &loc);
        TStorageQualifierWrapper *parseOutQualifier(const TSourceLoc &loc);
        TStorageQualifierWrapper *parseInOutQualifier(const TSourceLoc &loc);
        TLayoutQualifier joinLayoutQualifiers(TLayoutQualifier leftQualifier,
                                              TLayoutQualifier rightQualifier,
                                              const TSourceLoc &rightQualifierLocation);
    
        // Performs an error check for embedded struct declarations.
        void enterStructDeclaration(const TSourceLoc &line, const ImmutableString &identifier);
        void exitStructDeclaration();
    
        void checkIsBelowStructNestingLimit(const TSourceLoc &line, const TField &field);
    
        TIntermSwitch *addSwitch(TIntermTyped *init,
                                 TIntermBlock *statementList,
                                 const TSourceLoc &loc);
        TIntermCase *addCase(TIntermTyped *condition, const TSourceLoc &loc);
        TIntermCase *addDefault(const TSourceLoc &loc);
    
        TIntermTyped *addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc);
        TIntermTyped *addUnaryMathLValue(TOperator op, TIntermTyped *child, const TSourceLoc &loc);
        TIntermTyped *addBinaryMath(TOperator op,
                                    TIntermTyped *left,
                                    TIntermTyped *right,
                                    const TSourceLoc &loc);
        TIntermTyped *addBinaryMathBooleanResult(TOperator op,
                                                 TIntermTyped *left,
                                                 TIntermTyped *right,
                                                 const TSourceLoc &loc);
        TIntermTyped *addAssign(TOperator op,
                                TIntermTyped *left,
                                TIntermTyped *right,
                                const TSourceLoc &loc);
    
        TIntermTyped *addComma(TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
    
        TIntermBranch *addBranch(TOperator op, const TSourceLoc &loc);
        TIntermBranch *addBranch(TOperator op, TIntermTyped *expression, const TSourceLoc &loc);
    
        void appendStatement(TIntermBlock *block, TIntermNode *statement);
    
        void checkTextureGather(TIntermAggregate *functionCall);
        void checkTextureOffset(TIntermAggregate *functionCall);
        void checkImageMemoryAccessForBuiltinFunctions(TIntermAggregate *functionCall);
        void checkImageMemoryAccessForUserDefinedFunctions(const TFunction *functionDefinition,
                                                           const TIntermAggregate *functionCall);
        void checkAtomicMemoryBuiltinFunctions(TIntermAggregate *functionCall);
        void checkInterpolationFS(TIntermAggregate *functionCall);
    
        // fnCall is only storing the built-in op, and function name or constructor type. arguments
        // has the arguments.
        TIntermTyped *addFunctionCallOrMethod(TFunctionLookup *fnCall, const TSourceLoc &loc);
    
        TIntermTyped *addTernarySelection(TIntermTyped *cond,
                                          TIntermTyped *trueExpression,
                                          TIntermTyped *falseExpression,
                                          const TSourceLoc &line);
    
        int getGeometryShaderMaxVertices() const { return mGeometryShaderMaxVertices; }
        int getGeometryShaderInvocations() const
        {
            return (mGeometryShaderInvocations > 0) ? mGeometryShaderInvocations : 1;
        }
        TLayoutPrimitiveType getGeometryShaderInputPrimitiveType() const
        {
            return mGeometryShaderInputPrimitiveType;
        }
        TLayoutPrimitiveType getGeometryShaderOutputPrimitiveType() const
        {
            return mGeometryShaderOutputPrimitiveType;
        }
        int getTessControlShaderOutputVertices() const { return mTessControlShaderOutputVertices; }
        TLayoutTessEvaluationType getTessEvaluationShaderInputPrimitiveType() const
        {
            return mTessEvaluationShaderInputPrimitiveType;
        }
        TLayoutTessEvaluationType getTessEvaluationShaderInputVertexSpacingType() const
        {
            return mTessEvaluationShaderInputVertexSpacingType;
        }
        TLayoutTessEvaluationType getTessEvaluationShaderInputOrderingType() const
        {
            return mTessEvaluationShaderInputOrderingType;
        }
        TLayoutTessEvaluationType getTessEvaluationShaderInputPointType() const
        {
            return mTessEvaluationShaderInputPointType;
        }
    
        const TVector<TType *> &getDeferredArrayTypesToSize() const
        {
            return mDeferredArrayTypesToSize;
        }
    
        void markShaderHasPrecise() { mHasAnyPreciseType = true; }
        bool hasAnyPreciseType() const { return mHasAnyPreciseType; }
        AdvancedBlendEquations getAdvancedBlendEquations() const { return mAdvancedBlendEquations; }
    
        ShShaderOutput getOutputType() const { return mOutputType; }
    
        size_t getMaxExpressionComplexity() const { return mMaxExpressionComplexity; }
        size_t getMaxStatementDepth() const { return mMaxStatementDepth; }
    
        // TODO(jmadill): make this private
        TSymbolTable &symbolTable;  // symbol table that goes with the language currently being parsed
    
      private:
        class AtomicCounterBindingState;
        constexpr static size_t kAtomicCounterSize = 4;
        // UNIFORM_ARRAY_STRIDE for atomic counter arrays is an implementation-dependent value which
        // can be queried after a program is linked according to ES 3.10 section 7.7.1. This is
        // controversial with the offset inheritance as described in ESSL 3.10 section 4.4.6. Currently
        // we treat it as always 4 in favour of the original interpretation in
        // "ARB_shader_atomic_counters".
        // TODO(jie.a.chen@intel.com): Double check this once the spec vagueness is resolved.
        // Note that there may be tests in AtomicCounter_test that will need to be updated as well.
        constexpr static size_t kAtomicCounterArrayStride = 4;
    
        void markStaticReadIfSymbol(TIntermNode *node);
    
        // Returns a clamped index. If it prints out an error message, the token is "[]".
        int checkIndexLessThan(bool outOfRangeIndexIsError,
                               const TSourceLoc &location,
                               int index,
                               unsigned int arraySize,
                               const char *reason);
    
        bool declareVariable(const TSourceLoc &line,
                             const ImmutableString &identifier,
                             const TType *type,
                             TVariable **variable);
    
        void checkNestingLevel(const TSourceLoc &line);
    
        void checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line,
                                                  const ImmutableString &identifier,
                                                  TType *type);
        void checkDeclarationIsValidArraySize(const TSourceLoc &line,
                                              const ImmutableString &identifier,
                                              TType *type);
        bool checkIsValidTypeAndQualifierForArray(const TSourceLoc &indexLocation,
                                                  const TPublicType &elementType);
        // Done for all atomic counter declarations, whether empty or not.
        void atomicCounterQualifierErrorCheck(const TPublicType &publicType,
                                              const TSourceLoc &location);
    
        // Assumes that multiplication op has already been set based on the types.
        bool isMultiplicationTypeCombinationValid(TOperator op, const TType &left, const TType &right);
    
        void checkInternalFormatIsNotSpecified(const TSourceLoc &location,
                                               TLayoutImageInternalFormat internalFormat);
        void checkMemoryQualifierIsNotSpecified(const TMemoryQualifier &memoryQualifier,
                                                const TSourceLoc &location);
    
        void checkAtomicCounterOffsetIsValid(bool forceAppend, const TSourceLoc &loc, TType *type);
        void checkAtomicCounterOffsetDoesNotOverlap(bool forceAppend,
                                                    const TSourceLoc &loc,
                                                    TType *type);
        void checkAtomicCounterOffsetAlignment(const TSourceLoc &location, const TType &type);
        void checkAtomicCounterOffsetLimit(const TSourceLoc &location, const TType &type);
    
        void checkIndexIsNotSpecified(const TSourceLoc &location, int index);
        void checkBindingIsValid(const TSourceLoc &identifierLocation, const TType &type);
        void checkBindingIsNotSpecified(const TSourceLoc &location, int binding);
        void checkOffsetIsNotSpecified(const TSourceLoc &location, int offset);
        void checkImageBindingIsValid(const TSourceLoc &location,
                                      int binding,
                                      int arrayTotalElementCount);
        void checkSamplerBindingIsValid(const TSourceLoc &location,
                                        int binding,
                                        int arrayTotalElementCount);
        void checkBlockBindingIsValid(const TSourceLoc &location,
                                      const TQualifier &qualifier,
                                      int binding,
                                      int arraySize);
        void checkAtomicCounterBindingIsValid(const TSourceLoc &location, int binding);
        void checkPixelLocalStorageBindingIsValid(const TSourceLoc &, const TType &);
    
        void checkUniformLocationInRange(const TSourceLoc &location,
                                         int objectLocationCount,
                                         const TLayoutQualifier &layoutQualifier);
        void checkAttributeLocationInRange(const TSourceLoc &location,
                                           int objectLocationCount,
                                           const TLayoutQualifier &layoutQualifier);
    
        void checkDepthIsNotSpecified(const TSourceLoc &location, TLayoutDepth depth);
    
        void checkYuvIsNotSpecified(const TSourceLoc &location, bool yuv);
    
        void checkEarlyFragmentTestsIsNotSpecified(const TSourceLoc &location, bool earlyFragmentTests);
    
        void checkNoncoherentIsSpecified(const TSourceLoc &location, bool noncoherent);
    
        void checkNoncoherentIsNotSpecified(const TSourceLoc &location, bool noncoherent);
    
        bool checkUnsizedArrayConstructorArgumentDimensionality(const TIntermSequence &arguments,
                                                                TType type,
                                                                const TSourceLoc &line);
    
        // Check texture offset is within range.
        void checkSingleTextureOffset(const TSourceLoc &line,
                                      const TConstantUnion *values,
                                      size_t size,
                                      int minOffsetValue,
                                      int maxOffsetValue);
    
        // Will set the size of the outermost array according to geometry shader input layout.
        void checkGeometryShaderInputAndSetArraySize(const TSourceLoc &location,
                                                     const ImmutableString &token,
                                                     TType *type);
    
        // Similar, for tessellation shaders.
        void checkTessellationShaderUnsizedArraysAndSetSize(const TSourceLoc &location,
                                                            const ImmutableString &token,
                                                            TType *type);
    
        // Will size any unsized array type so unsized arrays won't need to be taken into account
        // further along the line in parsing.
        void checkIsNotUnsizedArray(const TSourceLoc &line,
                                    const char *errorMessage,
                                    const ImmutableString &token,
                                    TType *arrayType);
    
        TIntermTyped *addBinaryMathInternal(TOperator op,
                                            TIntermTyped *left,
                                            TIntermTyped *right,
                                            const TSourceLoc &loc);
        TIntermTyped *createUnaryMath(TOperator op,
                                      TIntermTyped *child,
                                      const TSourceLoc &loc,
                                      const TFunction *func);
    
        TIntermTyped *addMethod(TFunctionLookup *fnCall, const TSourceLoc &loc);
        TIntermTyped *addConstructor(TFunctionLookup *fnCall, const TSourceLoc &line);
        TIntermTyped *addNonConstructorFunctionCallImpl(TFunctionLookup *fnCall, const TSourceLoc &loc);
        TIntermTyped *addNonConstructorFunctionCall(TFunctionLookup *fnCall, const TSourceLoc &loc);
    
        // Return either the original expression or the folded version of the expression in case the
        // folded node will validate the same way during subsequent parsing.
        TIntermTyped *expressionOrFoldedResult(TIntermTyped *expression);
    
        // Return true if the checks pass
        bool binaryOpCommonCheck(TOperator op,
                                 TIntermTyped *left,
                                 TIntermTyped *right,
                                 const TSourceLoc &loc);
    
        TIntermFunctionPrototype *createPrototypeNodeFromFunction(const TFunction &function,
                                                                  const TSourceLoc &location,
                                                                  bool insertParametersToSymbolTable);
    
        void setAtomicCounterBindingDefaultOffset(const TPublicType &declaration,
                                                  const TSourceLoc &location);
    
        bool checkPrimitiveTypeMatchesTypeQualifier(const TTypeQualifier &typeQualifier);
        bool parseGeometryShaderInputLayoutQualifier(const TTypeQualifier &typeQualifier);
        bool parseGeometryShaderOutputLayoutQualifier(const TTypeQualifier &typeQualifier);
        void setGeometryShaderInputArraySize(unsigned int inputArraySize, const TSourceLoc &line);
    
        bool parseTessControlShaderOutputLayoutQualifier(const TTypeQualifier &typeQualifier);
        bool parseTessEvaluationShaderInputLayoutQualifier(const TTypeQualifier &typeQualifier);
    
        // Certain operations become illegal only iff the shader declares pixel local storage uniforms.
        enum class PLSIllegalOperations
        {
            // When polyfilled with shader images, pixel local storage requires early_fragment_tests,
            // which causes discard to interact differently with the depth and stencil tests.
            //
            // To ensure identical behavior across all backends (some of which may not have access to
            // early_fragment_tests), we disallow discard if pixel local storage uniforms have been
            // declared.
            Discard,
    
            // ARB_fragment_shader_interlock functions cannot be called within flow control, which
            // includes any code that might execute after a return statement. To keep things simple, and
            // since these "interlock" calls are automatically injected by the compiler inside of
            // main(), we disallow return from main() if pixel local storage uniforms have been
            // declared.
            ReturnFromMain,
    
            // When polyfilled with shader images, pixel local storage requires early_fragment_tests,
            // which causes assignments to gl_FragDepth(EXT) and gl_SampleMask to be ignored.
            //
            // To ensure identical behavior across all backends, we disallow assignment to these values
            // if pixel local storage uniforms have been declared.
            AssignFragDepth,
            AssignSampleMask,
    
            // EXT_blend_func_extended may restrict the number of draw buffers with a nonzero output
            // index, which can invalidate a PLS implementation.
            FragDataIndexNonzero,
    
            // KHR_blend_equation_advanced is incompatible with multiple draw buffers, which is a
            // required feature for many PLS implementations.
            EnableAdvancedBlendEquation,
        };
    
        // Generates an error if any pixel local storage uniforms have been declared (more specifically,
        // if mPLSFormats is not empty).
        //
        // If no pixel local storage uniforms have been declared, and if the PLS extension is enabled,
        // saves the potential error to mPLSPotentialErrors in case we encounter a PLS uniform later.
        void errorIfPLSDeclared(const TSourceLoc &, PLSIllegalOperations);
    
        // Set to true when the last/current declarator list was started with an empty declaration. The
        // non-empty declaration error check will need to be performed if the empty declaration is
        // followed by a declarator.
        bool mDeferredNonEmptyDeclarationErrorCheck;
    
        sh::GLenum mShaderType;    // vertex/fragment/geometry/etc shader
        ShShaderSpec mShaderSpec;  // The language specification compiler conforms to - GLES/WebGL/etc.
        ShCompileOptions mCompileOptions;  // Options passed to TCompiler
        int mShaderVersion;
        TIntermBlock *mTreeRoot;  // root of parse tree being created
        int mLoopNestingLevel;    // 0 if outside all loops
        int mStructNestingLevel;  // incremented while parsing a struct declaration
        int mSwitchNestingLevel;  // 0 if outside all switch statements
        const TType
            *mCurrentFunctionType;    // the return type of the function that's currently being parsed
        bool mFunctionReturnsValue;   // true if a non-void function has a return
        bool mFragmentPrecisionHighOnESSL1;  // true if highp precision is supported when compiling
                                             // ESSL1.
        bool mEarlyFragmentTestsSpecified;   // true if layout(early_fragment_tests) in; is specified.
        bool mHasDiscard;                    // true if |discard| is encountered in the shader.
        bool mSampleQualifierSpecified;      // true if the |sample| qualifier is used
        bool mPositionRedeclaredForSeparateShaderObject;       // true if EXT_separate_shader_objects is
                                                               // enabled and gl_Position is redefined.
        bool mPointSizeRedeclaredForSeparateShaderObject;      // true if EXT_separate_shader_objects is
                                                               // enabled and gl_PointSize is redefined.
        bool mPositionOrPointSizeUsedForSeparateShaderObject;  // true if gl_Position or gl_PointSize
                                                               // has been referenced.
        bool mUsesDerivatives;  // true if screen-space derivatives are used implicitly or explicitly
        TLayoutMatrixPacking mDefaultUniformMatrixPacking;
        TLayoutBlockStorage mDefaultUniformBlockStorage;
        TLayoutMatrixPacking mDefaultBufferMatrixPacking;
        TLayoutBlockStorage mDefaultBufferBlockStorage;
        TString mHashErrMsg;
        TDiagnostics *mDiagnostics;
        TDirectiveHandler mDirectiveHandler;
        angle::pp::Preprocessor mPreprocessor;
        void *mScanner;
        const size_t mMaxExpressionComplexity;
        const size_t mMaxStatementDepth;
        int mMinProgramTexelOffset;
        int mMaxProgramTexelOffset;
    
        int mMinProgramTextureGatherOffset;
        int mMaxProgramTextureGatherOffset;
    
        // keep track of local group size declared in layout. It should be declared only once.
        bool mComputeShaderLocalSizeDeclared;
        sh::WorkGroupSize mComputeShaderLocalSize;
        // keep track of number of views declared in layout.
        int mNumViews;
        int mMaxNumViews;
        int mMaxImageUnits;
        int mMaxCombinedTextureImageUnits;
        int mMaxUniformLocations;
        int mMaxUniformBufferBindings;
        int mMaxVertexAttribs;
        int mMaxAtomicCounterBindings;
        int mMaxAtomicCounterBufferSize;
        int mMaxShaderStorageBufferBindings;
        int mMaxPixelLocalStoragePlanes;
    
        // keeps track whether we are declaring / defining a function
        bool mDeclaringFunction;
    
        // keeps track whether we are declaring / defining the function main().
        bool mDeclaringMain;
    
        // Track the state of each atomic counter binding.
        std::map<int, AtomicCounterBindingState> mAtomicCounterBindingStates;
    
        // Track the format of each pixel local storage binding.
        std::map<int, ShPixelLocalStorageFormat> mPLSFormats;
    
        // Potential errors to generate immediately upon encountering a pixel local storage uniform.
        std::vector<std::tuple<const TSourceLoc, PLSIllegalOperations>> mPLSPotentialErrors;
    
        // Track the geometry shader global parameters declared in layout.
        TLayoutPrimitiveType mGeometryShaderInputPrimitiveType;
        TLayoutPrimitiveType mGeometryShaderOutputPrimitiveType;
        int mGeometryShaderInvocations;
        int mGeometryShaderMaxVertices;
        int mMaxGeometryShaderInvocations;
        int mMaxGeometryShaderMaxVertices;
        unsigned int mGeometryInputArraySize;
    
        int mMaxPatchVertices;
        int mTessControlShaderOutputVertices;
        TLayoutTessEvaluationType mTessEvaluationShaderInputPrimitiveType;
        TLayoutTessEvaluationType mTessEvaluationShaderInputVertexSpacingType;
        TLayoutTessEvaluationType mTessEvaluationShaderInputOrderingType;
        TLayoutTessEvaluationType mTessEvaluationShaderInputPointType;
        // List of array declarations without an explicit size that have come before layout(vertices=N).
        // Once the vertex count is specified, these arrays are sized.
        TVector<TType *> mDeferredArrayTypesToSize;
        // Whether the |precise| keyword has been seen in the shader.
        bool mHasAnyPreciseType;
    
        AdvancedBlendEquations mAdvancedBlendEquations;
    
        // Track when we add new scope for func body in ESSL 1.00 spec
        bool mFunctionBodyNewScope;
    
        ShShaderOutput mOutputType;
    };
    
    int PaParseStrings(size_t count,
                       const char *const string[],
                       const int length[],
                       TParseContext *context);
    
    }  // namespace sh
    
    #endif  // COMPILER_TRANSLATOR_PARSECONTEXT_H_