Merge pull request #38 from google/preprocessing-line-number
Preprocessing line number handling
This commit is contained in:
		
						commit
						b159bd5821
					
				@ -599,6 +599,67 @@ bool ProcessDeferred(
 | 
				
			|||||||
    return success;
 | 
					    return success;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Responsible for keeping track of the most recent source string and line in
 | 
				
			||||||
 | 
					// the preprocessor and outputting newlines appropriately if the source string
 | 
				
			||||||
 | 
					// or line changes.
 | 
				
			||||||
 | 
					class SourceLineSynchronizer {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    SourceLineSynchronizer(const std::function<int()>& lastSourceIndex,
 | 
				
			||||||
 | 
					                           std::stringstream* output)
 | 
				
			||||||
 | 
					      : getLastSourceIndex(lastSourceIndex), output(output) {}
 | 
				
			||||||
 | 
					    SourceLineSynchronizer(const SourceLineSynchronizer&) = delete;
 | 
				
			||||||
 | 
					    SourceLineSynchronizer& operator=(const SourceLineSynchronizer&) = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Sets the internally tracked source string index to that of the most
 | 
				
			||||||
 | 
					    // recently read token. If we switched to a new source string, returns
 | 
				
			||||||
 | 
					    // true and inserts a newline. Otherwise, returns false and outputs nothing.
 | 
				
			||||||
 | 
					    bool syncToMostRecentString() {
 | 
				
			||||||
 | 
					        if (getLastSourceIndex() != lastSource) {
 | 
				
			||||||
 | 
					            // After switching to a new source string, we need to reset lastLine
 | 
				
			||||||
 | 
					            // because line number resets every time a new source string is
 | 
				
			||||||
 | 
					            // used. We also need to output a newline to separate the output
 | 
				
			||||||
 | 
					            // from the previous source string (if there is one).
 | 
				
			||||||
 | 
					            if (lastSource != -1 || lastLine != 0)
 | 
				
			||||||
 | 
					                *output << std::endl;
 | 
				
			||||||
 | 
					            lastSource = getLastSourceIndex();
 | 
				
			||||||
 | 
					            lastLine = -1;
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Calls syncToMostRecentString() and then sets the internally tracked line
 | 
				
			||||||
 | 
					    // number to tokenLine. If we switched to a new line, returns true and inserts
 | 
				
			||||||
 | 
					    // newlines appropriately. Otherwise, returns false and outputs nothing.
 | 
				
			||||||
 | 
					    bool syncToLine(int tokenLine) {
 | 
				
			||||||
 | 
					        syncToMostRecentString();
 | 
				
			||||||
 | 
					        const bool newLineStarted = lastLine < tokenLine;
 | 
				
			||||||
 | 
					        for (; lastLine < tokenLine; ++lastLine) {
 | 
				
			||||||
 | 
					            if (lastLine > 0) *output << std::endl;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return newLineStarted;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Sets the internally tracked line number to newLineNum.
 | 
				
			||||||
 | 
					    void setLineNum(int newLineNum) { lastLine = newLineNum; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    // A function for getting the index of the last valid source string we've
 | 
				
			||||||
 | 
					    // read tokens from.
 | 
				
			||||||
 | 
					    const std::function<int()> getLastSourceIndex;
 | 
				
			||||||
 | 
					    // output stream for newlines.
 | 
				
			||||||
 | 
					    std::stringstream* output;
 | 
				
			||||||
 | 
					    // lastSource is the source string index (starting from 0) of the last token
 | 
				
			||||||
 | 
					    // processed. It is tracked in order for newlines to be inserted when a new
 | 
				
			||||||
 | 
					    // source string starts. -1 means we haven't started processing any source
 | 
				
			||||||
 | 
					    // string.
 | 
				
			||||||
 | 
					    int lastSource = -1;
 | 
				
			||||||
 | 
					    // 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 +676,77 @@ 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(
 | 
				
			||||||
        auto adjustLine = [&lastLine, &outputStream](int line) {
 | 
					            std::bind(&TInputScanner::getLastValidSourceIndex, &input), &outputStream);
 | 
				
			||||||
            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 isNewString = lineSync.syncToMostRecentString();
 | 
				
			||||||
            bool newLine = false;
 | 
					            bool isNewLine = lineSync.syncToLine(token.loc.line);
 | 
				
			||||||
            while (lastLine < tokenLine) {
 | 
					
 | 
				
			||||||
                if (lastLine > -1) {
 | 
					            if (isNewLine) {
 | 
				
			||||||
                    outputStream << std::endl;
 | 
					 | 
				
			||||||
                    newLine = true;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                ++lastLine;
 | 
					 | 
				
			||||||
                if (lastLine == tokenLine) {
 | 
					 | 
				
			||||||
                // Don't emit whitespace onto empty lines.
 | 
					                // Don't emit whitespace onto empty lines.
 | 
				
			||||||
                // Copy any whitespace characters at the start of a line
 | 
					                // Copy any whitespace characters at the start of a line
 | 
				
			||||||
                // from the input to the output.
 | 
					                // from the input to the output.
 | 
				
			||||||
                    for(int i = 0; i < token.loc.column - 1; ++i) {
 | 
					                outputStream << std::string(token.loc.column - 1, ' ');
 | 
				
			||||||
                        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 (!isNewString && !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