Merge pull request #198 from AWoloszyn/update-includer
Updated the includer interface to allow relative includes.
This commit is contained in:
commit
56368b68ed
@ -699,8 +699,9 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
|
|||||||
|
|
||||||
if (Options & EOptionOutputPreprocessed) {
|
if (Options & EOptionOutputPreprocessed) {
|
||||||
std::string str;
|
std::string str;
|
||||||
|
glslang::TShader::ForbidInclude includer;
|
||||||
if (shader->preprocess(&Resources, defaultVersion, ENoProfile, false, false,
|
if (shader->preprocess(&Resources, defaultVersion, ENoProfile, false, false,
|
||||||
messages, &str, glslang::TShader::ForbidInclude())) {
|
messages, &str, includer)) {
|
||||||
PutsIfNonEmpty(str.c_str());
|
PutsIfNonEmpty(str.c_str());
|
||||||
} else {
|
} else {
|
||||||
CompileFailed = true;
|
CompileFailed = true;
|
||||||
|
@ -51,10 +51,10 @@ const int EndOfInput = -1;
|
|||||||
//
|
//
|
||||||
class TInputScanner {
|
class TInputScanner {
|
||||||
public:
|
public:
|
||||||
TInputScanner(int n, const char* const s[], size_t L[], const char* const* names = nullptr, int b = 0, int f = 0) :
|
TInputScanner(int n, const char* const s[], size_t L[], const char* const* names = nullptr, int b = 0, int f = 0, bool single = false) :
|
||||||
numSources(n),
|
numSources(n),
|
||||||
sources(reinterpret_cast<const unsigned char* const *>(s)), // up to this point, common usage is "char*", but now we need positive 8-bit characters
|
sources(reinterpret_cast<const unsigned char* const *>(s)), // up to this point, common usage is "char*", but now we need positive 8-bit characters
|
||||||
lengths(L), currentSource(0), currentChar(0), stringBias(b), finale(f)
|
lengths(L), currentSource(0), currentChar(0), stringBias(b), finale(f), singleLogical(single)
|
||||||
{
|
{
|
||||||
loc = new TSourceLoc[numSources];
|
loc = new TSourceLoc[numSources];
|
||||||
for (int i = 0; i < numSources; ++i) {
|
for (int i = 0; i < numSources; ++i) {
|
||||||
@ -67,6 +67,10 @@ public:
|
|||||||
loc[currentSource].string = -stringBias;
|
loc[currentSource].string = -stringBias;
|
||||||
loc[currentSource].line = 1;
|
loc[currentSource].line = 1;
|
||||||
loc[currentSource].column = 0;
|
loc[currentSource].column = 0;
|
||||||
|
logicalSourceLoc.string = 0;
|
||||||
|
logicalSourceLoc.line = 1;
|
||||||
|
logicalSourceLoc.column = 0;
|
||||||
|
logicalSourceLoc.name = loc[0].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~TInputScanner()
|
virtual ~TInputScanner()
|
||||||
@ -82,8 +86,11 @@ public:
|
|||||||
|
|
||||||
int ret = peek();
|
int ret = peek();
|
||||||
++loc[currentSource].column;
|
++loc[currentSource].column;
|
||||||
|
++logicalSourceLoc.column;
|
||||||
if (ret == '\n') {
|
if (ret == '\n') {
|
||||||
++loc[currentSource].line;
|
++loc[currentSource].line;
|
||||||
|
++logicalSourceLoc.line;
|
||||||
|
logicalSourceLoc.column = 0;
|
||||||
loc[currentSource].column = 0;
|
loc[currentSource].column = 0;
|
||||||
}
|
}
|
||||||
advance();
|
advance();
|
||||||
@ -118,6 +125,7 @@ public:
|
|||||||
if (currentChar > 0) {
|
if (currentChar > 0) {
|
||||||
--currentChar;
|
--currentChar;
|
||||||
--loc[currentSource].column;
|
--loc[currentSource].column;
|
||||||
|
--logicalSourceLoc.column;
|
||||||
if (loc[currentSource].column < 0) {
|
if (loc[currentSource].column < 0) {
|
||||||
// We've moved back past a new line. Find the
|
// We've moved back past a new line. Find the
|
||||||
// previous newline (or start of the file) to compute
|
// previous newline (or start of the file) to compute
|
||||||
@ -129,6 +137,7 @@ public:
|
|||||||
}
|
}
|
||||||
--chIndex;
|
--chIndex;
|
||||||
}
|
}
|
||||||
|
logicalSourceLoc.column = (int)(currentChar - chIndex);
|
||||||
loc[currentSource].column = (int)(currentChar - chIndex);
|
loc[currentSource].column = (int)(currentChar - chIndex);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -141,23 +150,49 @@ public:
|
|||||||
} else
|
} else
|
||||||
currentChar = lengths[currentSource] - 1;
|
currentChar = lengths[currentSource] - 1;
|
||||||
}
|
}
|
||||||
if (peek() == '\n')
|
if (peek() == '\n') {
|
||||||
--loc[currentSource].line;
|
--loc[currentSource].line;
|
||||||
|
--logicalSourceLoc.line;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// for #line override
|
// for #line override
|
||||||
void setLine(int newLine) { loc[getLastValidSourceIndex()].line = newLine; }
|
void setLine(int newLine)
|
||||||
void setFile(const char* filename) { loc[getLastValidSourceIndex()].name = filename; }
|
{
|
||||||
|
logicalSourceLoc.line = newLine;
|
||||||
|
loc[getLastValidSourceIndex()].line = newLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for #line override in filename based parsing
|
||||||
|
void setFile(const char* filename)
|
||||||
|
{
|
||||||
|
logicalSourceLoc.name = filename;
|
||||||
|
loc[getLastValidSourceIndex()].name = filename;
|
||||||
|
}
|
||||||
|
|
||||||
void setString(int newString)
|
void setString(int newString)
|
||||||
{
|
{
|
||||||
|
logicalSourceLoc.string = newString;
|
||||||
loc[getLastValidSourceIndex()].string = newString;
|
loc[getLastValidSourceIndex()].string = newString;
|
||||||
|
logicalSourceLoc.name = nullptr;
|
||||||
loc[getLastValidSourceIndex()].name = nullptr;
|
loc[getLastValidSourceIndex()].name = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// for #include content indentation
|
// for #include content indentation
|
||||||
void setColumn(int col) { loc[getLastValidSourceIndex()].column = col; }
|
void setColumn(int col)
|
||||||
|
{
|
||||||
|
logicalSourceLoc.column = col;
|
||||||
|
loc[getLastValidSourceIndex()].column = col;
|
||||||
|
}
|
||||||
|
|
||||||
const TSourceLoc& getSourceLoc() const { return loc[std::max(0, std::min(currentSource, numSources - finale - 1))]; }
|
const TSourceLoc& getSourceLoc() const
|
||||||
|
{
|
||||||
|
if (singleLogical) {
|
||||||
|
return logicalSourceLoc;
|
||||||
|
} else {
|
||||||
|
return loc[std::max(0, std::min(currentSource, numSources - finale - 1))];
|
||||||
|
}
|
||||||
|
}
|
||||||
// Returns the index (starting from 0) of the most recent valid source string we are reading from.
|
// Returns the index (starting from 0) of the most recent valid source string we are reading from.
|
||||||
int getLastValidSourceIndex() const { return std::min(currentSource, numSources - 1); }
|
int getLastValidSourceIndex() const { return std::min(currentSource, numSources - 1); }
|
||||||
|
|
||||||
@ -204,6 +239,10 @@ protected:
|
|||||||
|
|
||||||
int stringBias; // the first string that is the user's string number 0
|
int stringBias; // the first string that is the user's string number 0
|
||||||
int finale; // number of internal strings after user's last string
|
int finale; // number of internal strings after user's last string
|
||||||
|
|
||||||
|
TSourceLoc logicalSourceLoc;
|
||||||
|
bool singleLogical; // treats the strings as a single logical string.
|
||||||
|
// locations will be reported from the first string.
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace glslang
|
} // end namespace glslang
|
||||||
|
@ -131,7 +131,8 @@ bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profil
|
|||||||
TIntermediate intermediate(language, version, profile);
|
TIntermediate intermediate(language, version, profile);
|
||||||
|
|
||||||
TParseContext parseContext(symbolTable, intermediate, true, version, profile, spv, vulkan, language, infoSink);
|
TParseContext parseContext(symbolTable, intermediate, true, version, profile, spv, vulkan, language, infoSink);
|
||||||
TPpContext ppContext(parseContext, TShader::ForbidInclude());
|
TShader::ForbidInclude includer;
|
||||||
|
TPpContext ppContext(parseContext, "", includer);
|
||||||
TScanContext scanContext(parseContext);
|
TScanContext scanContext(parseContext);
|
||||||
parseContext.setScanContext(&scanContext);
|
parseContext.setScanContext(&scanContext);
|
||||||
parseContext.setPpContext(&ppContext);
|
parseContext.setPpContext(&ppContext);
|
||||||
@ -482,7 +483,7 @@ bool ProcessDeferred(
|
|||||||
TIntermediate& intermediate, // returned tree, etc.
|
TIntermediate& intermediate, // returned tree, etc.
|
||||||
ProcessingContext& processingContext,
|
ProcessingContext& processingContext,
|
||||||
bool requireNonempty,
|
bool requireNonempty,
|
||||||
const TShader::Includer& includer
|
TShader::Includer& includer
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (! InitThread())
|
if (! InitThread())
|
||||||
@ -550,7 +551,6 @@ bool ProcessDeferred(
|
|||||||
version = defaultVersion;
|
version = defaultVersion;
|
||||||
profile = defaultProfile;
|
profile = defaultProfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
int spv = (messages & EShMsgSpvRules) ? 100 : 0; // TODO find path to get real version number here, for now non-0 is what matters
|
int spv = (messages & EShMsgSpvRules) ? 100 : 0; // TODO find path to get real version number here, for now non-0 is what matters
|
||||||
bool goodVersion = DeduceVersionProfile(compiler->infoSink, compiler->getLanguage(), versionNotFirst, defaultVersion, version, profile, spv);
|
bool goodVersion = DeduceVersionProfile(compiler->infoSink, compiler->getLanguage(), versionNotFirst, defaultVersion, version, profile, spv);
|
||||||
bool versionWillBeError = (versionNotFound || (profile == EEsProfile && version >= 300 && versionNotFirst));
|
bool versionWillBeError = (versionNotFound || (profile == EEsProfile && version >= 300 && versionNotFirst));
|
||||||
@ -590,7 +590,7 @@ bool ProcessDeferred(
|
|||||||
|
|
||||||
TParseContext parseContext(symbolTable, intermediate, false, version, profile, spv, vulkan, compiler->getLanguage(), compiler->infoSink, forwardCompatible, messages);
|
TParseContext parseContext(symbolTable, intermediate, false, version, profile, spv, vulkan, compiler->getLanguage(), compiler->infoSink, forwardCompatible, messages);
|
||||||
glslang::TScanContext scanContext(parseContext);
|
glslang::TScanContext scanContext(parseContext);
|
||||||
TPpContext ppContext(parseContext, includer);
|
TPpContext ppContext(parseContext, names[numPre]? names[numPre]: "", includer);
|
||||||
parseContext.setScanContext(&scanContext);
|
parseContext.setScanContext(&scanContext);
|
||||||
parseContext.setPpContext(&ppContext);
|
parseContext.setPpContext(&ppContext);
|
||||||
parseContext.setLimits(*resources);
|
parseContext.setLimits(*resources);
|
||||||
@ -863,7 +863,7 @@ bool PreprocessDeferred(
|
|||||||
bool forceDefaultVersionAndProfile,
|
bool forceDefaultVersionAndProfile,
|
||||||
bool forwardCompatible, // give errors for use of deprecated features
|
bool forwardCompatible, // give errors for use of deprecated features
|
||||||
EShMessages messages, // warnings/errors/AST; things to print out
|
EShMessages messages, // warnings/errors/AST; things to print out
|
||||||
const TShader::Includer& includer,
|
TShader::Includer& includer,
|
||||||
TIntermediate& intermediate, // returned tree, etc.
|
TIntermediate& intermediate, // returned tree, etc.
|
||||||
std::string* outputString)
|
std::string* outputString)
|
||||||
{
|
{
|
||||||
@ -902,7 +902,7 @@ bool CompileDeferred(
|
|||||||
bool forwardCompatible, // give errors for use of deprecated features
|
bool forwardCompatible, // give errors for use of deprecated features
|
||||||
EShMessages messages, // warnings/errors/AST; things to print out
|
EShMessages messages, // warnings/errors/AST; things to print out
|
||||||
TIntermediate& intermediate,// returned tree, etc.
|
TIntermediate& intermediate,// returned tree, etc.
|
||||||
const TShader::Includer& includer)
|
TShader::Includer& includer)
|
||||||
{
|
{
|
||||||
DoFullParse parser;
|
DoFullParse parser;
|
||||||
return ProcessDeferred(compiler, shaderStrings, numStrings, inputLengths, stringNames,
|
return ProcessDeferred(compiler, shaderStrings, numStrings, inputLengths, stringNames,
|
||||||
@ -1051,9 +1051,10 @@ int ShCompile(
|
|||||||
compiler->infoSink.debug.erase();
|
compiler->infoSink.debug.erase();
|
||||||
|
|
||||||
TIntermediate intermediate(compiler->getLanguage());
|
TIntermediate intermediate(compiler->getLanguage());
|
||||||
|
TShader::ForbidInclude includer;
|
||||||
bool success = CompileDeferred(compiler, shaderStrings, numStrings, inputLengths, nullptr,
|
bool success = CompileDeferred(compiler, shaderStrings, numStrings, inputLengths, nullptr,
|
||||||
"", optLevel, resources, defaultVersion, ENoProfile, false,
|
"", optLevel, resources, defaultVersion, ENoProfile, false,
|
||||||
forwardCompatible, messages, intermediate, TShader::ForbidInclude());
|
forwardCompatible, messages, intermediate, includer);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Call the machine dependent compiler
|
// Call the machine dependent compiler
|
||||||
@ -1361,7 +1362,7 @@ void TShader::setStringsWithLengthsAndNames(
|
|||||||
// Returns true for success.
|
// Returns true for success.
|
||||||
//
|
//
|
||||||
bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
|
bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
|
||||||
bool forwardCompatible, EShMessages messages, const Includer& includer)
|
bool forwardCompatible, EShMessages messages, Includer& includer)
|
||||||
{
|
{
|
||||||
if (! InitThread())
|
if (! InitThread())
|
||||||
return false;
|
return false;
|
||||||
@ -1389,7 +1390,7 @@ bool TShader::preprocess(const TBuiltInResource* builtInResources,
|
|||||||
bool forceDefaultVersionAndProfile,
|
bool forceDefaultVersionAndProfile,
|
||||||
bool forwardCompatible, EShMessages message,
|
bool forwardCompatible, EShMessages message,
|
||||||
std::string* output_string,
|
std::string* output_string,
|
||||||
const TShader::Includer& includer)
|
Includer& includer)
|
||||||
{
|
{
|
||||||
if (! InitThread())
|
if (! InitThread())
|
||||||
return false;
|
return false;
|
||||||
|
@ -611,24 +611,28 @@ int TPpContext::CPPinclude(TPpToken* ppToken)
|
|||||||
if (token != '\n' && token != EndOfInput) {
|
if (token != '\n' && token != EndOfInput) {
|
||||||
parseContext.ppError(ppToken->loc, "extra content after file designation", "#include", "");
|
parseContext.ppError(ppToken->loc, "extra content after file designation", "#include", "");
|
||||||
} else {
|
} else {
|
||||||
auto include = includer.include(filename.c_str());
|
TShader::Includer::IncludeResult* res = includer.include(filename.c_str(), TShader::Includer::EIncludeRelative, currentSourceFile.c_str(), includeStack.size() + 1);
|
||||||
std::string sourceName = include.first;
|
if (res && !res->file_name.empty()) {
|
||||||
std::string replacement = include.second;
|
if (res->file_data && res->file_length) {
|
||||||
if (!sourceName.empty()) {
|
|
||||||
if (!replacement.empty()) {
|
|
||||||
const bool forNextLine = parseContext.lineDirectiveShouldSetNextLine();
|
const bool forNextLine = parseContext.lineDirectiveShouldSetNextLine();
|
||||||
std::ostringstream content;
|
std::ostringstream prologue;
|
||||||
content << "#line " << forNextLine << " " << "\"" << sourceName << "\"\n";
|
std::ostringstream epilogue;
|
||||||
content << replacement << (replacement.back() == '\n' ? "" : "\n");
|
prologue << "#line " << forNextLine << " " << "\"" << res->file_name << "\"\n";
|
||||||
content << "#line " << directiveLoc.line + forNextLine << " " << directiveLoc.getStringNameOrNum() << "\n";
|
epilogue << (res->file_data[res->file_length - 1] == '\n'? "" : "\n") << "#line " << directiveLoc.line + forNextLine << " " << directiveLoc.getStringNameOrNum() << "\n";
|
||||||
pushInput(new TokenizableString(directiveLoc, content.str(), this));
|
pushInput(new TokenizableIncludeFile(directiveLoc, prologue.str(), res, epilogue.str(), this));
|
||||||
}
|
}
|
||||||
// At EOF, there's no "current" location anymore.
|
// At EOF, there's no "current" location anymore.
|
||||||
if (token != EndOfInput) parseContext.setCurrentColumn(0);
|
if (token != EndOfInput) parseContext.setCurrentColumn(0);
|
||||||
// Don't accidentally return EndOfInput, which will end all preprocessing.
|
// Don't accidentally return EndOfInput, which will end all preprocessing.
|
||||||
return '\n';
|
return '\n';
|
||||||
} else {
|
} else {
|
||||||
parseContext.ppError(directiveLoc, replacement.c_str(), "#include", "");
|
std::string message =
|
||||||
|
res ? std::string(res->file_data, res->file_length)
|
||||||
|
: std::string("Could not process include directive");
|
||||||
|
parseContext.ppError(directiveLoc, message.c_str(), "#include", "");
|
||||||
|
if (res) {
|
||||||
|
includer.releaseInclude(res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,8 +83,10 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
|
|
||||||
namespace glslang {
|
namespace glslang {
|
||||||
|
|
||||||
TPpContext::TPpContext(TParseContext& pc, const TShader::Includer& inclr) :
|
TPpContext::TPpContext(TParseContext& pc, const std::string& rootFileName, TShader::Includer& inclr) :
|
||||||
preamble(0), strings(0), parseContext(pc), includer(inclr), inComment(false)
|
preamble(0), strings(0), parseContext(pc), includer(inclr), inComment(false),
|
||||||
|
rootFileName(rootFileName),
|
||||||
|
currentSourceFile(rootFileName)
|
||||||
{
|
{
|
||||||
InitAtomTable();
|
InitAtomTable();
|
||||||
InitScanner();
|
InitScanner();
|
||||||
|
@ -78,6 +78,7 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#ifndef PPCONTEXT_H
|
#ifndef PPCONTEXT_H
|
||||||
#define PPCONTEXT_H
|
#define PPCONTEXT_H
|
||||||
|
|
||||||
|
#include <stack>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "../ParseHelper.h"
|
#include "../ParseHelper.h"
|
||||||
@ -121,7 +122,7 @@ class TInputScanner;
|
|||||||
// Don't expect too much in terms of OO design.
|
// Don't expect too much in terms of OO design.
|
||||||
class TPpContext {
|
class TPpContext {
|
||||||
public:
|
public:
|
||||||
TPpContext(TParseContext&, const TShader::Includer&);
|
TPpContext(TParseContext&, const std::string& rootFileName, TShader::Includer&);
|
||||||
virtual ~TPpContext();
|
virtual ~TPpContext();
|
||||||
|
|
||||||
void setPreamble(const char* preamble, size_t length);
|
void setPreamble(const char* preamble, size_t length);
|
||||||
@ -290,7 +291,7 @@ protected:
|
|||||||
//
|
//
|
||||||
|
|
||||||
// Used to obtain #include content.
|
// Used to obtain #include content.
|
||||||
const TShader::Includer& includer;
|
TShader::Includer& includer;
|
||||||
|
|
||||||
int InitCPP();
|
int InitCPP();
|
||||||
int CPPdefine(TPpToken * ppToken);
|
int CPPdefine(TPpToken * ppToken);
|
||||||
@ -430,16 +431,30 @@ protected:
|
|||||||
TInputScanner* input;
|
TInputScanner* input;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Holds a string that can be tokenized via the tInput interface.
|
// Holds a reference to included file data, as well as a
|
||||||
class TokenizableString : public tInput {
|
// prologue and an epilogue string. This can be scanned using the tInput
|
||||||
|
// interface and acts as a single source string.
|
||||||
|
class TokenizableIncludeFile : public tInput {
|
||||||
public:
|
public:
|
||||||
// Copies str, which must be non-empty.
|
// Copies prologue and epilogue. The includedFile must remain valid
|
||||||
TokenizableString(const TSourceLoc& startLoc, const std::string& str, TPpContext* pp)
|
// until this TokenizableIncludeFile is no longer used.
|
||||||
|
TokenizableIncludeFile(const TSourceLoc& startLoc,
|
||||||
|
const std::string& prologue,
|
||||||
|
TShader::Includer::IncludeResult* includedFile,
|
||||||
|
const std::string& epilogue,
|
||||||
|
TPpContext* pp)
|
||||||
: tInput(pp),
|
: tInput(pp),
|
||||||
str_(str),
|
prologue_(prologue),
|
||||||
strings(str_.data()),
|
includedFile_(includedFile),
|
||||||
length(str_.size()),
|
epilogue_(epilogue),
|
||||||
scanner(1, &strings, &length),
|
strings({prologue_.data(), includedFile_->file_data, epilogue_.data()}),
|
||||||
|
lengths({prologue_.size(), includedFile_->file_length, epilogue_.size()}),
|
||||||
|
names({
|
||||||
|
includedFile_->file_name.c_str(),
|
||||||
|
includedFile_->file_name.c_str(),
|
||||||
|
includedFile_->file_name.c_str()
|
||||||
|
}),
|
||||||
|
scanner(3, strings, lengths, names, 0, 0, true),
|
||||||
prevScanner(nullptr),
|
prevScanner(nullptr),
|
||||||
stringInput(pp, scanner) {
|
stringInput(pp, scanner) {
|
||||||
scanner.setLine(startLoc.line);
|
scanner.setLine(startLoc.line);
|
||||||
@ -456,16 +471,34 @@ protected:
|
|||||||
{
|
{
|
||||||
prevScanner = pp->parseContext.getScanner();
|
prevScanner = pp->parseContext.getScanner();
|
||||||
pp->parseContext.setScanner(&scanner);
|
pp->parseContext.setScanner(&scanner);
|
||||||
|
pp->push_include(includedFile_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void notifyDeleted() override
|
||||||
|
{
|
||||||
|
pp->parseContext.setScanner(prevScanner);
|
||||||
|
pp->pop_include();
|
||||||
}
|
}
|
||||||
void notifyDeleted() override { pp->parseContext.setScanner(prevScanner); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Stores the titular string.
|
// Stores the prologue for this string.
|
||||||
const std::string str_;
|
const std::string prologue_;
|
||||||
// Will point to str_[0] and be passed to scanner constructor.
|
|
||||||
const char* const strings;
|
// Stores the epilogue for this string.
|
||||||
|
const std::string epilogue_;
|
||||||
|
|
||||||
|
// Points to the IncludeResult that this TokenizableIncludeFile represents.
|
||||||
|
TShader::Includer::IncludeResult* includedFile_;
|
||||||
|
|
||||||
|
// Will point to prologue_, includedFile_->file_data and epilogue_
|
||||||
|
// This is passed to scanner constructor.
|
||||||
|
// These do not own the storage and it must remain valid until this
|
||||||
|
// object has been destroyed.
|
||||||
|
const char* strings[3];
|
||||||
// Length of str_, passed to scanner constructor.
|
// Length of str_, passed to scanner constructor.
|
||||||
size_t length;
|
size_t lengths[3];
|
||||||
|
// String names
|
||||||
|
const char* names[3];
|
||||||
// Scans over str_.
|
// Scans over str_.
|
||||||
TInputScanner scanner;
|
TInputScanner scanner;
|
||||||
// The previous effective scanner before the scanner in this instance
|
// The previous effective scanner before the scanner in this instance
|
||||||
@ -480,6 +513,24 @@ protected:
|
|||||||
void missingEndifCheck();
|
void missingEndifCheck();
|
||||||
int lFloatConst(int len, int ch, TPpToken* ppToken);
|
int lFloatConst(int len, int ch, TPpToken* ppToken);
|
||||||
|
|
||||||
|
void push_include(TShader::Includer::IncludeResult* result)
|
||||||
|
{
|
||||||
|
currentSourceFile = result->file_name;
|
||||||
|
includeStack.push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_include()
|
||||||
|
{
|
||||||
|
TShader::Includer::IncludeResult* include = includeStack.top();
|
||||||
|
includeStack.pop();
|
||||||
|
includer.releaseInclude(include);
|
||||||
|
if (includeStack.empty()) {
|
||||||
|
currentSourceFile = rootFileName;
|
||||||
|
} else {
|
||||||
|
currentSourceFile = includeStack.top()->file_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool inComment;
|
bool inComment;
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -487,8 +538,12 @@ protected:
|
|||||||
//
|
//
|
||||||
typedef TUnorderedMap<TString, int> TAtomMap;
|
typedef TUnorderedMap<TString, int> TAtomMap;
|
||||||
typedef TVector<const TString*> TStringMap;
|
typedef TVector<const TString*> TStringMap;
|
||||||
|
|
||||||
TAtomMap atomMap;
|
TAtomMap atomMap;
|
||||||
TStringMap stringMap;
|
TStringMap stringMap;
|
||||||
|
std::stack<TShader::Includer::IncludeResult*> includeStack;
|
||||||
|
std::string currentSourceFile;
|
||||||
|
std::string rootFileName;
|
||||||
int nextAtom;
|
int nextAtom;
|
||||||
void InitAtomTable();
|
void InitAtomTable();
|
||||||
void AddAtomFixed(const char* s, int atom);
|
void AddAtomFixed(const char* s, int atom);
|
||||||
|
@ -292,25 +292,89 @@ public:
|
|||||||
void setPreamble(const char* s) { preamble = s; }
|
void setPreamble(const char* s) { preamble = s; }
|
||||||
|
|
||||||
// Interface to #include handlers.
|
// Interface to #include handlers.
|
||||||
|
//
|
||||||
|
// To support #include, a client of Glslang does the following:
|
||||||
|
// 1. Call setStringsWithNames to set the source strings and associated
|
||||||
|
// names. For example, the names could be the names of the files
|
||||||
|
// containing the shader sources.
|
||||||
|
// 2. Call parse with an Includer.
|
||||||
|
//
|
||||||
|
// When the Glslang parser encounters an #include directive, it calls
|
||||||
|
// the Includer's include method with the the requested include name
|
||||||
|
// together with the current string name. The returned IncludeResult
|
||||||
|
// contains the fully resolved name of the included source, together
|
||||||
|
// with the source text that should replace the #include directive
|
||||||
|
// in the source stream. After parsing that source, Glslang will
|
||||||
|
// release the IncludeResult object.
|
||||||
class Includer {
|
class Includer {
|
||||||
public:
|
public:
|
||||||
// On success, returns the full path and content of the file with the given
|
typedef enum {
|
||||||
// filename that replaces "#include filename". On failure, returns an empty
|
EIncludeRelative, // For #include "something"
|
||||||
// string and an error message.
|
EIncludeStandard // Reserved. For #include <something>
|
||||||
virtual std::pair<std::string, std::string> include(const char* filename) const = 0;
|
} IncludeType;
|
||||||
|
|
||||||
|
// An IncludeResult contains the resolved name and content of a source
|
||||||
|
// inclusion.
|
||||||
|
struct IncludeResult {
|
||||||
|
// For a successful inclusion, the fully resolved name of the requested
|
||||||
|
// include. For example, in a filesystem-based includer, full resolution
|
||||||
|
// should convert a relative path name into an absolute path name.
|
||||||
|
// For a failed inclusion, this is an empty string.
|
||||||
|
std::string file_name;
|
||||||
|
// The content and byte length of the requested inclusion. The
|
||||||
|
// Includer producing this IncludeResult retains ownership of the
|
||||||
|
// storage.
|
||||||
|
// For a failed inclusion, the file_data
|
||||||
|
// field points to a string containing error details.
|
||||||
|
const char* file_data;
|
||||||
|
const size_t file_length;
|
||||||
|
// Include resolver's context.
|
||||||
|
void* user_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Resolves an inclusion request by name, type, current source name,
|
||||||
|
// and include depth.
|
||||||
|
// On success, returns an IncludeResult containing the resolved name
|
||||||
|
// and content of the include. On failure, returns an IncludeResult
|
||||||
|
// with an empty string for the file_name and error details in the
|
||||||
|
// file_data field. The Includer retains ownership of the contents
|
||||||
|
// of the returned IncludeResult value, and those contents must
|
||||||
|
// remain valid until the releaseInclude method is called on that
|
||||||
|
// IncludeResult object.
|
||||||
|
virtual IncludeResult* include(const char* requested_source,
|
||||||
|
IncludeType type,
|
||||||
|
const char* requesting_source,
|
||||||
|
size_t inclusion_depth) = 0;
|
||||||
|
// Signals that the parser will no longer use the contents of the
|
||||||
|
// specified IncludeResult.
|
||||||
|
virtual void releaseInclude(IncludeResult* result) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns an error message for any #include directive.
|
// Returns an error message for any #include directive.
|
||||||
class ForbidInclude : public Includer {
|
class ForbidInclude : public Includer {
|
||||||
public:
|
public:
|
||||||
std::pair<std::string, std::string> include(const char* /*filename*/) const override
|
IncludeResult* include(const char*, IncludeType, const char*, size_t) override
|
||||||
{
|
{
|
||||||
return std::make_pair<std::string, std::string>("", "unexpected include directive");
|
static const char unexpected_include[] =
|
||||||
|
"unexpected include directive";
|
||||||
|
return new IncludeResult(
|
||||||
|
{"", unexpected_include, sizeof(unexpected_include) - 1, nullptr});
|
||||||
|
}
|
||||||
|
virtual void releaseInclude(IncludeResult* result) override
|
||||||
|
{
|
||||||
|
delete result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool parse(const TBuiltInResource* res, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
|
||||||
|
bool forwardCompatible, EShMessages messages)
|
||||||
|
{
|
||||||
|
TShader::ForbidInclude includer;
|
||||||
|
return parse(res, defaultVersion, defaultProfile, forceDefaultVersionAndProfile, forwardCompatible, messages, includer);
|
||||||
|
}
|
||||||
|
|
||||||
bool parse(const TBuiltInResource*, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
|
bool parse(const TBuiltInResource*, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
|
||||||
bool forwardCompatible, EShMessages, const Includer& = ForbidInclude());
|
bool forwardCompatible, EShMessages, Includer&);
|
||||||
|
|
||||||
// Equivalent to parse() without a default profile and without forcing defaults.
|
// Equivalent to parse() without a default profile and without forcing defaults.
|
||||||
// Provided for backwards compatibility.
|
// Provided for backwards compatibility.
|
||||||
@ -318,7 +382,7 @@ public:
|
|||||||
bool preprocess(const TBuiltInResource* builtInResources,
|
bool preprocess(const TBuiltInResource* builtInResources,
|
||||||
int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
|
int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
|
||||||
bool forwardCompatible, EShMessages message, std::string* outputString,
|
bool forwardCompatible, EShMessages message, std::string* outputString,
|
||||||
const TShader::Includer& includer);
|
Includer& includer);
|
||||||
|
|
||||||
const char* getInfoLog();
|
const char* getInfoLog();
|
||||||
const char* getInfoDebugLog();
|
const char* getInfoDebugLog();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user