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
28namespace glu
29{
30
31// VarTokenizer
32
33VarTokenizer::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
42int VarTokenizer::getNumber (void) const
43{
44	return atoi(getIdentifier().c_str());
45}
46
47static inline bool	isNum				(char c) { return de::inRange(c, '0', '9'); }
48static inline bool	isAlpha				(char c) { return de::inRange(c, 'a', 'z') || de::inRange(c, 'A', 'Z');	}
49static inline bool	isIdentifierChar	(char c) { return isAlpha(c) || isNum(c) || c == '_'; }
50
51void 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
85SubTypeAccess::SubTypeAccess (const VarType& type)
86	: m_type(type)
87{
88}
89
90std::string parseVariableName (const char* nameWithPath)
91{
92	VarTokenizer tokenizer(nameWithPath);
93	TCU_CHECK(tokenizer.getToken() == VarTokenizer::TOKEN_IDENTIFIER);
94	return tokenizer.getIdentifier();
95}
96
97void 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
162std::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