MachineIndependent/ScanContext.h
MachineIndependent/SymbolTable.h
MachineIndependent/Versions.h
+ MachineIndependent/parseVersions.h
MachineIndependent/preprocessor/PpContext.h
MachineIndependent/preprocessor/PpTokens.h)
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
// 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;
}
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
//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"
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);
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, ...);
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>&);
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;
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,
// 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
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;
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;
// 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
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();
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;
// 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 );
// 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 )
// 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)
// 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";
//
// 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 {
// 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;
// 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
// 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));
//
// 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;
}
// 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);
}
//
// 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));
// 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);
}
// 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) {
// 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) {
// 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) {
// 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;
// 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;
}
}
-TExtensionBehavior TParseContext::getExtensionBehavior(const char* extension)
+TExtensionBehavior TParseVersions::getExtensionBehavior(const char* extension)
{
auto iter = extensionBehavior.find(TString(extension));
if (iter == extensionBehavior.end())
}
// 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:
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;
//
// 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;
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) {
}
// 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);
}
// 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, "");
--- /dev/null
+//
+//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_
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();
// 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);
// 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.