Front-end "pure" built-in TOperator:  Finish adding full support, but still turned off.

This is to avoid all need to do text comparison of built-in function names
when consuming the AST.  All built-in functions get enumerants.

Will want to turn on soon.  See PureOperatorBuiltins.  See issue #8.
diff --git a/Test/300.frag b/Test/300.frag
index ff2da1f..97f3101 100644
--- a/Test/300.frag
+++ b/Test/300.frag
@@ -59,7 +59,7 @@
     v = textureLod(s2DArray, c3D, 1.2);
     f = textureOffset(s2DShadow, c3D, ic2D, c1D);  // ERROR, offset argument not constant
     v = texelFetch(s3D, ic3D, ic1D);
-    v = texelFetchOffset(arrayedSampler[2], ic2D, 4, ic2D);
+    v = texelFetchOffset(arrayedSampler[2], ic2D, 4, ic2D);   // ERROR, offset argument not constant
     f = textureLodOffset(s2DShadow, c3D, c1D, ic2D);
     v = textureProjLodOffset(s2D, c3D, c1D, ic2D);
     v = textureGrad(sCube, c3D, c3D, c3D);
diff --git a/Test/baseResults/newTexture.frag.out b/Test/baseResults/newTexture.frag.out
index 8690143..625dd80 100644
--- a/Test/baseResults/newTexture.frag.out
+++ b/Test/baseResults/newTexture.frag.out
@@ -49,7 +49,9 @@
 0:43          'ic2D' (flat in 2-component vector of int)

 0:43          Constant:

 0:43            4 (const int)

-0:43          'ic2D' (flat in 2-component vector of int)

+0:43          Constant:

+0:43            3 (const int)

+0:43            3 (const int)

 0:44      add second child into first child (temp float)

 0:44        direct index (temp float)

 0:44          'v' (temp 4-component vector of float)

@@ -301,7 +303,9 @@
 0:43          'ic2D' (flat in 2-component vector of int)

 0:43          Constant:

 0:43            4 (const int)

-0:43          'ic2D' (flat in 2-component vector of int)

+0:43          Constant:

+0:43            3 (const int)

+0:43            3 (const int)

 0:44      add second child into first child (temp float)

 0:44        direct index (temp float)

 0:44          'v' (temp 4-component vector of float)

diff --git a/Test/newTexture.frag b/Test/newTexture.frag
index 9d01209..138536d 100644
--- a/Test/newTexture.frag
+++ b/Test/newTexture.frag
@@ -40,7 +40,7 @@
     v += textureLod(s2DArray, c3D, 1.2);

     v.y += textureOffset(s2DShadow, c3D, ivec2(3), c1D);

     v += texelFetch(s3D, ic3D, ic1D);

-    v += texelFetchOffset(s2D, ic2D, 4, ic2D);

+    v += texelFetchOffset(s2D, ic2D, 4, ivec2(3));

     v.y += textureLodOffset(s2DShadow, c3D, c1D, ivec2(3));

     v += textureProjLodOffset(s2D, c3D, c1D, ivec2(3));

     v += textureGrad(sCube, c3D, c3D, c3D);

diff --git a/Test/spv.newTexture.frag b/Test/spv.newTexture.frag
index 5e3fb43..edb0423 100644
--- a/Test/spv.newTexture.frag
+++ b/Test/spv.newTexture.frag
@@ -38,7 +38,7 @@
     v += textureLod(s2DArray, c3D, 1.2);

     v.y += textureOffset(s2DShadow, c3D, ivec2(3), c1D);

     v += texelFetch(s3D, ic3D, ic1D);

-    v += texelFetchOffset(s2D, ic2D, 4, ic2D);

+    v += texelFetchOffset(s2D, ic2D, 4, ivec2(3));

     v.y += textureLodOffset(s2DShadow, c3D, c1D, ivec2(3));

     v += textureProjLodOffset(s2D, c3D, c1D, ivec2(3));

     v += textureGrad(sCube, c3D, c3D, c3D);

diff --git a/glslang/Include/revision.h b/glslang/Include/revision.h
index 627fb92..9078485 100644
--- a/glslang/Include/revision.h
+++ b/glslang/Include/revision.h
@@ -2,5 +2,5 @@
 // For the version, it uses the latest git tag followed by the number of commits.
 // For the date, it uses the current date (when then script is run).
 
-#define GLSLANG_REVISION "2.3.723"
+#define GLSLANG_REVISION "2.3.725"
 #define GLSLANG_DATE "18-Aug-2015"
diff --git a/glslang/MachineIndependent/Initialize.cpp b/glslang/MachineIndependent/Initialize.cpp
index 450884b..9dbefb2 100644
--- a/glslang/MachineIndependent/Initialize.cpp
+++ b/glslang/MachineIndependent/Initialize.cpp
@@ -59,7 +59,7 @@
 const bool ForwardCompatibility = false;
 
 // change this back to false if depending on textual spellings of texturing calls when consuming the AST
-const bool PureOperatorBuiltins = false;
+bool PureOperatorBuiltins = false;
 
 inline bool IncludeLegacy(int version, EProfile profile)
 {
@@ -3097,7 +3097,7 @@
 
     //
     // Next, identify which built-ins have a mapping to an operator.
-    // Those that are not identified as such are
+    // If PureOperatorBuiltins is false, those that are not identified as such are
     // expected to be resolved through a library of functions, versus as
     // operations.
     //
@@ -3267,30 +3267,59 @@
         symbolTable.relateToOperator("textureGatherOffset",     EOpTextureGatherOffset);
         symbolTable.relateToOperator("textureGatherOffsets",    EOpTextureGatherOffsets);
 
-        if (IncludeLegacy(version, profile)) {
-            // TBD: add ftransform(), any others?
-            symbolTable.relateToOperator("texture1D",         EOpTexture);
-            symbolTable.relateToOperator("texture1DProj",     EOpTextureProj);
-            symbolTable.relateToOperator("texture1DLod",      EOpTextureLod);
-            symbolTable.relateToOperator("texture1DProjLod",  EOpTextureProjLod);
-            symbolTable.relateToOperator("texture2D",         EOpTexture);
-            symbolTable.relateToOperator("texture2DProj",     EOpTextureProj);
-            symbolTable.relateToOperator("texture2DLod",      EOpTextureLod);
-            symbolTable.relateToOperator("texture2DProjLod",  EOpTextureProjLod);
-            symbolTable.relateToOperator("texture3D",         EOpTexture);
-            symbolTable.relateToOperator("texture3DProj",     EOpTextureProj);
-            symbolTable.relateToOperator("texture3DLod",      EOpTextureLod);
-            symbolTable.relateToOperator("texture3DProjLod",  EOpTextureProjLod);
-            symbolTable.relateToOperator("textureCube",       EOpTexture);
-            symbolTable.relateToOperator("textureCubeLod",    EOpTextureLod);
-            symbolTable.relateToOperator("shadow1D",          EOpTexture);
-            symbolTable.relateToOperator("shadow2D",          EOpTexture);
-            symbolTable.relateToOperator("shadow1DProj",      EOpTextureProj);
-            symbolTable.relateToOperator("shadow2DProj",      EOpTextureProj);
-            symbolTable.relateToOperator("shadow1DLod",       EOpTextureLod);
-            symbolTable.relateToOperator("shadow2DLod",       EOpTextureLod);
-            symbolTable.relateToOperator("shadow1DProjLod",   EOpTextureProjLod);
-            symbolTable.relateToOperator("shadow2DProjLod",   EOpTextureProjLod);
+        if (IncludeLegacy(version, profile) || (profile == EEsProfile && version == 100)) {
+            symbolTable.relateToOperator("ftransform",               EOpFtransform);
+
+            symbolTable.relateToOperator("texture1D",                EOpTexture);
+            symbolTable.relateToOperator("texture1DGradARB",         EOpTextureGrad);
+            symbolTable.relateToOperator("texture1DProj",            EOpTextureProj);
+            symbolTable.relateToOperator("texture1DProjGradARB",     EOpTextureProjGrad);
+            symbolTable.relateToOperator("texture1DLod",             EOpTextureLod);
+            symbolTable.relateToOperator("texture1DProjLod",         EOpTextureProjLod);
+
+            symbolTable.relateToOperator("texture2DRect",            EOpTexture);
+            symbolTable.relateToOperator("texture2DRectProj",        EOpTextureProj);
+            symbolTable.relateToOperator("texture2DRectGradARB",     EOpTextureGrad);
+            symbolTable.relateToOperator("texture2DRectProjGradARB", EOpTextureProjGrad);
+            symbolTable.relateToOperator("shadow2DRect",             EOpTexture);
+            symbolTable.relateToOperator("shadow2DRectProj",         EOpTextureProj);
+            symbolTable.relateToOperator("shadow2DRectGradARB",      EOpTextureGrad);
+            symbolTable.relateToOperator("shadow2DRectProjGradARB",  EOpTextureProjGrad);
+
+            symbolTable.relateToOperator("texture2D",                EOpTexture);
+            symbolTable.relateToOperator("texture2DProj",            EOpTextureProj);
+            symbolTable.relateToOperator("texture2DGradEXT",         EOpTextureGrad);
+            symbolTable.relateToOperator("texture2DGradARB",         EOpTextureGrad);
+            symbolTable.relateToOperator("texture2DProjGradEXT",     EOpTextureProjGrad);
+            symbolTable.relateToOperator("texture2DProjGradARB",     EOpTextureProjGrad);
+            symbolTable.relateToOperator("texture2DLod",             EOpTextureLod);
+            symbolTable.relateToOperator("texture2DLodEXT",          EOpTextureLod);
+            symbolTable.relateToOperator("texture2DProjLod",         EOpTextureProjLod);
+            symbolTable.relateToOperator("texture2DProjLodEXT",      EOpTextureProjLod);
+
+            symbolTable.relateToOperator("texture3D",                EOpTexture);
+            symbolTable.relateToOperator("texture3DGradARB",         EOpTextureGrad);
+            symbolTable.relateToOperator("texture3DProj",            EOpTextureProj);
+            symbolTable.relateToOperator("texture3DProjGradARB",     EOpTextureProjGrad);
+            symbolTable.relateToOperator("texture3DLod",             EOpTextureLod);
+            symbolTable.relateToOperator("texture3DProjLod",         EOpTextureProjLod);
+            symbolTable.relateToOperator("textureCube",              EOpTexture);
+            symbolTable.relateToOperator("textureCubeGradEXT",       EOpTextureGrad);
+            symbolTable.relateToOperator("textureCubeGradARB",       EOpTextureGrad);
+            symbolTable.relateToOperator("textureCubeLod",           EOpTextureLod);
+            symbolTable.relateToOperator("textureCubeLodEXT",        EOpTextureLod);
+            symbolTable.relateToOperator("shadow1D",                 EOpTexture);
+            symbolTable.relateToOperator("shadow1DGradARB",          EOpTextureGrad);
+            symbolTable.relateToOperator("shadow2D",                 EOpTexture);
+            symbolTable.relateToOperator("shadow2DGradARB",          EOpTextureGrad);
+            symbolTable.relateToOperator("shadow1DProj",             EOpTextureProj);
+            symbolTable.relateToOperator("shadow2DProj",             EOpTextureProj);
+            symbolTable.relateToOperator("shadow1DProjGradARB",      EOpTextureProjGrad);
+            symbolTable.relateToOperator("shadow2DProjGradARB",      EOpTextureProjGrad);
+            symbolTable.relateToOperator("shadow1DLod",              EOpTextureLod);
+            symbolTable.relateToOperator("shadow2DLod",              EOpTextureLod);
+            symbolTable.relateToOperator("shadow1DProjLod",          EOpTextureProjLod);
+            symbolTable.relateToOperator("shadow2DProjLod",          EOpTextureProjLod);
         }
     }
 
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index 297a2fb..c31396d 100644
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -1107,11 +1107,14 @@
                 result = intermediate.addBuiltInFunctionCall(loc, op, fnCandidate->getParamCount() == 1, arguments, fnCandidate->getType());
                 if (result == nullptr)  {
                     error(arguments->getLoc(), " wrong operand type", "Internal Error",
-                                        "built in unary operator function.  Type: %s",
-                                        static_cast<TIntermTyped*>(arguments)->getCompleteString().c_str());
+                                               "built in unary operator function.  Type: %s",
+                                               static_cast<TIntermTyped*>(arguments)->getCompleteString().c_str());
+                } else if (result->getAsOperator()) {
+                    builtInOpCheck(loc, *fnCandidate, *result->getAsOperator());
                 }
             } else {
-                // This is a function call not mapped to built-in operator, but it could still be a built-in function
+                // This is a function call not mapped to built-in operator.
+                // It could still be a built-in function, but only if PureOperatorBuiltins == false.
                 result = intermediate.setAggregateOperator(arguments, EOpFunctionCall, fnCandidate->getType(), loc);
                 TIntermAggregate* call = result->getAsAggregate();
                 call->setName(fnCandidate->getMangledName());
@@ -1325,6 +1328,173 @@
 }
 
 //
+// Do additional checking of built-in function calls that is not caught
+// by normal semantic checks on argument type, extension tagging, etc.
+//
+// Assumes there has been a semantically correct match to a built-in function prototype.
+//
+void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCandidate, TIntermOperator& callNode)
+{
+    // Set up convenience accessors to the argument(s).  There is almost always
+    // multiple arguments for the cases below, but when there might be one,
+    // check the unaryArg first.
+    const TIntermSequence* argp = nullptr;   // confusing to use [] syntax on a pointer, so this is to help get a reference
+    const TIntermTyped* unaryArg = nullptr;
+    const TIntermTyped* arg0 = nullptr;
+    if (callNode.getAsAggregate()) {
+        argp = &callNode.getAsAggregate()->getSequence();
+        if (argp->size() > 0)
+            arg0 = (*argp)[0]->getAsTyped();
+    } else {
+        assert(callNode.getAsUnaryNode());
+        unaryArg = callNode.getAsUnaryNode()->getOperand();
+        arg0 = unaryArg;
+    }
+    const TIntermSequence& aggArgs = *argp;  // only valid when unaryArg is nullptr
+
+    // built-in texturing functions get their return value precision from the precision of the sampler
+    if (fnCandidate.getType().getQualifier().precision == EpqNone &&
+        fnCandidate.getParamCount() > 0 && fnCandidate[0].type->getBasicType() == EbtSampler)
+        callNode.getQualifier().precision = arg0->getQualifier().precision;
+
+    switch (callNode.getOp()) {
+    case EOpTextureGather:
+    case EOpTextureGatherOffset:
+    case EOpTextureGatherOffsets:
+    {
+        // Figure out which variants are allowed by what extensions,
+        // and what arguments must be constant for which situations.
+
+        TString featureString = fnCandidate.getName() + "(...)";
+        const char* feature = featureString.c_str();
+        profileRequires(loc, EEsProfile, 310, nullptr, feature);
+        int compArg = -1;  // track which argument, if any, is the constant component argument
+        switch (callNode.getOp()) {
+        case EOpTextureGather:
+            // More than two arguments needs gpu_shader5, and rectangular or shadow needs gpu_shader5,
+            // otherwise, need GL_ARB_texture_gather.
+            if (fnCandidate.getParamCount() > 2 || fnCandidate[0].type->getSampler().dim == EsdRect || fnCandidate[0].type->getSampler().shadow) {
+                profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_gpu_shader5, feature);
+                if (! fnCandidate[0].type->getSampler().shadow)
+                    compArg = 2;
+            } else
+                profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_texture_gather, feature);
+            break;
+        case EOpTextureGatherOffset:
+            // GL_ARB_texture_gather is good enough for 2D non-shadow textures with no component argument
+            if (fnCandidate[0].type->getSampler().dim == Esd2D && ! fnCandidate[0].type->getSampler().shadow && fnCandidate.getParamCount() == 3)
+                profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_texture_gather, feature);
+            else
+                profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_gpu_shader5, feature);
+            if (! aggArgs[fnCandidate[0].type->getSampler().shadow ? 3 : 2]->getAsConstantUnion())
+                profileRequires(loc, EEsProfile, 0, Num_AEP_gpu_shader5, AEP_gpu_shader5, "non-constant offset argument");
+            if (! fnCandidate[0].type->getSampler().shadow)
+                compArg = 3;
+            break;
+        case EOpTextureGatherOffsets:
+            profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_gpu_shader5, feature);
+            if (! fnCandidate[0].type->getSampler().shadow)
+                compArg = 3;
+            // check for constant offsets
+            if (! aggArgs[fnCandidate[0].type->getSampler().shadow ? 3 : 2]->getAsConstantUnion())
+                error(loc, "must be a compile-time constant:", feature, "offsets argument");
+            break;
+        default:
+            break;
+        }
+
+        if (compArg > 0 && compArg < fnCandidate.getParamCount()) {
+            if (aggArgs[compArg]->getAsConstantUnion()) {
+                int value = aggArgs[compArg]->getAsConstantUnion()->getConstArray()[0].getIConst();
+                if (value < 0 || value > 3)
+                    error(loc, "must be 0, 1, 2, or 3:", feature, "component argument");
+            } else
+                error(loc, "must be a compile-time constant:", feature, "component argument");
+        }
+
+        break;
+    }
+
+    case EOpTextureOffset:
+    case EOpTextureFetchOffset:
+    case EOpTextureProjOffset:
+    case EOpTextureLodOffset:
+    case EOpTextureProjLodOffset:
+    case EOpTextureGradOffset:
+    case EOpTextureProjGradOffset:
+    {
+        // Handle texture-offset limits checking
+        // Pick which argument has to hold constant offsets
+        int arg = -1;
+        switch (callNode.getOp()) {
+        case EOpTextureOffset:          arg = 2;  break;
+        case EOpTextureFetchOffset:     arg = 3;  break;
+        case EOpTextureProjOffset:      arg = 2;  break;
+        case EOpTextureLodOffset:       arg = 3;  break;
+        case EOpTextureProjLodOffset:   arg = 3;  break;
+        case EOpTextureGradOffset:      arg = 4;  break;
+        case EOpTextureProjGradOffset:  arg = 4;  break;
+        default:
+            assert(0);
+            break;
+        }
+
+        if (arg > 0) {
+            if (! aggArgs[arg]->getAsConstantUnion())
+                error(loc, "argument must be compile-time constant", "texel offset", "");
+            else {
+                const TType& type = aggArgs[arg]->getAsTyped()->getType();
+                for (int c = 0; c < type.getVectorSize(); ++c) {
+                    int offset = aggArgs[arg]->getAsConstantUnion()->getConstArray()[c].getIConst();
+                    if (offset > resources.maxProgramTexelOffset || offset < resources.minProgramTexelOffset)
+                        error(loc, "value is out of range:", "texel offset", "[gl_MinProgramTexelOffset, gl_MaxProgramTexelOffset]");
+                }
+            }
+        }
+
+        break;
+    }
+
+    case EOpTextureQuerySamples:
+    case EOpImageQuerySamples:
+        // GL_ARB_shader_texture_image_samples
+        profileRequires(loc, ~EEsProfile, 450, E_GL_ARB_shader_texture_image_samples, "textureSamples and imageSamples");
+        break;
+
+    case EOpImageAtomicAdd:
+    case EOpImageAtomicMin:
+    case EOpImageAtomicMax:
+    case EOpImageAtomicAnd:
+    case EOpImageAtomicOr:
+    case EOpImageAtomicXor:
+    case EOpImageAtomicExchange:
+    case EOpImageAtomicCompSwap:
+    {
+        // Make sure the image types have the correct layout() format and correct argument types
+        const TType& imageType = arg0->getType();
+        if (imageType.getSampler().type == EbtInt || imageType.getSampler().type == EbtUint) {
+            if (imageType.getQualifier().layoutFormat != ElfR32i && imageType.getQualifier().layoutFormat != ElfR32ui)
+                error(loc, "only supported on image with format r32i or r32ui", fnCandidate.getName().c_str(), "");
+        } else {
+            if (fnCandidate.getName().compare(0, 19, "imageAtomicExchange") != 0) 
+                error(loc, "only supported on integer images", fnCandidate.getName().c_str(), "");
+            else if (imageType.getQualifier().layoutFormat != ElfR32f && profile == EEsProfile)
+                error(loc, "only supported on image with format r32f", fnCandidate.getName().c_str(), "");
+        }
+
+        break;
+    }
+
+    default:
+        break;
+    }
+}
+
+extern bool PureOperatorBuiltins;
+
+// Deprecated!  Use PureOperatorBuiltins == true instead, in which case this
+// functionality is handled in builtInOpCheck() instead of here.
+//
 // Do additional checking of built-in function calls that were not mapped
 // to built-in operations (e.g., texturing functions).
 //
@@ -1332,10 +1502,18 @@
 //
 void TParseContext::nonOpBuiltInCheck(const TSourceLoc& loc, const TFunction& fnCandidate, TIntermAggregate& callNode)
 {
+    // Further maintainance of this function is deprecated, because the "correct" 
+    // future-oriented design is to not have to do string compares on function names.
+
+    // If PureOperatorBuiltins == true, then all built-ins should be mapped
+    // to a TOperator, and this function would then never get called.
+
+    assert(PureOperatorBuiltins == false);
+
     // built-in texturing functions get their return value precision from the precision of the sampler
     if (fnCandidate.getType().getQualifier().precision == EpqNone &&
         fnCandidate.getParamCount() > 0 && fnCandidate[0].type->getBasicType() == EbtSampler)
-        callNode.getQualifier().precision = callNode.getAsAggregate()->getSequence()[0]->getAsTyped()->getQualifier().precision;
+        callNode.getQualifier().precision = callNode.getSequence()[0]->getAsTyped()->getQualifier().precision;
 
     if (fnCandidate.getName().compare(0, 7, "texture") == 0) {
         if (fnCandidate.getName().compare(0, 13, "textureGather") == 0) {
diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h
index 81c9eac..17a5b3f 100644
--- a/glslang/MachineIndependent/ParseHelper.h
+++ b/glslang/MachineIndependent/ParseHelper.h
@@ -119,6 +119,7 @@
     TIntermTyped* handleLengthMethod(const TSourceLoc&, TFunction*, TIntermNode*);
     void addInputArgumentConversions(const TFunction&, TIntermNode*&) const;
     TIntermTyped* addOutputArgumentConversions(const TFunction&, TIntermAggregate&) const;
+    void builtInOpCheck(const TSourceLoc&, const TFunction&, TIntermOperator&);
     void nonOpBuiltInCheck(const TSourceLoc&, const TFunction&, TIntermAggregate&);
     TFunction* handleConstructorCall(const TSourceLoc&, const TPublicType&);