Refactor TParseContext into 3 level inheritance.
authorJohn Kessenich <cepheus@frii.com>
Sun, 13 Mar 2016 02:08:55 +0000 (19:08 -0700)
committerJohn Kessenich <cepheus@frii.com>
Sun, 13 Mar 2016 02:08:55 +0000 (19:08 -0700)
Adds parseVersions.h as the base TParseVersions for versioning,
and splits the remainder between TParseContextBase (sharable across parsers)
and TParseContext (now the GLSL-specific part).

glslang/CMakeLists.txt
glslang/MachineIndependent/ParseHelper.cpp
glslang/MachineIndependent/ParseHelper.h
glslang/MachineIndependent/ScanContext.h
glslang/MachineIndependent/ShaderLang.cpp
glslang/MachineIndependent/Versions.cpp
glslang/MachineIndependent/parseVersions.h [new file with mode: 0755]
glslang/MachineIndependent/preprocessor/PpContext.cpp
glslang/MachineIndependent/preprocessor/PpContext.h

index 28f4742..b6c70c4 100644 (file)
@@ -63,6 +63,7 @@ set(HEADERS
     MachineIndependent/ScanContext.h
     MachineIndependent/SymbolTable.h
     MachineIndependent/Versions.h
+    MachineIndependent/parseVersions.h
     MachineIndependent/preprocessor/PpContext.h
     MachineIndependent/preprocessor/PpTokens.h)
 
index a43df95..f005da4 100644 (file)
@@ -48,14 +48,14 @@ extern int yyparse(glslang::TParseContext*);
 
 namespace glslang {
 
-TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, bool pb, int v, EProfile p, int spv, int vulkan, EShLanguage L, TInfoSink& is,
-                             bool fc, EShMessages m) :
-            intermediate(interm), symbolTable(symt), infoSink(is), language(L),
-            version(v), profile(p), spv(spv), vulkan(vulkan), forwardCompatible(fc), 
+TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, bool parsingBuiltins,
+                             int version, EProfile profile, int spv, int vulkan, EShLanguage language,
+                             TInfoSink& infoSink, bool forwardCompatible, EShMessages messages) :
+            TParseContextBase(symbolTable, interm, version, profile, spv, vulkan, language, infoSink, forwardCompatible, messages), 
             contextPragma(true, false), loopNestingLevel(0), structNestingLevel(0), controlFlowNestingLevel(0), statementNestingLevel(0),
-            postMainReturn(false),
-            tokensBeforeEOF(false), limits(resources.limits), messages(m), currentScanner(nullptr),
-            numErrors(0), parsingBuiltins(pb), afterEOF(false),
+            inMain(false), postMainReturn(false), currentFunctionType(nullptr), blockName(nullptr),
+            limits(resources.limits), parsingBuiltins(parsingBuiltins),
+            afterEOF(false),
             atomicUintOffsets(nullptr), anyIndexLimits(false)
 {
     // ensure we always have a linkage node, even if empty, to simplify tree topology algorithms
@@ -3133,7 +3133,8 @@ void TParseContext::updateImplicitArraySize(const TSourceLoc& loc, TIntermNode *
 // Desktop, version 3.30 and later, and ES:  "After processing this directive
 // (including its new-line), the implementation will behave as if it is compiling at line number line and
 // source string number source-string-number.
-bool TParseContext::lineDirectiveShouldSetNextLine() const {
+bool TParseContext::lineDirectiveShouldSetNextLine() const
+{
     return profile == EEsProfile || version >= 330;
 }
 
@@ -5941,32 +5942,4 @@ TIntermNode* TParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* expre
     return switchNode;
 }
 
-void TParseContext::notifyVersion(int line, int version, const char* type_string)
-{
-    if (versionCallback) {
-        versionCallback(line, version, type_string);
-    }
-}
-
-void TParseContext::notifyErrorDirective(int line, const char* error_message)
-{
-    if (errorCallback) {
-        errorCallback(line, error_message);
-    }
-}
-
-void TParseContext::notifyLineDirective(int curLineNo, int newLineNo, bool hasSource, int sourceNum, const char* sourceName)
-{
-    if (lineCallback) {
-        lineCallback(curLineNo, newLineNo, hasSource, sourceNum, sourceName);
-    }
-}
-
-void TParseContext::notifyExtensionDirective(int line, const char* extension, const char* behavior)
-{
-    if (extensionCallback) {
-        extensionCallback(line, extension, behavior);
-    }
-}
-
 } // end namespace glslang
index ac1932d..ea5d0ba 100644 (file)
 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 //POSSIBILITY OF SUCH DAMAGE.
 //
+
+//
+// This header defines a two-level parse-helper hierarchy, derived from
+// TParseVersions:
+//  - TParseContextBase:  sharable across multiple parsers
+//  - TParseContext:      GLSL specific helper
+//
+
 #ifndef _PARSER_HELPER_INCLUDED_
 #define _PARSER_HELPER_INCLUDED_
 
-#include "Versions.h"
+#include "parseVersions.h"
 #include "../Include/ShHandle.h"
 #include "SymbolTable.h"
 #include "localintermediate.h"
@@ -60,10 +68,88 @@ class TPpContext;
 typedef std::set<int> TIdSetType;
 
 //
-// The following are extra variables needed during parsing, grouped together so
-// they can be passed to the parser without needing a global.
+// Sharable code (as well as what's in TParseVersions) across
+// parse helpers.
+//
+class TParseContextBase : public TParseVersions {
+public:
+    TParseContextBase(TSymbolTable& symbolTable, TIntermediate& interm, int version,
+                      EProfile profile, int spv, int vulkan, EShLanguage language,
+                      TInfoSink& infoSink, bool forwardCompatible, EShMessages messages)
+          : TParseVersions(interm, version, profile, spv, vulkan, language, infoSink, forwardCompatible, messages),
+            symbolTable(symbolTable), tokensBeforeEOF(false),
+            linkage(nullptr), scanContext(nullptr), ppContext(nullptr) { }
+    virtual ~TParseContextBase() { }
+    
+    virtual void setLimits(const TBuiltInResource&) = 0;
+    
+    EShLanguage getLanguage() const { return language; }
+    TIntermAggregate*& getLinkage() { return linkage; }
+    void setScanContext(TScanContext* c) { scanContext = c; }
+    TScanContext* getScanContext() const { return scanContext; }
+    void setPpContext(TPpContext* c) { ppContext = c; }
+    TPpContext* getPpContext() const { return ppContext; }
+
+    virtual void setLineCallback(const std::function<void(int, int, bool, int, const char*)>& func) { lineCallback = func; }
+    virtual void setExtensionCallback(const std::function<void(int, const char*, const char*)>& func) { extensionCallback = func; }
+    virtual void setVersionCallback(const std::function<void(int, int, const char*)>& func) { versionCallback = func; }
+    virtual void setPragmaCallback(const std::function<void(int, const TVector<TString>&)>& func) { pragmaCallback = func; }
+    virtual void setErrorCallback(const std::function<void(int, const char*)>& func) { errorCallback = func; }
+
+    virtual void reservedPpErrorCheck(const TSourceLoc&, const char* name, const char* op) = 0;
+    virtual bool lineContinuationCheck(const TSourceLoc&, bool endOfComment) = 0;
+    virtual bool lineDirectiveShouldSetNextLine() const = 0;
+    virtual void handlePragma(const TSourceLoc&, const TVector<TString>&) = 0;
+
+    virtual bool parseShaderStrings(TPpContext&, TInputScanner& input, bool versionWillBeError = false) = 0;
+
+    virtual void notifyVersion(int line, int version, const char* type_string)
+    {
+        if (versionCallback)
+            versionCallback(line, version, type_string);
+    }
+    virtual void notifyErrorDirective(int line, const char* error_message)
+    {
+        if (errorCallback)
+            errorCallback(line, error_message);
+    }
+    virtual void notifyLineDirective(int curLineNo, int newLineNo, bool hasSource, int sourceNum, const char* sourceName)
+    {
+        if (lineCallback)
+            lineCallback(curLineNo, newLineNo, hasSource, sourceNum, sourceName);
+    }
+    virtual void notifyExtensionDirective(int line, const char* extension, const char* behavior)
+    {
+        if (extensionCallback)
+            extensionCallback(line, extension, behavior);
+    }
+
+    TSymbolTable& symbolTable;   // symbol table that goes with the current language, version, and profile
+    bool tokensBeforeEOF;
+
+protected:
+    TParseContextBase(TParseContextBase&);
+    TParseContextBase& operator=(TParseContextBase&);
+
+    TIntermAggregate* linkage;   // aggregate node of objects the linker may need, if not referenced by the rest of the AST
+    TScanContext* scanContext;
+    TPpContext* ppContext;
+
+    // These, if set, will be called when a line, pragma ... is preprocessed.
+    // They will be called with any parameters to the original directive.
+    std::function<void(int, int, bool, int, const char*)> lineCallback;
+    std::function<void(int, const TVector<TString>&)> pragmaCallback;
+    std::function<void(int, int, const char*)> versionCallback;
+    std::function<void(int, const char*, const char*)> extensionCallback;
+    std::function<void(int, const char*)> errorCallback;
+};
+
+//
+// GLSL-specific parse helper.  Should have GLSL in the name, but that's
+// too big of a change for comparing branches at the moment, and perhaps
+// impacts downstream consumers as well.
 //
-class TParseContext {
+class TParseContext : public TParseContextBase {
 public:
     TParseContext(TSymbolTable&, TIntermediate&, bool parsingBuiltins, int version, EProfile, int spv, int vulkan, EShLanguage, TInfoSink&,
                   bool forwardCompatible = false, EShMessages messages = EShMsgDefault);
@@ -72,7 +158,6 @@ public:
     void setLimits(const TBuiltInResource&);
     bool parseShaderStrings(TPpContext&, TInputScanner& input, bool versionWillBeError = false);
     void parserError(const char* s);     // for bison's yyerror
-    const char* getPreamble();
 
     void C_DECL error(const TSourceLoc&, const char* szReason, const char* szToken,
                       const char* szExtraInfoFormat, ...);
@@ -83,12 +168,10 @@ public:
     void C_DECL ppWarn(const TSourceLoc&, const char* szReason, const char* szToken,
                       const char* szExtraInfoFormat, ...);
 
-    bool relaxedErrors()    const { return (messages & EShMsgRelaxedErrors)    != 0; }
-    bool suppressWarnings() const { return (messages & EShMsgSuppressWarnings) != 0; }
-
     void reservedErrorCheck(const TSourceLoc&, const TString&);
     void reservedPpErrorCheck(const TSourceLoc&, const char* name, const char* op);
     bool lineContinuationCheck(const TSourceLoc&, bool endOfComment);
+    bool lineDirectiveShouldSetNextLine() const;
     bool builtInName(const TString&);
 
     void handlePragma(const TSourceLoc&, const TVector<TString>&);
@@ -210,55 +293,6 @@ public:
 
     void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index);
 
-    void setScanContext(TScanContext* c) { scanContext = c; }
-    TScanContext* getScanContext() const { return scanContext; }
-    void setPpContext(TPpContext* c) { ppContext = c; }
-    TPpContext* getPpContext() const { return ppContext; }
-    void addError() { ++numErrors; }
-    int getNumErrors() const { return numErrors; }
-    const TSourceLoc& getCurrentLoc() const { return currentScanner->getSourceLoc(); }
-    void setCurrentLine(int line) { currentScanner->setLine(line); }
-    void setCurrentColumn(int col) { currentScanner->setColumn(col); }
-    void setCurrentSourceName(const char* name) { currentScanner->setFile(name); }
-    void setCurrentString(int string) { currentScanner->setString(string); }
-    void setScanner(TInputScanner* scanner) { currentScanner  = scanner; }
-    TInputScanner* getScanner() const { return currentScanner; }
-
-    bool lineDirectiveShouldSetNextLine() const;
-
-    void notifyVersion(int line, int version, const char* type_string);
-    void notifyErrorDirective(int line, const char* error_message);
-    void notifyLineDirective(int curLineNo, int newLineNo, bool hasSource, int sourceNum, const char* sourceName);
-    void notifyExtensionDirective(int line, const char* extension, const char* behavior);
-
-    // The following are implemented in Versions.cpp to localize version/profile/stage/extensions control
-    void initializeExtensionBehavior();
-    void requireProfile(const TSourceLoc&, int queryProfiles, const char* featureDesc);
-    void profileRequires(const TSourceLoc&, int queryProfiles, int minVersion, int numExtensions, const char* const extensions[], const char* featureDesc);
-    void profileRequires(const TSourceLoc&, int queryProfiles, int minVersion, const char* const extension, const char* featureDesc);
-    void requireStage(const TSourceLoc&, EShLanguageMask, const char* featureDesc);
-    void requireStage(const TSourceLoc&, EShLanguage, const char* featureDesc);
-    void checkDeprecated(const TSourceLoc&, int queryProfiles, int depVersion, const char* featureDesc);
-    void requireNotRemoved(const TSourceLoc&, int queryProfiles, int removedVersion, const char* featureDesc);
-    void requireExtensions(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc);
-    void ppRequireExtensions(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc);
-    TExtensionBehavior getExtensionBehavior(const char*);
-    bool extensionTurnedOn(const char* const extension);
-    bool extensionsTurnedOn(int numExtensions, const char* const extensions[]);
-    void updateExtensionBehavior(int line, const char* const extension, const char* behavior);
-    void fullIntegerCheck(const TSourceLoc&, const char* op);
-    void doubleCheck(const TSourceLoc&, const char* op);
-    void spvRemoved(const TSourceLoc&, const char* op);
-    void vulkanRemoved(const TSourceLoc&, const char* op);
-    void requireVulkan(const TSourceLoc&, const char* op);
-    void requireSpv(const TSourceLoc&, const char* op);
-
-    void setVersionCallback(const std::function<void(int, int, const char*)>& func) { versionCallback = func; }
-    void setPragmaCallback(const std::function<void(int, const TVector<TString>&)>& func) { pragmaCallback = func; }
-    void setLineCallback(const std::function<void(int, int, bool, int, const char*)>& func) { lineCallback = func; }
-    void setExtensionCallback(const std::function<void(int, const char*, const char*)>& func) { extensionCallback = func; }
-    void setErrorCallback(const std::function<void(int, const char*)>& func) { errorCallback = func; }
-
 protected:
     void nonInitConstCheck(const TSourceLoc&, TString& identifier, TType& type);
     void inheritGlobalDefaults(TQualifier& dst) const;
@@ -268,8 +302,6 @@ protected:
     TIntermNode* executeInitializer(const TSourceLoc&, TIntermTyped* initializer, TVariable* variable);
     TIntermTyped* convertInitializerList(const TSourceLoc&, const TType&, TIntermTyped* initializer);
     TOperator mapTypeToConstructorOp(const TType&) const;
-    bool checkExtensionsRequested(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc);
-    void updateExtensionBehavior(const char* const extension, TExtensionBehavior);
     void finalErrorCheck();
     void outputMessage(const TSourceLoc&, const char* szReason, const char* szToken,
                        const char* szExtraInfoFormat, TPrefixType prefix,
@@ -280,18 +312,6 @@ public:
     // Generally, bison productions, the scanner, and the PP need read/write access to these; just give them direct access
     //
 
-    TIntermediate& intermediate; // helper for making and hooking up pieces of the parse tree
-    TSymbolTable& symbolTable;   // symbol table that goes with the current language, version, and profile
-    TInfoSink& infoSink;
-
-    // compilation mode
-    EShLanguage language;        // vertex or fragment language
-    int version;                 // version, updated by #version in the shader
-    EProfile profile;            // the declared profile in the shader (core by default)
-    int spv;                     // SPIR-V version; 0 means not SPIR-V
-    int vulkan;                  // Vulkan version; 0 means not vulkan
-    bool forwardCompatible;      // true if errors are to be given for use of deprecated features
-
     // Current state of parsing
     struct TPragma contextPragma;
     int loopNestingLevel;        // 0 if outside all loops
@@ -306,9 +326,7 @@ public:
     bool functionReturnsValue;   // true if a non-void function has a return
     const TString* blockName;
     TQualifier currentBlockQualifier;
-    TIntermAggregate *linkage;   // aggregate node of objects the linker may need, if not referenced by the rest of the AST
     TPrecisionQualifier defaultPrecision[EbtNumTypes];
-    bool tokensBeforeEOF;
     TBuiltInResource resources;
     TLimits& limits;
 
@@ -316,13 +334,7 @@ protected:
     TParseContext(TParseContext&);
     TParseContext& operator=(TParseContext&);
 
-    EShMessages messages;        // errors/warnings/rule-sets
-    TScanContext* scanContext;
-    TPpContext* ppContext;
-    TInputScanner* currentScanner;
-    int numErrors;               // number of compile-time errors encountered
     bool parsingBuiltins;        // true if parsing built-in symbols/functions
-    TMap<TString, TExtensionBehavior> extensionBehavior;    // for each extension string, what its current behavior is set to
     static const int maxSamplerIndex = EsdNumDims * (EbtNumTypes * (2 * 2 * 2)); // see computeSamplerTypeIndex()
     TPrecisionQualifier defaultSamplerPrecision[maxSamplerIndex];
     bool afterEOF;
@@ -369,14 +381,6 @@ protected:
     //    array-sizing declarations
     //
     TVector<TSymbol*> ioArraySymbolResizeList;
-
-    // These, if set, will be called when a line, pragma ... is preprocessed.
-    // They will be called with any parameters to the original directive.
-    std::function<void(int, int, bool, int, const char*)> lineCallback;
-    std::function<void(int, const TVector<TString>&)> pragmaCallback;
-    std::function<void(int, int, const char*)> versionCallback;
-    std::function<void(int, const char*, const char*)> extensionCallback;
-    std::function<void(int, const char*)> errorCallback;
 };
 
 } // end namespace glslang
index 5f1ffb5..f237bee 100644 (file)
@@ -48,7 +48,7 @@ class TParserToken;
 
 class TScanContext {
 public:
-    explicit TScanContext(TParseContext& pc) : parseContext(pc), afterType(false), field(false) { }
+    explicit TScanContext(TParseContextBase& pc) : parseContext(pc), afterType(false), field(false) { }
     virtual ~TScanContext() { }
 
     static void fillInKeywordMap();
@@ -72,7 +72,7 @@ protected:
     int firstGenerationImage(bool inEs310);
     int secondGenerationImage();
 
-    TParseContext& parseContext;
+    TParseContextBase& parseContext;
     bool afterType;           // true if we've recognized a type, so can only be looking for an identifier
     bool field;               // true if we're on a field, right after a '.'
     TSourceLoc loc;
index 230929a..27bfc69 100644 (file)
@@ -464,7 +464,7 @@ bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNo
 // This is the common setup and cleanup code for PreprocessDeferred and
 // CompileDeferred.
 // It takes any callable with a signature of
-//  bool (TParseContext& parseContext, TPpContext& ppContext,
+//  bool (TParseContextBase& parseContext, TPpContext& ppContext,
 //                  TInputScanner& input, bool versionWillBeError,
 //                  TSymbolTable& , TIntermediate& ,
 //                  EShOptimizationLevel , EShMessages );
@@ -717,7 +717,7 @@ private:
 // It places the result in the "string" argument to its constructor.
 struct DoPreprocessing {
     explicit DoPreprocessing(std::string* string): outputString(string) {}
-    bool operator()(TParseContext& parseContext, TPpContext& ppContext,
+    bool operator()(TParseContextBase& parseContext, TPpContext& ppContext,
                     TInputScanner& input, bool versionWillBeError,
                     TSymbolTable& , TIntermediate& ,
                     EShOptimizationLevel , EShMessages )
@@ -828,7 +828,7 @@ struct DoPreprocessing {
 // DoFullParse is a valid ProcessingConext template argument for fully
 // parsing the shader.  It populates the "intermediate" with the AST.
 struct DoFullParse{
-  bool operator()(TParseContext& parseContext, TPpContext& ppContext,
+  bool operator()(TParseContextBase& parseContext, TPpContext& ppContext,
                   TInputScanner& fullInput, bool versionWillBeError,
                   TSymbolTable& symbolTable, TIntermediate& intermediate,
                   EShOptimizationLevel optLevel, EShMessages messages) 
@@ -837,13 +837,13 @@ struct DoFullParse{
         // Parse the full shader.
         if (! parseContext.parseShaderStrings(ppContext, fullInput, versionWillBeError))
             success = false;
-        intermediate.addSymbolLinkageNodes(parseContext.linkage, parseContext.language, symbolTable);
+        intermediate.addSymbolLinkageNodes(parseContext.getLinkage(), parseContext.getLanguage(), symbolTable);
 
         if (success && intermediate.getTreeRoot()) {
             if (optLevel == EShOptNoGeneration)
                 parseContext.infoSink.info.message(EPrefixNone, "No errors.  No code generation or linking was requested.");
             else
-                success = intermediate.postProcess(intermediate.getTreeRoot(), parseContext.language);
+                success = intermediate.postProcess(intermediate.getTreeRoot(), parseContext.getLanguage());
         } else if (! success) {
             parseContext.infoSink.info.prefix(EPrefixError);
             parseContext.infoSink.info << parseContext.getNumErrors() << " compilation errors.  No code generated.\n\n";
index 676f4fd..af2f7f2 100644 (file)
 //
 //     const char* const XXX_extension_X = "XXX_extension_X";
 // 
-// 2) Add extension initialization to TParseContext::initializeExtensionBehavior(),
+// 2) Add extension initialization to TParseVersions::initializeExtensionBehavior(),
 //    the first function below:
 // 
 //     extensionBehavior[XXX_extension_X] = EBhDisable;
 //
-// 3) Add any preprocessor directives etc. in the next function, TParseContext::getPreamble():
+// 3) Add any preprocessor directives etc. in the next function, TParseVersions::getPreamble():
 //
 //           "#define XXX_extension_X 1\n"
 //
 //    table. (There is a different symbol table for each version.)
 //
 
-#include "ParseHelper.h"
+#include "parseVersions.h"
+#include "localintermediate.h"
 
 namespace glslang {
 
@@ -147,7 +148,7 @@ namespace glslang {
 // are incorporated into a core version, their features are supported through allowing that
 // core version, not through a pseudo-enablement of the extension.
 //
-void TParseContext::initializeExtensionBehavior()
+void TParseVersions::initializeExtensionBehavior()
 {
     extensionBehavior[E_GL_OES_texture_3D]                   = EBhDisable;
     extensionBehavior[E_GL_OES_standard_derivatives]         = EBhDisable;
@@ -213,7 +214,7 @@ void TParseContext::initializeExtensionBehavior()
 
 // Get code that is not part of a shared symbol table, is specific to this shader,
 // or needed by the preprocessor (which does not use a shared symbol table).
-const char* TParseContext::getPreamble()
+const char* TParseVersions::getPreamble()
 {
     if (profile == EEsProfile) {
         return
@@ -297,7 +298,7 @@ const char* TParseContext::getPreamble()
 // Operation:  If the current profile is not one of the profileMask,
 // give an error message.
 //
-void TParseContext::requireProfile(const TSourceLoc& loc, int profileMask, const char* featureDesc)
+void TParseVersions::requireProfile(const TSourceLoc& loc, int profileMask, const char* featureDesc)
 {
     if (! (profile & profileMask))
         error(loc, "not supported with this profile:", featureDesc, ProfileName(profile));
@@ -336,7 +337,7 @@ const char* StageName(EShLanguage stage)
 //
 
 // entry point that takes multiple extensions
-void TParseContext::profileRequires(const TSourceLoc& loc, int profileMask, int minVersion, int numExtensions, const char* const extensions[], const char* featureDesc)
+void TParseVersions::profileRequires(const TSourceLoc& loc, int profileMask, int minVersion, int numExtensions, const char* const extensions[], const char* featureDesc)
 {
     if (profile & profileMask) {
         bool okay = false;
@@ -361,7 +362,7 @@ void TParseContext::profileRequires(const TSourceLoc& loc, int profileMask, int
 }
 
 // entry point for the above that takes a single extension
-void TParseContext::profileRequires(const TSourceLoc& loc, int profileMask, int minVersion, const char* extension, const char* featureDesc)
+void TParseVersions::profileRequires(const TSourceLoc& loc, int profileMask, int minVersion, const char* extension, const char* featureDesc)
 {
     profileRequires(loc, profileMask, minVersion, extension ? 1 : 0, &extension, featureDesc);
 }
@@ -373,7 +374,7 @@ void TParseContext::profileRequires(const TSourceLoc& loc, int profileMask, int
 //
 // Operation: If the current stage is not present, give an error message.
 //
-void TParseContext::requireStage(const TSourceLoc& loc, EShLanguageMask languageMask, const char* featureDesc)
+void TParseVersions::requireStage(const TSourceLoc& loc, EShLanguageMask languageMask, const char* featureDesc)
 {
     if (((1 << language) & languageMask) == 0)
         error(loc, "not supported in this stage:", featureDesc, StageName(language));
@@ -381,7 +382,7 @@ void TParseContext::requireStage(const TSourceLoc& loc, EShLanguageMask language
 
 // If only one stage supports a feature, this can be called.  But, all supporting stages
 // must be specified with one call.
-void TParseContext::requireStage(const TSourceLoc& loc, EShLanguage stage, const char* featureDesc)
+void TParseVersions::requireStage(const TSourceLoc& loc, EShLanguage stage, const char* featureDesc)
 {
     requireStage(loc, static_cast<EShLanguageMask>(1 << stage), featureDesc);
 }
@@ -390,7 +391,7 @@ void TParseContext::requireStage(const TSourceLoc& loc, EShLanguage stage, const
 // Within a set of profiles, see if a feature is deprecated and give an error or warning based on whether
 // a future compatibility context is being use.
 //
-void TParseContext::checkDeprecated(const TSourceLoc& loc, int profileMask, int depVersion, const char* featureDesc)
+void TParseVersions::checkDeprecated(const TSourceLoc& loc, int profileMask, int depVersion, const char* featureDesc)
 {
     if (profile & profileMask) {
         if (version >= depVersion) {
@@ -407,7 +408,7 @@ void TParseContext::checkDeprecated(const TSourceLoc& loc, int profileMask, int
 // Within a set of profiles, see if a feature has now been removed and if so, give an error.
 // The version argument is the first version no longer having the feature.
 //
-void TParseContext::requireNotRemoved(const TSourceLoc& loc, int profileMask, int removedVersion, const char* featureDesc)
+void TParseVersions::requireNotRemoved(const TSourceLoc& loc, int profileMask, int removedVersion, const char* featureDesc)
 {
     if (profile & profileMask) {
         if (version >= removedVersion) {
@@ -421,7 +422,7 @@ void TParseContext::requireNotRemoved(const TSourceLoc& loc, int profileMask, in
 
 // Returns true if at least one of the extensions in the extensions parameter is requested. Otherwise, returns false.
 // Warns appropriately if the requested behavior of an extension is "warn".
-bool TParseContext::checkExtensionsRequested(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc)
+bool TParseVersions::checkExtensionsRequested(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc)
 {
     // First, see if any of the extensions are enabled
     for (int i = 0; i < numExtensions; ++i) {
@@ -452,7 +453,7 @@ bool TParseContext::checkExtensionsRequested(const TSourceLoc& loc, int numExten
 // Use when there are no profile/version to check, it's just an error if one of the
 // extensions is not present.
 //
-void TParseContext::requireExtensions(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc)
+void TParseVersions::requireExtensions(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc)
 {
     if (checkExtensionsRequested(loc, numExtensions, extensions, featureDesc)) return;
 
@@ -470,7 +471,7 @@ void TParseContext::requireExtensions(const TSourceLoc& loc, int numExtensions,
 // Use by preprocessor when there are no profile/version to check, it's just an error if one of the
 // extensions is not present.
 //
-void TParseContext::ppRequireExtensions(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc)
+void TParseVersions::ppRequireExtensions(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc)
 {
     if (checkExtensionsRequested(loc, numExtensions, extensions, featureDesc)) return;
 
@@ -484,7 +485,7 @@ void TParseContext::ppRequireExtensions(const TSourceLoc& loc, int numExtensions
     }
 }
 
-TExtensionBehavior TParseContext::getExtensionBehavior(const char* extension)
+TExtensionBehavior TParseVersions::getExtensionBehavior(const char* extension)
 {
     auto iter = extensionBehavior.find(TString(extension));
     if (iter == extensionBehavior.end())
@@ -494,7 +495,7 @@ TExtensionBehavior TParseContext::getExtensionBehavior(const char* extension)
 }
 
 // Returns true if the given extension is set to enable, require, or warn.
-bool TParseContext::extensionTurnedOn(const char* const extension)
+bool TParseVersions::extensionTurnedOn(const char* const extension)
 {
       switch (getExtensionBehavior(extension)) {
       case EBhEnable:
@@ -507,7 +508,7 @@ bool TParseContext::extensionTurnedOn(const char* const extension)
       return false;
 }
 // See if any of the extensions are set to enable, require, or warn.
-bool TParseContext::extensionsTurnedOn(int numExtensions, const char* const extensions[])
+bool TParseVersions::extensionsTurnedOn(int numExtensions, const char* const extensions[])
 {
     for (int i = 0; i < numExtensions; ++i) {
         if (extensionTurnedOn(extensions[i])) return true;
@@ -518,7 +519,7 @@ bool TParseContext::extensionsTurnedOn(int numExtensions, const char* const exte
 //
 // Change the current state of an extension's behavior.
 //
-void TParseContext::updateExtensionBehavior(int line, const char* extension, const char* behaviorString)
+void TParseVersions::updateExtensionBehavior(int line, const char* extension, const char* behaviorString)
 {
     // Translate from text string of extension's behavior to an enum.
     TExtensionBehavior behavior = EBhDisable;
@@ -571,7 +572,7 @@ void TParseContext::updateExtensionBehavior(int line, const char* extension, con
         spv = 100;
 }
 
-void TParseContext::updateExtensionBehavior(const char* extension, TExtensionBehavior behavior)
+void TParseVersions::updateExtensionBehavior(const char* extension, TExtensionBehavior behavior)
 {
     // Update the current behavior
     if (strcmp(extension, "all") == 0) {
@@ -612,14 +613,14 @@ void TParseContext::updateExtensionBehavior(const char* extension, TExtensionBeh
 }
 
 // Call for any operation needing full GLSL integer data-type support.
-void TParseContext::fullIntegerCheck(const TSourceLoc& loc, const char* op)
+void TParseVersions::fullIntegerCheck(const TSourceLoc& loc, const char* op)
 {
     profileRequires(loc, ENoProfile, 130, nullptr, op); 
     profileRequires(loc, EEsProfile, 300, nullptr, op);
 }
 
 // Call for any operation needing GLSL double data-type support.
-void TParseContext::doubleCheck(const TSourceLoc& loc, const char* op)
+void TParseVersions::doubleCheck(const TSourceLoc& loc, const char* op)
 {
     requireProfile(loc, ECoreProfile | ECompatibilityProfile, op);
     profileRequires(loc, ECoreProfile, 400, nullptr, op);
@@ -627,28 +628,28 @@ void TParseContext::doubleCheck(const TSourceLoc& loc, const char* op)
 }
 
 // Call for any operation removed because SPIR-V is in use.
-void TParseContext::spvRemoved(const TSourceLoc& loc, const char* op)
+void TParseVersions::spvRemoved(const TSourceLoc& loc, const char* op)
 {
     if (spv > 0)
         error(loc, "not allowed when generating SPIR-V", op, "");
 }
 
 // Call for any operation removed because Vulkan SPIR-V is being generated.
-void TParseContext::vulkanRemoved(const TSourceLoc& loc, const char* op)
+void TParseVersions::vulkanRemoved(const TSourceLoc& loc, const char* op)
 {
     if (vulkan > 0)
         error(loc, "not allowed when using GLSL for Vulkan", op, "");
 }
 
 // Call for any operation that requires Vulkan.
-void TParseContext::requireVulkan(const TSourceLoc& loc, const char* op)
+void TParseVersions::requireVulkan(const TSourceLoc& loc, const char* op)
 {
     if (vulkan == 0)
         error(loc, "only allowed when using GLSL for Vulkan", op, "");
 }
 
 // Call for any operation that requires SPIR-V.
-void TParseContext::requireSpv(const TSourceLoc& loc, const char* op)
+void TParseVersions::requireSpv(const TSourceLoc& loc, const char* op)
 {
     if (spv == 0)
         error(loc, "only allowed when generating SPIR-V", op, "");
diff --git a/glslang/MachineIndependent/parseVersions.h b/glslang/MachineIndependent/parseVersions.h
new file mode 100755 (executable)
index 0000000..c9dfdc9
--- /dev/null
@@ -0,0 +1,134 @@
+//
+//Copyright (C) 2016 Google, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+//
+
+// This is implemented in Versions.cpp
+
+#ifndef _PARSE_VERSIONS_INCLUDED_
+#define _PARSE_VERSIONS_INCLUDED_
+
+#include "../Public/ShaderLang.h"
+#include "../Include/InfoSink.h"
+#include "Scan.h"
+
+#include <map>
+
+namespace glslang {
+
+//
+// Base class for parse helpers.
+// This just has version-related information and checking.
+// This class should be sufficient for preprocessing.
+//
+class TParseVersions {
+public:
+    TParseVersions(TIntermediate& interm, int version, EProfile profile,
+                   int spv, int vulkan, EShLanguage language, TInfoSink& infoSink,
+                   bool forwardCompatible, EShMessages messages)
+        : infoSink(infoSink), version(version), profile(profile), language(language),
+          spv(spv), vulkan(vulkan), forwardCompatible(forwardCompatible),
+          intermediate(interm), messages(messages), numErrors(0), currentScanner(0) { }
+    virtual ~TParseVersions() { }
+    virtual void initializeExtensionBehavior();
+    virtual void requireProfile(const TSourceLoc&, int queryProfiles, const char* featureDesc);
+    virtual void profileRequires(const TSourceLoc&, int queryProfiles, int minVersion, int numExtensions, const char* const extensions[], const char* featureDesc);
+    virtual void profileRequires(const TSourceLoc&, int queryProfiles, int minVersion, const char* const extension, const char* featureDesc);
+    virtual void requireStage(const TSourceLoc&, EShLanguageMask, const char* featureDesc);
+    virtual void requireStage(const TSourceLoc&, EShLanguage, const char* featureDesc);
+    virtual void checkDeprecated(const TSourceLoc&, int queryProfiles, int depVersion, const char* featureDesc);
+    virtual void requireNotRemoved(const TSourceLoc&, int queryProfiles, int removedVersion, const char* featureDesc);
+    virtual void requireExtensions(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc);
+    virtual void ppRequireExtensions(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc);
+    virtual TExtensionBehavior getExtensionBehavior(const char*);
+    virtual bool extensionTurnedOn(const char* const extension);
+    virtual bool extensionsTurnedOn(int numExtensions, const char* const extensions[]);
+    virtual void updateExtensionBehavior(int line, const char* const extension, const char* behavior);
+    virtual void fullIntegerCheck(const TSourceLoc&, const char* op);
+    virtual void doubleCheck(const TSourceLoc&, const char* op);
+    virtual void spvRemoved(const TSourceLoc&, const char* op);
+    virtual void vulkanRemoved(const TSourceLoc&, const char* op);
+    virtual void requireVulkan(const TSourceLoc&, const char* op);
+    virtual void requireSpv(const TSourceLoc&, const char* op);
+    virtual bool checkExtensionsRequested(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc);
+    virtual void updateExtensionBehavior(const char* const extension, TExtensionBehavior);
+
+    virtual void C_DECL error(const TSourceLoc&, const char* szReason, const char* szToken,
+        const char* szExtraInfoFormat, ...) = 0;
+    virtual void C_DECL  warn(const TSourceLoc&, const char* szReason, const char* szToken,
+        const char* szExtraInfoFormat, ...) = 0;
+    virtual void C_DECL ppError(const TSourceLoc&, const char* szReason, const char* szToken,
+        const char* szExtraInfoFormat, ...) = 0;
+    virtual void C_DECL ppWarn(const TSourceLoc&, const char* szReason, const char* szToken,
+        const char* szExtraInfoFormat, ...) = 0;
+
+    void addError() { ++numErrors; }
+    int getNumErrors() const { return numErrors; }
+
+    void setScanner(TInputScanner* scanner) { currentScanner = scanner; }
+    TInputScanner* getScanner() const { return currentScanner; }
+    const TSourceLoc& getCurrentLoc() const { return currentScanner->getSourceLoc(); }
+    void setCurrentLine(int line) { currentScanner->setLine(line); }
+    void setCurrentColumn(int col) { currentScanner->setColumn(col); }
+    void setCurrentSourceName(const char* name) { currentScanner->setFile(name); }
+    void setCurrentString(int string) { currentScanner->setString(string); }
+
+    const char* getPreamble();
+    bool relaxedErrors()    const { return (messages & EShMsgRelaxedErrors) != 0; }
+    bool suppressWarnings() const { return (messages & EShMsgSuppressWarnings) != 0; }
+
+    TInfoSink& infoSink;
+
+    // compilation mode
+    int version;                 // version, updated by #version in the shader
+    EProfile profile;            // the declared profile in the shader (core by default)
+    EShLanguage language;        // really the stage
+    int spv;                     // SPIR-V version; 0 means not SPIR-V
+    int vulkan;                  // Vulkan version; 0 means not vulkan
+    bool forwardCompatible;      // true if errors are to be given for use of deprecated features
+    TIntermediate& intermediate; // helper for making and hooking up pieces of the parse tree
+
+protected:
+    EShMessages messages;        // errors/warnings/rule-sets
+    int numErrors;               // number of compile-time errors encountered
+    TInputScanner* currentScanner;
+
+private:
+    TMap<TString, TExtensionBehavior> extensionBehavior;    // for each extension string, what its current behavior is set to
+    explicit TParseVersions(const TParseVersions&);
+    TParseVersions& operator=(const TParseVersions&);
+};
+
+} // end namespace glslang
+
+#endif // _PARSE_VERSIONS_INCLUDED_
index b8d2c73..b18ba4f 100644 (file)
@@ -83,7 +83,7 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace glslang {
 
-TPpContext::TPpContext(TParseContext& pc, const TShader::Includer& inclr) : 
+TPpContext::TPpContext(TParseContextBase& pc, const TShader::Includer& inclr) : 
     preamble(0), strings(0), parseContext(pc), includer(inclr), inComment(false)
 {
     InitAtomTable();
index f1d5469..6716c7e 100644 (file)
@@ -121,7 +121,7 @@ class TInputScanner;
 // Don't expect too much in terms of OO design.
 class TPpContext {
 public:
-    TPpContext(TParseContext&, const TShader::Includer&);
+    TPpContext(TParseContextBase&, const TShader::Includer&);
     virtual ~TPpContext();
 
     void setPreamble(const char* preamble, size_t length);
@@ -213,7 +213,7 @@ protected:
 
     // Scanner data:
     int previous_token;
-    TParseContext& parseContext;
+    TParseContextBase& parseContext;
 
     // Get the next token from *stack* of input sources, popping input sources
     // that are out of tokens, down until an input sources is found that has a token.