/*------------------------------------------------------------------------- * 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 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; } } // glu