Line data Source code
1 : /*
2 : * Copyright 2014 Google Inc.
3 : *
4 : * Use of this source code is governed by a BSD-style license that can be
5 : * found in the LICENSE file.
6 : */
7 : #include "gl/GrGLSLPrettyPrint.h"
8 :
9 : namespace GrGLSLPrettyPrint {
10 :
11 0 : class GLSLPrettyPrint {
12 : public:
13 0 : GLSLPrettyPrint() {}
14 :
15 0 : SkString prettify(const char** strings,
16 : int* lengths,
17 : int count,
18 : bool countlines) {
19 0 : fCountlines = countlines;
20 0 : fTabs = 0;
21 0 : fLinecount = 1;
22 0 : fFreshline = true;
23 :
24 : // If a string breaks while in the middle 'parse until' we need to continue parsing on the
25 : // next string
26 0 : fInParseUntilNewline = false;
27 0 : fInParseUntil = false;
28 :
29 0 : int parensDepth = 0;
30 :
31 : // number 1st line
32 0 : this->lineNumbering();
33 0 : for (int i = 0; i < count; i++) {
34 : // setup pretty state
35 0 : fIndex = 0;
36 0 : fLength = lengths[i];
37 0 : fInput = strings[i];
38 :
39 0 : while (fLength > fIndex) {
40 : /* the heart and soul of our prettification algorithm. The rules should hopefully
41 : * be self explanatory. For '#' and '//' tokens we parse until we reach a newline.
42 : *
43 : * For long style comments like this one, we search for the ending token. We also
44 : * preserve whitespace in these comments WITH THE CAVEAT that we do the newlines
45 : * ourselves. This allows us to remain in control of line numbers, and matching
46 : * tabs Existing tabs in the input string are copied over too, but this will look
47 : * funny
48 : *
49 : * '{' and '}' are handled in basically the same way. We add a newline if we aren't
50 : * on a fresh line, dirty the line, then add a second newline, ie braces are always
51 : * on their own lines indented properly. The one funkiness here is structs print
52 : * with the semicolon on its own line. Its not a problem for a glsl compiler though
53 : *
54 : * '(' and ')' are basically ignored, except as a sign we need to ignore ';' ala
55 : * in for loops.
56 : *
57 : * ';' means add a new line
58 : *
59 : * '\t' and '\n' are ignored in general parsing for backwards compatability with
60 : * existing shader code and we also have a special case for handling whitespace
61 : * at the beginning of fresh lines.
62 : *
63 : * Otherwise just add the new character to the pretty string, indenting if necessary.
64 : */
65 0 : if (fInParseUntilNewline) {
66 0 : this->parseUntilNewline();
67 0 : } else if (fInParseUntil) {
68 0 : this->parseUntil(fInParseUntilToken);
69 0 : } else if (this->hasToken("#") || this->hasToken("//")) {
70 0 : this->parseUntilNewline();
71 0 : } else if (this->hasToken("/*")) {
72 0 : this->parseUntil("*/");
73 0 : } else if ('{' == fInput[fIndex]) {
74 0 : this->newline();
75 0 : this->appendChar('{');
76 0 : fTabs++;
77 0 : this->newline();
78 0 : } else if ('}' == fInput[fIndex]) {
79 0 : fTabs--;
80 0 : this->newline();
81 0 : this->appendChar('}');
82 0 : this->newline();
83 0 : } else if (this->hasToken(")")) {
84 0 : parensDepth--;
85 0 : } else if (this->hasToken("(")) {
86 0 : parensDepth++;
87 0 : } else if (!parensDepth && this->hasToken(";")) {
88 0 : this->newline();
89 0 : } else if ('\t' == fInput[fIndex] || '\n' == fInput[fIndex] ||
90 0 : (fFreshline && ' ' == fInput[fIndex])) {
91 0 : fIndex++;
92 : } else {
93 0 : this->appendChar(fInput[fIndex]);
94 : }
95 : }
96 : }
97 0 : return fPretty;
98 : }
99 : private:
100 0 : void appendChar(char c) {
101 0 : this->tabString();
102 0 : fPretty.appendf("%c", fInput[fIndex++]);
103 0 : fFreshline = false;
104 0 : }
105 :
106 : // hasToken automatically consumes the next token, if it is a match, and then tabs
107 : // if necessary, before inserting the token into the pretty string
108 0 : bool hasToken(const char* token) {
109 0 : size_t i = fIndex;
110 0 : for (size_t j = 0; token[j] && fLength > i; i++, j++) {
111 0 : if (token[j] != fInput[i]) {
112 0 : return false;
113 : }
114 : }
115 0 : this->tabString();
116 0 : fIndex = i;
117 0 : fPretty.append(token);
118 0 : fFreshline = false;
119 0 : return true;
120 : }
121 :
122 0 : void parseUntilNewline() {
123 0 : while (fLength > fIndex) {
124 0 : if ('\n' == fInput[fIndex]) {
125 0 : fIndex++;
126 0 : this->newline();
127 0 : fInParseUntilNewline = false;
128 0 : break;
129 : }
130 0 : fPretty.appendf("%c", fInput[fIndex++]);
131 0 : fInParseUntilNewline = true;
132 : }
133 0 : }
134 :
135 : // this code assumes it is not actually searching for a newline. If you need to search for a
136 : // newline, then use the function above. If you do search for a newline with this function
137 : // it will consume the entire string and the output will certainly not be prettified
138 0 : void parseUntil(const char* token) {
139 0 : while (fLength > fIndex) {
140 : // For embedded newlines, this code will make sure to embed the newline in the
141 : // pretty string, increase the linecount, and tab out the next line to the appropriate
142 : // place
143 0 : if ('\n' == fInput[fIndex]) {
144 0 : this->newline();
145 0 : this->tabString();
146 0 : fIndex++;
147 : }
148 0 : if (this->hasToken(token)) {
149 0 : fInParseUntil = false;
150 0 : break;
151 : }
152 0 : fFreshline = false;
153 0 : fPretty.appendf("%c", fInput[fIndex++]);
154 0 : fInParseUntil = true;
155 0 : fInParseUntilToken = token;
156 : }
157 0 : }
158 :
159 : // We only tab if on a newline, otherwise consider the line tabbed
160 0 : void tabString() {
161 0 : if (fFreshline) {
162 0 : for (int t = 0; t < fTabs; t++) {
163 0 : fPretty.append("\t");
164 : }
165 : }
166 0 : }
167 :
168 : // newline is really a request to add a newline, if we are on a fresh line there is no reason
169 : // to add another newline
170 0 : void newline() {
171 0 : if (!fFreshline) {
172 0 : fFreshline = true;
173 0 : fPretty.append("\n");
174 0 : this->lineNumbering();
175 : }
176 0 : }
177 :
178 0 : void lineNumbering() {
179 0 : if (fCountlines) {
180 0 : fPretty.appendf("%4d\t", fLinecount++);
181 : }
182 0 : }
183 :
184 : bool fCountlines, fFreshline;
185 : int fTabs, fLinecount;
186 : size_t fIndex, fLength;
187 : const char* fInput;
188 : SkString fPretty;
189 :
190 : // Some helpers for parseUntil when we go over a string length
191 : bool fInParseUntilNewline;
192 : bool fInParseUntil;
193 : const char* fInParseUntilToken;
194 : };
195 :
196 0 : SkString PrettyPrintGLSL(const char** strings,
197 : int* lengths,
198 : int count,
199 : bool countlines) {
200 0 : GLSLPrettyPrint pp;
201 0 : return pp.prettify(strings, lengths, count, countlines);
202 : }
203 :
204 : } // end namespace
|