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