2 * Copyright 2014 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
7 #include "gl/GrGLSLPrettyPrint.h"
9 namespace GrGLSLPrettyPrint {
11 class GLSLPrettyPrint {
15 SkString prettify(const SkString& input, bool countlines) {
18 fLength = input.size();
20 fCountlines = countlines;
27 this->lineNumbering();
28 while (fLength > fIndex) {
29 /* the heart and soul of our prettification algorithm. The rules should hopefully be
30 * self explanatory. For '#' and '//' tokens we parse until we reach a newline.
32 * For long style comments like this one, we search for the ending token. We also
33 * preserve whitespace in these comments WITH THE CAVEAT that we do the newlines
34 * ourselves. This allows us to remain in control of line numbers, and matching tabs
35 * Existing tabs in the input string are copied over too, but this will look funny
37 * '{' and '}' are handled in basically the same way. We add a newline if we aren't
38 * on a fresh line, dirty the line, then add a second newline, ie braces are always
39 * on their own lines indented properly. The one funkiness here is structs print with
40 * the semicolon on its own line. Its not a problem for a glsl compiler though
42 * '(' and ')' are basically ignored, except as a sign we need to ignore ';' ala
45 * ';' means add a new line
47 * '\t' and '\n' are ignored in general parsing for backwards compatability with
48 * existing shader code and we also have a special case for handling whitespace
49 * at the beginning of fresh lines.
51 * Otherwise just add the new character to the pretty string, indenting if necessary.
53 if (this->hasToken("#") || this->hasToken("//")) {
54 this->parseUntilNewline();
55 } else if (this->hasToken("/*")) {
56 this->parseUntil("*/");
57 } else if ('{' == fInput[fIndex]) {
59 this->appendChar('{');
62 } else if ('}' == fInput[fIndex]) {
65 this->appendChar('}');
67 } else if (this->hasToken(")")) {
69 } else if (this->hasToken("(")) {
71 } else if (!parensDepth && this->hasToken(";")) {
73 } else if ('\t' == fInput[fIndex] || '\n' == fInput[fIndex] ||
74 (fFreshline && ' ' == fInput[fIndex])) {
77 this->appendChar(input[fIndex]);
83 void appendChar(char c) {
85 fPretty.appendf("%c", fInput[fIndex++]);
89 // hasToken automatically consumes the next token, if it is a match, and then tabs
90 // if necessary, before inserting the token into the pretty string
91 bool hasToken(const char* token) {
93 for (size_t j = 0; token[j] && fLength > i; i++, j++) {
94 if (token[j] != fInput[i]) {
100 fPretty.append(token);
105 void parseUntilNewline() {
106 while (fLength > fIndex) {
107 if ('\n' == fInput[fIndex]) {
112 fPretty.appendf("%c", fInput[fIndex++]);
116 // this code assumes it is not actually searching for a newline. If you need to search for a
117 // newline, then use the function above. If you do search for a newline with this function
118 // it will consume the entire string and the output will certainly not be prettified
119 void parseUntil(const char* token) {
120 while (fLength > fIndex) {
121 // For embedded newlines, this code will make sure to embed the newline in the
122 // pretty string, increase the linecount, and tab out the next line to the appropriate
124 if ('\n' == fInput[fIndex]) {
129 if (this->hasToken(token)) {
133 fPretty.appendf("%c", fInput[fIndex++]);
137 // We only tab if on a newline, otherwise consider the line tabbed
140 for (int t = 0; t < fTabs; t++) {
141 fPretty.append("\t");
146 // newline is really a request to add a newline, if we are on a fresh line there is no reason
147 // to add another newline
151 fPretty.append("\n");
152 this->lineNumbering();
156 void lineNumbering() {
158 fPretty.appendf("%4d\t", fLinecount++);
162 bool fCountlines, fFreshline;
163 int fTabs, fLinecount;
164 size_t fIndex, fLength;
165 SkString fInput, fPretty;
168 SkString PrettyPrintGLSL(const SkString& input, bool countlines) {
170 return pp.prettify(input, countlines);