1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES Utilities 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 variable type utilities. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "gluVarTypeUtil.hpp" 25 26 #include <stdlib.h> 27 28 namespace glu 29 { 30 31 // VarTokenizer 32 33 VarTokenizer::VarTokenizer (const char* str) 34 : m_str (str) 35 , m_token (TOKEN_LAST) 36 , m_tokenStart (0) 37 , m_tokenLen (0) 38 { 39 advance(); 40 } 41 42 int VarTokenizer::getNumber (void) const 43 { 44 return atoi(getIdentifier().c_str()); 45 } 46 47 static inline bool isNum (char c) { return de::inRange(c, '0', '9'); } 48 static inline bool isAlpha (char c) { return de::inRange(c, 'a', 'z') || de::inRange(c, 'A', 'Z'); } 49 static inline bool isIdentifierChar (char c) { return isAlpha(c) || isNum(c) || c == '_'; } 50 51 void VarTokenizer::advance (void) 52 { 53 DE_ASSERT(m_token != TOKEN_END); 54 55 m_tokenStart += m_tokenLen; 56 m_token = TOKEN_LAST; 57 m_tokenLen = 1; 58 59 if (m_str[m_tokenStart] == '[') 60 m_token = TOKEN_LEFT_BRACKET; 61 else if (m_str[m_tokenStart] == ']') 62 m_token = TOKEN_RIGHT_BRACKET; 63 else if (m_str[m_tokenStart] == 0) 64 m_token = TOKEN_END; 65 else if (m_str[m_tokenStart] == '.') 66 m_token = TOKEN_PERIOD; 67 else if (isNum(m_str[m_tokenStart])) 68 { 69 m_token = TOKEN_NUMBER; 70 while (isNum(m_str[m_tokenStart+m_tokenLen])) 71 m_tokenLen += 1; 72 } 73 else if (isIdentifierChar(m_str[m_tokenStart])) 74 { 75 m_token = TOKEN_IDENTIFIER; 76 while (isIdentifierChar(m_str[m_tokenStart+m_tokenLen])) 77 m_tokenLen += 1; 78 } 79 else 80 TCU_FAIL("Unexpected character"); 81 } 82 83 // SubTypeAccess 84 85 SubTypeAccess::SubTypeAccess (const VarType& type) 86 : m_type(type) 87 { 88 } 89 90 std::string parseVariableName (const char* nameWithPath) 91 { 92 VarTokenizer tokenizer(nameWithPath); 93 TCU_CHECK(tokenizer.getToken() == VarTokenizer::TOKEN_IDENTIFIER); 94 return tokenizer.getIdentifier(); 95 } 96 97 void parseTypePath (const char* nameWithPath, const VarType& type, TypeComponentVector& path) 98 { 99 VarTokenizer tokenizer(nameWithPath); 100 101 if (tokenizer.getToken() == VarTokenizer::TOKEN_IDENTIFIER) 102 tokenizer.advance(); 103 104 path.clear(); 105 while (tokenizer.getToken() != VarTokenizer::TOKEN_END) 106 { 107 VarType curType = getVarType(type, path); 108 109 if (tokenizer.getToken() == VarTokenizer::TOKEN_PERIOD) 110 { 111 tokenizer.advance(); 112 TCU_CHECK(tokenizer.getToken() == VarTokenizer::TOKEN_IDENTIFIER); 113 TCU_CHECK_MSG(curType.isStructType(), "Invalid field selector"); 114 115 // Find member. 116 std::string memberName = tokenizer.getIdentifier(); 117 int ndx = 0; 118 for (; ndx < curType.getStructPtr()->getNumMembers(); ndx++) 119 { 120 if (memberName == curType.getStructPtr()->getMember(ndx).getName()) 121 break; 122 } 123 TCU_CHECK_MSG(ndx < curType.getStructPtr()->getNumMembers(), "Member not found in type"); 124 125 path.push_back(VarTypeComponent(VarTypeComponent::STRUCT_MEMBER, ndx)); 126 tokenizer.advance(); 127 } 128 else if (tokenizer.getToken() == VarTokenizer::TOKEN_LEFT_BRACKET) 129 { 130 tokenizer.advance(); 131 TCU_CHECK(tokenizer.getToken() == VarTokenizer::TOKEN_NUMBER); 132 133 int ndx = tokenizer.getNumber(); 134 135 if (curType.isArrayType()) 136 { 137 TCU_CHECK(de::inBounds(ndx, 0, curType.getArraySize())); 138 path.push_back(VarTypeComponent(VarTypeComponent::ARRAY_ELEMENT, ndx)); 139 } 140 else if (curType.isBasicType() && isDataTypeMatrix(curType.getBasicType())) 141 { 142 TCU_CHECK(de::inBounds(ndx, 0, getDataTypeMatrixNumColumns(curType.getBasicType()))); 143 path.push_back(VarTypeComponent(VarTypeComponent::MATRIX_COLUMN, ndx)); 144 } 145 else if (curType.isBasicType() && isDataTypeVector(curType.getBasicType())) 146 { 147 TCU_CHECK(de::inBounds(ndx, 0, getDataTypeScalarSize(curType.getBasicType()))); 148 path.push_back(VarTypeComponent(VarTypeComponent::VECTOR_COMPONENT, ndx)); 149 } 150 else 151 TCU_FAIL("Invalid subscript"); 152 153 tokenizer.advance(); 154 TCU_CHECK(tokenizer.getToken() == VarTokenizer::TOKEN_RIGHT_BRACKET); 155 tokenizer.advance(); 156 } 157 else 158 TCU_FAIL("Unexpected token"); 159 } 160 } 161 162 std::ostream& operator<< (std::ostream& str, const TypeAccessFormat& format) 163 { 164 const VarType* curType = &format.type; 165 166 for (TypeComponentVector::const_iterator iter = format.path.begin(); iter != format.path.end(); iter++) 167 { 168 switch (iter->type) 169 { 170 case VarTypeComponent::ARRAY_ELEMENT: 171 curType = &curType->getElementType(); // Update current type. 172 // Fall-through. 173 174 case VarTypeComponent::MATRIX_COLUMN: 175 case VarTypeComponent::VECTOR_COMPONENT: 176 str << "[" << iter->index << "]"; 177 break; 178 179 case VarTypeComponent::STRUCT_MEMBER: 180 { 181 const StructMember& member = curType->getStructPtr()->getMember(iter->index); 182 str << "." << member.getName(); 183 curType = &member.getType(); 184 break; 185 } 186 187 default: 188 DE_ASSERT(false); 189 } 190 } 191 192 return str; 193 } 194 195 } // glu 196