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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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,
 | 
			
		||||
// which only performs the preprocessing step of compilation.
 | 
			
		||||
@ -615,99 +676,77 @@ struct DoPreprocessing {
 | 
			
		||||
        static const std::string noSpaceBeforeTokens = ",";
 | 
			
		||||
        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);
 | 
			
		||||
        ppContext.setInput(input, versionWillBeError);
 | 
			
		||||
 | 
			
		||||
        // Inserts newlines and incremnets lastLine until
 | 
			
		||||
        // lastLine >= line.
 | 
			
		||||
        auto adjustLine = [&lastLine, &outputStream](int line) {
 | 
			
		||||
            int tokenLine = line - 1;
 | 
			
		||||
            while(lastLine < tokenLine) {
 | 
			
		||||
                if (lastLine >= 0) {
 | 
			
		||||
                     outputStream << std::endl;
 | 
			
		||||
                }
 | 
			
		||||
                ++lastLine;
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        std::stringstream outputStream;
 | 
			
		||||
        SourceLineSynchronizer lineSync(
 | 
			
		||||
            std::bind(&TInputScanner::getLastValidSourceIndex, &input), &outputStream);
 | 
			
		||||
 | 
			
		||||
        parseContext.setExtensionCallback([&adjustLine, &outputStream](
 | 
			
		||||
        parseContext.setExtensionCallback([&lineSync, &outputStream](
 | 
			
		||||
            int line, const char* extension, const char* behavior) {
 | 
			
		||||
                adjustLine(line);
 | 
			
		||||
                lineSync.syncToLine(line);
 | 
			
		||||
                outputStream << "#extension " << extension << " : " << behavior;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        parseContext.setLineCallback([&adjustLine, &lastLine, &outputStream, &parseContext](
 | 
			
		||||
            int curLineNo, int newLineNo, bool hasSource, int sourceNum) {
 | 
			
		||||
        parseContext.setLineCallback([&lineSync, &outputStream, &parseContext](
 | 
			
		||||
            int curLineNum, int newLineNum, bool hasSource, int sourceNum) {
 | 
			
		||||
            // SourceNum is the number of the source-string that is being parsed.
 | 
			
		||||
            adjustLine(curLineNo);
 | 
			
		||||
            outputStream << "#line " << newLineNo;
 | 
			
		||||
            lineSync.syncToLine(curLineNum);
 | 
			
		||||
            outputStream << "#line " << newLineNum;
 | 
			
		||||
            if (hasSource) {
 | 
			
		||||
                outputStream << " " << sourceNum;
 | 
			
		||||
            }
 | 
			
		||||
            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
 | 
			
		||||
                newLineNo -= 1;
 | 
			
		||||
                newLineNum -= 1;
 | 
			
		||||
            }
 | 
			
		||||
            outputStream << std::endl;
 | 
			
		||||
            // Line number starts from 1. And we are at the next line of the #line
 | 
			
		||||
            // directive now. So lastLine (from 0) should be (newLineNo - 1) + 1.
 | 
			
		||||
            lastLine = newLineNo;
 | 
			
		||||
            // And we are at the next line of the #line directive now.
 | 
			
		||||
            lineSync.setLineNum(newLineNum + 1);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        parseContext.setVersionCallback(
 | 
			
		||||
            [&adjustLine, &outputStream](int line, int version, const char* str) {
 | 
			
		||||
                adjustLine(line);
 | 
			
		||||
            [&lineSync, &outputStream](int line, int version, const char* str) {
 | 
			
		||||
                lineSync.syncToLine(line);
 | 
			
		||||
                outputStream << "#version " << version;
 | 
			
		||||
                if (str) {
 | 
			
		||||
                    outputStream << " " << str;
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        parseContext.setPragmaCallback([&adjustLine, &outputStream](
 | 
			
		||||
        parseContext.setPragmaCallback([&lineSync, &outputStream](
 | 
			
		||||
            int line, const glslang::TVector<glslang::TString>& ops) {
 | 
			
		||||
                adjustLine(line);
 | 
			
		||||
                lineSync.syncToLine(line);
 | 
			
		||||
                outputStream << "#pragma ";
 | 
			
		||||
                for(size_t i = 0; i < ops.size(); ++i) {
 | 
			
		||||
                    outputStream << ops[i];
 | 
			
		||||
                }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        parseContext.setErrorCallback([&adjustLine, &outputStream](
 | 
			
		||||
        parseContext.setErrorCallback([&lineSync, &outputStream](
 | 
			
		||||
            int line, const char* errorMessage) {
 | 
			
		||||
                adjustLine(line);
 | 
			
		||||
                lineSync.syncToLine(line);
 | 
			
		||||
                outputStream << "#error " << errorMessage;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        int lastToken = EOF; // lastToken records the last token processed.
 | 
			
		||||
        while (const char* tok = ppContext.tokenize(&token)) {
 | 
			
		||||
            int tokenLine = token.loc.line - 1;  // start at 0;
 | 
			
		||||
            bool newLine = false;
 | 
			
		||||
            while (lastLine < tokenLine) {
 | 
			
		||||
                if (lastLine > -1) {
 | 
			
		||||
                    outputStream << std::endl;
 | 
			
		||||
                    newLine = true;
 | 
			
		||||
                }
 | 
			
		||||
                ++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 << " ";
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            bool isNewString = lineSync.syncToMostRecentString();
 | 
			
		||||
            bool isNewLine = lineSync.syncToLine(token.loc.line);
 | 
			
		||||
 | 
			
		||||
            if (isNewLine) {
 | 
			
		||||
                // Don't emit whitespace onto empty lines.
 | 
			
		||||
                // Copy any whitespace characters at the start of a line
 | 
			
		||||
                // from the input to the output.
 | 
			
		||||
                outputStream << std::string(token.loc.column - 1, ' ');
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // 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 consistency.
 | 
			
		||||
            if (!newLine &&
 | 
			
		||||
                lastToken != -1 &&
 | 
			
		||||
            if (!isNewString && !isNewLine && lastToken != -1 &&
 | 
			
		||||
                (unNeededSpaceTokens.find((char)token.token) == std::string::npos) &&
 | 
			
		||||
                (unNeededSpaceTokens.find((char)lastToken) == std::string::npos) &&
 | 
			
		||||
                (noSpaceBeforeTokens.find((char)token.token) == std::string::npos)) {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user