/*-------------------------------------------------------------------------
* 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