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
27namespace rsg
28{
29
30static 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
117PrettyPrinter::PrettyPrinter (std::ostringstream& str)
118	: m_str			(str)
119	, m_indentDepth	(0)
120{
121}
122
123inline 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
129void PrettyPrinter::append (const TokenStream& tokens)
130{
131	for (int ndx = 0; ndx < tokens.getSize(); ndx++)
132		processToken(tokens[ndx]);
133}
134
135inline 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
140void 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