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)
34 	: m_str			(str)
35 	, m_token		(TOKEN_LAST)
36 	, m_tokenStart	(0)
37 	, m_tokenLen	(0)
38 {
39 	advance();
40 }
41 
getNumber(void) const42 int VarTokenizer::getNumber (void) const
43 {
44 	return atoi(getIdentifier().c_str());
45 }
46 
isNum(char c)47 static inline bool	isNum				(char c) { return de::inRange(c, '0', '9'); }
isAlpha(char c)48 static inline bool	isAlpha				(char c) { return de::inRange(c, 'a', 'z') || de::inRange(c, 'A', 'Z');	}
isIdentifierChar(char c)49 static inline bool	isIdentifierChar	(char c) { return isAlpha(c) || isNum(c) || c == '_'; }
50 
advance(void)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 
SubTypeAccess(const VarType & type)85 SubTypeAccess::SubTypeAccess (const VarType& type)
86 	: m_type(type)
87 {
88 }
89 
parseVariableName(const char * nameWithPath)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 
parseTypePath(const char * nameWithPath,const VarType & type,TypeComponentVector & path)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 
operator <<(std::ostream & str,const TypeAccessFormat & format)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