1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program Random Shader Generator
3 * ----------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Shader Source Formatter.
22 *//*--------------------------------------------------------------------*/
23
24 #include "rsgPrettyPrinter.hpp"
25 #include "deStringUtil.hpp"
26
27 namespace rsg
28 {
29
30 static const char* s_tokenStr[] =
31 {
32 DE_NULL, // IDENTIFIER,
33 "struct", // STRUCT,
34 "invariant", // INVARIANT,
35 "precision", // PRECISION,
36 "void", // VOID,
37 "break", // BREAK,
38 "continue", // CONTINUE,
39 "do ", // DO,
40 "while ", // WHILE,
41 "else ", // ELSE,
42 "for ", // FOR,
43 "if ", // IF,
44 "discard", // DISCARD,
45 "return ", // RETURN,
46 "++", // INC_OP,
47 "--", // DEC_OP,
48 "(", // LEFT_PAREN,
49 ")", // RIGHT_PAREN,
50 "[", // LEFT_BRACKET,
51 "]", // RIGHT_BRACKET,
52 "{", // LEFT_BRACE,
53 "}", // RIGHT_BRACE,
54 ".", // DOT,
55 ", ", // COMMA,
56 " : ", // COLON,
57 ";", // SEMICOLON,
58 " - ", // MINUS,
59 " + ", // PLUS,
60 " * ", // MUL,
61 " / ", // DIV,
62 " % ", // MOD,
63 " ? ", // QUESTION,
64 "bool", // BOOL,
65 "bvec2", // BVEC2,
66 "bvec3", // BVEC3,
67 "bvec4", // BVEC4,
68 "int", // INT,
69 "ivec2", // IVEC2,
70 "ivec3", // IVEC3,
71 "ivec4", // IVEC4,
72 "float", // FLOAT,
73 "vec2", // VEC2,
74 "vec3", // VEC3,
75 "vec4", // VEC4,
76 "mat2", // MAT2,
77 "mat3", // MAT3,
78 "mat4", // MAT4,
79 "sampler2D", // SAMPLER2D,
80 "samplerCube", // SAMPLERCUBE,
81 DE_NULL, // FLOAT_LITERAL,
82 DE_NULL, // INT_LITERAL,
83 DE_NULL, // BOOL_LITERAL,
84 " = ", // EQUAL,
85 " *= ", // MUL_ASSIGN,
86 " /= ", // DIV_ASSIGN,
87 " += ", // ADD_ASSIGN,
88 " -= ", // SUB_ASSIGN,
89 " < ", // CMP_LT,
90 " > ", // CMP_GT,
91 " <= ", // CMP_LE,
92 " >= ", // CMP_GE,
93 " == ", // CMP_EQ,
94 " != ", // CMP_NE,
95 " && ", // LOGICAL_AND,
96 " || ", // LOGICAL_OR,
97 "!", // LOGICAL_NOT,
98 " ^^ ", // LOGICAL_XOR,
99 "attribute", // ATTRIBUTE,
100 "uniform", // UNIFORM,
101 "varying", // VARYING,
102 "const", // CONST,
103 "flat", // FLAT,
104 "highp", // HIGH_PRECISION,
105 "mediump", // MEDIUM_PRECISION,
106 "lowp", // LOW_PRECISION,
107 "in", // IN,
108 "out", // OUT,
109 "inout", // INOUT,
110 "layout", // LAYOUT,
111 "location", // LOCATION,
112 DE_NULL, // INDENT_INC,
113 DE_NULL, // INDENT_DEC,
114 "\n" // NEWLINE,
115 };
116
PrettyPrinter(std::ostringstream & str)117 PrettyPrinter::PrettyPrinter (std::ostringstream& str)
118 : m_str (str)
119 , m_indentDepth (0)
120 {
121 }
122
getSimpleTokenStr(Token::Type token)123 inline const char* PrettyPrinter::getSimpleTokenStr (Token::Type token)
124 {
125 DE_ASSERT(de::inBounds<int>(token, 0, (int)DE_LENGTH_OF_ARRAY(s_tokenStr)));
126 return s_tokenStr[token];
127 }
128
append(const TokenStream & tokens)129 void PrettyPrinter::append (const TokenStream& tokens)
130 {
131 for (int ndx = 0; ndx < tokens.getSize(); ndx++)
132 processToken(tokens[ndx]);
133 }
134
isIdentifierChar(char c)135 inline bool isIdentifierChar (char c)
136 {
137 return de::inRange(c, 'a', 'z') || de::inRange(c, 'A', 'Z') || de::inRange(c, '0', '9') || c == '_';
138 }
139
processToken(const Token & token)140 void PrettyPrinter::processToken (const Token& token)
141 {
142 bool prevIsIdentifierChar = m_line.length() > 0 && isIdentifierChar(m_line[m_line.length()-1]);
143
144 switch (token.getType())
145 {
146 case Token::IDENTIFIER:
147 if (prevIsIdentifierChar)
148 m_line += " ";
149 m_line += token.getIdentifier();
150 break;
151
152 case Token::FLOAT_LITERAL:
153 {
154 std::string f = de::toString(token.getFloat());
155 if (f.find('.') == std::string::npos)
156 f += ".0"; // Make sure value parses as float
157 m_line += f;
158 break;
159 }
160
161 case Token::INT_LITERAL:
162 m_line += de::toString(token.getInt());
163 break;
164
165 case Token::BOOL_LITERAL:
166 m_line += (token.getBool() ? "true" : "false");
167 break;
168
169 case Token::INDENT_INC:
170 m_indentDepth += 1;
171 break;
172
173 case Token::INDENT_DEC:
174 m_indentDepth -= 1;
175 break;
176
177 case Token::NEWLINE:
178 // Indent
179 for (int i = 0; i < m_indentDepth; i++)
180 m_str << "\t";
181
182 // Flush line to source
183 m_str << m_line + "\n";
184 m_line = "";
185 break;
186
187 default:
188 {
189 const char* tokenStr = getSimpleTokenStr(token.getType());
190 if (prevIsIdentifierChar && isIdentifierChar(tokenStr[0]))
191 m_line += " ";
192 m_line += tokenStr;
193 break;
194 }
195 }
196 }
197
198 } // rsg
199