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