Home | History | Annotate | Download | only in common
      1 /*-------------------------------------------------------------------------
      2  * OpenGL Conformance Test Suite
      3  * -----------------------------
      4  *
      5  * Copyright (c) 2016 Google Inc.
      6  * Copyright (c) 2016 The Khronos Group Inc.
      7  *
      8  * Licensed under the Apache License, Version 2.0 (the "License");
      9  * you may not use this file except in compliance with the License.
     10  * You may obtain a copy of the License at
     11  *
     12  *      http://www.apache.org/licenses/LICENSE-2.0
     13  *
     14  * Unless required by applicable law or agreed to in writing, software
     15  * distributed under the License is distributed on an "AS IS" BASIS,
     16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     17  * See the License for the specific language governing permissions and
     18  * limitations under the License.
     19  *
     20  */ /*!
     21  * \file
     22  * \brief Compiler test case.
     23  */ /*-------------------------------------------------------------------*/
     24 
     25 #include "glcShaderLibrary.hpp"
     26 #include "glcShaderLibraryCase.hpp"
     27 #include "gluShaderUtil.hpp"
     28 #include "tcuResource.hpp"
     29 
     30 #include "deInt32.h"
     31 
     32 #include <fstream>
     33 #include <sstream>
     34 #include <string>
     35 #include <vector>
     36 
     37 #include <stdarg.h>
     38 #include <stdlib.h>
     39 #include <string.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 sl
     56 {
     57 
     58 static const glu::GLSLVersion DEFAULT_GLSL_VERSION = glu::GLSL_VERSION_100_ES;
     59 
     60 DE_INLINE deBool isWhitespace(char c)
     61 {
     62 	return (c == ' ') || (c == '\t') || (c == '\r') || (c == '\n');
     63 }
     64 
     65 DE_INLINE deBool isEOL(char c)
     66 {
     67 	return (c == '\r') || (c == '\n');
     68 }
     69 
     70 DE_INLINE deBool isNumeric(char c)
     71 {
     72 	return deInRange32(c, '0', '9');
     73 }
     74 
     75 DE_INLINE deBool isAlpha(char c)
     76 {
     77 	return deInRange32(c, 'a', 'z') || deInRange32(c, 'A', 'Z');
     78 }
     79 
     80 DE_INLINE deBool isCaseNameChar(char c)
     81 {
     82 	return deInRange32(c, 'a', 'z') || deInRange32(c, 'A', 'Z') || deInRange32(c, '0', '9') || (c == '_') ||
     83 		   (c == '-') || (c == '.');
     84 }
     85 
     86 // \todo [2011-02-11 pyry] Should not depend on Context or TestContext!
     87 class ShaderParser
     88 {
     89 public:
     90 	ShaderParser(tcu::TestContext& testCtx, RenderContext& renderCtx);
     91 	~ShaderParser(void);
     92 
     93 	vector<tcu::TestNode*> parse(const char* input);
     94 
     95 private:
     96 	enum Token
     97 	{
     98 		TOKEN_INVALID = 0,
     99 		TOKEN_EOF,
    100 		TOKEN_STRING,
    101 		TOKEN_SHADER_SOURCE,
    102 
    103 		TOKEN_INT_LITERAL,
    104 		TOKEN_FLOAT_LITERAL,
    105 
    106 		// identifiers
    107 		TOKEN_IDENTIFIER,
    108 		TOKEN_TRUE,
    109 		TOKEN_FALSE,
    110 		TOKEN_DESC,
    111 		TOKEN_EXPECT,
    112 		TOKEN_GROUP,
    113 		TOKEN_CASE,
    114 		TOKEN_END,
    115 		TOKEN_VALUES,
    116 		TOKEN_BOTH,
    117 		TOKEN_VERTEX,
    118 		TOKEN_FRAGMENT,
    119 		TOKEN_UNIFORM,
    120 		TOKEN_INPUT,
    121 		TOKEN_OUTPUT,
    122 		TOKEN_FLOAT,
    123 		TOKEN_FLOAT_VEC2,
    124 		TOKEN_FLOAT_VEC3,
    125 		TOKEN_FLOAT_VEC4,
    126 		TOKEN_FLOAT_MAT2,
    127 		TOKEN_FLOAT_MAT2X3,
    128 		TOKEN_FLOAT_MAT2X4,
    129 		TOKEN_FLOAT_MAT3X2,
    130 		TOKEN_FLOAT_MAT3,
    131 		TOKEN_FLOAT_MAT3X4,
    132 		TOKEN_FLOAT_MAT4X2,
    133 		TOKEN_FLOAT_MAT4X3,
    134 		TOKEN_FLOAT_MAT4,
    135 		TOKEN_INT,
    136 		TOKEN_INT_VEC2,
    137 		TOKEN_INT_VEC3,
    138 		TOKEN_INT_VEC4,
    139 		TOKEN_UINT,
    140 		TOKEN_UINT_VEC2,
    141 		TOKEN_UINT_VEC3,
    142 		TOKEN_UINT_VEC4,
    143 		TOKEN_BOOL,
    144 		TOKEN_BOOL_VEC2,
    145 		TOKEN_BOOL_VEC3,
    146 		TOKEN_BOOL_VEC4,
    147 		TOKEN_VERSION,
    148 
    149 		// symbols
    150 		TOKEN_ASSIGN,
    151 		TOKEN_PLUS,
    152 		TOKEN_MINUS,
    153 		TOKEN_COMMA,
    154 		TOKEN_VERTICAL_BAR,
    155 		TOKEN_SEMI_COLON,
    156 		TOKEN_LEFT_PAREN,
    157 		TOKEN_RIGHT_PAREN,
    158 		TOKEN_LEFT_BRACKET,
    159 		TOKEN_RIGHT_BRACKET,
    160 		TOKEN_LEFT_BRACE,
    161 		TOKEN_RIGHT_BRACE,
    162 
    163 		TOKEN_LAST
    164 	};
    165 
    166 	void parseError(const std::string& errorStr);
    167 	float parseFloatLiteral(const char* str);
    168 	long long int parseIntLiteral(const char* str);
    169 	string parseStringLiteral(const char* str);
    170 	string parseShaderSource(const char* str);
    171 	void advanceToken(void);
    172 	void advanceToken(Token assumed);
    173 	void assumeToken(Token token);
    174 	DataType mapDataTypeToken(Token token);
    175 	const char* getTokenName(Token token);
    176 
    177 	void parseValueElement(DataType dataType, ShaderCase::Value& result);
    178 	void parseValue(ShaderCase::ValueBlock& valueBlock);
    179 	void parseValueBlock(ShaderCase::ValueBlock& valueBlock);
    180 	void parseShaderCase(vector<tcu::TestNode*>& shaderNodeList);
    181 	void parseShaderGroup(vector<tcu::TestNode*>& shaderNodeList);
    182 
    183 	// Member variables.
    184 	tcu::TestContext& m_testCtx;
    185 	RenderContext&	m_renderCtx;
    186 	std::string		  m_input;
    187 	const char*		  m_curPtr;
    188 	Token			  m_curToken;
    189 	std::string		  m_curTokenStr;
    190 };
    191 
    192 ShaderParser::ShaderParser(tcu::TestContext& testCtx, RenderContext& renderCtx)
    193 	: m_testCtx(testCtx), m_renderCtx(renderCtx), m_curPtr(DE_NULL), m_curToken(TOKEN_LAST)
    194 {
    195 }
    196 
    197 ShaderParser::~ShaderParser(void)
    198 {
    199 	// nada
    200 }
    201 
    202 void ShaderParser::parseError(const std::string& errorStr)
    203 {
    204 	string atStr = string(m_curPtr, 80);
    205 	throw tcu::InternalError((string("Parser error: ") + errorStr + " near '" + atStr + " ...'").c_str(), "", __FILE__,
    206 							 __LINE__);
    207 }
    208 
    209 float ShaderParser::parseFloatLiteral(const char* str)
    210 {
    211 	return (float)atof(str);
    212 }
    213 
    214 long long int ShaderParser::parseIntLiteral(const char* str)
    215 {
    216 	return strtoll(str, NULL, 0);
    217 }
    218 
    219 string ShaderParser::parseStringLiteral(const char* str)
    220 {
    221 	const char*   p		  = str;
    222 	char		  endChar = *p++;
    223 	ostringstream o;
    224 
    225 	while (*p != endChar && *p)
    226 	{
    227 		if (*p == '\\')
    228 		{
    229 			switch (p[1])
    230 			{
    231 			case 0:
    232 				DE_ASSERT(DE_FALSE);
    233 				break;
    234 			case 'n':
    235 				o << '\n';
    236 				break;
    237 			case 't':
    238 				o << '\t';
    239 				break;
    240 			default:
    241 				o << p[1];
    242 				break;
    243 			}
    244 
    245 			p += 2;
    246 		}
    247 		else
    248 			o << *p++;
    249 	}
    250 
    251 	return o.str();
    252 }
    253 
    254 static string removeExtraIndentation(const string& source)
    255 {
    256 	// Detect indentation from first line.
    257 	int numIndentChars = 0;
    258 	for (int ndx = 0; isWhitespace(source[ndx]) && ndx < (int)source.length(); ndx++)
    259 		numIndentChars += source[ndx] == '\t' ? 4 : 1;
    260 
    261 	// Process all lines and remove preceding indentation.
    262 	ostringstream processed;
    263 	{
    264 		bool atLineStart		= true;
    265 		int  indentCharsOmitted = 0;
    266 
    267 		for (int pos = 0; pos < (int)source.length(); pos++)
    268 		{
    269 			char c = source[pos];
    270 
    271 			if (atLineStart && indentCharsOmitted < numIndentChars && (c == ' ' || c == '\t'))
    272 			{
    273 				indentCharsOmitted += c == '\t' ? 4 : 1;
    274 			}
    275 			else if (isEOL(c))
    276 			{
    277 				if (source[pos] == '\r' && source[pos + 1] == '\n')
    278 				{
    279 					pos += 1;
    280 					processed << '\n';
    281 				}
    282 				else
    283 					processed << c;
    284 
    285 				atLineStart		   = true;
    286 				indentCharsOmitted = 0;
    287 			}
    288 			else
    289 			{
    290 				processed << c;
    291 				atLineStart = false;
    292 			}
    293 		}
    294 	}
    295 
    296 	return processed.str();
    297 }
    298 
    299 string ShaderParser::parseShaderSource(const char* str)
    300 {
    301 	const char*   p = str + 2;
    302 	ostringstream o;
    303 
    304 	// Eat first empty line from beginning.
    305 	while (*p == ' ')
    306 		p++;
    307 	while (isEOL(*p))
    308 		p++;
    309 
    310 	while ((p[0] != '"') || (p[1] != '"'))
    311 	{
    312 		if (*p == '\\')
    313 		{
    314 			switch (p[1])
    315 			{
    316 			case 0:
    317 				DE_ASSERT(DE_FALSE);
    318 				break;
    319 			case 'n':
    320 				o << '\n';
    321 				break;
    322 			case 't':
    323 				o << '\t';
    324 				break;
    325 			default:
    326 				o << p[1];
    327 				break;
    328 			}
    329 
    330 			p += 2;
    331 		}
    332 		else
    333 			o << *p++;
    334 	}
    335 
    336 	return removeExtraIndentation(o.str());
    337 }
    338 
    339 void ShaderParser::advanceToken(void)
    340 {
    341 	// Skip old token.
    342 	m_curPtr += m_curTokenStr.length();
    343 
    344 	// Reset token (for safety).
    345 	m_curToken	= TOKEN_INVALID;
    346 	m_curTokenStr = "";
    347 
    348 	// Eat whitespace & comments while they last.
    349 	for (;;)
    350 	{
    351 		while (isWhitespace(*m_curPtr))
    352 			m_curPtr++;
    353 
    354 		// Check for EOL comment.
    355 		if (*m_curPtr == '#')
    356 		{
    357 			while (*m_curPtr && !isEOL(*m_curPtr))
    358 				m_curPtr++;
    359 		}
    360 		else
    361 			break;
    362 	}
    363 
    364 	if (!*m_curPtr)
    365 	{
    366 		m_curToken	= TOKEN_EOF;
    367 		m_curTokenStr = "<EOF>";
    368 	}
    369 	else if (isAlpha(*m_curPtr))
    370 	{
    371 		struct Named
    372 		{
    373 			const char* str;
    374 			Token		token;
    375 		};
    376 
    377 		static const Named s_named[] = { { "true", TOKEN_TRUE },
    378 										 { "false", TOKEN_FALSE },
    379 										 { "desc", TOKEN_DESC },
    380 										 { "expect", TOKEN_EXPECT },
    381 										 { "group", TOKEN_GROUP },
    382 										 { "case", TOKEN_CASE },
    383 										 { "end", TOKEN_END },
    384 										 { "values", TOKEN_VALUES },
    385 										 { "both", TOKEN_BOTH },
    386 										 { "vertex", TOKEN_VERTEX },
    387 										 { "fragment", TOKEN_FRAGMENT },
    388 										 { "uniform", TOKEN_UNIFORM },
    389 										 { "input", TOKEN_INPUT },
    390 										 { "output", TOKEN_OUTPUT },
    391 										 { "float", TOKEN_FLOAT },
    392 										 { "vec2", TOKEN_FLOAT_VEC2 },
    393 										 { "vec3", TOKEN_FLOAT_VEC3 },
    394 										 { "vec4", TOKEN_FLOAT_VEC4 },
    395 										 { "mat2", TOKEN_FLOAT_MAT2 },
    396 										 { "mat2x3", TOKEN_FLOAT_MAT2X3 },
    397 										 { "mat2x4", TOKEN_FLOAT_MAT2X4 },
    398 										 { "mat3x2", TOKEN_FLOAT_MAT3X2 },
    399 										 { "mat3", TOKEN_FLOAT_MAT3 },
    400 										 { "mat3x4", TOKEN_FLOAT_MAT3X4 },
    401 										 { "mat4x2", TOKEN_FLOAT_MAT4X2 },
    402 										 { "mat4x3", TOKEN_FLOAT_MAT4X3 },
    403 										 { "mat4", TOKEN_FLOAT_MAT4 },
    404 										 { "int", TOKEN_INT },
    405 										 { "ivec2", TOKEN_INT_VEC2 },
    406 										 { "ivec3", TOKEN_INT_VEC3 },
    407 										 { "ivec4", TOKEN_INT_VEC4 },
    408 										 { "uint", TOKEN_UINT },
    409 										 { "uvec2", TOKEN_UINT_VEC2 },
    410 										 { "uvec3", TOKEN_UINT_VEC3 },
    411 										 { "uvec4", TOKEN_UINT_VEC4 },
    412 										 { "bool", TOKEN_BOOL },
    413 										 { "bvec2", TOKEN_BOOL_VEC2 },
    414 										 { "bvec3", TOKEN_BOOL_VEC3 },
    415 										 { "bvec4", TOKEN_BOOL_VEC4 },
    416 										 { "version", TOKEN_VERSION } };
    417 
    418 		const char* end = m_curPtr + 1;
    419 		while (isCaseNameChar(*end))
    420 			end++;
    421 		m_curTokenStr = string(m_curPtr, end - m_curPtr);
    422 
    423 		m_curToken = TOKEN_IDENTIFIER;
    424 
    425 		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_named); ndx++)
    426 		{
    427 			if (m_curTokenStr == s_named[ndx].str)
    428 			{
    429 				m_curToken = s_named[ndx].token;
    430 				break;
    431 			}
    432 		}
    433 	}
    434 	else if (isNumeric(*m_curPtr))
    435 	{
    436 		/* \todo [2010-03-31 petri] Hex? */
    437 		const char* p = m_curPtr;
    438 		while (isNumeric(*p))
    439 			p++;
    440 		if (*p == '.')
    441 		{
    442 			p++;
    443 			while (isNumeric(*p))
    444 				p++;
    445 
    446 			if (*p == 'e' || *p == 'E')
    447 			{
    448 				p++;
    449 				if (*p == '+' || *p == '-')
    450 					p++;
    451 				DE_ASSERT(isNumeric(*p));
    452 				while (isNumeric(*p))
    453 					p++;
    454 			}
    455 
    456 			m_curToken	= TOKEN_FLOAT_LITERAL;
    457 			m_curTokenStr = string(m_curPtr, p - m_curPtr);
    458 		}
    459 		else
    460 		{
    461 			m_curToken	= TOKEN_INT_LITERAL;
    462 			m_curTokenStr = string(m_curPtr, p - m_curPtr);
    463 		}
    464 	}
    465 	else if (*m_curPtr == '"' && m_curPtr[1] == '"')
    466 	{
    467 		const char* p = m_curPtr + 2;
    468 
    469 		while ((p[0] != '"') || (p[1] != '"'))
    470 		{
    471 			DE_ASSERT(*p);
    472 			if (*p == '\\')
    473 			{
    474 				DE_ASSERT(p[1] != 0);
    475 				p += 2;
    476 			}
    477 			else
    478 				p++;
    479 		}
    480 		p += 2;
    481 
    482 		m_curToken	= TOKEN_SHADER_SOURCE;
    483 		m_curTokenStr = string(m_curPtr, (int)(p - m_curPtr));
    484 	}
    485 	else if (*m_curPtr == '"' || *m_curPtr == '\'')
    486 	{
    487 		char		endChar = *m_curPtr;
    488 		const char* p		= m_curPtr + 1;
    489 
    490 		while (*p != endChar)
    491 		{
    492 			DE_ASSERT(*p);
    493 			if (*p == '\\')
    494 			{
    495 				DE_ASSERT(p[1] != 0);
    496 				p += 2;
    497 			}
    498 			else
    499 				p++;
    500 		}
    501 		p++;
    502 
    503 		m_curToken	= TOKEN_STRING;
    504 		m_curTokenStr = string(m_curPtr, (int)(p - m_curPtr));
    505 	}
    506 	else
    507 	{
    508 		struct SimpleToken
    509 		{
    510 			const char* str;
    511 			Token		token;
    512 		};
    513 
    514 		static const SimpleToken s_simple[] = { { "=", TOKEN_ASSIGN },		 { "+", TOKEN_PLUS },
    515 												{ "-", TOKEN_MINUS },		 { ",", TOKEN_COMMA },
    516 												{ "|", TOKEN_VERTICAL_BAR }, { ";", TOKEN_SEMI_COLON },
    517 												{ "(", TOKEN_LEFT_PAREN },   { ")", TOKEN_RIGHT_PAREN },
    518 												{ "[", TOKEN_LEFT_BRACKET }, { "]", TOKEN_RIGHT_BRACKET },
    519 												{ "{", TOKEN_LEFT_BRACE },   { "}", TOKEN_RIGHT_BRACE } };
    520 
    521 		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_simple); ndx++)
    522 		{
    523 			if (strncmp(s_simple[ndx].str, m_curPtr, strlen(s_simple[ndx].str)) == 0)
    524 			{
    525 				m_curToken	= s_simple[ndx].token;
    526 				m_curTokenStr = s_simple[ndx].str;
    527 				return;
    528 			}
    529 		}
    530 
    531 		// Otherwise invalid token.
    532 		m_curToken	= TOKEN_INVALID;
    533 		m_curTokenStr = *m_curPtr;
    534 	}
    535 }
    536 
    537 void ShaderParser::advanceToken(Token assumed)
    538 {
    539 	assumeToken(assumed);
    540 	advanceToken();
    541 }
    542 
    543 void ShaderParser::assumeToken(Token token)
    544 {
    545 	if (m_curToken != token)
    546 		parseError(
    547 			(string("unexpected token '") + m_curTokenStr + "', expecting '" + getTokenName(token) + "'").c_str());
    548 	DE_TEST_ASSERT(m_curToken == token);
    549 }
    550 
    551 DataType ShaderParser::mapDataTypeToken(Token token)
    552 {
    553 	switch (token)
    554 	{
    555 	case TOKEN_FLOAT:
    556 		return TYPE_FLOAT;
    557 	case TOKEN_FLOAT_VEC2:
    558 		return TYPE_FLOAT_VEC2;
    559 	case TOKEN_FLOAT_VEC3:
    560 		return TYPE_FLOAT_VEC3;
    561 	case TOKEN_FLOAT_VEC4:
    562 		return TYPE_FLOAT_VEC4;
    563 	case TOKEN_FLOAT_MAT2:
    564 		return TYPE_FLOAT_MAT2;
    565 	case TOKEN_FLOAT_MAT2X3:
    566 		return TYPE_FLOAT_MAT2X3;
    567 	case TOKEN_FLOAT_MAT2X4:
    568 		return TYPE_FLOAT_MAT2X4;
    569 	case TOKEN_FLOAT_MAT3X2:
    570 		return TYPE_FLOAT_MAT3X2;
    571 	case TOKEN_FLOAT_MAT3:
    572 		return TYPE_FLOAT_MAT3;
    573 	case TOKEN_FLOAT_MAT3X4:
    574 		return TYPE_FLOAT_MAT3X4;
    575 	case TOKEN_FLOAT_MAT4X2:
    576 		return TYPE_FLOAT_MAT4X2;
    577 	case TOKEN_FLOAT_MAT4X3:
    578 		return TYPE_FLOAT_MAT4X3;
    579 	case TOKEN_FLOAT_MAT4:
    580 		return TYPE_FLOAT_MAT4;
    581 	case TOKEN_INT:
    582 		return TYPE_INT;
    583 	case TOKEN_INT_VEC2:
    584 		return TYPE_INT_VEC2;
    585 	case TOKEN_INT_VEC3:
    586 		return TYPE_INT_VEC3;
    587 	case TOKEN_INT_VEC4:
    588 		return TYPE_INT_VEC4;
    589 	case TOKEN_UINT:
    590 		return TYPE_UINT;
    591 	case TOKEN_UINT_VEC2:
    592 		return TYPE_UINT_VEC2;
    593 	case TOKEN_UINT_VEC3:
    594 		return TYPE_UINT_VEC3;
    595 	case TOKEN_UINT_VEC4:
    596 		return TYPE_UINT_VEC4;
    597 	case TOKEN_BOOL:
    598 		return TYPE_BOOL;
    599 	case TOKEN_BOOL_VEC2:
    600 		return TYPE_BOOL_VEC2;
    601 	case TOKEN_BOOL_VEC3:
    602 		return TYPE_BOOL_VEC3;
    603 	case TOKEN_BOOL_VEC4:
    604 		return TYPE_BOOL_VEC4;
    605 	default:
    606 		return TYPE_INVALID;
    607 	}
    608 }
    609 
    610 const char* ShaderParser::getTokenName(Token token)
    611 {
    612 	switch (token)
    613 	{
    614 	case TOKEN_INVALID:
    615 		return "<invalid>";
    616 	case TOKEN_EOF:
    617 		return "<eof>";
    618 	case TOKEN_STRING:
    619 		return "<string>";
    620 	case TOKEN_SHADER_SOURCE:
    621 		return "source";
    622 
    623 	case TOKEN_INT_LITERAL:
    624 		return "<int>";
    625 	case TOKEN_FLOAT_LITERAL:
    626 		return "<float>";
    627 
    628 	// identifiers
    629 	case TOKEN_IDENTIFIER:
    630 		return "<identifier>";
    631 	case TOKEN_TRUE:
    632 		return "true";
    633 	case TOKEN_FALSE:
    634 		return "false";
    635 	case TOKEN_DESC:
    636 		return "desc";
    637 	case TOKEN_EXPECT:
    638 		return "expect";
    639 	case TOKEN_GROUP:
    640 		return "group";
    641 	case TOKEN_CASE:
    642 		return "case";
    643 	case TOKEN_END:
    644 		return "end";
    645 	case TOKEN_VALUES:
    646 		return "values";
    647 	case TOKEN_BOTH:
    648 		return "both";
    649 	case TOKEN_VERTEX:
    650 		return "vertex";
    651 	case TOKEN_FRAGMENT:
    652 		return "fragment";
    653 	case TOKEN_UNIFORM:
    654 		return "uniform";
    655 	case TOKEN_INPUT:
    656 		return "input";
    657 	case TOKEN_OUTPUT:
    658 		return "output";
    659 	case TOKEN_FLOAT:
    660 		return "float";
    661 	case TOKEN_FLOAT_VEC2:
    662 		return "vec2";
    663 	case TOKEN_FLOAT_VEC3:
    664 		return "vec3";
    665 	case TOKEN_FLOAT_VEC4:
    666 		return "vec4";
    667 	case TOKEN_FLOAT_MAT2:
    668 		return "mat2";
    669 	case TOKEN_FLOAT_MAT2X3:
    670 		return "mat2x3";
    671 	case TOKEN_FLOAT_MAT2X4:
    672 		return "mat2x4";
    673 	case TOKEN_FLOAT_MAT3X2:
    674 		return "mat3x2";
    675 	case TOKEN_FLOAT_MAT3:
    676 		return "mat3";
    677 	case TOKEN_FLOAT_MAT3X4:
    678 		return "mat3x4";
    679 	case TOKEN_FLOAT_MAT4X2:
    680 		return "mat4x2";
    681 	case TOKEN_FLOAT_MAT4X3:
    682 		return "mat4x3";
    683 	case TOKEN_FLOAT_MAT4:
    684 		return "mat4";
    685 	case TOKEN_INT:
    686 		return "int";
    687 	case TOKEN_INT_VEC2:
    688 		return "ivec2";
    689 	case TOKEN_INT_VEC3:
    690 		return "ivec3";
    691 	case TOKEN_INT_VEC4:
    692 		return "ivec4";
    693 	case TOKEN_UINT:
    694 		return "uint";
    695 	case TOKEN_UINT_VEC2:
    696 		return "uvec2";
    697 	case TOKEN_UINT_VEC3:
    698 		return "uvec3";
    699 	case TOKEN_UINT_VEC4:
    700 		return "uvec4";
    701 	case TOKEN_BOOL:
    702 		return "bool";
    703 	case TOKEN_BOOL_VEC2:
    704 		return "bvec2";
    705 	case TOKEN_BOOL_VEC3:
    706 		return "bvec3";
    707 	case TOKEN_BOOL_VEC4:
    708 		return "bvec4";
    709 
    710 	case TOKEN_ASSIGN:
    711 		return "=";
    712 	case TOKEN_PLUS:
    713 		return "+";
    714 	case TOKEN_MINUS:
    715 		return "-";
    716 	case TOKEN_COMMA:
    717 		return ",";
    718 	case TOKEN_VERTICAL_BAR:
    719 		return "|";
    720 	case TOKEN_SEMI_COLON:
    721 		return ";";
    722 	case TOKEN_LEFT_PAREN:
    723 		return "(";
    724 	case TOKEN_RIGHT_PAREN:
    725 		return ")";
    726 	case TOKEN_LEFT_BRACKET:
    727 		return "[";
    728 	case TOKEN_RIGHT_BRACKET:
    729 		return "]";
    730 	case TOKEN_LEFT_BRACE:
    731 		return "{";
    732 	case TOKEN_RIGHT_BRACE:
    733 		return "}";
    734 
    735 	default:
    736 		return "<unknown>";
    737 	}
    738 }
    739 
    740 void ShaderParser::parseValueElement(DataType expectedDataType, ShaderCase::Value& result)
    741 {
    742 	DataType scalarType = getDataTypeScalarType(expectedDataType);
    743 	int		 scalarSize = getDataTypeScalarSize(expectedDataType);
    744 
    745 	/* \todo [2010-04-19 petri] Support arrays. */
    746 	ShaderCase::Value::Element elems[16];
    747 
    748 	if (scalarSize > 1)
    749 	{
    750 		DE_ASSERT(mapDataTypeToken(m_curToken) == expectedDataType);
    751 		advanceToken(); // data type (float, vec2, etc.)
    752 		advanceToken(TOKEN_LEFT_PAREN);
    753 	}
    754 
    755 	for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
    756 	{
    757 		if (scalarType == TYPE_FLOAT)
    758 		{
    759 			float signMult = 1.0f;
    760 			if (m_curToken == TOKEN_MINUS)
    761 			{
    762 				signMult = -1.0f;
    763 				advanceToken();
    764 			}
    765 
    766 			assumeToken(TOKEN_FLOAT_LITERAL);
    767 			elems[scalarNdx].float32 = signMult * parseFloatLiteral(m_curTokenStr.c_str());
    768 			advanceToken(TOKEN_FLOAT_LITERAL);
    769 		}
    770 		else if (scalarType == TYPE_INT || scalarType == TYPE_UINT)
    771 		{
    772 			int signMult = 1;
    773 			if (m_curToken == TOKEN_MINUS)
    774 			{
    775 				signMult = -1;
    776 				advanceToken();
    777 			}
    778 
    779 			assumeToken(TOKEN_INT_LITERAL);
    780 			elems[scalarNdx].int32 = signMult * parseIntLiteral(m_curTokenStr.c_str());
    781 			advanceToken(TOKEN_INT_LITERAL);
    782 		}
    783 		else
    784 		{
    785 			DE_ASSERT(scalarType == TYPE_BOOL);
    786 			elems[scalarNdx].bool32 = (m_curToken == TOKEN_TRUE);
    787 			if (m_curToken != TOKEN_TRUE && m_curToken != TOKEN_FALSE)
    788 				parseError(string("unexpected token, expecting bool: " + m_curTokenStr));
    789 			advanceToken(); // true/false
    790 		}
    791 
    792 		if (scalarNdx != (scalarSize - 1))
    793 			advanceToken(TOKEN_COMMA);
    794 	}
    795 
    796 	if (scalarSize > 1)
    797 		advanceToken(TOKEN_RIGHT_PAREN);
    798 
    799 	// Store results.
    800 	for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
    801 		result.elements.push_back(elems[scalarNdx]);
    802 }
    803 
    804 void ShaderParser::parseValue(ShaderCase::ValueBlock& valueBlock)
    805 {
    806 	PARSE_DBG(("      parseValue()\n"));
    807 
    808 	// Parsed results.
    809 	ShaderCase::Value result;
    810 
    811 	// Parse storage.
    812 	if (m_curToken == TOKEN_UNIFORM)
    813 		result.storageType = ShaderCase::Value::STORAGE_UNIFORM;
    814 	else if (m_curToken == TOKEN_INPUT)
    815 		result.storageType = ShaderCase::Value::STORAGE_INPUT;
    816 	else if (m_curToken == TOKEN_OUTPUT)
    817 		result.storageType = ShaderCase::Value::STORAGE_OUTPUT;
    818 	else
    819 		parseError(string("unexpected token encountered when parsing value classifier"));
    820 	advanceToken();
    821 
    822 	// Parse data type.
    823 	result.dataType = mapDataTypeToken(m_curToken);
    824 	if (result.dataType == TYPE_INVALID)
    825 		parseError(string("unexpected token when parsing value data type: " + m_curTokenStr));
    826 	advanceToken();
    827 
    828 	// Parse value name.
    829 	if (m_curToken == TOKEN_IDENTIFIER || m_curToken == TOKEN_STRING)
    830 	{
    831 		if (m_curToken == TOKEN_IDENTIFIER)
    832 			result.valueName = m_curTokenStr;
    833 		else
    834 			result.valueName = parseStringLiteral(m_curTokenStr.c_str());
    835 	}
    836 	else
    837 		parseError(string("unexpected token when parsing value name: " + m_curTokenStr));
    838 	advanceToken();
    839 
    840 	// Parse assignment operator.
    841 	advanceToken(TOKEN_ASSIGN);
    842 
    843 	// Parse actual value.
    844 	if (m_curToken == TOKEN_LEFT_BRACKET) // value list
    845 	{
    846 		advanceToken(TOKEN_LEFT_BRACKET);
    847 		result.arrayLength = 0;
    848 
    849 		for (;;)
    850 		{
    851 			parseValueElement(result.dataType, result);
    852 			result.arrayLength++;
    853 
    854 			if (m_curToken == TOKEN_RIGHT_BRACKET)
    855 				break;
    856 			else if (m_curToken == TOKEN_VERTICAL_BAR)
    857 			{
    858 				advanceToken();
    859 				continue;
    860 			}
    861 			else
    862 				parseError(string("unexpected token in value element array: " + m_curTokenStr));
    863 		}
    864 
    865 		advanceToken(TOKEN_RIGHT_BRACKET);
    866 	}
    867 	else // arrays, single elements
    868 	{
    869 		parseValueElement(result.dataType, result);
    870 		result.arrayLength = 1;
    871 	}
    872 
    873 	advanceToken(TOKEN_SEMI_COLON); // end of declaration
    874 
    875 	valueBlock.values.push_back(result);
    876 }
    877 
    878 void ShaderParser::parseValueBlock(ShaderCase::ValueBlock& valueBlock)
    879 {
    880 	PARSE_DBG(("    parseValueBlock()\n"));
    881 	advanceToken(TOKEN_VALUES);
    882 	advanceToken(TOKEN_LEFT_BRACE);
    883 
    884 	for (;;)
    885 	{
    886 		if (m_curToken == TOKEN_UNIFORM || m_curToken == TOKEN_INPUT || m_curToken == TOKEN_OUTPUT)
    887 			parseValue(valueBlock);
    888 		else if (m_curToken == TOKEN_RIGHT_BRACE)
    889 			break;
    890 		else
    891 			parseError(string("unexpected token when parsing a value block: " + m_curTokenStr));
    892 	}
    893 
    894 	advanceToken(TOKEN_RIGHT_BRACE);
    895 
    896 	// Compute combined array length of value block.
    897 	int arrayLength = 1;
    898 	for (int valueNdx = 0; valueNdx < (int)valueBlock.values.size(); valueNdx++)
    899 	{
    900 		const ShaderCase::Value& val = valueBlock.values[valueNdx];
    901 		if (val.arrayLength > 1)
    902 		{
    903 			DE_ASSERT(arrayLength == 1 || arrayLength == val.arrayLength);
    904 			arrayLength = val.arrayLength;
    905 		}
    906 	}
    907 	valueBlock.arrayLength = arrayLength;
    908 }
    909 
    910 void ShaderParser::parseShaderCase(vector<tcu::TestNode*>& shaderNodeList)
    911 {
    912 	// Parse 'case'.
    913 	PARSE_DBG(("  parseShaderCase()\n"));
    914 	advanceToken(TOKEN_CASE);
    915 
    916 	// Parse case name.
    917 	string caseName = m_curTokenStr;
    918 	advanceToken(); // \note [pyry] All token types are allowed here.
    919 
    920 	// Setup case.
    921 	vector<ShaderCase::ValueBlock> valueBlockList;
    922 
    923 	GLSLVersion				 version	  = DEFAULT_GLSL_VERSION;
    924 	ShaderCase::ExpectResult expectResult = ShaderCase::EXPECT_PASS;
    925 	string					 description;
    926 	string					 bothSource;
    927 	string					 vertexSource;
    928 	string					 fragmentSource;
    929 
    930 	for (;;)
    931 	{
    932 		if (m_curToken == TOKEN_END)
    933 			break;
    934 		else if (m_curToken == TOKEN_DESC)
    935 		{
    936 			advanceToken();
    937 			assumeToken(TOKEN_STRING);
    938 
    939 			description = parseStringLiteral(m_curTokenStr.c_str());
    940 			advanceToken();
    941 		}
    942 		else if (m_curToken == TOKEN_EXPECT)
    943 		{
    944 			advanceToken();
    945 			assumeToken(TOKEN_IDENTIFIER);
    946 
    947 			if (m_curTokenStr == "pass")
    948 				expectResult = ShaderCase::EXPECT_PASS;
    949 			else if (m_curTokenStr == "compile_fail")
    950 				expectResult = ShaderCase::EXPECT_COMPILE_FAIL;
    951 			else if (m_curTokenStr == "link_fail")
    952 				expectResult = ShaderCase::EXPECT_LINK_FAIL;
    953 			else
    954 				parseError(string("invalid expected result value: " + m_curTokenStr));
    955 
    956 			advanceToken();
    957 		}
    958 		else if (m_curToken == TOKEN_VALUES)
    959 		{
    960 			ShaderCase::ValueBlock block;
    961 			parseValueBlock(block);
    962 			valueBlockList.push_back(block);
    963 		}
    964 		else if (m_curToken == TOKEN_BOTH || m_curToken == TOKEN_VERTEX || m_curToken == TOKEN_FRAGMENT)
    965 		{
    966 			Token token = m_curToken;
    967 			advanceToken();
    968 			assumeToken(TOKEN_SHADER_SOURCE);
    969 			string source = parseShaderSource(m_curTokenStr.c_str());
    970 			advanceToken();
    971 			if (token == TOKEN_BOTH)
    972 				bothSource = source;
    973 			else if (token == TOKEN_VERTEX)
    974 				vertexSource = source;
    975 			else if (token == TOKEN_FRAGMENT)
    976 				fragmentSource = source;
    977 			else
    978 				DE_ASSERT(DE_FALSE);
    979 		}
    980 		else if (m_curToken == TOKEN_VERSION)
    981 		{
    982 			advanceToken();
    983 
    984 			int			versionNum = 0;
    985 			std::string postfix	= "";
    986 
    987 			assumeToken(TOKEN_INT_LITERAL);
    988 			versionNum = parseIntLiteral(m_curTokenStr.c_str());
    989 			advanceToken();
    990 
    991 			if (m_curToken == TOKEN_IDENTIFIER)
    992 			{
    993 				postfix = m_curTokenStr;
    994 				advanceToken();
    995 			}
    996 
    997 			if (versionNum == 100 && postfix == "es")
    998 				version = glu::GLSL_VERSION_100_ES;
    999 			else if (versionNum == 300 && postfix == "es")
   1000 				version = glu::GLSL_VERSION_300_ES;
   1001 			else if (versionNum == 310 && postfix == "es")
   1002 				version = glu::GLSL_VERSION_310_ES;
   1003 			else if (versionNum == 130)
   1004 				version = glu::GLSL_VERSION_130;
   1005 			else if (versionNum == 140)
   1006 				version = glu::GLSL_VERSION_140;
   1007 			else if (versionNum == 150)
   1008 				version = glu::GLSL_VERSION_150;
   1009 			else if (versionNum == 330)
   1010 				version = glu::GLSL_VERSION_330;
   1011 			else if (versionNum == 400)
   1012 				version = glu::GLSL_VERSION_400;
   1013 			else if (versionNum == 410)
   1014 				version = glu::GLSL_VERSION_410;
   1015 			else if (versionNum == 420)
   1016 				version = glu::GLSL_VERSION_420;
   1017 			else if (versionNum == 430)
   1018 				version = glu::GLSL_VERSION_430;
   1019 			else if (versionNum == 440)
   1020 				version = glu::GLSL_VERSION_440;
   1021 			else if (versionNum == 450)
   1022 				version = glu::GLSL_VERSION_450;
   1023 			else
   1024 				parseError("Unknown GLSL version");
   1025 		}
   1026 		else
   1027 			parseError(string("unexpected token while parsing shader case: " + m_curTokenStr));
   1028 	}
   1029 
   1030 	advanceToken(TOKEN_END); // case end
   1031 
   1032 	if (bothSource.length() > 0)
   1033 	{
   1034 		DE_ASSERT(vertexSource.length() == 0);
   1035 		DE_ASSERT(fragmentSource.length() == 0);
   1036 
   1037 		string vertName = caseName + "_vertex";
   1038 		string fragName = caseName + "_fragment";
   1039 		shaderNodeList.push_back(new ShaderCase(m_testCtx, m_renderCtx, vertName.c_str(), description.c_str(),
   1040 												expectResult, valueBlockList, version, bothSource.c_str(), DE_NULL));
   1041 		shaderNodeList.push_back(new ShaderCase(m_testCtx, m_renderCtx, fragName.c_str(), description.c_str(),
   1042 												expectResult, valueBlockList, version, DE_NULL, bothSource.c_str()));
   1043 	}
   1044 	else
   1045 	{
   1046 		shaderNodeList.push_back(new ShaderCase(m_testCtx, m_renderCtx, caseName.c_str(), description.c_str(),
   1047 												expectResult, valueBlockList, version, vertexSource.c_str(),
   1048 												fragmentSource.c_str()));
   1049 	}
   1050 }
   1051 
   1052 void ShaderParser::parseShaderGroup(vector<tcu::TestNode*>& shaderNodeList)
   1053 {
   1054 	// Parse 'case'.
   1055 	PARSE_DBG(("  parseShaderGroup()\n"));
   1056 	advanceToken(TOKEN_GROUP);
   1057 
   1058 	// Parse case name.
   1059 	string name = m_curTokenStr;
   1060 	advanceToken(); // \note [pyry] We don't want to check token type here (for instance to allow "uniform") group.
   1061 
   1062 	// Parse description.
   1063 	assumeToken(TOKEN_STRING);
   1064 	string description = parseStringLiteral(m_curTokenStr.c_str());
   1065 	advanceToken(TOKEN_STRING);
   1066 
   1067 	std::vector<tcu::TestNode*> children;
   1068 
   1069 	// Parse group children.
   1070 	for (;;)
   1071 	{
   1072 		if (m_curToken == TOKEN_END)
   1073 			break;
   1074 		else if (m_curToken == TOKEN_GROUP)
   1075 			parseShaderGroup(children);
   1076 		else if (m_curToken == TOKEN_CASE)
   1077 			parseShaderCase(children);
   1078 		else
   1079 			parseError(string("unexpected token while parsing shader group: " + m_curTokenStr));
   1080 	}
   1081 
   1082 	advanceToken(TOKEN_END); // group end
   1083 
   1084 	// Create group node.
   1085 	tcu::TestCaseGroup* groupNode = new tcu::TestCaseGroup(m_testCtx, name.c_str(), description.c_str(), children);
   1086 	shaderNodeList.push_back(groupNode);
   1087 }
   1088 
   1089 vector<tcu::TestNode*> ShaderParser::parse(const char* input)
   1090 {
   1091 	// Initialize parser.
   1092 	m_input		  = input;
   1093 	m_curPtr	  = m_input.c_str();
   1094 	m_curToken	= TOKEN_INVALID;
   1095 	m_curTokenStr = "";
   1096 	advanceToken();
   1097 
   1098 	vector<tcu::TestNode*> nodeList;
   1099 
   1100 	// Parse all cases.
   1101 	PARSE_DBG(("parse()\n"));
   1102 	for (;;)
   1103 	{
   1104 		if (m_curToken == TOKEN_CASE)
   1105 			parseShaderCase(nodeList);
   1106 		else if (m_curToken == TOKEN_GROUP)
   1107 			parseShaderGroup(nodeList);
   1108 		else if (m_curToken == TOKEN_EOF)
   1109 			break;
   1110 		else
   1111 			parseError(string("invalid token encountered at main level: '") + m_curTokenStr + "'");
   1112 	}
   1113 
   1114 	assumeToken(TOKEN_EOF);
   1115 	//  printf("  parsed %d test cases.\n", caseList.size());
   1116 	return nodeList;
   1117 }
   1118 
   1119 } // sl
   1120 
   1121 ShaderLibrary::ShaderLibrary(tcu::TestContext& testCtx, RenderContext& renderCtx)
   1122 	: m_testCtx(testCtx), m_renderCtx(renderCtx)
   1123 {
   1124 }
   1125 
   1126 ShaderLibrary::~ShaderLibrary(void)
   1127 {
   1128 }
   1129 
   1130 vector<tcu::TestNode*> ShaderLibrary::loadShaderFile(const char* fileName)
   1131 {
   1132 	tcu::Resource*	resource = m_testCtx.getArchive().getResource(fileName);
   1133 	std::vector<char> buf;
   1134 
   1135 	/*  printf("  loading '%s'\n", fileName);*/
   1136 
   1137 	try
   1138 	{
   1139 		int size = resource->getSize();
   1140 		buf.resize(size + 1);
   1141 		resource->read((deUint8*)&buf[0], size);
   1142 		buf[size] = '\0';
   1143 	}
   1144 	catch (const std::exception&)
   1145 	{
   1146 		delete resource;
   1147 		throw;
   1148 	}
   1149 
   1150 	delete resource;
   1151 
   1152 	sl::ShaderParser	   parser(m_testCtx, m_renderCtx);
   1153 	vector<tcu::TestNode*> nodes = parser.parse(&buf[0]);
   1154 
   1155 	return nodes;
   1156 }
   1157 
   1158 // ShaderLibraryGroup
   1159 
   1160 ShaderLibraryGroup::ShaderLibraryGroup(Context& context, const char* name, const char* description,
   1161 									   const char* filename)
   1162 	: TestCaseGroup(context, name, description), m_filename(filename)
   1163 {
   1164 }
   1165 
   1166 ShaderLibraryGroup::~ShaderLibraryGroup(void)
   1167 {
   1168 }
   1169 
   1170 void ShaderLibraryGroup::init(void)
   1171 {
   1172 	deqp::ShaderLibrary			shaderLibrary(m_testCtx, m_context.getRenderContext());
   1173 	std::vector<tcu::TestNode*> children = shaderLibrary.loadShaderFile(m_filename.c_str());
   1174 
   1175 	for (int i = 0; i < (int)children.size(); i++)
   1176 		addChild(children[i]);
   1177 }
   1178 
   1179 } // deqp
   1180