Chromium Code Reviews| Index: src/gpu/gl/GrGLSLPrettyPrint.cpp |
| diff --git a/src/gpu/gl/GrGLSLPrettyPrint.cpp b/src/gpu/gl/GrGLSLPrettyPrint.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..52dc0f6b9a7aaf449eabf936fe66ee7a6e13e315 |
| --- /dev/null |
| +++ b/src/gpu/gl/GrGLSLPrettyPrint.cpp |
| @@ -0,0 +1,174 @@ |
| +/* |
| + * Copyright 2014 Google Inc. |
| + * |
| + * Use of this source code is governed by a BSD-style license that can be |
| + * found in the LICENSE file. |
| + */ |
| +#include "gl/GrGLSLPrettyPrint.h" |
| + |
| +namespace GrGLSLPrettyPrint { |
| + |
| +class GrGLSLPrettyPrint { |
|
bsalomon
2014/08/04 15:20:01
For classes that are private to a particular trans
|
| +public: |
| + GrGLSLPrettyPrint() {} |
| + |
| + SkString prettify(const SkString& input, bool countlines) { |
| + // setup pretty state |
| + fIndex = 0; |
| + fLength = input.size(); |
| + fInput = input; |
| + fCountlines = countlines; |
| + fTabs = 0; |
| + fLinecount = 1; |
| + fFreshline = true; |
| + |
| + int parensDepth = 0; |
| + // number 1st line |
| + lineNumbering(); |
| + while (fLength > fIndex) { |
| + /* the heart and soul of our prettification algorithm. The rules should hopefully be |
| + * self explanatory. For '#' and '//' tokens we parse until we reach a newline. |
| + * |
| + * For long style comments like this one, we search for the ending token. We also |
| + * preserve whitespace in these comments WITH THE CAVEAT that we do the newlines |
| + * ourselves. This allows us to remain in control of line numbers, and matching tabs |
| + * Existing tabs in the input string are copied over too, but this will look funny |
| + * |
| + * '{' and '}' are handled in basically the same way. We add a newline if we aren't |
| + * on a fresh line, dirty the line, then add a second newline, ie braces are always |
| + * on their own lines indented properly. The one funkiness here is structs print with |
| + * the semicolon on its own line. Its not a problem for a glsl compiler though |
| + * |
| + * '(' and ')' are basically ignored, except as a sign we need to ignore ';' ala |
| + * in for loops. |
| + * |
| + * ';' means add a new line |
| + * |
| + * '\t' and '\n' are ignored in general parsing for backwards compatability with |
| + * existing shader code and we also have a special case for handling whitespace |
| + * at the beginning of fresh lines. |
| + * |
| + * Otherwise just add the new character to the pretty string, indenting if necessary. |
| + */ |
| + if (hasToken("#") || hasToken("//")) { |
|
Stephen White
2014/08/04 15:10:29
I guess ad hoc parsing is ok for this, since we kn
bsalomon
2014/08/04 15:20:01
Part of the advantage of having a separate functio
|
| + parseUntilNewline(); |
| + } else if (hasToken("/*")) { |
|
bsalomon
2014/08/04 15:20:01
minor style nit: this->hasToken() (and similar in
|
| + parseUntil("*/"); |
| + } else if ('{' == fInput[fIndex]) { |
| + newline(); |
| + appendChar('{'); |
| + fTabs++; |
| + newline(); |
| + } else if ('}' == fInput[fIndex]) { |
| + fTabs--; |
| + newline(); |
| + appendChar('}'); |
| + newline(); |
| + } else if (hasToken(")")) { |
| + parensDepth--; |
| + } else if (hasToken("(")) { |
| + parensDepth++; |
| + } else if (!parensDepth && hasToken(";")) { |
| + newline(); |
| + } else if ('\t' == fInput[fIndex] || '\n' == fInput[fIndex] || |
| + (fFreshline && ' ' == fInput[fIndex])) { |
| + fIndex++; |
| + continue; |
| + } else { |
| + appendChar(input[fIndex]); |
| + } |
| + } |
| + return fPretty; |
| + } |
| +private: |
| + void appendChar(char c) { |
| + tabString(); |
| + fPretty.appendf("%c", fInput[fIndex++]); |
| + fFreshline = false; |
| + } |
| + |
| + // hasToken automatically consumes the next token, if it is a match, and then tabs |
| + // if necessary, before inserting the token into the pretty string |
| + bool hasToken(const char* token) { |
| + size_t i = fIndex; |
| + for (size_t j = 0; token[j] && fLength > i; i++, j++) { |
| + if (token[j] != fInput[i]) { |
| + return false; |
| + } |
| + } |
| + tabString(); |
| + fIndex = i; |
| + fPretty.append(token); |
| + fFreshline = false; |
| + return true; |
| + } |
| + |
| + void parseUntilNewline() { |
| + while (fLength > fIndex) { |
| + if ('\n' == fInput[fIndex]) { |
| + fIndex++; |
| + newline(); |
| + break; |
| + } |
| + fPretty.appendf("%c", fInput[fIndex++]); |
| + } |
| + } |
| + |
| + // this code assumes it is not actually searching for a newline. If you need to search for a |
| + // newline, then use the function above. If you do search for a newline with this function |
| + // it will consume the entire string and the output will certainly not be prettified |
| + void parseUntil(const char* token) { |
| + while (fLength > fIndex) { |
| + // For embedded newlines, this code will make sure to embed the newline in the |
| + // pretty string, increase the linecount, and tab out the next line to the appropriate |
| + // place |
| + if ('\n' == fInput[fIndex]) { |
| + newline(); |
| + tabString(); |
| + fIndex++; |
| + } |
| + if (hasToken(token)) { |
| + break; |
| + } |
| + fFreshline = false; |
| + fPretty.appendf("%c", fInput[fIndex++]); |
| + } |
| + } |
| + |
| + // We only tab if on a newline, otherwise consider the line tabbed |
| + void tabString() { |
| + if (fFreshline) { |
| + for (int t = 0; t < fTabs; t++) { |
| + fPretty.append("\t"); |
| + } |
| + } |
| + } |
| + |
| + // newline is really a request to add a newline, if we are on a fresh line there is no reason |
| + // to add another newline |
| + void newline() { |
| + if (!fFreshline) { |
| + fFreshline = true; |
| + fPretty.append("\n"); |
| + lineNumbering(); |
| + } |
| + } |
| + |
| + void lineNumbering() { |
| + if (fCountlines) { |
| + fPretty.appendf("%4d\t", fLinecount++); |
| + } |
| + } |
| + |
| + bool fCountlines, fFreshline, fRequestNewline; |
| + int fTabs, fLinecount; |
| + size_t fIndex, fLength; |
| + SkString fInput, fPretty; |
| +}; |
| + |
| +SkString PrettyPrintGLSL(const SkString& input, bool countlines) { |
| + GrGLSLPrettyPrint pp; |
| + return pp.prettify(input, countlines); |
| +} |
| + |
| +} // end namespace |