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
41using std::string;
42using std::vector;
43using std::ostringstream;
44
45using 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
53namespace deqp
54{
55namespace gls
56{
57namespace sl
58{
59
60static const glu::GLSLVersion DEFAULT_GLSL_VERSION = glu::GLSL_VERSION_100_ES;
61
62DE_INLINE deBool isWhitespace (char c)
63{
64	return (c == ' ') || (c == '\t') || (c == '\r') || (c == '\n');
65}
66
67DE_INLINE deBool isEOL (char c)
68{
69	return (c == '\r') || (c == '\n');
70}
71
72DE_INLINE deBool isNumeric (char c)
73{
74	return deInRange32(c, '0', '9');
75}
76
77DE_INLINE deBool isAlpha (char c)
78{
79	return deInRange32(c, 'a', 'z') || deInRange32(c, 'A', 'Z');
80}
81
82DE_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!
88class ShaderParser
89{
90public:
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
96private:
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
212ShaderParser::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
222ShaderParser::~ShaderParser (void)
223{
224	// nada
225}
226
227void 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
233float ShaderParser::parseFloatLiteral (const char* str)
234{
235	return (float)atof(str);
236}
237
238int ShaderParser::parseIntLiteral (const char* str)
239{
240	return atoi(str);
241}
242
243string 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
270static 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
315string 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
346void 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
565void ShaderParser::advanceToken (Token assumed)
566{
567	assumeToken(assumed);
568	advanceToken();
569}
570
571void 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
578DataType 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
611const 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
691deUint32 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
707deUint32 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
729void 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
793void 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
867void 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
899deUint32 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
934void 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
1004void 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
1024void 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
1054void 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
1124void 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
1298void 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
1337void 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
1356vector<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
1390static 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
1400ShaderLibrary::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
1407ShaderLibrary::~ShaderLibrary (void)
1408{
1409}
1410
1411vector<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
1440vector<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