| /*------------------------------------------------------------------------- |
| * drawElements Quality Program Random Shader Generator |
| * ---------------------------------------------------- |
| * |
| * Copyright 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file |
| * \brief Shader Source Formatter. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "rsgPrettyPrinter.hpp" |
| #include "deStringUtil.hpp" |
| |
| namespace rsg |
| { |
| |
| static const char* s_tokenStr[] = |
| { |
| DE_NULL, // IDENTIFIER, |
| "struct", // STRUCT, |
| "invariant", // INVARIANT, |
| "precision", // PRECISION, |
| "void", // VOID, |
| "break", // BREAK, |
| "continue", // CONTINUE, |
| "do ", // DO, |
| "while ", // WHILE, |
| "else ", // ELSE, |
| "for ", // FOR, |
| "if ", // IF, |
| "discard", // DISCARD, |
| "return ", // RETURN, |
| "++", // INC_OP, |
| "--", // DEC_OP, |
| "(", // LEFT_PAREN, |
| ")", // RIGHT_PAREN, |
| "[", // LEFT_BRACKET, |
| "]", // RIGHT_BRACKET, |
| "{", // LEFT_BRACE, |
| "}", // RIGHT_BRACE, |
| ".", // DOT, |
| ", ", // COMMA, |
| " : ", // COLON, |
| ";", // SEMICOLON, |
| " - ", // MINUS, |
| " + ", // PLUS, |
| " * ", // MUL, |
| " / ", // DIV, |
| " % ", // MOD, |
| " ? ", // QUESTION, |
| "bool", // BOOL, |
| "bvec2", // BVEC2, |
| "bvec3", // BVEC3, |
| "bvec4", // BVEC4, |
| "int", // INT, |
| "ivec2", // IVEC2, |
| "ivec3", // IVEC3, |
| "ivec4", // IVEC4, |
| "float", // FLOAT, |
| "vec2", // VEC2, |
| "vec3", // VEC3, |
| "vec4", // VEC4, |
| "mat2", // MAT2, |
| "mat3", // MAT3, |
| "mat4", // MAT4, |
| "sampler2D", // SAMPLER2D, |
| "samplerCube", // SAMPLERCUBE, |
| DE_NULL, // FLOAT_LITERAL, |
| DE_NULL, // INT_LITERAL, |
| DE_NULL, // BOOL_LITERAL, |
| " = ", // EQUAL, |
| " *= ", // MUL_ASSIGN, |
| " /= ", // DIV_ASSIGN, |
| " += ", // ADD_ASSIGN, |
| " -= ", // SUB_ASSIGN, |
| " < ", // CMP_LT, |
| " > ", // CMP_GT, |
| " <= ", // CMP_LE, |
| " >= ", // CMP_GE, |
| " == ", // CMP_EQ, |
| " != ", // CMP_NE, |
| " && ", // LOGICAL_AND, |
| " || ", // LOGICAL_OR, |
| "!", // LOGICAL_NOT, |
| " ^^ ", // LOGICAL_XOR, |
| "attribute", // ATTRIBUTE, |
| "uniform", // UNIFORM, |
| "varying", // VARYING, |
| "const", // CONST, |
| "flat", // FLAT, |
| "highp", // HIGH_PRECISION, |
| "mediump", // MEDIUM_PRECISION, |
| "lowp", // LOW_PRECISION, |
| "in", // IN, |
| "out", // OUT, |
| "inout", // INOUT, |
| "layout", // LAYOUT, |
| "location", // LOCATION, |
| DE_NULL, // INDENT_INC, |
| DE_NULL, // INDENT_DEC, |
| "\n" // NEWLINE, |
| }; |
| |
| PrettyPrinter::PrettyPrinter (std::ostringstream& str) |
| : m_str (str) |
| , m_indentDepth (0) |
| { |
| } |
| |
| inline const char* PrettyPrinter::getSimpleTokenStr (Token::Type token) |
| { |
| DE_ASSERT(de::inBounds<int>(token, 0, (int)DE_LENGTH_OF_ARRAY(s_tokenStr))); |
| return s_tokenStr[token]; |
| } |
| |
| void PrettyPrinter::append (const TokenStream& tokens) |
| { |
| for (int ndx = 0; ndx < tokens.getSize(); ndx++) |
| processToken(tokens[ndx]); |
| } |
| |
| inline bool isIdentifierChar (char c) |
| { |
| return de::inRange(c, 'a', 'z') || de::inRange(c, 'A', 'Z') || de::inRange(c, '0', '9') || c == '_'; |
| } |
| |
| void PrettyPrinter::processToken (const Token& token) |
| { |
| bool prevIsIdentifierChar = m_line.length() > 0 && isIdentifierChar(m_line[m_line.length()-1]); |
| |
| switch (token.getType()) |
| { |
| case Token::IDENTIFIER: |
| if (prevIsIdentifierChar) |
| m_line += " "; |
| m_line += token.getIdentifier(); |
| break; |
| |
| case Token::FLOAT_LITERAL: |
| { |
| std::string f = de::toString(token.getFloat()); |
| if (f.find('.') == std::string::npos) |
| f += ".0"; // Make sure value parses as float |
| m_line += f; |
| break; |
| } |
| |
| case Token::INT_LITERAL: |
| m_line += de::toString(token.getInt()); |
| break; |
| |
| case Token::BOOL_LITERAL: |
| m_line += (token.getBool() ? "true" : "false"); |
| break; |
| |
| case Token::INDENT_INC: |
| m_indentDepth += 1; |
| break; |
| |
| case Token::INDENT_DEC: |
| m_indentDepth -= 1; |
| break; |
| |
| case Token::NEWLINE: |
| // Indent |
| for (int i = 0; i < m_indentDepth; i++) |
| m_str << "\t"; |
| |
| // Flush line to source |
| m_str << m_line + "\n"; |
| m_line = ""; |
| break; |
| |
| default: |
| { |
| const char* tokenStr = getSimpleTokenStr(token.getType()); |
| if (prevIsIdentifierChar && isIdentifierChar(tokenStr[0])) |
| m_line += " "; |
| m_line += tokenStr; |
| break; |
| } |
| } |
| } |
| |
| } // rsg |