Home | History | Annotate | Download | only in glshared
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL (ES) Module
      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 Compiler test case.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "glsShaderLibrary.hpp"
     25 #include "glsShaderLibraryCase.hpp"
     26 #include "gluShaderUtil.hpp"
     27 #include "tcuResource.hpp"
     28 #include "glwEnums.hpp"
     29 
     30 #include "deInt32.h"
     31 
     32 #include <string>
     33 #include <vector>
     34 #include <fstream>
     35 #include <sstream>
     36 
     37 #include <string.h>
     38 #include <stdarg.h>
     39 #include <stdlib.h>
     40 
     41 using std::string;
     42 using std::vector;
     43 using std::ostringstream;
     44 
     45 using namespace glu;
     46 
     47 #if 0
     48 #	define PARSE_DBG(X) printf X
     49 #else
     50 #	define PARSE_DBG(X) DE_NULL_STATEMENT
     51 #endif
     52 
     53 namespace deqp
     54 {
     55 namespace gls
     56 {
     57 namespace sl
     58 {
     59 
     60 static const glu::GLSLVersion DEFAULT_GLSL_VERSION = glu::GLSL_VERSION_100_ES;
     61 
     62 DE_INLINE deBool isWhitespace (char c)
     63 {
     64 	return (c == ' ') || (c == '\t') || (c == '\r') || (c == '\n');
     65 }
     66 
     67 DE_INLINE deBool isEOL (char c)
     68 {
     69 	return (c == '\r') || (c == '\n');
     70 }
     71 
     72 DE_INLINE deBool isNumeric (char c)
     73 {
     74 	return deInRange32(c, '0', '9');
     75 }
     76 
     77 DE_INLINE deBool isAlpha (char c)
     78 {
     79 	return deInRange32(c, 'a', 'z') || deInRange32(c, 'A', 'Z');
     80 }
     81 
     82 DE_INLINE deBool isCaseNameChar (char c)
     83 {
     84 	return deInRange32(c, 'a', 'z') || deInRange32(c, 'A', 'Z') || deInRange32(c, '0', '9') || (c == '_') || (c == '-') || (c == '.');
     85 }
     86 
     87 // \todo [2011-02-11 pyry] Should not depend on Context or TestContext!
     88 class ShaderParser
     89 {
     90 public:
     91 							ShaderParser			(tcu::TestContext& testCtx, RenderContext& renderCtx, const glu::ContextInfo& contextInfo, const char* currentDir = DE_NULL);
     92 							~ShaderParser			(void);
     93 
     94 	vector<tcu::TestNode*>	parse					(const char* input);
     95 
     96 private:
     97 	enum Token
     98 	{
     99 		TOKEN_INVALID = 0,
    100 		TOKEN_EOF,
    101 		TOKEN_STRING,
    102 		TOKEN_SHADER_SOURCE,
    103 
    104 		TOKEN_INT_LITERAL,
    105 		TOKEN_FLOAT_LITERAL,
    106 
    107 		// identifiers
    108 		TOKEN_IDENTIFIER,
    109 		TOKEN_TRUE,
    110 		TOKEN_FALSE,
    111 		TOKEN_DESC,
    112 		TOKEN_EXPECT,
    113 		TOKEN_GROUP,
    114 		TOKEN_CASE,
    115 		TOKEN_END,
    116 		TOKEN_VALUES,
    117 		TOKEN_BOTH,
    118 		TOKEN_VERTEX,
    119 		TOKEN_FRAGMENT,
    120 		TOKEN_UNIFORM,
    121 		TOKEN_INPUT,
    122 		TOKEN_OUTPUT,
    123 		TOKEN_FLOAT,
    124 		TOKEN_FLOAT_VEC2,
    125 		TOKEN_FLOAT_VEC3,
    126 		TOKEN_FLOAT_VEC4,
    127 		TOKEN_FLOAT_MAT2,
    128 		TOKEN_FLOAT_MAT2X3,
    129 		TOKEN_FLOAT_MAT2X4,
    130 		TOKEN_FLOAT_MAT3X2,
    131 		TOKEN_FLOAT_MAT3,
    132 		TOKEN_FLOAT_MAT3X4,
    133 		TOKEN_FLOAT_MAT4X2,
    134 		TOKEN_FLOAT_MAT4X3,
    135 		TOKEN_FLOAT_MAT4,
    136 		TOKEN_INT,
    137 		TOKEN_INT_VEC2,
    138 		TOKEN_INT_VEC3,
    139 		TOKEN_INT_VEC4,
    140 		TOKEN_UINT,
    141 		TOKEN_UINT_VEC2,
    142 		TOKEN_UINT_VEC3,
    143 		TOKEN_UINT_VEC4,
    144 		TOKEN_BOOL,
    145 		TOKEN_BOOL_VEC2,
    146 		TOKEN_BOOL_VEC3,
    147 		TOKEN_BOOL_VEC4,
    148 		TOKEN_VERSION,
    149 		TOKEN_TESSELLATION_CONTROL,
    150 		TOKEN_TESSELLATION_EVALUATION,
    151 		TOKEN_GEOMETRY,
    152 		TOKEN_REQUIRE,
    153 		TOKEN_IN,
    154 		TOKEN_IMPORT,
    155 		TOKEN_PIPELINE_PROGRAM,
    156 		TOKEN_ACTIVE_STAGES,
    157 
    158 		// symbols
    159 		TOKEN_ASSIGN,
    160 		TOKEN_PLUS,
    161 		TOKEN_MINUS,
    162 		TOKEN_COMMA,
    163 		TOKEN_VERTICAL_BAR,
    164 		TOKEN_SEMI_COLON,
    165 		TOKEN_LEFT_PAREN,
    166 		TOKEN_RIGHT_PAREN,
    167 		TOKEN_LEFT_BRACKET,
    168 		TOKEN_RIGHT_BRACKET,
    169 		TOKEN_LEFT_BRACE,
    170 		TOKEN_RIGHT_BRACE,
    171 		TOKEN_GREATER,
    172 
    173 		TOKEN_LAST
    174 	};
    175 
    176 	void						parseError					(const std::string& errorStr);
    177 	float						parseFloatLiteral			(const char* str);
    178 	int							parseIntLiteral				(const char* str);
    179 	string						parseStringLiteral			(const char* str);
    180 	string						parseShaderSource			(const char* str);
    181 	void						advanceToken				(void);
    182 	void						advanceToken				(Token assumed);
    183 	void						assumeToken					(Token token);
    184 	DataType					mapDataTypeToken			(Token token);
    185 	const char*					getTokenName				(Token token);
    186 	deUint32					getShaderStageLiteralFlag	(void);
    187 	deUint32					getGLEnumFromName			(const std::string& enumName);
    188 
    189 	void						parseValueElement			(DataType dataType, ShaderCase::Value& result);
    190 	void						parseValue					(ShaderCase::ValueBlock& valueBlock);
    191 	void						parseValueBlock				(ShaderCase::ValueBlock& valueBlock);
    192 	deUint32					parseShaderStageList		(void);
    193 	void						parseRequirement			(ShaderCase::CaseRequirement& valueBlock);
    194 	void						parseExpectResult			(ShaderCase::ExpectResult& expectResult);
    195 	void						parseGLSLVersion			(glu::GLSLVersion& version);
    196 	void						parsePipelineProgram		(ShaderCase::PipelineProgram& program);
    197 	void						parseShaderCase				(vector<tcu::TestNode*>& shaderNodeList);
    198 	void						parseShaderGroup			(vector<tcu::TestNode*>& shaderNodeList);
    199 	void						parseImport					(vector<tcu::TestNode*>& shaderNodeList);
    200 
    201 	// Member variables.
    202 	tcu::TestContext&			m_testCtx;
    203 	RenderContext&				m_renderCtx;
    204 	const glu::ContextInfo&		m_contextInfo;
    205 	std::string					m_input;
    206 	const char*					m_curPtr;
    207 	Token						m_curToken;
    208 	std::string					m_curTokenStr;
    209 	const char* const			m_currentDir;
    210 };
    211 
    212 ShaderParser::ShaderParser (tcu::TestContext& testCtx, RenderContext& renderCtx, const glu::ContextInfo& contextInfo, const char* currentDir)
    213 	: m_testCtx			(testCtx)
    214 	, m_renderCtx		(renderCtx)
    215 	, m_contextInfo		(contextInfo)
    216 	, m_curPtr			(DE_NULL)
    217 	, m_curToken		(TOKEN_LAST)
    218 	, m_currentDir		(currentDir)
    219 {
    220 }
    221 
    222 ShaderParser::~ShaderParser (void)
    223 {
    224 	// nada
    225 }
    226 
    227 void ShaderParser::parseError (const std::string& errorStr)
    228 {
    229 	string atStr = string(m_curPtr, 80);
    230 	throw tcu::InternalError((string("Parser error: ") + errorStr + " near '" + atStr + " ...'").c_str(), "", __FILE__, __LINE__);
    231 }
    232 
    233 float ShaderParser::parseFloatLiteral (const char* str)
    234 {
    235 	return (float)atof(str);
    236 }
    237 
    238 int ShaderParser::parseIntLiteral (const char* str)
    239 {
    240 	return atoi(str);
    241 }
    242 
    243 string ShaderParser::parseStringLiteral (const char* str)
    244 {
    245 	const char*		p		= str;
    246 	char			endChar = *p++;
    247 	ostringstream	o;
    248 
    249 	while (*p != endChar && *p)
    250 	{
    251 		if (*p == '\\')
    252 		{
    253 			switch (p[1])
    254 			{
    255 				case 0:		DE_ASSERT(DE_FALSE);	break;
    256 				case 'n':	o << '\n';				break;
    257 				case 't':	o << '\t';				break;
    258 				default:	o << p[1];				break;
    259 			}
    260 
    261 			p += 2;
    262 		}
    263 		else
    264 			o << *p++;
    265 	}
    266 
    267 	return o.str();
    268 }
    269 
    270 static string removeExtraIndentation (const string& source)
    271 {
    272 	// Detect indentation from first line.
    273 	int numIndentChars = 0;
    274 	for (int ndx = 0; ndx < (int)source.length() && isWhitespace(source[ndx]); ndx++)
    275 		numIndentChars += source[ndx] == '\t' ? 4 : 1;
    276 
    277 	// Process all lines and remove preceding indentation.
    278 	ostringstream processed;
    279 	{
    280 		bool	atLineStart			= true;
    281 		int		indentCharsOmitted	= 0;
    282 
    283 		for (int pos = 0; pos < (int)source.length(); pos++)
    284 		{
    285 			char c = source[pos];
    286 
    287 			if (atLineStart && indentCharsOmitted < numIndentChars && (c == ' ' || c == '\t'))
    288 			{
    289 				indentCharsOmitted += c == '\t' ? 4 : 1;
    290 			}
    291 			else if (isEOL(c))
    292 			{
    293 				if (source[pos] == '\r' && source[pos+1] == '\n')
    294 				{
    295 					pos += 1;
    296 					processed << '\n';
    297 				}
    298 				else
    299 					processed << c;
    300 
    301 				atLineStart			= true;
    302 				indentCharsOmitted	= 0;
    303 			}
    304 			else
    305 			{
    306 				processed << c;
    307 				atLineStart = false;
    308 			}
    309 		}
    310 	}
    311 
    312 	return processed.str();
    313 }
    314 
    315 string ShaderParser::parseShaderSource (const char* str)
    316 {
    317 	const char*		p = str+2;
    318 	ostringstream	o;
    319 
    320 	// Eat first empty line from beginning.
    321 	while (*p == ' ') p++;
    322 	if (*p == '\r') p++;
    323 	if (*p == '\n') p++;
    324 
    325 	while ((p[0] != '"') || (p[1] != '"'))
    326 	{
    327 		if (*p == '\\')
    328 		{
    329 			switch (p[1])
    330 			{
    331 				case 0:		DE_ASSERT(DE_FALSE);	break;
    332 				case 'n':	o << '\n';				break;
    333 				case 't':	o << '\t';				break;
    334 				default:	o << p[1];				break;
    335 			}
    336 
    337 			p += 2;
    338 		}
    339 		else
    340 			o << *p++;
    341 	}
    342 
    343 	return removeExtraIndentation(o.str());
    344 }
    345 
    346 void ShaderParser::advanceToken (void)
    347 {
    348 	// Skip old token.
    349 	m_curPtr += m_curTokenStr.length();
    350 
    351 	// Reset token (for safety).
    352 	m_curToken		= TOKEN_INVALID;
    353 	m_curTokenStr	= "";
    354 
    355 	// Eat whitespace & comments while they last.
    356 	for (;;)
    357 	{
    358 		while (isWhitespace(*m_curPtr))
    359 			m_curPtr++;
    360 
    361 		// Check for EOL comment.
    362 		if (*m_curPtr == '#')
    363 		{
    364 			while (*m_curPtr && !isEOL(*m_curPtr))
    365 				m_curPtr++;
    366 		}
    367 		else
    368 			break;
    369 	}
    370 
    371 	if (!*m_curPtr)
    372 	{
    373 		m_curToken = TOKEN_EOF;
    374 		m_curTokenStr = "<EOF>";
    375 	}
    376 	else if (isAlpha(*m_curPtr))
    377 	{
    378 		struct Named
    379 		{
    380 			const char*		str;
    381 			Token			token;
    382 		};
    383 
    384 		static const Named s_named[] =
    385 		{
    386 			{ "true",						TOKEN_TRUE						},
    387 			{ "false",						TOKEN_FALSE						},
    388 			{ "desc",						TOKEN_DESC						},
    389 			{ "expect",						TOKEN_EXPECT					},
    390 			{ "group",						TOKEN_GROUP						},
    391 			{ "case",						TOKEN_CASE						},
    392 			{ "end",						TOKEN_END						},
    393 			{ "values",						TOKEN_VALUES					},
    394 			{ "both",						TOKEN_BOTH						},
    395 			{ "vertex",						TOKEN_VERTEX					},
    396 			{ "fragment",					TOKEN_FRAGMENT					},
    397 			{ "uniform",					TOKEN_UNIFORM					},
    398 			{ "input",						TOKEN_INPUT						},
    399 			{ "output",						TOKEN_OUTPUT					},
    400 			{ "float",						TOKEN_FLOAT						},
    401 			{ "vec2",						TOKEN_FLOAT_VEC2				},
    402 			{ "vec3",						TOKEN_FLOAT_VEC3				},
    403 			{ "vec4",						TOKEN_FLOAT_VEC4				},
    404 			{ "mat2",						TOKEN_FLOAT_MAT2				},
    405 			{ "mat2x3",						TOKEN_FLOAT_MAT2X3				},
    406 			{ "mat2x4",						TOKEN_FLOAT_MAT2X4				},
    407 			{ "mat3x2",						TOKEN_FLOAT_MAT3X2				},
    408 			{ "mat3",						TOKEN_FLOAT_MAT3				},
    409 			{ "mat3x4",						TOKEN_FLOAT_MAT3X4				},
    410 			{ "mat4x2",						TOKEN_FLOAT_MAT4X2				},
    411 			{ "mat4x3",						TOKEN_FLOAT_MAT4X3				},
    412 			{ "mat4",						TOKEN_FLOAT_MAT4				},
    413 			{ "int",						TOKEN_INT						},
    414 			{ "ivec2",						TOKEN_INT_VEC2					},
    415 			{ "ivec3",						TOKEN_INT_VEC3					},
    416 			{ "ivec4",						TOKEN_INT_VEC4					},
    417 			{ "uint",						TOKEN_UINT						},
    418 			{ "uvec2",						TOKEN_UINT_VEC2					},
    419 			{ "uvec3",						TOKEN_UINT_VEC3					},
    420 			{ "uvec4",						TOKEN_UINT_VEC4					},
    421 			{ "bool",						TOKEN_BOOL						},
    422 			{ "bvec2",						TOKEN_BOOL_VEC2					},
    423 			{ "bvec3",						TOKEN_BOOL_VEC3					},
    424 			{ "bvec4",						TOKEN_BOOL_VEC4					},
    425 			{ "version",					TOKEN_VERSION					},
    426 			{ "tessellation_control",		TOKEN_TESSELLATION_CONTROL		},
    427 			{ "tessellation_evaluation",	TOKEN_TESSELLATION_EVALUATION	},
    428 			{ "geometry",					TOKEN_GEOMETRY					},
    429 			{ "require",					TOKEN_REQUIRE					},
    430 			{ "in",							TOKEN_IN						},
    431 			{ "import",						TOKEN_IMPORT					},
    432 			{ "pipeline_program",			TOKEN_PIPELINE_PROGRAM			},
    433 			{ "active_stages",				TOKEN_ACTIVE_STAGES				},
    434 		};
    435 
    436 		const char* end = m_curPtr + 1;
    437 		while (isCaseNameChar(*end))
    438 			end++;
    439 		m_curTokenStr = string(m_curPtr, end - m_curPtr);
    440 
    441 		m_curToken = TOKEN_IDENTIFIER;
    442 
    443 		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_named); ndx++)
    444 		{
    445 			if (m_curTokenStr == s_named[ndx].str)
    446 			{
    447 				m_curToken = s_named[ndx].token;
    448 				break;
    449 			}
    450 		}
    451 	}
    452 	else if (isNumeric(*m_curPtr))
    453 	{
    454 		/* \todo [2010-03-31 petri] Hex? */
    455 		const char* p = m_curPtr;
    456 		while (isNumeric(*p))
    457 			p++;
    458 		if (*p == '.')
    459 		{
    460 			p++;
    461 			while (isNumeric(*p))
    462 				p++;
    463 
    464 			if (*p == 'e' || *p == 'E')
    465 			{
    466 				p++;
    467 				if (*p == '+' || *p == '-')
    468 					p++;
    469 				DE_ASSERT(isNumeric(*p));
    470 				while (isNumeric(*p))
    471 					p++;
    472 			}
    473 
    474 			m_curToken = TOKEN_FLOAT_LITERAL;
    475 			m_curTokenStr = string(m_curPtr, p - m_curPtr);
    476 		}
    477 		else
    478 		{
    479 			m_curToken = TOKEN_INT_LITERAL;
    480 			m_curTokenStr = string(m_curPtr, p - m_curPtr);
    481 		}
    482 	}
    483 	else if (*m_curPtr == '"' && m_curPtr[1] == '"')
    484 	{
    485 		const char*	p = m_curPtr + 2;
    486 
    487 		while ((p[0] != '"') || (p[1] != '"'))
    488 		{
    489 			DE_ASSERT(*p);
    490 			if (*p == '\\')
    491 			{
    492 				DE_ASSERT(p[1] != 0);
    493 				p += 2;
    494 			}
    495 			else
    496 				p++;
    497 		}
    498 		p += 2;
    499 
    500 		m_curToken		= TOKEN_SHADER_SOURCE;
    501 		m_curTokenStr	= string(m_curPtr, (int)(p - m_curPtr));
    502 	}
    503 	else if (*m_curPtr == '"' || *m_curPtr == '\'')
    504 	{
    505 		char		endChar = *m_curPtr;
    506 		const char*	p		= m_curPtr + 1;
    507 
    508 		while (*p != endChar)
    509 		{
    510 			DE_ASSERT(*p);
    511 			if (*p == '\\')
    512 			{
    513 				DE_ASSERT(p[1] != 0);
    514 				p += 2;
    515 			}
    516 			else
    517 				p++;
    518 		}
    519 		p++;
    520 
    521 		m_curToken		= TOKEN_STRING;
    522 		m_curTokenStr	= string(m_curPtr, (int)(p - m_curPtr));
    523 	}
    524 	else
    525 	{
    526 		struct SimpleToken
    527 		{
    528 			const char*		str;
    529 			Token			token;
    530 		};
    531 
    532 		static const SimpleToken s_simple[] =
    533 		{
    534 			{ "=",			TOKEN_ASSIGN		},
    535 			{ "+",			TOKEN_PLUS			},
    536 			{ "-",			TOKEN_MINUS			},
    537 			{ ",",			TOKEN_COMMA			},
    538 			{ "|",			TOKEN_VERTICAL_BAR	},
    539 			{ ";",			TOKEN_SEMI_COLON	},
    540 			{ "(",			TOKEN_LEFT_PAREN	},
    541 			{ ")",			TOKEN_RIGHT_PAREN	},
    542 			{ "[",			TOKEN_LEFT_BRACKET	},
    543 			{ "]",			TOKEN_RIGHT_BRACKET },
    544 			{ "{",			TOKEN_LEFT_BRACE	},
    545 			{ "}",			TOKEN_RIGHT_BRACE	},
    546 			{ ">",			TOKEN_GREATER		},
    547 		};
    548 
    549 		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_simple); ndx++)
    550 		{
    551 			if (strncmp(s_simple[ndx].str, m_curPtr, strlen(s_simple[ndx].str)) == 0)
    552 			{
    553 				m_curToken		= s_simple[ndx].token;
    554 				m_curTokenStr	= s_simple[ndx].str;
    555 				return;
    556 			}
    557 		}
    558 
    559 		// Otherwise invalid token.
    560 		m_curToken = TOKEN_INVALID;
    561 		m_curTokenStr = *m_curPtr;
    562 	}
    563 }
    564 
    565 void ShaderParser::advanceToken (Token assumed)
    566 {
    567 	assumeToken(assumed);
    568 	advanceToken();
    569 }
    570 
    571 void ShaderParser::assumeToken (Token token)
    572 {
    573 	if (m_curToken != token)
    574 		parseError((string("unexpected token '") + m_curTokenStr + "', expecting '" + getTokenName(token) + "'").c_str());
    575 	DE_TEST_ASSERT(m_curToken == token);
    576 }
    577 
    578 DataType ShaderParser::mapDataTypeToken (Token token)
    579 {
    580 	switch (token)
    581 	{
    582 		case TOKEN_FLOAT:			return TYPE_FLOAT;
    583 		case TOKEN_FLOAT_VEC2:		return TYPE_FLOAT_VEC2;
    584 		case TOKEN_FLOAT_VEC3:		return TYPE_FLOAT_VEC3;
    585 		case TOKEN_FLOAT_VEC4:		return TYPE_FLOAT_VEC4;
    586 		case TOKEN_FLOAT_MAT2:		return TYPE_FLOAT_MAT2;
    587 		case TOKEN_FLOAT_MAT2X3:	return TYPE_FLOAT_MAT2X3;
    588 		case TOKEN_FLOAT_MAT2X4:	return TYPE_FLOAT_MAT2X4;
    589 		case TOKEN_FLOAT_MAT3X2:	return TYPE_FLOAT_MAT3X2;
    590 		case TOKEN_FLOAT_MAT3:		return TYPE_FLOAT_MAT3;
    591 		case TOKEN_FLOAT_MAT3X4:	return TYPE_FLOAT_MAT3X4;
    592 		case TOKEN_FLOAT_MAT4X2:	return TYPE_FLOAT_MAT4X2;
    593 		case TOKEN_FLOAT_MAT4X3:	return TYPE_FLOAT_MAT4X3;
    594 		case TOKEN_FLOAT_MAT4:		return TYPE_FLOAT_MAT4;
    595 		case TOKEN_INT:				return TYPE_INT;
    596 		case TOKEN_INT_VEC2:		return TYPE_INT_VEC2;
    597 		case TOKEN_INT_VEC3:		return TYPE_INT_VEC3;
    598 		case TOKEN_INT_VEC4:		return TYPE_INT_VEC4;
    599 		case TOKEN_UINT:			return TYPE_UINT;
    600 		case TOKEN_UINT_VEC2:		return TYPE_UINT_VEC2;
    601 		case TOKEN_UINT_VEC3:		return TYPE_UINT_VEC3;
    602 		case TOKEN_UINT_VEC4:		return TYPE_UINT_VEC4;
    603 		case TOKEN_BOOL:			return TYPE_BOOL;
    604 		case TOKEN_BOOL_VEC2:		return TYPE_BOOL_VEC2;
    605 		case TOKEN_BOOL_VEC3:		return TYPE_BOOL_VEC3;
    606 		case TOKEN_BOOL_VEC4:		return TYPE_BOOL_VEC4;
    607 		default:					return TYPE_INVALID;
    608 	}
    609 }
    610 
    611 const char* ShaderParser::getTokenName (Token token)
    612 {
    613 	switch (token)
    614 	{
    615 		case TOKEN_INVALID:					return "<invalid>";
    616 		case TOKEN_EOF:						return "<eof>";
    617 		case TOKEN_STRING:					return "<string>";
    618 		case TOKEN_SHADER_SOURCE:			return "source";
    619 
    620 		case TOKEN_INT_LITERAL:				return "<int>";
    621 		case TOKEN_FLOAT_LITERAL:			return "<float>";
    622 
    623 		// identifiers
    624 		case TOKEN_IDENTIFIER:				return "<identifier>";
    625 		case TOKEN_TRUE:					return "true";
    626 		case TOKEN_FALSE:					return "false";
    627 		case TOKEN_DESC:					return "desc";
    628 		case TOKEN_EXPECT:					return "expect";
    629 		case TOKEN_GROUP:					return "group";
    630 		case TOKEN_CASE:					return "case";
    631 		case TOKEN_END:						return "end";
    632 		case TOKEN_VALUES:					return "values";
    633 		case TOKEN_BOTH:					return "both";
    634 		case TOKEN_VERTEX:					return "vertex";
    635 		case TOKEN_FRAGMENT:				return "fragment";
    636 		case TOKEN_TESSELLATION_CONTROL:	return "tessellation_control";
    637 		case TOKEN_TESSELLATION_EVALUATION:	return "tessellation_evaluation";
    638 		case TOKEN_GEOMETRY:				return "geometry";
    639 		case TOKEN_REQUIRE:					return "require";
    640 		case TOKEN_UNIFORM:					return "uniform";
    641 		case TOKEN_INPUT:					return "input";
    642 		case TOKEN_OUTPUT:					return "output";
    643 		case TOKEN_FLOAT:					return "float";
    644 		case TOKEN_FLOAT_VEC2:				return "vec2";
    645 		case TOKEN_FLOAT_VEC3:				return "vec3";
    646 		case TOKEN_FLOAT_VEC4:				return "vec4";
    647 		case TOKEN_FLOAT_MAT2:				return "mat2";
    648 		case TOKEN_FLOAT_MAT2X3:			return "mat2x3";
    649 		case TOKEN_FLOAT_MAT2X4:			return "mat2x4";
    650 		case TOKEN_FLOAT_MAT3X2:			return "mat3x2";
    651 		case TOKEN_FLOAT_MAT3:				return "mat3";
    652 		case TOKEN_FLOAT_MAT3X4:			return "mat3x4";
    653 		case TOKEN_FLOAT_MAT4X2:			return "mat4x2";
    654 		case TOKEN_FLOAT_MAT4X3:			return "mat4x3";
    655 		case TOKEN_FLOAT_MAT4:				return "mat4";
    656 		case TOKEN_INT:						return "int";
    657 		case TOKEN_INT_VEC2:				return "ivec2";
    658 		case TOKEN_INT_VEC3:				return "ivec3";
    659 		case TOKEN_INT_VEC4:				return "ivec4";
    660 		case TOKEN_UINT:					return "uint";
    661 		case TOKEN_UINT_VEC2:				return "uvec2";
    662 		case TOKEN_UINT_VEC3:				return "uvec3";
    663 		case TOKEN_UINT_VEC4:				return "uvec4";
    664 		case TOKEN_BOOL:					return "bool";
    665 		case TOKEN_BOOL_VEC2:				return "bvec2";
    666 		case TOKEN_BOOL_VEC3:				return "bvec3";
    667 		case TOKEN_BOOL_VEC4:				return "bvec4";
    668 		case TOKEN_IN:						return "in";
    669 		case TOKEN_IMPORT:					return "import";
    670 		case TOKEN_PIPELINE_PROGRAM:		return "pipeline_program";
    671 		case TOKEN_ACTIVE_STAGES:			return "active_stages";
    672 
    673 		case TOKEN_ASSIGN:					return "=";
    674 		case TOKEN_PLUS:					return "+";
    675 		case TOKEN_MINUS:					return "-";
    676 		case TOKEN_COMMA:					return ",";
    677 		case TOKEN_VERTICAL_BAR:			return "|";
    678 		case TOKEN_SEMI_COLON:				return ";";
    679 		case TOKEN_LEFT_PAREN:				return "(";
    680 		case TOKEN_RIGHT_PAREN:				return ")";
    681 		case TOKEN_LEFT_BRACKET:			return "[";
    682 		case TOKEN_RIGHT_BRACKET:			return "]";
    683 		case TOKEN_LEFT_BRACE:				return "{";
    684 		case TOKEN_RIGHT_BRACE:				return "}";
    685 		case TOKEN_GREATER:					return ">";
    686 
    687 		default:							return "<unknown>";
    688 	}
    689 }
    690 
    691 deUint32 ShaderParser::getShaderStageLiteralFlag (void)
    692 {
    693 	switch (m_curToken)
    694 	{
    695 		case TOKEN_VERTEX:					return (1 << glu::SHADERTYPE_VERTEX);
    696 		case TOKEN_FRAGMENT:				return (1 << glu::SHADERTYPE_FRAGMENT);
    697 		case TOKEN_GEOMETRY:				return (1 << glu::SHADERTYPE_GEOMETRY);
    698 		case TOKEN_TESSELLATION_CONTROL:	return (1 << glu::SHADERTYPE_TESSELLATION_CONTROL);
    699 		case TOKEN_TESSELLATION_EVALUATION:	return (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION);
    700 
    701 		default:
    702 			parseError(std::string() + "invalid shader stage name, got " + m_curTokenStr);
    703 			return 0;
    704 	}
    705 }
    706 
    707 deUint32 ShaderParser::getGLEnumFromName (const std::string& enumName)
    708 {
    709 	static const struct
    710 	{
    711 		const char*	name;
    712 		deUint32	value;
    713 	} names[] =
    714 	{
    715 		{ "GL_MAX_VERTEX_IMAGE_UNIFORMS",			GL_MAX_VERTEX_IMAGE_UNIFORMS			},
    716 		{ "GL_MAX_VERTEX_ATOMIC_COUNTERS",			GL_MAX_VERTEX_ATOMIC_COUNTERS			},
    717 		{ "GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS",	GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS		},
    718 		{ "GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS",	GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS	},
    719 	};
    720 
    721 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(names); ++ndx)
    722 		if (names[ndx].name == enumName)
    723 			return names[ndx].value;
    724 
    725 	parseError(std::string() + "unknown enum name, got " + enumName);
    726 	return 0;
    727 }
    728 
    729 void ShaderParser::parseValueElement (DataType expectedDataType, ShaderCase::Value& result)
    730 {
    731 	DataType	scalarType	= getDataTypeScalarType(expectedDataType);
    732 	int			scalarSize	= getDataTypeScalarSize(expectedDataType);
    733 
    734 	/* \todo [2010-04-19 petri] Support arrays. */
    735 	ShaderCase::Value::Element elems[16];
    736 
    737 	if (scalarSize > 1)
    738 	{
    739 		DE_ASSERT(mapDataTypeToken(m_curToken) == expectedDataType);
    740 		advanceToken(); // data type (float, vec2, etc.)
    741 		advanceToken(TOKEN_LEFT_PAREN);
    742 	}
    743 
    744 	for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
    745 	{
    746 		if (scalarType == TYPE_FLOAT)
    747 		{
    748 			float signMult = 1.0f;
    749 			if (m_curToken == TOKEN_MINUS)
    750 			{
    751 				signMult = -1.0f;
    752 				advanceToken();
    753 			}
    754 
    755 			assumeToken(TOKEN_FLOAT_LITERAL);
    756 			elems[scalarNdx].float32 = signMult * parseFloatLiteral(m_curTokenStr.c_str());
    757 			advanceToken(TOKEN_FLOAT_LITERAL);
    758 		}
    759 		else if (scalarType == TYPE_INT || scalarType == TYPE_UINT)
    760 		{
    761 			int signMult = 1;
    762 			if (m_curToken == TOKEN_MINUS)
    763 			{
    764 				signMult = -1;
    765 				advanceToken();
    766 			}
    767 
    768 			assumeToken(TOKEN_INT_LITERAL);
    769 			elems[scalarNdx].int32 = signMult * parseIntLiteral(m_curTokenStr.c_str());
    770 			advanceToken(TOKEN_INT_LITERAL);
    771 		}
    772 		else
    773 		{
    774 			DE_ASSERT(scalarType == TYPE_BOOL);
    775 			elems[scalarNdx].bool32 = (m_curToken == TOKEN_TRUE);
    776 			if (m_curToken != TOKEN_TRUE && m_curToken != TOKEN_FALSE)
    777 				parseError(string("unexpected token, expecting bool: " + m_curTokenStr));
    778 			advanceToken(); // true/false
    779 		}
    780 
    781 		if (scalarNdx != (scalarSize - 1))
    782 			advanceToken(TOKEN_COMMA);
    783 	}
    784 
    785 	if (scalarSize > 1)
    786 		advanceToken(TOKEN_RIGHT_PAREN);
    787 
    788 	// Store results.
    789 	for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
    790 		result.elements.push_back(elems[scalarNdx]);
    791 }
    792 
    793 void ShaderParser::parseValue (ShaderCase::ValueBlock& valueBlock)
    794 {
    795 	PARSE_DBG(("      parseValue()\n"));
    796 
    797 	// Parsed results.
    798 	ShaderCase::Value result;
    799 
    800 	// Parse storage.
    801 	if (m_curToken == TOKEN_UNIFORM)
    802 		result.storageType = ShaderCase::Value::STORAGE_UNIFORM;
    803 	else if (m_curToken == TOKEN_INPUT)
    804 		result.storageType = ShaderCase::Value::STORAGE_INPUT;
    805 	else if (m_curToken == TOKEN_OUTPUT)
    806 		result.storageType = ShaderCase::Value::STORAGE_OUTPUT;
    807 	else
    808 		parseError(string("unexpected token encountered when parsing value classifier"));
    809 	advanceToken();
    810 
    811 	// Parse data type.
    812 	result.dataType = mapDataTypeToken(m_curToken);
    813 	if (result.dataType == TYPE_INVALID)
    814 		parseError(string("unexpected token when parsing value data type: " + m_curTokenStr));
    815 	advanceToken();
    816 
    817 	// Parse value name.
    818 	if (m_curToken == TOKEN_IDENTIFIER || m_curToken == TOKEN_STRING)
    819 	{
    820 		if (m_curToken == TOKEN_IDENTIFIER)
    821 			result.valueName = m_curTokenStr;
    822 		else
    823 			result.valueName = parseStringLiteral(m_curTokenStr.c_str());
    824 	}
    825 	else
    826 		parseError(string("unexpected token when parsing value name: " + m_curTokenStr));
    827 	advanceToken();
    828 
    829 	// Parse assignment operator.
    830 	advanceToken(TOKEN_ASSIGN);
    831 
    832 	// Parse actual value.
    833 	if (m_curToken == TOKEN_LEFT_BRACKET) // value list
    834 	{
    835 		advanceToken(TOKEN_LEFT_BRACKET);
    836 		result.arrayLength = 0;
    837 
    838 		for (;;)
    839 		{
    840 			parseValueElement(result.dataType, result);
    841 			result.arrayLength++;
    842 
    843 			if (m_curToken == TOKEN_RIGHT_BRACKET)
    844 				break;
    845 			else if (m_curToken == TOKEN_VERTICAL_BAR)
    846 			{
    847 				advanceToken();
    848 				continue;
    849 			}
    850 			else
    851 				parseError(string("unexpected token in value element array: " + m_curTokenStr));
    852 		}
    853 
    854 		advanceToken(TOKEN_RIGHT_BRACKET);
    855 	}
    856 	else // arrays, single elements
    857 	{
    858 		parseValueElement(result.dataType, result);
    859 		result.arrayLength = 1;
    860 	}
    861 
    862 	advanceToken(TOKEN_SEMI_COLON); // end of declaration
    863 
    864 	valueBlock.values.push_back(result);
    865 }
    866 
    867 void ShaderParser::parseValueBlock (ShaderCase::ValueBlock& valueBlock)
    868 {
    869 	PARSE_DBG(("    parseValueBlock()\n"));
    870 	advanceToken(TOKEN_VALUES);
    871 	advanceToken(TOKEN_LEFT_BRACE);
    872 
    873 	for (;;)
    874 	{
    875 		if (m_curToken == TOKEN_UNIFORM || m_curToken == TOKEN_INPUT || m_curToken == TOKEN_OUTPUT)
    876 			parseValue(valueBlock);
    877 		else if (m_curToken == TOKEN_RIGHT_BRACE)
    878 			break;
    879 		else
    880 			parseError(string("unexpected token when parsing a value block: " + m_curTokenStr));
    881 	}
    882 
    883 	advanceToken(TOKEN_RIGHT_BRACE);
    884 
    885 	// Compute combined array length of value block.
    886 	int arrayLength = 1;
    887 	for (int valueNdx = 0; valueNdx < (int)valueBlock.values.size(); valueNdx++)
    888 	{
    889 		const ShaderCase::Value& val = valueBlock.values[valueNdx];
    890 		if (val.arrayLength > 1)
    891 		{
    892 			DE_ASSERT(arrayLength == 1 || arrayLength == val.arrayLength);
    893 			arrayLength = val.arrayLength;
    894 		}
    895 	}
    896 	valueBlock.arrayLength = arrayLength;
    897 }
    898 
    899 deUint32 ShaderParser::parseShaderStageList (void)
    900 {
    901 	deUint32 mask = 0;
    902 
    903 	assumeToken(TOKEN_LEFT_BRACE);
    904 
    905 	// don't allow 0-sized lists
    906 	advanceToken();
    907 	mask |= getShaderStageLiteralFlag();
    908 	advanceToken();
    909 
    910 	for (;;)
    911 	{
    912 		if (m_curToken == TOKEN_RIGHT_BRACE)
    913 			break;
    914 		else if (m_curToken == TOKEN_COMMA)
    915 		{
    916 			deUint32 stageFlag;
    917 			advanceToken();
    918 
    919 			stageFlag = getShaderStageLiteralFlag();
    920 			if (stageFlag & mask)
    921 				parseError(string("stage already set in the shader stage set: " + m_curTokenStr));
    922 
    923 			mask |= stageFlag;
    924 			advanceToken();
    925 		}
    926 		else
    927 			parseError(string("invalid shader stage set token: " + m_curTokenStr));
    928 	}
    929 	advanceToken(TOKEN_RIGHT_BRACE);
    930 
    931 	return mask;
    932 }
    933 
    934 void ShaderParser::parseRequirement (ShaderCase::CaseRequirement& valueBlock)
    935 {
    936 	PARSE_DBG(("    parseRequirement()\n"));
    937 
    938 	advanceToken();
    939 	assumeToken(TOKEN_IDENTIFIER);
    940 
    941 	if (m_curTokenStr == "extension")
    942 	{
    943 		std::vector<std::string>	anyExtensionStringList;
    944 		deUint32					affectedCasesFlags		= -1; // by default all stages
    945 
    946 		advanceToken();
    947 		assumeToken(TOKEN_LEFT_BRACE);
    948 
    949 		advanceToken();
    950 		assumeToken(TOKEN_STRING);
    951 
    952 		anyExtensionStringList.push_back(parseStringLiteral(m_curTokenStr.c_str()));
    953 		advanceToken();
    954 
    955 		for (;;)
    956 		{
    957 			if (m_curToken == TOKEN_RIGHT_BRACE)
    958 				break;
    959 			else if (m_curToken == TOKEN_VERTICAL_BAR)
    960 			{
    961 				advanceToken();
    962 				assumeToken(TOKEN_STRING);
    963 
    964 				anyExtensionStringList.push_back(parseStringLiteral(m_curTokenStr.c_str()));
    965 				advanceToken();
    966 			}
    967 			else
    968 				parseError(string("invalid extension list token: " + m_curTokenStr));
    969 		}
    970 		advanceToken(TOKEN_RIGHT_BRACE);
    971 
    972 		if (m_curToken == TOKEN_IN)
    973 		{
    974 			advanceToken();
    975 			affectedCasesFlags = parseShaderStageList();
    976 		}
    977 
    978 		valueBlock = ShaderCase::CaseRequirement::createAnyExtensionRequirement(anyExtensionStringList, affectedCasesFlags);
    979 	}
    980 	else if (m_curTokenStr == "limit")
    981 	{
    982 		deUint32	limitEnum;
    983 		int			limitValue;
    984 
    985 		advanceToken();
    986 
    987 		assumeToken(TOKEN_STRING);
    988 		limitEnum = getGLEnumFromName(parseStringLiteral(m_curTokenStr.c_str()));
    989 		advanceToken();
    990 
    991 		assumeToken(TOKEN_GREATER);
    992 		advanceToken();
    993 
    994 		assumeToken(TOKEN_INT_LITERAL);
    995 		limitValue = parseIntLiteral(m_curTokenStr.c_str());
    996 		advanceToken();
    997 
    998 		valueBlock = ShaderCase::CaseRequirement::createLimitRequirement(limitEnum, limitValue);
    999 	}
   1000 	else
   1001 		parseError(string("invalid requirement value: " + m_curTokenStr));
   1002 }
   1003 
   1004 void ShaderParser::parseExpectResult (ShaderCase::ExpectResult& expectResult)
   1005 {
   1006 	assumeToken(TOKEN_IDENTIFIER);
   1007 
   1008 	if (m_curTokenStr == "pass")
   1009 		expectResult = ShaderCase::EXPECT_PASS;
   1010 	else if (m_curTokenStr == "compile_fail")
   1011 		expectResult = ShaderCase::EXPECT_COMPILE_FAIL;
   1012 	else if (m_curTokenStr == "link_fail")
   1013 		expectResult = ShaderCase::EXPECT_LINK_FAIL;
   1014 	else if (m_curTokenStr == "compile_or_link_fail")
   1015 		expectResult = ShaderCase::EXPECT_COMPILE_LINK_FAIL;
   1016 	else if (m_curTokenStr == "validation_fail")
   1017 		expectResult = ShaderCase::EXPECT_VALIDATION_FAIL;
   1018 	else
   1019 		parseError(string("invalid expected result value: " + m_curTokenStr));
   1020 
   1021 	advanceToken();
   1022 }
   1023 
   1024 void ShaderParser::parseGLSLVersion (glu::GLSLVersion& version)
   1025 {
   1026 	int			versionNum		= 0;
   1027 	std::string	postfix			= "";
   1028 
   1029 	assumeToken(TOKEN_INT_LITERAL);
   1030 	versionNum = parseIntLiteral(m_curTokenStr.c_str());
   1031 	advanceToken();
   1032 
   1033 	if (m_curToken == TOKEN_IDENTIFIER)
   1034 	{
   1035 		postfix = m_curTokenStr;
   1036 		advanceToken();
   1037 	}
   1038 
   1039 	if		(versionNum == 100 && postfix == "es")	version = glu::GLSL_VERSION_100_ES;
   1040 	else if (versionNum == 300 && postfix == "es")	version = glu::GLSL_VERSION_300_ES;
   1041 	else if (versionNum == 310 && postfix == "es")	version = glu::GLSL_VERSION_310_ES;
   1042 	else if (versionNum == 130)						version = glu::GLSL_VERSION_130;
   1043 	else if (versionNum == 140)						version = glu::GLSL_VERSION_140;
   1044 	else if (versionNum == 150)						version = glu::GLSL_VERSION_150;
   1045 	else if (versionNum == 330)						version = glu::GLSL_VERSION_330;
   1046 	else if (versionNum == 400)						version = glu::GLSL_VERSION_400;
   1047 	else if (versionNum == 410)						version = glu::GLSL_VERSION_410;
   1048 	else if (versionNum == 420)						version = glu::GLSL_VERSION_420;
   1049 	else if (versionNum == 430)						version = glu::GLSL_VERSION_430;
   1050 	else
   1051 		parseError("Unknown GLSL version");
   1052 }
   1053 
   1054 void ShaderParser::parsePipelineProgram (ShaderCase::PipelineProgram& program)
   1055 {
   1056 	deUint32							activeStages			= 0;
   1057 	vector<string>						vertexSources;
   1058 	vector<string>						fragmentSources;
   1059 	vector<string>						tessellationCtrlSources;
   1060 	vector<string>						tessellationEvalSources;
   1061 	vector<string>						geometrySources;
   1062 	vector<ShaderCase::CaseRequirement>	requirements;
   1063 
   1064 	advanceToken(TOKEN_PIPELINE_PROGRAM);
   1065 
   1066 	for (;;)
   1067 	{
   1068 		if (m_curToken == TOKEN_END)
   1069 			break;
   1070 		else if (m_curToken == TOKEN_ACTIVE_STAGES)
   1071 		{
   1072 			advanceToken();
   1073 			activeStages = parseShaderStageList();
   1074 		}
   1075 		else if (m_curToken == TOKEN_REQUIRE)
   1076 		{
   1077 			ShaderCase::CaseRequirement requirement;
   1078 			parseRequirement(requirement);
   1079 			requirements.push_back(requirement);
   1080 		}
   1081 		else if (m_curToken == TOKEN_VERTEX						||
   1082 				 m_curToken == TOKEN_FRAGMENT					||
   1083 				 m_curToken == TOKEN_TESSELLATION_CONTROL		||
   1084 				 m_curToken == TOKEN_TESSELLATION_EVALUATION	||
   1085 				 m_curToken == TOKEN_GEOMETRY)
   1086 		{
   1087 			const Token	token = m_curToken;
   1088 			string		source;
   1089 
   1090 			advanceToken();
   1091 			assumeToken(TOKEN_SHADER_SOURCE);
   1092 			source = parseShaderSource(m_curTokenStr.c_str());
   1093 			advanceToken();
   1094 
   1095 			switch (token)
   1096 			{
   1097 				case TOKEN_VERTEX:					vertexSources.push_back(source);			break;
   1098 				case TOKEN_FRAGMENT:				fragmentSources.push_back(source);			break;
   1099 				case TOKEN_TESSELLATION_CONTROL:	tessellationCtrlSources.push_back(source);	break;
   1100 				case TOKEN_TESSELLATION_EVALUATION:	tessellationEvalSources.push_back(source);	break;
   1101 				case TOKEN_GEOMETRY:				geometrySources.push_back(source);			break;
   1102 				default:
   1103 					parseError(DE_FALSE);
   1104 			}
   1105 		}
   1106 		else
   1107 			parseError(string("invalid pipeline program value: " + m_curTokenStr));
   1108 	}
   1109 	advanceToken(TOKEN_END);
   1110 
   1111 	if (activeStages == 0)
   1112 		parseError("program pipeline object must have active stages");
   1113 
   1114 	// return pipeline part
   1115 	program.activeStageBits = activeStages;
   1116 	program.requirements.swap(requirements);
   1117 	program.vertexSources.swap(vertexSources);
   1118 	program.fragmentSources.swap(fragmentSources);
   1119 	program.tessCtrlSources.swap(tessellationCtrlSources);
   1120 	program.tessEvalSources.swap(tessellationEvalSources);
   1121 	program.geometrySources.swap(geometrySources);
   1122 }
   1123 
   1124 void ShaderParser::parseShaderCase (vector<tcu::TestNode*>& shaderNodeList)
   1125 {
   1126 	// Parse 'case'.
   1127 	PARSE_DBG(("  parseShaderCase()\n"));
   1128 	advanceToken(TOKEN_CASE);
   1129 
   1130 	// Parse case name.
   1131 	string caseName = m_curTokenStr;
   1132 	advanceToken(); // \note [pyry] All token types are allowed here.
   1133 
   1134 	// Setup case.
   1135 	GLSLVersion							version			= DEFAULT_GLSL_VERSION;
   1136 	ShaderCase::ExpectResult			expectResult	= ShaderCase::EXPECT_PASS;
   1137 	string								description;
   1138 	string								bothSource;
   1139 	vector<string>						vertexSources;
   1140 	vector<string>						fragmentSources;
   1141 	vector<string>						tessellationCtrlSources;
   1142 	vector<string>						tessellationEvalSources;
   1143 	vector<string>						geometrySources;
   1144 	vector<ShaderCase::ValueBlock>		valueBlockList;
   1145 	vector<ShaderCase::CaseRequirement>	requirements;
   1146 	vector<ShaderCase::PipelineProgram>	pipelinePrograms;
   1147 
   1148 	for (;;)
   1149 	{
   1150 		if (m_curToken == TOKEN_END)
   1151 			break;
   1152 		else if (m_curToken == TOKEN_DESC)
   1153 		{
   1154 			advanceToken();
   1155 			assumeToken(TOKEN_STRING);
   1156 			description = parseStringLiteral(m_curTokenStr.c_str());
   1157 			advanceToken();
   1158 		}
   1159 		else if (m_curToken == TOKEN_EXPECT)
   1160 		{
   1161 			advanceToken();
   1162 			parseExpectResult(expectResult);
   1163 		}
   1164 		else if (m_curToken == TOKEN_VALUES)
   1165 		{
   1166 			ShaderCase::ValueBlock block;
   1167 			parseValueBlock(block);
   1168 			valueBlockList.push_back(block);
   1169 		}
   1170 		else if (m_curToken == TOKEN_BOTH						||
   1171 				 m_curToken == TOKEN_VERTEX						||
   1172 				 m_curToken == TOKEN_FRAGMENT					||
   1173 				 m_curToken == TOKEN_TESSELLATION_CONTROL		||
   1174 				 m_curToken == TOKEN_TESSELLATION_EVALUATION	||
   1175 				 m_curToken == TOKEN_GEOMETRY)
   1176 		{
   1177 			const Token	token = m_curToken;
   1178 			string		source;
   1179 
   1180 			advanceToken();
   1181 			assumeToken(TOKEN_SHADER_SOURCE);
   1182 			source = parseShaderSource(m_curTokenStr.c_str());
   1183 			advanceToken();
   1184 
   1185 			switch (token)
   1186 			{
   1187 				case TOKEN_VERTEX:					vertexSources.push_back(source);			break;
   1188 				case TOKEN_FRAGMENT:				fragmentSources.push_back(source);			break;
   1189 				case TOKEN_TESSELLATION_CONTROL:	tessellationCtrlSources.push_back(source);	break;
   1190 				case TOKEN_TESSELLATION_EVALUATION:	tessellationEvalSources.push_back(source);	break;
   1191 				case TOKEN_GEOMETRY:				geometrySources.push_back(source);			break;
   1192 				case TOKEN_BOTH:
   1193 				{
   1194 					if (!bothSource.empty())
   1195 						parseError("multiple 'both' blocks");
   1196 					bothSource = source;
   1197 					break;
   1198 				}
   1199 
   1200 				default:
   1201 					parseError(DE_FALSE);
   1202 			}
   1203 		}
   1204 		else if (m_curToken == TOKEN_VERSION)
   1205 		{
   1206 			advanceToken();
   1207 			parseGLSLVersion(version);
   1208 		}
   1209 		else if (m_curToken == TOKEN_REQUIRE)
   1210 		{
   1211 			ShaderCase::CaseRequirement requirement;
   1212 			parseRequirement(requirement);
   1213 			requirements.push_back(requirement);
   1214 		}
   1215 		else if (m_curToken == TOKEN_PIPELINE_PROGRAM)
   1216 		{
   1217 			ShaderCase::PipelineProgram pipelineProgram;
   1218 			parsePipelineProgram(pipelineProgram);
   1219 			pipelinePrograms.push_back(pipelineProgram);
   1220 		}
   1221 		else
   1222 			parseError(string("unexpected token while parsing shader case: " + m_curTokenStr));
   1223 	}
   1224 
   1225 	advanceToken(TOKEN_END); // case end
   1226 
   1227 	if (!bothSource.empty())
   1228 	{
   1229 		if (!vertexSources.empty()				||
   1230 			!fragmentSources.empty()			||
   1231 			!tessellationCtrlSources.empty()	||
   1232 			!tessellationEvalSources.empty()	||
   1233 			!geometrySources.empty()			||
   1234 			!pipelinePrograms.empty())
   1235 		{
   1236 			parseError("'both' cannot be mixed with other shader stages");
   1237 		}
   1238 
   1239 		// vertex
   1240 		{
   1241 			ShaderCase::ShaderCaseSpecification spec = ShaderCase::ShaderCaseSpecification::generateSharedSourceVertexCase(expectResult, version, valueBlockList, bothSource);
   1242 			spec.requirements = requirements;
   1243 
   1244 			shaderNodeList.push_back(new ShaderCase(m_testCtx, m_renderCtx, m_contextInfo, (caseName + "_vertex").c_str(), description.c_str(), spec));
   1245 		}
   1246 
   1247 		// fragment
   1248 		{
   1249 			ShaderCase::ShaderCaseSpecification spec = ShaderCase::ShaderCaseSpecification::generateSharedSourceFragmentCase(expectResult, version, valueBlockList, bothSource);
   1250 			spec.requirements = requirements;
   1251 
   1252 			shaderNodeList.push_back(new ShaderCase(m_testCtx, m_renderCtx, m_contextInfo, (caseName + "_fragment").c_str(), description.c_str(), spec));
   1253 		}
   1254 	}
   1255 	else if (pipelinePrograms.empty())
   1256 	{
   1257 		ShaderCase::ShaderCaseSpecification spec;
   1258 
   1259 		spec.expectResult	= expectResult;
   1260 		spec.caseType		= ShaderCase::CASETYPE_COMPLETE;
   1261 		spec.targetVersion	= version;
   1262 		spec.requirements.swap(requirements);
   1263 		spec.valueBlocks.swap(valueBlockList);
   1264 		spec.vertexSources.swap(vertexSources);
   1265 		spec.fragmentSources.swap(fragmentSources);
   1266 		spec.tessCtrlSources.swap(tessellationCtrlSources);
   1267 		spec.tessEvalSources.swap(tessellationEvalSources);
   1268 		spec.geometrySources.swap(geometrySources);
   1269 
   1270 		shaderNodeList.push_back(new ShaderCase(m_testCtx, m_renderCtx, m_contextInfo, caseName.c_str(), description.c_str(), spec));
   1271 	}
   1272 	else
   1273 	{
   1274 		if (!vertexSources.empty()				||
   1275 			!fragmentSources.empty()			||
   1276 			!tessellationCtrlSources.empty()	||
   1277 			!tessellationEvalSources.empty()	||
   1278 			!geometrySources.empty())
   1279 		{
   1280 			parseError("pipeline programs cannot be mixed with complete programs");
   1281 		}
   1282 
   1283 		// Pipeline case, multiple programs
   1284 		{
   1285 			ShaderCase::PipelineCaseSpecification spec;
   1286 
   1287 			spec.expectResult	= expectResult;
   1288 			spec.caseType		= ShaderCase::CASETYPE_COMPLETE;
   1289 			spec.targetVersion	= version;
   1290 			spec.valueBlocks.swap(valueBlockList);
   1291 			spec.programs.swap(pipelinePrograms);
   1292 
   1293 			shaderNodeList.push_back(new ShaderCase(m_testCtx, m_renderCtx, m_contextInfo, caseName.c_str(), description.c_str(), spec));
   1294 		}
   1295 	}
   1296 }
   1297 
   1298 void ShaderParser::parseShaderGroup (vector<tcu::TestNode*>& shaderNodeList)
   1299 {
   1300 	// Parse 'case'.
   1301 	PARSE_DBG(("  parseShaderGroup()\n"));
   1302 	advanceToken(TOKEN_GROUP);
   1303 
   1304 	// Parse case name.
   1305 	string name = m_curTokenStr;
   1306 	advanceToken(); // \note [pyry] We don't want to check token type here (for instance to allow "uniform") group.
   1307 
   1308 	// Parse description.
   1309 	assumeToken(TOKEN_STRING);
   1310 	string description = parseStringLiteral(m_curTokenStr.c_str());
   1311 	advanceToken(TOKEN_STRING);
   1312 
   1313 	std::vector<tcu::TestNode*> children;
   1314 
   1315 	// Parse group children.
   1316 	for (;;)
   1317 	{
   1318 		if (m_curToken == TOKEN_END)
   1319 			break;
   1320 		else if (m_curToken == TOKEN_GROUP)
   1321 			parseShaderGroup(children);
   1322 		else if (m_curToken == TOKEN_CASE)
   1323 			parseShaderCase(children);
   1324 		else if (m_curToken == TOKEN_IMPORT)
   1325 			parseImport(children);
   1326 		else
   1327 			parseError(string("unexpected token while parsing shader group: " + m_curTokenStr));
   1328 	}
   1329 
   1330 	advanceToken(TOKEN_END); // group end
   1331 
   1332 	// Create group node.
   1333 	tcu::TestCaseGroup* groupNode = new tcu::TestCaseGroup(m_testCtx, name.c_str(), description.c_str(), children);
   1334 	shaderNodeList.push_back(groupNode);
   1335 }
   1336 
   1337 void ShaderParser::parseImport (vector<tcu::TestNode*>& shaderNodeList)
   1338 {
   1339 	ShaderLibrary			subLibrary		(m_testCtx, m_renderCtx, m_contextInfo);
   1340 	vector<tcu::TestNode*>	importedCases;
   1341 	std::string				filename;
   1342 
   1343 	if (!m_currentDir)
   1344 		parseError(string("cannot use import in inline shader source"));
   1345 
   1346 	advanceToken(TOKEN_IMPORT);
   1347 
   1348 	assumeToken(TOKEN_STRING);
   1349 	filename = m_currentDir + parseStringLiteral(m_curTokenStr.c_str());
   1350 	advanceToken(TOKEN_STRING);
   1351 
   1352 	importedCases = subLibrary.loadShaderFile(filename.c_str());
   1353 	shaderNodeList.insert(shaderNodeList.end(), importedCases.begin(), importedCases.end());
   1354 }
   1355 
   1356 vector<tcu::TestNode*> ShaderParser::parse (const char* input)
   1357 {
   1358 	// Initialize parser.
   1359 	m_input			= input;
   1360 	m_curPtr		= m_input.c_str();
   1361 	m_curToken		= TOKEN_INVALID;
   1362 	m_curTokenStr	= "";
   1363 	advanceToken();
   1364 
   1365 	vector<tcu::TestNode*> nodeList;
   1366 
   1367 	// Parse all cases.
   1368 	PARSE_DBG(("parse()\n"));
   1369 	for (;;)
   1370 	{
   1371 		if (m_curToken == TOKEN_CASE)
   1372 			parseShaderCase(nodeList);
   1373 		else if (m_curToken == TOKEN_GROUP)
   1374 			parseShaderGroup(nodeList);
   1375 		else if (m_curToken == TOKEN_IMPORT)
   1376 			parseImport(nodeList);
   1377 		else if (m_curToken == TOKEN_EOF)
   1378 			break;
   1379 		else
   1380 			parseError(string("invalid token encountered at main level: '") + m_curTokenStr + "'");
   1381 	}
   1382 
   1383 	assumeToken(TOKEN_EOF);
   1384 //	printf("  parsed %d test cases.\n", caseList.size());
   1385 	return nodeList;
   1386 }
   1387 
   1388 } // sl
   1389 
   1390 static std::string getFileDirectory (const std::string& filePath)
   1391 {
   1392 	const std::string::size_type lastDelim = filePath.find_last_of('/');
   1393 
   1394 	if (lastDelim == std::string::npos)
   1395 		return "";
   1396 	else
   1397 		return filePath.substr(0, lastDelim+1);
   1398 }
   1399 
   1400 ShaderLibrary::ShaderLibrary (tcu::TestContext& testCtx, RenderContext& renderCtx, const glu::ContextInfo& contextInfo)
   1401 	: m_testCtx			(testCtx)
   1402 	, m_renderCtx		(renderCtx)
   1403 	, m_contextInfo		(contextInfo)
   1404 {
   1405 }
   1406 
   1407 ShaderLibrary::~ShaderLibrary (void)
   1408 {
   1409 }
   1410 
   1411 vector<tcu::TestNode*> ShaderLibrary::loadShaderFile (const char* fileName)
   1412 {
   1413 	tcu::Resource*		resource		= m_testCtx.getArchive().getResource(fileName);
   1414 	std::string			fileDirectory	= getFileDirectory(fileName);
   1415 	std::vector<char>	buf;
   1416 
   1417 /*	printf("  loading '%s'\n", fileName);*/
   1418 
   1419 	try
   1420 	{
   1421 		int size = resource->getSize();
   1422 		buf.resize(size + 1);
   1423 		resource->read((deUint8*)&buf[0], size);
   1424 		buf[size] = '\0';
   1425 	}
   1426 	catch (const std::exception&)
   1427 	{
   1428 		delete resource;
   1429 		throw;
   1430 	}
   1431 
   1432 	delete resource;
   1433 
   1434 	sl::ShaderParser parser(m_testCtx, m_renderCtx, m_contextInfo, fileDirectory.c_str());
   1435 	vector<tcu::TestNode*> nodes = parser.parse(&buf[0]);
   1436 
   1437 	return nodes;
   1438 }
   1439 
   1440 vector<tcu::TestNode*> ShaderLibrary::parseShader (const char* shaderSource)
   1441 {
   1442 	sl::ShaderParser parser(m_testCtx, m_renderCtx, m_contextInfo);
   1443 	vector<tcu::TestNode*> nodes = parser.parse(shaderSource);
   1444 
   1445 	return nodes;
   1446 }
   1447 
   1448 } // gls
   1449 } // deqp
   1450