Create a new class to keep track of line number in preprocessor.
SourceLineSynchronizer is added for keeping track of the last line number and output newlines appropriately if we switch to a new line in the preprocessor.
This commit is contained in:
parent
62aa5bdfca
commit
d67e15e9b4
@ -599,6 +599,36 @@ bool ProcessDeferred(
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Responsible for keeping track of the most recent line in the preprocessor
|
||||||
|
// and outputting newlines appropriately if the line changes.
|
||||||
|
class SourceLineSynchronizer {
|
||||||
|
public:
|
||||||
|
SourceLineSynchronizer(std::stringstream* output) : output(output) {}
|
||||||
|
SourceLineSynchronizer(const SourceLineSynchronizer&) = delete;
|
||||||
|
SourceLineSynchronizer& operator=(const SourceLineSynchronizer&) = delete;
|
||||||
|
|
||||||
|
// If we switched to a new line, returns true and inserts newlines
|
||||||
|
// appropriately. Otherwise, returns false and outputs nothing.
|
||||||
|
bool syncToLine(int tokenLine) {
|
||||||
|
const bool newLineStarted = lastLine < tokenLine;
|
||||||
|
for (; lastLine < tokenLine; ++lastLine) {
|
||||||
|
if (lastLine > 0) *output << std::endl;
|
||||||
|
}
|
||||||
|
return newLineStarted;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the line number of the most recent line to newLineNum.
|
||||||
|
void setLineNum(int newLineNum) { lastLine = newLineNum; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// output stream for newlines.
|
||||||
|
std::stringstream* output;
|
||||||
|
// lastLine is the line number (starting from 1) of the last token processed.
|
||||||
|
// It is tracked in order for newlines to be inserted when a token appears
|
||||||
|
// on a new line. 0 means we haven't started processing any line in the
|
||||||
|
// current source string.
|
||||||
|
int lastLine = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// DoPreprocessing is a valid ProcessingContext template argument,
|
// DoPreprocessing is a valid ProcessingContext template argument,
|
||||||
// which only performs the preprocessing step of compilation.
|
// which only performs the preprocessing step of compilation.
|
||||||
@ -615,99 +645,75 @@ struct DoPreprocessing {
|
|||||||
static const std::string noSpaceBeforeTokens = ",";
|
static const std::string noSpaceBeforeTokens = ",";
|
||||||
glslang::TPpToken token;
|
glslang::TPpToken token;
|
||||||
|
|
||||||
std::stringstream outputStream;
|
|
||||||
int lastLine = -1; // lastLine is the line number of the last token
|
|
||||||
// processed. It is tracked in order for new-lines to be inserted when
|
|
||||||
// a token appears on a new line.
|
|
||||||
int lastToken = -1;
|
|
||||||
parseContext.setScanner(&input);
|
parseContext.setScanner(&input);
|
||||||
ppContext.setInput(input, versionWillBeError);
|
ppContext.setInput(input, versionWillBeError);
|
||||||
|
|
||||||
// Inserts newlines and incremnets lastLine until
|
std::stringstream outputStream;
|
||||||
// lastLine >= line.
|
SourceLineSynchronizer lineSync(&outputStream);
|
||||||
auto adjustLine = [&lastLine, &outputStream](int line) {
|
|
||||||
int tokenLine = line - 1;
|
|
||||||
while(lastLine < tokenLine) {
|
|
||||||
if (lastLine >= 0) {
|
|
||||||
outputStream << std::endl;
|
|
||||||
}
|
|
||||||
++lastLine;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
parseContext.setExtensionCallback([&adjustLine, &outputStream](
|
parseContext.setExtensionCallback([&lineSync, &outputStream](
|
||||||
int line, const char* extension, const char* behavior) {
|
int line, const char* extension, const char* behavior) {
|
||||||
adjustLine(line);
|
lineSync.syncToLine(line);
|
||||||
outputStream << "#extension " << extension << " : " << behavior;
|
outputStream << "#extension " << extension << " : " << behavior;
|
||||||
});
|
});
|
||||||
|
|
||||||
parseContext.setLineCallback([&adjustLine, &lastLine, &outputStream, &parseContext](
|
parseContext.setLineCallback([&lineSync, &outputStream, &parseContext](
|
||||||
int curLineNo, int newLineNo, bool hasSource, int sourceNum) {
|
int curLineNum, int newLineNum, bool hasSource, int sourceNum) {
|
||||||
// SourceNum is the number of the source-string that is being parsed.
|
// SourceNum is the number of the source-string that is being parsed.
|
||||||
adjustLine(curLineNo);
|
lineSync.syncToLine(curLineNum);
|
||||||
outputStream << "#line " << newLineNo;
|
outputStream << "#line " << newLineNum;
|
||||||
if (hasSource) {
|
if (hasSource) {
|
||||||
outputStream << " " << sourceNum;
|
outputStream << " " << sourceNum;
|
||||||
}
|
}
|
||||||
if (parseContext.lineDirectiveShouldSetNextLine()) {
|
if (parseContext.lineDirectiveShouldSetNextLine()) {
|
||||||
// newLineNo is the new line number for the line following the #line
|
// newLineNum is the new line number for the line following the #line
|
||||||
// directive. So the new line number for the current line is
|
// directive. So the new line number for the current line is
|
||||||
newLineNo -= 1;
|
newLineNum -= 1;
|
||||||
}
|
}
|
||||||
outputStream << std::endl;
|
outputStream << std::endl;
|
||||||
// Line number starts from 1. And we are at the next line of the #line
|
// And we are at the next line of the #line directive now.
|
||||||
// directive now. So lastLine (from 0) should be (newLineNo - 1) + 1.
|
lineSync.setLineNum(newLineNum + 1);
|
||||||
lastLine = newLineNo;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
parseContext.setVersionCallback(
|
parseContext.setVersionCallback(
|
||||||
[&adjustLine, &outputStream](int line, int version, const char* str) {
|
[&lineSync, &outputStream](int line, int version, const char* str) {
|
||||||
adjustLine(line);
|
lineSync.syncToLine(line);
|
||||||
outputStream << "#version " << version;
|
outputStream << "#version " << version;
|
||||||
if (str) {
|
if (str) {
|
||||||
outputStream << " " << str;
|
outputStream << " " << str;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
parseContext.setPragmaCallback([&adjustLine, &outputStream](
|
parseContext.setPragmaCallback([&lineSync, &outputStream](
|
||||||
int line, const glslang::TVector<glslang::TString>& ops) {
|
int line, const glslang::TVector<glslang::TString>& ops) {
|
||||||
adjustLine(line);
|
lineSync.syncToLine(line);
|
||||||
outputStream << "#pragma ";
|
outputStream << "#pragma ";
|
||||||
for(size_t i = 0; i < ops.size(); ++i) {
|
for(size_t i = 0; i < ops.size(); ++i) {
|
||||||
outputStream << ops[i];
|
outputStream << ops[i];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
parseContext.setErrorCallback([&adjustLine, &outputStream](
|
parseContext.setErrorCallback([&lineSync, &outputStream](
|
||||||
int line, const char* errorMessage) {
|
int line, const char* errorMessage) {
|
||||||
adjustLine(line);
|
lineSync.syncToLine(line);
|
||||||
outputStream << "#error " << errorMessage;
|
outputStream << "#error " << errorMessage;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
int lastToken = EOF; // lastToken records the last token processed.
|
||||||
while (const char* tok = ppContext.tokenize(&token)) {
|
while (const char* tok = ppContext.tokenize(&token)) {
|
||||||
int tokenLine = token.loc.line - 1; // start at 0;
|
bool isNewLine = lineSync.syncToLine(token.loc.line);
|
||||||
bool newLine = false;
|
|
||||||
while (lastLine < tokenLine) {
|
if (isNewLine) {
|
||||||
if (lastLine > -1) {
|
// Don't emit whitespace onto empty lines.
|
||||||
outputStream << std::endl;
|
// Copy any whitespace characters at the start of a line
|
||||||
newLine = true;
|
// from the input to the output.
|
||||||
}
|
outputStream << std::string(token.loc.column - 1, ' ');
|
||||||
++lastLine;
|
|
||||||
if (lastLine == tokenLine) {
|
|
||||||
// Don't emit whitespace onto empty lines.
|
|
||||||
// Copy any whitespace characters at the start of a line
|
|
||||||
// from the input to the output.
|
|
||||||
for(int i = 0; i < token.loc.column - 1; ++i) {
|
|
||||||
outputStream << " ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output a space in between tokens, but not at the start of a line,
|
// Output a space in between tokens, but not at the start of a line,
|
||||||
// and also not around special tokens. This helps with readability
|
// and also not around special tokens. This helps with readability
|
||||||
// and consistency.
|
// and consistency.
|
||||||
if (!newLine &&
|
if (!isNewLine && lastToken != -1 &&
|
||||||
lastToken != -1 &&
|
|
||||||
(unNeededSpaceTokens.find((char)token.token) == std::string::npos) &&
|
(unNeededSpaceTokens.find((char)token.token) == std::string::npos) &&
|
||||||
(unNeededSpaceTokens.find((char)lastToken) == std::string::npos) &&
|
(unNeededSpaceTokens.find((char)lastToken) == std::string::npos) &&
|
||||||
(noSpaceBeforeTokens.find((char)token.token) == std::string::npos)) {
|
(noSpaceBeforeTokens.find((char)token.token) == std::string::npos)) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user