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