blob: 07d5493ec5fac314bc76da37f84a0919176ef439 [file] [log] [blame]
/*-------------------------------------------------------------------------
* drawElements Quality Program OpenGL ES Utilities
* ------------------------------------------------
*
* 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 variable type utilities.
*//*--------------------------------------------------------------------*/
#include "gluVarTypeUtil.hpp"
#include <stdlib.h>
namespace glu
{
// VarTokenizer
VarTokenizer::VarTokenizer(const char *str) : m_str(str), m_token(TOKEN_LAST), m_tokenStart(0), m_tokenLen(0)
{
advance();
}
int VarTokenizer::getNumber(void) const
{
return atoi(getIdentifier().c_str());
}
static inline bool isNum(char c)
{
return de::inRange(c, '0', '9');
}
static inline bool isAlpha(char c)
{
return de::inRange(c, 'a', 'z') || de::inRange(c, 'A', 'Z');
}
static inline bool isIdentifierChar(char c)
{
return isAlpha(c) || isNum(c) || c == '_';
}
void VarTokenizer::advance(void)
{
DE_ASSERT(m_token != TOKEN_END);
m_tokenStart += m_tokenLen;
m_token = TOKEN_LAST;
m_tokenLen = 1;
if (m_str[m_tokenStart] == '[')
m_token = TOKEN_LEFT_BRACKET;
else if (m_str[m_tokenStart] == ']')
m_token = TOKEN_RIGHT_BRACKET;
else if (m_str[m_tokenStart] == 0)
m_token = TOKEN_END;
else if (m_str[m_tokenStart] == '.')
m_token = TOKEN_PERIOD;
else if (isNum(m_str[m_tokenStart]))
{
m_token = TOKEN_NUMBER;
while (isNum(m_str[m_tokenStart + m_tokenLen]))
m_tokenLen += 1;
}
else if (isIdentifierChar(m_str[m_tokenStart]))
{
m_token = TOKEN_IDENTIFIER;
while (isIdentifierChar(m_str[m_tokenStart + m_tokenLen]))
m_tokenLen += 1;
}
else
TCU_FAIL("Unexpected character");
}
// SubTypeAccess
SubTypeAccess::SubTypeAccess(const VarType &type) : m_type(type)
{
}
std::string parseVariableName(const char *nameWithPath)
{
VarTokenizer tokenizer(nameWithPath);
TCU_CHECK(tokenizer.getToken() == VarTokenizer::TOKEN_IDENTIFIER);
return tokenizer.getIdentifier();
}
void parseTypePath(const char *nameWithPath, const VarType &type, TypeComponentVector &path)
{
VarTokenizer tokenizer(nameWithPath);
if (tokenizer.getToken() == VarTokenizer::TOKEN_IDENTIFIER)
tokenizer.advance();
path.clear();
while (tokenizer.getToken() != VarTokenizer::TOKEN_END)
{
VarType curType = getVarType(type, path);
if (tokenizer.getToken() == VarTokenizer::TOKEN_PERIOD)
{
tokenizer.advance();
TCU_CHECK(tokenizer.getToken() == VarTokenizer::TOKEN_IDENTIFIER);
TCU_CHECK_MSG(curType.isStructType(), "Invalid field selector");
// Find member.
std::string memberName = tokenizer.getIdentifier();
int ndx = 0;
for (; ndx < curType.getStructPtr()->getNumMembers(); ndx++)
{
if (memberName == curType.getStructPtr()->getMember(ndx).getName())
break;
}
TCU_CHECK_MSG(ndx < curType.getStructPtr()->getNumMembers(), "Member not found in type");
path.push_back(VarTypeComponent(VarTypeComponent::STRUCT_MEMBER, ndx));
tokenizer.advance();
}
else if (tokenizer.getToken() == VarTokenizer::TOKEN_LEFT_BRACKET)
{
tokenizer.advance();
TCU_CHECK(tokenizer.getToken() == VarTokenizer::TOKEN_NUMBER);
int ndx = tokenizer.getNumber();
if (curType.isArrayType())
{
TCU_CHECK(de::inBounds(ndx, 0, curType.getArraySize()));
path.push_back(VarTypeComponent(VarTypeComponent::ARRAY_ELEMENT, ndx));
}
else if (curType.isBasicType() && isDataTypeMatrix(curType.getBasicType()))
{
TCU_CHECK(de::inBounds(ndx, 0, getDataTypeMatrixNumColumns(curType.getBasicType())));
path.push_back(VarTypeComponent(VarTypeComponent::MATRIX_COLUMN, ndx));
}
else if (curType.isBasicType() && isDataTypeVector(curType.getBasicType()))
{
TCU_CHECK(de::inBounds(ndx, 0, getDataTypeScalarSize(curType.getBasicType())));
path.push_back(VarTypeComponent(VarTypeComponent::VECTOR_COMPONENT, ndx));
}
else
TCU_FAIL("Invalid subscript");
tokenizer.advance();
TCU_CHECK(tokenizer.getToken() == VarTokenizer::TOKEN_RIGHT_BRACKET);
tokenizer.advance();
}
else
TCU_FAIL("Unexpected token");
}
}
std::ostream &operator<<(std::ostream &str, const TypeAccessFormat &format)
{
const VarType *curType = &format.type;
for (TypeComponentVector::const_iterator iter = format.path.begin(); iter != format.path.end(); iter++)
{
switch (iter->type)
{
case VarTypeComponent::ARRAY_ELEMENT:
curType = &curType->getElementType(); // Update current type.
// Fall-through.
case VarTypeComponent::MATRIX_COLUMN:
case VarTypeComponent::VECTOR_COMPONENT:
str << "[" << iter->index << "]";
break;
case VarTypeComponent::STRUCT_MEMBER:
{
const StructMember &member = curType->getStructPtr()->getMember(iter->index);
str << "." << member.getName();
curType = &member.getType();
break;
}
default:
DE_ASSERT(false);
}
}
return str;
}
} // namespace glu