Added support for associating functions with extensions and performing validation when those functions are used in a shader.
BUG=25
Review URL: http://codereview.appspot.com/2141046

git-svn-id: https://angleproject.googlecode.com/svn/trunk@415 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/compiler/Initialize.cpp b/src/compiler/Initialize.cpp
index df5e3fd..e55437a 100644
--- a/src/compiler/Initialize.cpp
+++ b/src/compiler/Initialize.cpp
@@ -601,6 +601,10 @@
             symbolTable.relateToOperator("dFdx",   EOpDFdx);
             symbolTable.relateToOperator("dFdy",   EOpDFdy);
             symbolTable.relateToOperator("fwidth", EOpFwidth);
+
+            symbolTable.relateToExtension("dFdx", "GL_OES_standard_derivatives");
+            symbolTable.relateToExtension("dFdy", "GL_OES_standard_derivatives");
+            symbolTable.relateToExtension("fwidth", "GL_OES_standard_derivatives");
         }
         break;
     default: break;
diff --git a/src/compiler/ParseHelper.cpp b/src/compiler/ParseHelper.cpp
index 3c61615..ef01c5a 100644
--- a/src/compiler/ParseHelper.cpp
+++ b/src/compiler/ParseHelper.cpp
@@ -884,16 +884,22 @@
     return false;
 }
 
-bool TParseContext::extensionErrorCheck(int line, const char* extension)
-{       
-    if (extensionBehavior[extension] == EBhWarn) {
-        infoSink.info.message(EPrefixWarning, ("extension " + TString(extension) + " is being used").c_str(), line);
-        return false;
-    }
-    if (extensionBehavior[extension] == EBhDisable) {
-        error(line, "extension", extension, "is disabled");
+bool TParseContext::extensionErrorCheck(int line, const TString& extension)
+{
+    TExtensionBehavior::const_iterator iter = extensionBehavior.find(extension);
+    if (iter == extensionBehavior.end()) {
+        error(line, "extension", extension.c_str(), "is not supported");
         return true;
     }
+    if (iter->second == EBhDisable) {
+        error(line, "extension", extension.c_str(), "is disabled");
+        return true;
+    }
+    if (iter->second == EBhWarn) {
+        TString msg = "extension " + extension + " is being used";
+        infoSink.info.message(EPrefixWarning, msg.c_str(), line);
+        return false;
+    }
 
     return false;
 }
diff --git a/src/compiler/ParseHelper.h b/src/compiler/ParseHelper.h
index fb29d94..5c72239 100644
--- a/src/compiler/ParseHelper.h
+++ b/src/compiler/ParseHelper.h
@@ -79,7 +79,7 @@
     bool nonInitConstErrorCheck(int line, TString& identifier, TPublicType& type);
     bool nonInitErrorCheck(int line, TString& identifier, TPublicType& type);
     bool paramErrorCheck(int line, TQualifier qualifier, TQualifier paramQualifier, TType* type);
-    bool extensionErrorCheck(int line, const char*);
+    bool extensionErrorCheck(int line, const TString&);
     const TFunction* findFunction(int line, TFunction* pfnCall, bool *builtIn = 0);
     bool executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType,
                             TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable = 0);
diff --git a/src/compiler/SymbolTable.cpp b/src/compiler/SymbolTable.cpp
index 1b08667..02817d4 100644
--- a/src/compiler/SymbolTable.cpp
+++ b/src/compiler/SymbolTable.cpp
@@ -140,6 +140,22 @@
     }
 }
 
+//
+// Change all function entries in the table with the non-mangled name
+// to be related to the provided built-in extension. This is a low
+// performance operation, and only intended for symbol tables that
+// live across a large number of compiles.
+//
+void TSymbolTableLevel::relateToExtension(const char* name, const TString& ext)
+{
+    for (tLevel::iterator it = level.begin(); it != level.end(); ++it) {
+        if (it->second->isFunction()) {
+            TFunction* function = static_cast<TFunction*>(it->second);
+            if (function->getName() == name)
+                function->relateToExtension(ext);
+        }
+    }
+}
 
 TSymbol::TSymbol(const TSymbol& copyOf)
 {
diff --git a/src/compiler/SymbolTable.h b/src/compiler/SymbolTable.h
index 7476407..42cf736 100644
--- a/src/compiler/SymbolTable.h
+++ b/src/compiler/SymbolTable.h
@@ -156,8 +156,13 @@
 
     const TString& getMangledName() const { return mangledName; }
     const TType& getReturnType() const { return returnType; }
+
     void relateToOperator(TOperator o) { op = o; }
     TOperator getBuiltInOp() const { return op; }
+
+    void relateToExtension(const TString& ext) { extension = ext; }
+    const TString& getExtension() const { return extension; }
+
     void setDefined() { defined = true; }
     bool isDefined() { return defined; }
 
@@ -174,6 +179,7 @@
     TType returnType;
     TString mangledName;
     TOperator op;
+    TString extension;
     bool defined;
 };
 
@@ -220,6 +226,7 @@
     }
 
     void relateToOperator(const char* name, TOperator op);
+    void relateToExtension(const char* name, const TString& ext);
     void dump(TInfoSink &infoSink) const;
     TSymbolTableLevel* clone(TStructureMap& remapper);
 
@@ -288,8 +295,16 @@
         return symbol;
     }
 
-    TSymbolTableLevel* getGlobalLevel() { assert(table.size() >= 2); return table[1]; }
-    void relateToOperator(const char* name, TOperator op) { table[0]->relateToOperator(name, op); }
+    TSymbolTableLevel* getGlobalLevel() {
+        assert(table.size() >= 2);
+        return table[1];
+    }
+    void relateToOperator(const char* name, TOperator op) {
+        table[0]->relateToOperator(name, op);
+    }
+    void relateToExtension(const char* name, const TString& ext) {
+        table[0]->relateToExtension(name, ext);
+    }
     int getMaxSymbolId() { return uniqueId; }
     void dump(TInfoSink &infoSink) const;
     void copyTable(const TSymbolTable& copyOf);
diff --git a/src/compiler/glslang.y b/src/compiler/glslang.y
index 1044873..c96b8d8 100644
--- a/src/compiler/glslang.y
+++ b/src/compiler/glslang.y
@@ -501,9 +501,12 @@
             fnCandidate = parseContext->findFunction($1.line, fnCall, &builtIn);
             if (fnCandidate) {
                 //
-                // A declared function.  But, it might still map to a built-in
-                // operation.
+                // A declared function.
                 //
+                if (builtIn && !fnCandidate->getExtension().empty() &&
+                    parseContext->extensionErrorCheck($1.line, fnCandidate->getExtension())) {
+                    parseContext->recover();
+                }
                 op = fnCandidate->getBuiltInOp();
                 if (builtIn && op != EOpNull) {
                     //