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 DE_NULL, // IDENTIFIER,
32 "struct", // STRUCT,
33 "invariant", // INVARIANT,
34 "precision", // PRECISION,
35 "void", // VOID,
36 "break", // BREAK,
37 "continue", // CONTINUE,
38 "do ", // DO,
39 "while ", // WHILE,
40 "else ", // ELSE,
41 "for ", // FOR,
42 "if ", // IF,
43 "discard", // DISCARD,
44 "return ", // RETURN,
45 "++", // INC_OP,
46 "--", // DEC_OP,
47 "(", // LEFT_PAREN,
48 ")", // RIGHT_PAREN,
49 "[", // LEFT_BRACKET,
50 "]", // RIGHT_BRACKET,
51 "{", // LEFT_BRACE,
52 "}", // RIGHT_BRACE,
53 ".", // DOT,
54 ", ", // COMMA,
55 " : ", // COLON,
56 ";", // SEMICOLON,
57 " - ", // MINUS,
58 " + ", // PLUS,
59 " * ", // MUL,
60 " / ", // DIV,
61 " % ", // MOD,
62 " ? ", // QUESTION,
63 "bool", // BOOL,
64 "bvec2", // BVEC2,
65 "bvec3", // BVEC3,
66 "bvec4", // BVEC4,
67 "int", // INT,
68 "ivec2", // IVEC2,
69 "ivec3", // IVEC3,
70 "ivec4", // IVEC4,
71 "float", // FLOAT,
72 "vec2", // VEC2,
73 "vec3", // VEC3,
74 "vec4", // VEC4,
75 "mat2", // MAT2,
76 "mat3", // MAT3,
77 "mat4", // MAT4,
78 "sampler2D", // SAMPLER2D,
79 "samplerCube", // SAMPLERCUBE,
80 DE_NULL, // FLOAT_LITERAL,
81 DE_NULL, // INT_LITERAL,
82 DE_NULL, // BOOL_LITERAL,
83 " = ", // EQUAL,
84 " *= ", // MUL_ASSIGN,
85 " /= ", // DIV_ASSIGN,
86 " += ", // ADD_ASSIGN,
87 " -= ", // SUB_ASSIGN,
88 " < ", // CMP_LT,
89 " > ", // CMP_GT,
90 " <= ", // CMP_LE,
91 " >= ", // CMP_GE,
92 " == ", // CMP_EQ,
93 " != ", // CMP_NE,
94 " && ", // LOGICAL_AND,
95 " || ", // LOGICAL_OR,
96 "!", // LOGICAL_NOT,
97 " ^^ ", // LOGICAL_XOR,
98 "attribute", // ATTRIBUTE,
99 "uniform", // UNIFORM,
100 "varying", // VARYING,
101 "const", // CONST,
102 "flat", // FLAT,
103 "highp", // HIGH_PRECISION,
104 "mediump", // MEDIUM_PRECISION,
105 "lowp", // LOW_PRECISION,
106 "in", // IN,
107 "out", // OUT,
108 "inout", // INOUT,
109 "layout", // LAYOUT,
110 "location", // LOCATION,
111 DE_NULL, // INDENT_INC,
112 DE_NULL, // INDENT_DEC,
113 "\n" // NEWLINE,
114 };
115
PrettyPrinter(std::ostringstream & str)116 PrettyPrinter::PrettyPrinter(std::ostringstream &str) : m_str(str), m_indentDepth(0)
117 {
118 }
119
getSimpleTokenStr(Token::Type token)120 inline const char *PrettyPrinter::getSimpleTokenStr(Token::Type token)
121 {
122 DE_ASSERT(de::inBounds<int>(token, 0, (int)DE_LENGTH_OF_ARRAY(s_tokenStr)));
123 return s_tokenStr[token];
124 }
125
append(const TokenStream & tokens)126 void PrettyPrinter::append(const TokenStream &tokens)
127 {
128 for (int ndx = 0; ndx < tokens.getSize(); ndx++)
129 processToken(tokens[ndx]);
130 }
131
isIdentifierChar(char c)132 inline bool isIdentifierChar(char c)
133 {
134 return de::inRange(c, 'a', 'z') || de::inRange(c, 'A', 'Z') || de::inRange(c, '0', '9') || c == '_';
135 }
136
processToken(const Token & token)137 void PrettyPrinter::processToken(const Token &token)
138 {
139 bool prevIsIdentifierChar = m_line.length() > 0 && isIdentifierChar(m_line[m_line.length() - 1]);
140
141 switch (token.getType())
142 {
143 case Token::IDENTIFIER:
144 if (prevIsIdentifierChar)
145 m_line += " ";
146 m_line += token.getIdentifier();
147 break;
148
149 case Token::FLOAT_LITERAL:
150 {
151 std::string f = de::toString(token.getFloat());
152 if (f.find('.') == std::string::npos)
153 f += ".0"; // Make sure value parses as float
154 m_line += f;
155 break;
156 }
157
158 case Token::INT_LITERAL:
159 m_line += de::toString(token.getInt());
160 break;
161
162 case Token::BOOL_LITERAL:
163 m_line += (token.getBool() ? "true" : "false");
164 break;
165
166 case Token::INDENT_INC:
167 m_indentDepth += 1;
168 break;
169
170 case Token::INDENT_DEC:
171 m_indentDepth -= 1;
172 break;
173
174 case Token::NEWLINE:
175 // Indent
176 for (int i = 0; i < m_indentDepth; i++)
177 m_str << "\t";
178
179 // Flush line to source
180 m_str << m_line + "\n";
181 m_line = "";
182 break;
183
184 default:
185 {
186 const char *tokenStr = getSimpleTokenStr(token.getType());
187 if (prevIsIdentifierChar && isIdentifierChar(tokenStr[0]))
188 m_line += " ";
189 m_line += tokenStr;
190 break;
191 }
192 }
193 }
194
195 } // namespace rsg
196